考虑以下简单的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 manual第3.5节“Makefile如何重新制作”)。在开始执行makefile之前,尝试更新它可以找到的每个包含的makefile(在本例中为依赖文件main.d
,foo.d
,bar.d
和baz.d
)。我在下图中对此进行了总结:
完全。我没有看到将依赖项文件指定为目标的任何规则。
请帮助我了解接下来会发生什么。请将您的答案写成一个循序渐进的事件链。如果能够深入了解此事,那将是很好的。
注意:
当然,编译命令中的-MMD
和-MP
参数(请参阅中间的模式规则)会导致创建依赖项文件。但是这种模式规则的目标是对象 - 文件,而不是依赖 - 文件。
注意:
我错误地认为GNU make有一个隐式规则在这里被激活。但是由于你的意见和答案,我现在知道这是错的: - )
答案 0 :(得分:1)
.d
个文件没有built-in make
rule。您可以看到make
确实考虑使用.d
重建make -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
会跳过更新规则,请参阅How Makefiles Are Remade:
...在阅读所有makefile后,
make
会将每个作为目标目标并尝试更新它。 如果一个makefile有一条规则说明如何更新它(在那个makefile或另一个中找到),或者隐含规则适用于它,那么它将在必要时更新。
这就是为什么它不会每次.c
编译两次。
您可以使用make --print-data-base
打印所有规则,包括内置插件。
答案 1 :(得分:1)
我会一起回答这两个问题,因为它更有意义。
Make没有.d
的内置规则 - 它不需要一个。 -MMD -MP
指示编译器输出依赖项作为编译的一部分。
如果您考虑它,这正是您想要的,因为您需要更新依赖项文件的唯一时间是相对源文件自身已更改,如果在编译期间生成依赖项,则只需运行编译器一次生成.d
和.o
文件。
拼图的最后一部分是-include
,告诉make如果能找到它们就包含依赖项,但如果它们不存在就不用担心,它们无论如何都会由编译器生成
答案 2 :(得分:1)
在make
之后运行make clean
并且依赖文件尚未存在时会发生什么:
make
读取文本并到达-include
指令。-include
指令make
的每个参数,尝试查找将其作为目标并运行该规则的规则。 make
这是处理-include
指令的一部分。没有找到这样的规则,因为你没有提供这样的规则。make
尝试读取-include
指令中指定的文件,并跳过那些不存在的文件(在这种情况下全部都是这样)。make
用于构建项目,该项目又创建了*.d
个文件。如果再次运行make
:
make
会读取它们。您可能会注意到这意味着make
使用上一次运行的依赖项,这正是它的工作原理。
依赖性滞后于源文件中的更改。
这通常不会造成不便,并且当删除依赖项文件时,可以使用它来修复构建。