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" 是什么意思?