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

 二、自动管理文件依赖关系

  上面的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     
Makefile

  3. 上面的makefile中用到条件语句,ifeq, ifneq, ifdef, ifndef。使用时注意这些指令和要判断的表达式之间要有空格。

  4. 在生成依赖关系时,将依赖文件也作为规则的目标,这样规则中的依赖有任何改变,make都会去重新构建项目的依赖关系,确保依赖关系是最新的。

          举例:项目中新增加任意文件,只要现有文件使用了新增加的文件都会更新.dep文件。

    否则的话,如果某个目标的依赖改变,而恰好此依赖不在生成.dep目标的规则的依赖中[一般是头文件],那么依赖关系就会得不到更新。

  5. include依赖关系后,.dep文件只有依赖,没有命令, makefile会将同一目标的不同规则合并。合并的内容包括先决条件和命令。

posted on 2015-12-31 16:20  pdsrazor  阅读(176)  评论(0)    收藏  举报

导航