多规则目标与自动产生依赖
Makefile
中,一个文件可以作为多个规则的目标(多个规则中只能有一个规则定义命令)。这种情况时,以这个文件为目标的规则的所有依赖文件将会被合并成此目标一个依赖文件列表,当其中任何一个依赖文件比目标更新时,
make
将会执行特定的命令来重建这个目标。
利用这一特性,我们可以将
gcc
自动产生的依赖关系集成到
Makefile
中。
第一步,生成依赖文件的规则:
%.d: %.c
rm -f $@.$$$$
此规则的含义是:所有的
.d
文件依赖于同名的
.c
文件。
第一行
,
使用
c
编译器自自动生成依赖文件(
$<
)的头文件的依赖关系,并输出成为一个临时文件,
“$$$$”
表示当前进程号。如果
$(CC)
为
GNU
的
c
编译工具,产生的依赖关系的规则中,依赖头文件包括了所有的使用的系统头文件和用户定义的头文件。如果需要生成的依赖描述文件不包含系统头文件,可使用
“-MM”
代替
“-M”
。
第二行
,
使用
sed
处理第二行已产生的那个临时文件并生成此规则的目标文件。这里
sed
完成了如下的转换过程。例如对已一个
.c
源文件。将编译器产生的依赖关系:
main.o : main.c defs.h
转成:
main.o main.d : main.c defs.h
这样就将
.d
加入到了规则的目标中,其和对应的
.o
文件文件一样依赖于对应的
.c
源文件和源文件所包含的头文件。当
.c
源文件或者头文件被改变之后规则将会被执行,相应的
.d
文件同样会被更新。
第三行
,
删除临时文件。
第二步,将依赖文件包含进Makefile中,可以参考如下命令:
sources = foo.c bar.c
-include $(sources:.c=.d)
需要注意的是,
-include
命令应该放在
Makefile
中第一个目标之后。
第三步,为每一个目标文件(.o文件)创建一条带编译命令的规则,比如:
%.o: %.cpp
@$(CXX) $< -o $@
由于该规则就和第一步中产生的规则具有相同的目标,所以这两条规则被合并为一条规则,即.o文件依赖于对应的.cpp文件以及相关的.h文件
在我们的项目中,还使用了另外一种方法:
$(TMPDIR)/%.o: %.cpp
@echo Creating object file for $*...
@$(CXX) -Wp,-MMD,$(TMPDIR)/$*.dd $(CXXFLAGS) $(DEBUG_OPT) $(foreach INC,$(INCLUDES),-I$(INC))/
$(foreach MACRO,$(BUILD_DEFINES),-D$(MACRO)) -c $< -o $@
@sed -e '1s/^/(.*/)$$/$(subst /,//,$(dir $@))/1/' $(TMPDIR)/$*.dd > $(TMPDIR)/$*.d
@rm -f $(TMPDIR)/$*.dd
其中sed命令的作用是在目标文件名前面加上集中存放目标文件的文件夹的名字。
然后将产生的.d文件包含中Makefile中。
当第一次执行make时,.d文件还没有生成,这时会按规则指定的命令将每个cpp文件编译成对应的.o文件,并同时生成.d文件。
之后,当.cpp文件及相关的.h文件有更新时,会重新生成相应的.o文件和.d文件。
该方法比第一种方法更简单。