我有一个Makefile生成 a 的文件makefile.mk,它随后包含在主 makefile 中。因为输入文件集(*.in在本例中)可以随时更改,所以我需要makefile.mk为每个文件重新生成一次make运行重新生成一次。
文档指出include:
\n\n\n\n\n一旦完成读取 makefile,make 将尝试重新生成任何已过期或不存在的 [included makefile]。
\n
\n\n\n[A]读入所有 makefile 后,make 会将每个 makefile 视为目标并尝试更新它。如果 makefile 有一条规则说明如何更新它 [...],则如有必要,它将被更新。检查完所有 makefile 后,如果确实有任何更改,make 将从头开始并重新读取所有 makefile。
\n
基于此,我认为以下应该有效:
\n\ninclude 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 ---"\nRun Code Online (Sandbox Code Playgroud)\n\n(我知道我可以在这个简单的示例中使用模式规则和通配符。在实际情况中,makefile.mk具有更复杂的依赖关系并且由 Python 脚本生成。)
因此,我们将其放入一个空目录中并运行它:
\n\n$ ls\nMakefile\n$ make\n--- Begin makefile.mk ---\nall:\n--- End makefile.mk ---\nmake: Nothing to be done for \'all\'.\nRun 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\'.\nRun Code Online (Sandbox Code Playgroud)\n\n因为makefile.mk没有依赖关系,所以不会更新。坏的!通过将其标记为虚假来强制它始终被视为过时怎么样:
.PHONY: makefile.mk\nRun Code Online (Sandbox Code Playgroud)\n\n添加此行后,确实makefile.mk正在重新生成:
$ 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\'.\nRun Code Online (Sandbox Code Playgroud)\n\n然而,它似乎没有被重新阅读,因为make声称all即使它的先决条件test.out不存在,也没有什么可做的。
make第二次运行会做正确的事情:
$ make\n--- Begin makefile.mk ---\nall: test.out\ntest.out: test.in\n cp $< $@\n--- End makefile.mk ---\ncp test.in test.out\nRun Code Online (Sandbox Code Playgroud)\n\n为什么不make重新启动并读取更新的makefile.mk,正如文档似乎承诺的那样?
我找到了这个相关的答案,这表明这.PHONY是罪魁祸首,并提供了这样的解决方案:
makefile.mk: force\n ...\n\n.PHONY: force\nforce:\nRun Code Online (Sandbox Code Playgroud)\n\n然而,如果我尝试这样做,make就会陷入无限循环,makefile.mk一遍又一遍地重新制作。
我看到有两种方法可以解决这个问题:
\n\n对生成的 makefile 使用唯一的后缀,以便在运行 make 时它永远不会存在,例如:
\n\nUNIQUE := $(shell date +%s.%N)\ninclude makefile.mk.$(UNIQUE)\nmakefile.mk.$(UNIQUE): [\xe2\x80\xa6]\nRun Code Online (Sandbox Code Playgroud)makefile.mk像以前一样使用 )生成force,但使其包含(以及 makefile 的其他部分)以某些 make 变量为条件,以便默认情况下不执行。makefile.mk按相反条件保存配方。然后使用此变量递归调用 make 以激活包含并禁用重建规则。Thomas 编辑:使用内置MAKE_RESTARTS变量可以非常有效地解决无限循环。
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\nRun Code Online (Sandbox Code Playgroud)\n