make总结(二):进阶
一、管理目录
真实项目会设计合理的目录树结构,提高维护性。利用make中的函数,实现目录管理,将生成的中间文件保存在指定目录中。
假想项目,complicate, 在目录complicate下有main.c foo.c foo.h。执行make自动生成objs bins目录,并将目标文件存于objs,可执行文件存于bins
1 .PHONY: all 2 3 MKDIR=mkdir 4 5 RM=rm 6 RMFLAGS=-rf 7 8 CC=gcc 9 10 DIR_OBJS=objs 11 DIR_BINS=bins 12 DIRS=$(DIR_OBJS) $(DIR_BINS) 13 BIN=complicate 14 BIN:=$(addprefix $(DIR_BINS)/, $(BIN)) 15 SRC=$(wildcard *.c) 16 OBJ=$(SRC:.c=.o) 17 OBJ:=$(addprefix $(DIR_OBJS)/, $(OBJ)) 18 19 20 all:$(DIRS) $(BIN) 21 22 $(DIRS): 23 $(MKDIR) $@ 24 25 $(BIN):$(OBJ) 26 $(CC) -o $@ $^ 27 28 $(DIR_OBJS)/%.o: %.c 29 $(CC) -c -o $@ $^ 30 31 clean: 32 $(RM) $(RMFLAGS) $(DIRS) $(BIN)
二、自动管理文件依赖关系
上面的Makefile在foo.h头文件改变后,并不能重新构建。直接在规则中添加foo.h依赖不灵活,项目比较大时很麻烦。make可以利用gcc自动获得一个文件的依赖列表。
gcc的-MM选项得到源文件的依赖,将其用于在makefile中,自动构建项目中的依赖关系。
1. 通过gcc和sed将依赖关系存于文件中,在makefile中用include包含这些文件。
2. include包含时的动作:在当前目录和其他一些默认目录中找不到要包含的文件时,make先打印warning,并试图通过使用规则创建未找到的文件,当不能创建时将出错并退出。
1 .PHONY: all 2 3 MKDIR=mkdir 4 5 RM=rm 6 RMFLAGS=-rf 7 8 CC=gcc 9 10 DIR_OBJS=objs 11 DIR_BINS=bins 12 DIR_DEPS=deps 13 DIRS=$(DIR_OBJS) $(DIR_BINS) $(DIR_DEPS) 14 15 BIN=complicate 16 BIN:=$(addprefix $(DIR_BINS)/, $(BIN)) 17 18 SRC=$(wildcard *.c) 19 OBJ=$(SRC:.c=.o) 20 OBJ:=$(addprefix $(DIR_OBJS)/, $(OBJ)) 21 DEP=$(SRC:.c=.dep) 22 DEP:=$(addprefix $(DIR_DEPS)/, $(DEP)) 23 24 ifeq ("$(wildcard $(DIR_OBJS))", "") 25 DEP_DIR_OBJS := $(DIR_OBJS) 26 endif 27 28 ifeq ("$(wildcard $(DIR_BINS))", "") 29 DEP_DIR_BINS := $(DIR_BINS) 30 endif 31 32 ifeq ("$(wildcard $(DIR_DEPS))", "") 33 DEP_DIR_DEPS := $(DIR_DEPS) 34 endif 35 36 all: $(BIN) 37 38 39 ifneq ("$(MAKECMDGOALS)", "clean") 40 include $(DEP) 41 endif 42 43 $(DIRS): 44 $(MKDIR) $@ 45 46 $(BIN): $(DEP_DIR_BINS) $(OBJ) 47 $(CC) -o $@ $(filter %.o, $^) 48 49 $(DIR_OBJS)/%.o: $(DEP_DIR_OBJS) %.c 50 $(CC) -c -o $@ $(filter %.c, $^) 51 52 $(DIR_DEPS)/%.dep: $(DEP_DIR_DEPS) %.c 53 @echo "Creating $@ ..." 54 @set -e; \ 55 $(RM) $(RMFLAGS) $@.tmp; \ 56 $(CC) -E -MM $(filter %.c, $^) > $@.tmp; \ 57 sed 's,\(.*\)\.o[ :]*,objs/\1.o $@: ,g' < $@.tmp > $@; \ 58 $(RM) $(RMFLAGS) $@.tmp 59 60 clean: 61 $(RM) $(RMFLAGS) $(DIRS) 62
3. 上面的makefile中用到条件语句,ifeq, ifneq, ifdef, ifndef。使用时注意这些指令和要判断的表达式之间要有空格。
4. 在生成依赖关系时,将依赖文件也作为规则的目标,这样规则中的依赖有任何改变,make都会去重新构建项目的依赖关系,确保依赖关系是最新的。
举例:项目中新增加任意文件,只要现有文件使用了新增加的文件都会更新.dep文件。
否则的话,如果某个目标的依赖改变,而恰好此依赖不在生成.dep目标的规则的依赖中[一般是头文件],那么依赖关系就会得不到更新。
5. include依赖关系后,.dep文件只有依赖,没有命令, makefile会将同一目标的不同规则合并。合并的内容包括先决条件和命令。
浙公网安备 33010602011771号