[英]What is the exact chain of events when GNU make updates the .d files?
考虑以下简单的makefile:
#------------------------------#
# List all object files #
#------------------------------#
objects := main.o foo.o bar.o baz.o
#------------------------------#
# Define pattern rule #
# for *.c -> *.o #
#------------------------------#
%.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
#------------------------------#
# Define the rule to make #
# the end result #
#------------------------------#
.PHONY all
all: myApp.elf
myApp.elf: $(objects)
$(CC) $(objects) -o myApp.elf $(LFLAGS) $(LIBS)
如果您给出命令make all
,那么GNU make将从目标myApp.elf
开始。 它着眼于所有先决条件main.o
, foo.o
, bar.o
和baz.o
并试图对其进行更新。
为此,make使用在makefile中间定义的模式规则。 该模式规则扩展如下:
main.o: main.c
$(CC) -c $(CFLAGS) main.c -o main.o
foo.o: foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o: bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o
baz.o: baz.c
$(CC) -c $(CFLAGS) baz.c -o baz.o
到现在为止还挺好。 但是您可以清楚地看到缺少依赖项(包括的h文件)。
我找到了一些建议采用以下方法的资源:
#------------------------------#
# List all object files #
# and all dependency files #
#------------------------------#
objects := main.o foo.o bar.o baz.o
deps := $(objects:.o=.d)
#------------------------------#
# Define pattern rule #
# for *.c -> *.o #
#------------------------------#
%.o: %.c
$(CC) -c $(CFLAGS) -MMD -MP $< -o $@
#------------------------------#
# Define the rule to make #
# the end result #
#------------------------------#
.PHONY all
all: myApp.elf
myApp.elf: $(objects)
$(CC) $(objects) -o myApp.elf $(LFLAGS) $(LIBS)
-include $(deps)
我正在尝试把这种方法包住头。 首先,GNU make读取makefile并查找其他包含的makefile(请参阅GNU make手册第3.5节“如何重新制作Makefile”)。 在开始执行makefile之前,尝试更新它可以找到的每个包含的makefile(在本例中为依赖文件main.d
, foo.d
, bar.d
和baz.d
)。 我在下图中总结了这一点:
究竟。 我没有看到任何将依赖文件指定为目标的规则。
请帮助我了解接下来会发生什么。 请把您的答案写成一个循序渐进的事件链。 这将是获得有关此事的见识的好方法。
注意:
当然,编译命令中的-MMD
和-MP
参数(请参阅中间的模式规则)导致创建依赖文件。 但是此模式规则的目标是对象文件,而不是依赖文件。
注意:
我错误地认为GNU make具有在此处被激活的隐式规则。 但是感谢您的评论和回答,我现在知道这是错误的:-)
没有内置的make
规则为.d
文件。 您可以看到make
确实考虑使用make -d
重建.d
文件,但是没有规则,例如:
Reading makefile 'test/debug/library.d' (search path) (don't care) (no ~ expansion)...
Updating makefiles....
Considering target file 'test/debug/library.d'.
File 'test/debug/library.d' does not exist.
Looking for an implicit rule for 'test/debug/library.d'.
No implicit rule found for 'test/debug/library.d'.
Finished prerequisites of target file 'test/debug/library.d'.
Must remake target 'test/debug/library.d'.
Failed to remake target file 'test/debug/library.d'.
在上面的输出make
检查是否library.d
需要更新。 未能找到它的规则, make
跳过更新它,看到的Makefile如何都经过了重组 :
...读完所有makefile文件后,
make
会将每个文件视为目标目标并尝试对其进行更新。 如果一个makefile有一条规则说明如何更新它(在那个makefile或另一个makefile中找到),或者如果一个隐式规则适用于它,则必要时将对其进行更新 。
这就是为什么它不会两次编译每个.c
。
您可以使用make --print-data-base
打印所有规则,包括内置规则。
我将同时回答两个问题,因为这样做更有意义。
Make没有.d
内置规则-它不需要一个。 -MMD -MP
指示编译器输出依赖项,作为适当的编译的一部分。
如果您考虑到了这正是您想要的,因为唯一需要更新依赖项的就是相关源文件本身已经更改,如果在编译过程中生成了依赖项,则只需运行一次编译器即可生成依赖项.d
和.o
文件。
难题的最后一部分是-include
,它告诉make如果可以找到依赖项,则包含make依赖关系,但不必担心它们是否不存在,它们还是会由编译器生成。
在make clean
和依赖文件尚不存在之后运行make
, make clean
发生以下情况:
make
读取文本并到达-include
指令。 -include
指令make
试图找到具有它作为一个目标的规则和运行规则。 make
在-include
指令的处理过程中执行此操作。 找不到这样的规则,因为您没有提供。 make
试图读取指定的文件-include
指令,并只是跳过那些不存在的(所有的人在这种情况下)。 make
开始构建项目,该项目又创建了*.d
文件。 如果再次运行make
:
make
读取它们。 您可能会注意到,这意味着make
使用上一次运行的依赖关系,而这正是它的工作方式。 依赖关系落后于源文件中的更改。 但是,这通常不会带来任何不便,并且当确实删除依赖项文件时,可以用来修复构建。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.