如何强制 make 始终更新并重新读取包含的 makefile?

Tho*_*mas 5 makefile gnu-make

我有一个Makefile生成 a 的文件makefile.mk,它随后包含在主 makefile 中。因为输入文件集(*.in在本例中)可以随时更改,所以我需要makefile.mk为每个文件重新生成一次make运行重新生成一次。

\n\n

文档指出include

\n\n
\n

一旦完成读取 makefile,make 将尝试重新生成任何已过期或不存在的 [included makefile]。

\n
\n\n

以及如何重新制作 Makefile

\n\n
\n

[A]读入所有 makefile 后,make 会将每个 makefile 视为目标并尝试更新它。如果 makefile 有一条规则说明如何更新它 [...],则如有必要,它将被更新。检查完所有 makefile 后,如果确实有任何更改,make 将从头开始并重新读取所有 makefile。

\n
\n\n

基于此,我认为以下应该有效:

\n\n
include makefile.mk\n\nmakefile.mk:\n    echo "--- Begin makefile.mk ---"\n    @( \\\n        shopt -q -s nullglob; \\\n        INPUTS=(*.in); \\\n        echo "all:" $${INPUTS//.in/.out}; \\\n        for f in $$INPUTS; do \\\n            echo "$${f/.in/.out}: $$f"; \\\n            echo -e \'\\tcp $$< $$@\'; \\\n        done \\\n    ) | tee $@\n    echo "--- End makefile.mk ---"\n
Run Code Online (Sandbox Code Playgroud)\n\n

(我知道我可以在这个简单的示例中使用模式规则和通配符。在实际情况中,makefile.mk具有更复杂的依赖关系并且由 Python 脚本生成。)

\n\n

因此,我们将其放入一个空目录中并运行它:

\n\n
$ ls\nMakefile\n$ make\n--- Begin makefile.mk ---\nall:\n--- End makefile.mk ---\nmake: Nothing to be done for \'all\'.\n
Run Code Online (Sandbox Code Playgroud)\n\n

到目前为止,一切都很好。如果我们创建一个输入文件会发生什么?

\n\n
$ touch test.in\n$ ls\nMakefile  makefile.mk  test.in\n$ make\nmake: Nothing to be done for \'all\'.\n
Run Code Online (Sandbox Code Playgroud)\n\n

因为makefile.mk没有依赖关系,所以不会更新。坏的!通过将其标记为虚假来强制它始终被视为过时怎么样:

\n\n
.PHONY: makefile.mk\n
Run Code Online (Sandbox Code Playgroud)\n\n

添加此行后,确实makefile.mk正在重新生成:

\n\n
$ make\n--- Begin makefile.mk ---\nall: test.out\ntest.out: test.in\n    cp $< $@\n--- End makefile.mk ---\nmake: Nothing to be done for \'all\'.\n
Run Code Online (Sandbox Code Playgroud)\n\n

然而,它似乎没有被重新阅读,因为make声称all即使它的先决条件test.out不存在,也没有什么可做的。

\n\n

make第二次运行会做正确的事情:

\n\n
$ make\n--- Begin makefile.mk ---\nall: test.out\ntest.out: test.in\n    cp $< $@\n--- End makefile.mk ---\ncp test.in test.out\n
Run Code Online (Sandbox Code Playgroud)\n\n

为什么不make重新启动并读取更新的makefile.mk,正如文档似乎承诺的那样?

\n\n

我找到了这个相关的答案,这表明这.PHONY是罪魁祸首,并提供了这样的解决方案:

\n\n
makefile.mk: force\n    ...\n\n.PHONY: force\nforce:\n
Run Code Online (Sandbox Code Playgroud)\n\n

然而,如果我尝试这样做,make就会陷入无限循环,makefile.mk一遍又一遍地重新制作。

\n

Flo*_*mer 3

我看到有两种方法可以解决这个问题:

\n\n
    \n
  • 对生成的 makefile 使用唯一的后缀,以便在运行 make 时它永远不会存在,例如:

    \n\n
    UNIQUE := $(shell date +%s.%N)\ninclude makefile.mk.$(UNIQUE)\nmakefile.mk.$(UNIQUE): [\xe2\x80\xa6]\n
    Run Code Online (Sandbox Code Playgroud)
  • \n
  • makefile.mk像以前一样使用 )生成force,但使其包含(以及 makefile 的其他部分)以某些 make 变量为条件,以便默认情况下不执行。makefile.mk按相反条件保存配方。然后使用此变量递归调用 make 以激活包含并禁用重建规则。
  • \n
\n\n
\n\n

Thomas 编辑:使用内置MAKE_RESTARTS变量可以非常有效地解决无限循环。

\n\n
include makefile.mk\n\nifndef MAKE_RESTARTS\nmakefile.mk: .FORCE\n    @( \\\n        shopt -q -s nullglob; \\\n        INPUTS=(*.in); \\\n        echo "all:" $${INPUTS//.in/.out}; \\\n        for f in $$INPUTS; do \\\n            echo "$${f/.in/.out}: $$f"; \\\n            echo -e \'\\tcp $$< $$@\'; \\\n        done \\\n    ) | tee $@\n\n.PHONY: .FORCE\n.FORCE:\nendif\n
Run Code Online (Sandbox Code Playgroud)\n