Makefile 每隔一段时间忽略一次依赖
Makefile ignores dependency every other time
我希望我的 Makefile 执行以下操作:
- 当主目标需要某个文件时总是运行一些命令
- 如果文件发生变化(运行执行这些命令),则重建依赖于该文件的所有内容
在我的例子中,这个文件是一个 C-header 文件,应该包含 version-information;我希望 makefile 始终更新此 version-header 并重建包含它的所有文件。
发生了什么:
当我 运行 make 时,每次都会执行 version-header 更新(如我所愿)。
但是依赖于此 header 的文件仅每隔一次重建一次。
这是我精简的 Makefile:
SOURCES:= main.c
app.exe: $(SOURCES:%.c=%.o)
gcc -o $@ $^
# always recompile when dependency information is missing
$(SOURCES:%.c=%.o): %.o: %.c %.d
gcc -c $< -MMD
$(SOURCES:%.c=%.d):
version.h: update-version
update-version:
touch version.h
# include C/C++ header-dependencies
-include $(SOURCES:%.c=%.d)
.PHONY: update-version
# disables builtin suffix-rules
.SUFFIXES:
谁能帮我理解为什么这不是每次都重新编译,而是每隔一次才重新编译?
make
是 GNU Make 4.2.1,remake
的行为完全相同。
此 excerpt from make
's manual 阐明了为什么您的 makefile
没有按照您预期的方式工作:
GNU make does its work in two distinct phases. During the first phase
it reads all the makefiles, included makefiles, etc. and internalizes
all the variables and their values, implicit and explicit rules, and
constructs a dependency graph of all the targets and their
prerequisites. During the second phase, make uses these internal
structures to determine what targets will need to be rebuilt and to
invoke the rules necessary to do so.
由于您在规则内执行命令(touch
,在您的示例中),make
将在第二阶段执行它。但到那时,依赖图和过时的目标已经确定;这在第一阶段已经发生了。
考虑到这一点,您就会明白为什么它每隔一段时间都有效。您想要的命令 确实 每次都会执行,但是 main.o
只有在文件 version.h
已经比 main.o
更新时才被认为是过时的第一阶段,即在任何规则被执行之前。因此,基本上 main.o
只有在您调用 make
命令时早于 version.h
时才会被视为过时。如果上次调用 make
.
时未重新编译 main.o
就是这种情况
每次都可以及时执行命令的一个技巧是在开始的某处添加一个虚拟变量,并让它在评估期间执行您想要的命令。再次以 touch
作为示例命令,你会在第一行做这样的事情:
DUMMY := $(shell touch version.h)
由于这是立即分配,因此命令将在第一阶段执行。如果该命令更新 version.h
,则所有依赖于 version.h
的目标都将被视为已过时并重建。这包括 main.o
.
使用这种方法,您不再需要任何 .PHONY: update-version
机制及其关联的规则和方法。
更新
重读,我发现你写了:"Always run some commands when a certain file is required by the main target"。你是什么意思?再往下,您写了 "When I run make, the version-header update is performed every time (like I want)" - 这就是此答案产生的 makefile
的作用。你能澄清一下吗? "main target" 是什么意思?
我希望我的 Makefile 执行以下操作:
- 当主目标需要某个文件时总是运行一些命令
- 如果文件发生变化(运行执行这些命令),则重建依赖于该文件的所有内容
在我的例子中,这个文件是一个 C-header 文件,应该包含 version-information;我希望 makefile 始终更新此 version-header 并重建包含它的所有文件。
发生了什么: 当我 运行 make 时,每次都会执行 version-header 更新(如我所愿)。 但是依赖于此 header 的文件仅每隔一次重建一次。
这是我精简的 Makefile:
SOURCES:= main.c
app.exe: $(SOURCES:%.c=%.o)
gcc -o $@ $^
# always recompile when dependency information is missing
$(SOURCES:%.c=%.o): %.o: %.c %.d
gcc -c $< -MMD
$(SOURCES:%.c=%.d):
version.h: update-version
update-version:
touch version.h
# include C/C++ header-dependencies
-include $(SOURCES:%.c=%.d)
.PHONY: update-version
# disables builtin suffix-rules
.SUFFIXES:
谁能帮我理解为什么这不是每次都重新编译,而是每隔一次才重新编译?
make
是 GNU Make 4.2.1,remake
的行为完全相同。
此 excerpt from make
's manual 阐明了为什么您的 makefile
没有按照您预期的方式工作:
GNU make does its work in two distinct phases. During the first phase it reads all the makefiles, included makefiles, etc. and internalizes all the variables and their values, implicit and explicit rules, and constructs a dependency graph of all the targets and their prerequisites. During the second phase, make uses these internal structures to determine what targets will need to be rebuilt and to invoke the rules necessary to do so.
由于您在规则内执行命令(touch
,在您的示例中),make
将在第二阶段执行它。但到那时,依赖图和过时的目标已经确定;这在第一阶段已经发生了。
考虑到这一点,您就会明白为什么它每隔一段时间都有效。您想要的命令 确实 每次都会执行,但是 main.o
只有在文件 version.h
已经比 main.o
更新时才被认为是过时的第一阶段,即在任何规则被执行之前。因此,基本上 main.o
只有在您调用 make
命令时早于 version.h
时才会被视为过时。如果上次调用 make
.
main.o
就是这种情况
每次都可以及时执行命令的一个技巧是在开始的某处添加一个虚拟变量,并让它在评估期间执行您想要的命令。再次以 touch
作为示例命令,你会在第一行做这样的事情:
DUMMY := $(shell touch version.h)
由于这是立即分配,因此命令将在第一阶段执行。如果该命令更新 version.h
,则所有依赖于 version.h
的目标都将被视为已过时并重建。这包括 main.o
.
使用这种方法,您不再需要任何 .PHONY: update-version
机制及其关联的规则和方法。
更新
重读,我发现你写了:"Always run some commands when a certain file is required by the main target"。你是什么意思?再往下,您写了 "When I run make, the version-header update is performed every time (like I want)" - 这就是此答案产生的 makefile
的作用。你能澄清一下吗? "main target" 是什么意思?