make -B 始终为 shell 任务打印 "is up to date"

make -B always prints "is up to date" for a shell task

考虑这个 Makefile

test.txt: foo.bar
        $(shell grep ^hello $< >$@)

要测试它,需要创建一个文件 foo.bar 包含,例如,

hello
hello 2

make 总是打印

make: 'test.txt' is up to date.

即使文件 test.txt 不存在,也会发生这种情况。在这种情况下,make 可以正确运行并创建 test.txt,但仍会打印上述消息。即使使用 make -B 也会给出相同的信息。

我正在使用 GNU Make 4.2.1。

为什么会出现这种行为?

发生这种情况是因为它实际上是一个空的食谱,所以 运行 没有任何内容。

$(shell) 函数根据 Makefile 配方解析进行评估,其输出被视为配方内容。碰巧这个语句生成了一个输出文件作为副产品,但是语句的输出是空的,因此 make 没有任何关系并得出 target 是最新的结论。事实上,如果食谱结果是空的,它总是会这样说:

$ ls
Makefile  foo.bar
$ cat Makefile
test.txt: foo.bar
        $(info Making $@ from $<)
$ make
Making test.txt from foo.bar
make: 'test.txt' is up to date.
$ ls
Makefile  foo.bar

请注意,上面的示例没有创建 test.txtmake 只是得出结论,运行 更新它的(空)配方,所以现在它是最新的。

为了 运行 它正确,你应该完全放弃 $(shell) 功能。 make 的食谱已在 shell:

中调用
$ cat Makefile
test.txt: foo.bar
        grep ^hello $< >$@
$ make
grep ^hello foo.bar >test.txt
$ make
make: 'test.txt' is up to date.
$ make -B
grep ^hello foo.bar >test.txt
$ ls
Makefile  foo.bar  test.txt