在GNU-Make手册中,如何制作读取制作文件 https://www.gnu.org/software/make/manual/make.html#Reading-Makefiles部分说
GNU make在两个不同的阶段完成它的工作.在第一阶段,它读取所有makefile,包括makefile等,并内化所有变量及其值,隐式和显式规则,并构建所有目标及其先决条件的依赖关系图.在第二阶段,make使用这些内部结构来确定需要重建的目标,并调用执行此操作所需的规则.
我无法清楚地了解这两个阶段的差异.可能正在寻找一个有助于理解的例子.是否有任何链接或教程阐明了第一阶段和第二阶段到底发生了什么.
拿这个琐碎的makefile:
var := some_other_file
some_file: $(var)
some_command $^ $@
Run Code Online (Sandbox Code Playgroud)
在第一阶段之后,文件将如下所示
var := some_other_file
some_file: some_other_file
some_command $^ $@
Run Code Online (Sandbox Code Playgroud)
注意如何扩展$^和$@未扩展,仅在第2阶段扩展和调用配方.
在阶段2中,make将使用阶段1产生的规则并确定需要重新制作哪些目标,您可以通过使用-d标志运行make来查看make如何"思考" (警告:大量输出).
在上述情况的第2阶段,在检查了所有some_other_file的依赖关系并在必要时重新创建它之后,它会考虑是否some_other_file更新some_file.
如果是这种情况那么(并且只有那时)是扩展了配方的变量,并且每行的内容被传递给shell,这将是some_command some_other_file some_file.
因此,$@除了作为配方的一部分之外,您不能在任何地方使用等,因为自动变量仅在阶段2期间设置.
foo: $@bar
some_command $^
Run Code Online (Sandbox Code Playgroud)
这将在第1阶段扩展到:
foo: bar
some_command $^
Run Code Online (Sandbox Code Playgroud)
在第2阶段将导致:
foo: bar
some_command bar
Run Code Online (Sandbox Code Playgroud)
可能不是你想要的.
一些人有办法解决这个限制.GNU make for instance has .SECONDEXPANSION,以下内容将按预期工作:
.SECONDEXPANSION:
foo: $$@bar
some_command $^
Run Code Online (Sandbox Code Playgroud)
之后的任何事情.SECONDEXPANSION都将在第一阶段扩展:
.SECONDEXPANSION:
foo: $@bar
some_command $^
Run Code Online (Sandbox Code Playgroud)
和阶段2:
.SECONDEXPANSION:
foo: foobar
some_command foobar
Run Code Online (Sandbox Code Playgroud)