注意:这个问题最初是由一个现已删除的用户发布的,但是这个咆哮背后有一个有效的问题; 这是我试图提供答案.
鉴于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
Run Code Online (Sandbox Code Playgroud)
期望是export foo会导致make导出override声明中定义的值.但它没有:
$ make -s foo=original
outer: foo is replaced
inner: foo is original
Run Code Online (Sandbox Code Playgroud)
期望可能是合理的,但事实证明这不是Gnu的工作方式.很可能是make文档可以改进以澄清过程,但暗示似乎都在那里.
var=value命令行参数的命令行上以上列表是普通优先顺序; 在列表"wins"中找到的第一个定义.但是,您可以使用该override指令交换前两种方法的优先级.(您也可以使用该-e标志来交换最后两个方法的优先级-e.Posix需要该标志,但不建议使用它,并且它不会与之交互override.)
make与shell非常相似,因为环境用于传递变量值.如果将变量标记为已导出,则将其值放入环境中,以用于由make启动的任何进程,包括sub-make.与shell一样,如果变量的定义来自环境,或者它明确标记为使用该export指令导出,则变量将标记为已导出.如果在命令行中设置了变量,也会导出变量.
但是,还有另一种机制,命令行上的变量将传递给子进程:MAKEFLAGS导出的变量..MAKEFLAGS包含(大多数)命令行选项以及所有命令行变量覆盖.如果make MAKEFLAGS在环境中找到,它会将该变量中的设置与其命令行中实际指定的设置合并.这意味着make中的命令行变量设置也将在子make中占优势.
由于命令行变量设置是通过变量传递的MAKEFLAGS,因此它们不会受到makefile中任何更改的影响.makefile可以在命令行上设置unexport或override变量,但这只会影响环境中变量的值(或存在); 它不会删除或更改值MAKEFLAGS.
因此,如果意图是在make本身和子make的环境中覆盖(或修改)命令行变量,则必须同时使用覆盖和显式修改MAKEFLAGS.(正如make手册中所解释的那样,MAKEFLAGS实际上是使用MAKEOVERRIDES变量递归组合的,所以我们实际上修改了那个变量.)
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
Run Code Online (Sandbox Code Playgroud)
现在我们得到了预期的结果:
$ make -s foo=original
outer: foo is replaced
inner: foo is replaced
Run Code Online (Sandbox Code Playgroud)
覆盖的主要目的是允许makefile将单词附加到命令行上可能提供的变量.gnu make手册中提供的示例坚持CFLAGS始终包含-g标志,即使它是在make命令行中指定的:
override CFLAGS += -g
Run Code Online (Sandbox Code Playgroud)
通过附加到子制作需要一点点谨慎; 特别是,显而易见的:
MAKEOVERRIDES += CFLAGS=$(CFLAGS) # Don't do this
Run Code Online (Sandbox Code Playgroud)
将无法正常工作,因为CFLAGS变量中的空格在添加时不会被转义MAKEFLAGS; 结果将是MAKEFLAGS这样的:
-- CFLAGS=-O3 CFLAGS=-O3 -g
Run Code Online (Sandbox Code Playgroud)
而不是期望的
-- CFLAGS=-O3 CFLAGS=-O3\ -g
Run Code Online (Sandbox Code Playgroud)
如果在CFLAGS命令行上分配的值包含空格,则转义空格MAKEFLAGS.使用的特定转义机制没有记录,Posix只要求有一些机制; 显然,Gnu make使用反斜杠.可以手动反斜杠转义空格,从而得到如下内容:
# Don't do this either
MAKEOVERRIDES += CFLAGS=$(subst $(space),\ ,$(CFLAGS))
Run Code Online (Sandbox Code Playgroud)
(定义和使用space基于gnu make手册中的示例.)
但实际上更容易使用附加的赋值MAKEOVERRIDES,它没有文档但似乎有效.它也适用于命令行.
override CFLAGS+=-g
MAKEOVERRIDES += CFLAGS+=-g
Run Code Online (Sandbox Code Playgroud)
重要说明make v4.1:一些测试显示,只有CFLAGS在命令行上实际设置(或某些其他变量)时,上述节才会起作用.我把这个bug报告为Savannah问题46013,在bug报告中有一个非常简单的修复.与此同时,如果您确实想要这样做,请使用以下解决方法:
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1585 次 |
| 最近记录: |