在大型项目中,源文件的更改尤其是头文件的增删会导致makefile文件需要修改,手动修改是不切实际的,于是可以使用自动生成依赖性。
大多数的C/C++编译器都支持一个“-M”的选项,即自动找寻源文件中包含的头文件,并生成一个依赖关系,如下:
cc -M main.c命令会输出这样格式的内容:
main.o : main.c defs.hGNU的C/C++编译器需要使用-MM而不是-M因为-M参数会把一些标准库的头文件也包含进来。
为了让make可以自动更新依赖关系并生成文件,可以为每一个name.c的文件都生成一个name.d的Makefile文件,.d文件中就存放对应的.c文件的依赖关系。
书中在讲自动生成依赖性的时候对于以下这段生成.d文件的模式规则解释比较模糊,我在搜索网上的解释之后结合书中的内容尝试给出自己的理解。
%.d: %.c
@set -e; rm -f $@
$(CC) -M $(CPPFLAGS) $< > $@.$$$$
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@
rm -f $@.$$$$第一行中,$@代表make的目标(target),即%.d文件,整体是在删除所有.d文件,因为在进行更新依赖关系时要先把旧有的文件删除。
第二行中,$@.代表名为“%.d.四位随机数”的文件,就是四位随机数的意思,比如2597,整行是在用c语言编译器生成$<(即第一个依赖文件%.c)文件的依赖关系。
第三行整体运用了sed命令对$@.的内容进行替换,并输出到$@文件中,其中引号中的内容意思如下:
首先整体上是在用sed的s命令对文件中的内容进行替换,并用“,”作为分隔符,猜测是为了避免正斜杠和反斜杠容易混淆。第一对逗号之间的内容是用正则表达式匹配文件中的字符串,其中$*表示匹配除文件后缀以外的所有文件名,\.o表示匹配以.o为后缀的文件,[ :]表示匹配空格和冒号,最后的*表示对前面的内容整体多次匹配,这里本质上就是在匹配像前面编译器输出的内容中的main.o :这样的部分。然后第二个逗号与第三个逗号之间的内容表示要替换的格式,这里的“\1”表示前面写过的$*这一部分,考虑到正则表达式中小括号中的部分表示可以获取供以后使用的子表达式,我猜测前面的(和)其实就是表示正则表达式中的小括号,可能由于一些其他原因不能直接被识别为正则表达式的内容,需要转义后才能用。接着是$@ :即在main.o后加上空格%.d空格冒号空格这部分内容,用例子直观的看就是使main.o :变成main.o main.d :。
第四行是已经完成.d文件的生成,删除$@.
