如何强制立即设置特定于目标的变量(第 2 行)?我想要的输出是make
torelease
和make debug
to be debug
。
X = release
debug: X = debug
debug: all
# the rest is included from an external file; cannot be changed
Y := $(X)
BUILD := $(Y)
all:
@echo $(BUILD)
答案1
您的问题是由于 GNUMake 如何解析 make 文件造成的。
GNU make 的工作分为两个不同的阶段。在第一阶段,它读取所有 makefile、包含的 makefile 等,并将所有变量及其值、隐式和显式规则内化,并构建所有目标及其先决条件的依赖关系图。在第二阶段,make 使用这些内部结构来确定需要重建哪些目标并调用执行此操作所需的规则。
看起来好像当您运行make debug
依赖项时all:
,它会打印出值,就像您运行一样make all
。您需要做的是修改您的 makefile,以便all
两者debug
都触发相同的依赖关系。你通常会看到类似的东西
all: $(executable)
debug: $(executable)
$(executable): $(objs)
<compile objects to executable>
debug
永远不会触发all
,但在任何一种情况下都会编译可执行文件。
至于你的代码:
X = release
debug: X = debug
Y = $(X)
BUILD = $(Y)
.PHONY: print
print:
@echo $(BUILD)
all: print
debug: print
我必须使 print 成为一个虚假的依赖项,因为它不是正在创建的实际对象。否则,这将是您的依赖项,两者debug
都all
需要,但根据您设置的标志进行不同的编译。
答案2
Y
和BUILD
变量是简单扩展变量因为它们是使用:=
(而不是=
)分配的,请参阅手动的了解更多信息。基本上变量已赋值当变量被定义时,这会阻止您做您想做的事情。
但是特定于目标的变量应该优先于全局变量,因此覆盖该变量将起作用,因为它将在(以及)目标范围内BUILD
隐藏全局变量:BUILD
debug:
all:
X = release
debug: BUILD = debug
debug: all
Y := $(X)
BUILD := $(Y)
all:
@echo $(BUILD)
请注意,使用debug: Y = debug
相反 不起作用,因为BUILD
它本身只是一个扩展变量。
我无法确切理解为什么类似的东西debug: X := debug
不起作用。但我认为特定于目标的变量是在全局简单扩展变量之后解析的。这也可能是为什么特定于目标的BUILD
变量可以在我的解决方案中掩盖全局变量的原因。
请注意,@jecxjo 的答案有部分错误。阻止您覆盖Y
(或)分配的原因BUILD
是它们是用:=
和 不是分配的=
。即您的初始代码使用=
而不是:=
完全符合您的要求:
X = release
debug: X = debug
debug: all
# Note the '=' assignment instead of the ':='
Y = $(X)
BUILD = $(Y)
all:
@echo $(BUILD)
这实际上是在他的答案中解决您的问题的更改,而不是重写目标。但由于您提到这些分配包含在您无法编辑的另一个文件中,因此这不是解决方案。