%.d: %.c
@set -e; rm -f $@; \
$(CC) -MM $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
sinclude $(SOURCES:.c=.d)
上面是我在某人的博客上看到的,但它没有解释代码如何在makefile中创建.c和.h文件之间的依赖关系。
有人会为我解释或提供一些材料吗?
我非常感谢您的帮助!谢谢!
答案 0 :(得分:3)
-M
Instead of outputting the result of preprocessing, output a rule suitable for make describing the dependencies of the main source file. ...
-MM
Like -M but do not mention header files that are found in system header directories, ...
所以这里的命令:
$(CC) -MM $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
使用gcc -MM
输出创建一个临时的($ @。$$$$,即目标文件名附加一个唯一编号)文件并使用sed格式,以便当makefile包含时,依赖文件看起来像target file: [gcc generated dependencies]
。然后删除原始gcc -MM
输出。
答案 1 :(得分:0)
#include
的实际跟踪由预处理器执行(参见-M
and -MM
options)。
-M
输出适用于描述主源文件依赖关系的
make
的规则,而不是输出预处理的结果。预处理器输出一个make
规则,其中包含该源文件的目标文件名,冒号以及所有包含文件的名称,包括来自-include
或-imacros
命令行选项的文件
-MM
与
-M
类似,但不提及在系统头目录中找到的头文件,也不提及直接或间接包含在此头文件中的头文件。
另外,我们可以很好地了解跟踪这些类型依赖关系的可能方法here。
答案 2 :(得分:0)
假设您唯一的新源文件是foo.c
,其中包含
#include "foo.h"
#include "bar.h"
Make确定foo.d
已过期(因为它不存在或foo.c较新),因此它会执行规则。
%.d: %.c
@set -e; rm -f $@; \
$(CC) -MM $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
sinclude $(SOURCES:.c=.d)
Make将$$$$
评估为$$
并将其传递给shell; shell将此解释为$
参数的值,该参数是shell的进程ID,规则要用于构造唯一的文件名。这将仅在一个命令中保持不变,这就是使用行连续符(“\”)写入规则的原因。这不是一个很好的方法;如果有不同的进程试图同时建立foo.d
,你可能无论如何都要被冲洗。所以我们可以改写规则:
%.d: %.c
@set -e; rm -f $@
$(CC) -MM $< > $@.temp
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.temp > $@
rm -f $@.temp
sinclude $(SOURCES:.c=.d)
我们可以免除第一条规则,但它并没有真正解决这个问题。
第二个命令$(CC) -MM $< > $@.temp
扩展为gcc -MM foo.c > foo.d.temp
(或其他一些编译器)。 -MM
标志告诉编译器生成依赖项列表:
foo.o: foo.c foo.h bar.h
下一行用sed
来清理这个列表sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g'
大致翻译为“将foo.o:
更改为foo.o foo.d :
”:
foo.o foo.d : foo.c foo.h bar.h
(最后一个命令删除临时文件。)
这不是处理依赖项的最佳方法,因为它会在每次运行Make时重建所有%.d
个文件,即使是与您无关的目标也是如此。更加精致的方法是Advanced Auto-Dependency Generation。
答案 3 :(得分:0)
对于所有带有四个美元符号的gobbledegook等,这个想法很简单:
xyz.d
创建文件xyz.c
,请运行显示的命令... $(CC)
行可能应该包含$(CFLAGS),但它假定编译器是GCC(-MM
选项在其他地方不是标准的)。 -MM
标志请求编译器生成列出源中包含的标头(或其他文件)的输出,以便您获得当前平台的正确依赖关系信息。$@.$$$$
的扩展是(例如)shell中的xyz.$$
,其中$$
成为运行脚本的shell的PID。sed
命令对编译器的输出进行清除,以便以xyz.o
开头的行开始xyz.o xyz
(因此目标文件和从目标文件创建的程序都是取决于冒号之后的文件xyz.o xyz.d
,因此如果任何源文件或头文件发生变化,则需要更新目标文件和依赖文件。xyz.d
。sinclude
行会尽可能多地读取.d
个文件。[已编辑以修复Beta指出的差异。]