注意:这个问题最初是由现在删除的用户发布为rant的,但是在rant后面有一个有效的问题;这是我提供答案的尝试。
给定Makefile:
ifeq "$(MAKELEVEL)" "0"
# Override the command-line specification of "foo".
override foo=replaced
export foo
all::
@echo outer: foo is "$(foo)"
@$(MAKE)
else
# Variable 'foo' was "exported" from the top-level Makefile.
all::
@echo inner: foo is "$(foo)"
endif
期望
export foo
将导致make导出override
声明中定义的值。但事实并非如此:$ make -s foo=original
outer: foo is replaced
inner: foo is original
最佳答案
期望可能是合理的,但事实证明,这不是Gnu的工作方式。很有可能可以改进make
文档以澄清该过程,但是所有提示似乎都在那里。
变量如何获取其值
变量可以通过三种方式为set by the programmer:
var=value
命令行参数上面的列表是正常的优先顺序;在列表“wins”中找到的第一个定义。但是,您可以使用
override
directive交换前两种方法的优先级。 (您还可以使用-e
标志来交换后两种方法的优先级。Posix要求-e
标志,但不鼓励使用它,并且它不会与override
交互。)变量如何传递给子品牌
make
与shell非常相似,因为环境用于传递变量值。如果将变量标记为已导出,则将其值放入由make发起的任何过程(包括子make)的环境中。与 shell 程序一样,如果变量的定义来自环境,或者使用export
指令将其明确标记为已导出,则将其标记为已导出。如果变量是在命令行上设置的,则也会导出。但是,还有另一种将命令行上的变量传递给子进程的机制:
MAKEFLAGS
exported variable.。 MAKEFLAGS
包含(大多数)命令行选项以及所有命令行变量替代。如果make在环境中找到MAKEFLAGS
,它将合并该变量中的设置与其在命令行中实际指定的设置。这意味着make中的命令行变量设置也将在子make中具有优先级。由于命令行变量设置是通过
MAKEFLAGS
变量传递的,因此它们不会在makefile中进行任何更改。 Makefile可以unexport
或override
在命令行上设置的变量,但这只会影响环境中变量的值(或存在)。它不会删除或更改MAKEFLAGS
中的值。解析度
因此,如果要在make本身和子make环境中重写(或修改)命令行变量,则必须同时使用
MAKEFLAGS
和MAKEFLAGS
进行显式修改。 (如make手册中所述,MAKEOVERRIDES
实际上是使用CFLAGS
变量递归组成的,因此我们实际上是对该变量进行了修改。)ifeq "$(MAKELEVEL)" "0"
# Override the command-line specification of "foo".
override foo=replaced
MAKEOVERRIDES += foo=replaced
all::
@echo outer: foo is "$(foo)"
@$(MAKE) -s
else
# Variable 'foo' was "exported" from the top-level Makefile.
all::
@echo inner: foo is "$(foo)"
endif
现在我们得到了预期的结果:
$ make -s foo=original
outer: foo is replaced
inner: foo is replaced
现实应用:处理空白
覆盖的主要目的是允许makefile将单词附加到命令行上可能提供的变量中。 gnu make手册中提供的示例坚持认为,即使在
-g
命令行上指定了make
标志,它也始终包含CFLAGS
标志:override CFLAGS += -g
将附件传递到子模型时需要谨慎一些。特别是显而易见的是:
MAKEOVERRIDES += CFLAGS=$(CFLAGS) # Don't do this
将不起作用,因为将
MAKEFLAGS
变量中的空格添加到MAKEFLAGS
时不会逃脱;结果将是CFLAGS
看起来像这样:-- CFLAGS=-O3 CFLAGS=-O3 -g
而不是期望的
-- CFLAGS=-O3 CFLAGS=-O3\ -g
如果在命令行上分配给
MAKEFLAGS
的值包含空格,则在space
中转义该空格。没有记录使用的特殊转义机制,Posix仅要求有某种机制。显然,Gnu make使用反斜杠。可以手动反斜杠转义空白,结果是这样的:# Don't do this either
MAKEOVERRIDES += CFLAGS=$(subst $(space),\ ,$(CFLAGS))
(
MAKEOVERRIDES
的定义和使用基于example in the gnu make manual。)但是,实际上,仅在
CFLAGS
中使用附加分配会更容易,该记录未记录但似乎可以使用。它也可以在命令行上使用。override CFLAGS+=-g
MAKEOVERRIDES += CFLAGS+=-g
从make v4.1开始的重要说明:一点测试表明,仅当在命令行上实际设置了ojit_code(或其他变量)时,以上节才会起作用。我将此错误报告为Savannah issue 46013,并在错误报告中进行了非常简单的修复。同时,如果您确实要执行此操作,请使用以下解决方法:
override CFLAGS+=-g
MAKEOVERRIDES += CFLAGS+=-g
# This line is necessary in case there were no command-line overrides.
# In effect, it produces a command-line override, although that value
# will not be passed on to sub-makes.
MAKEFLAGS += dummy=dummy
更新2019年5月19日:今天,我得知已经提交了针对上述错误的修复程序,因此应在下一个gmake版本中对其进行修复。