GNU Makefile 变量赋值 =、?=、:= 和 += 之间有什么区别?
任何人都可以清楚地解释变量分配在 Makefile 中的实际工作原理吗?
之间有什么区别:
VARIABLE = value
VARIABLE ?= value
VARIABLE := value
VARIABLE += value
我已阅读 部分在GNU Make的手册中,但它对我来说仍然没有意义。
Can anybody give a clear explanation of how variable assignment really works in Makefiles.
What is the difference between :
VARIABLE = value
VARIABLE ?= value
VARIABLE := value
VARIABLE += value
I have read the section in GNU Make's manual, but it still doesn't make sense to me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
当您使用
VARIABLE = value
时,如果value
实际上是对另一个变量的引用,则仅在使用VARIABLE
时才确定该值。 最好用一个例子来说明这一点:当您使用
VARIABLE := value
时,您将获得value
现在的值。 例如:使用
VARIABLE ?= val
表示您仅设置VARIABLE
的值 if 未设置VARIABLE
已经。 如果尚未设置,则该值的设置将推迟到使用VARIABLE
为止(如示例 1 所示)。VARIABLE += value
只是将value
附加到VARIABLE
。value
的实际值是使用=
或:=
最初设置时确定的。When you use
VARIABLE = value
, ifvalue
is actually a reference to another variable, then the value is only determined whenVARIABLE
is used. This is best illustrated with an example:When you use
VARIABLE := value
, you get the value ofvalue
as it is now. For example:Using
VARIABLE ?= val
means that you only set the value ofVARIABLE
ifVARIABLE
is not set already. If it's not set already, the setting of the value is deferred untilVARIABLE
is used (as in example 1).VARIABLE += value
just appendsvalue
toVARIABLE
. The actual value ofvalue
is determined as it was when it was initially set, using either=
or:=
.在上面的答案中,理解“值在声明/使用时扩展”的含义非常重要。 提供像
*.c
这样的值并不需要任何扩展。 只有当命令使用该字符串时,它才可能触发一些通配符。 类似地,像$(wildcard *.c)
或$(shell ls *.c)
这样的值不需要任何扩展,并且在定义时完全评估,即使我们在变量定义中使用:=
。在有一些 C 文件的目录中尝试以下 Makefile:
运行
make
将触发一条规则,创建一个额外的(空)C 文件,名为foo.c
但没有这 6 个变量的值包含 foo.c。In the above answers, it is important to understand what is meant by "values are expanded at declaration/use time". Giving a value like
*.c
does not entail any expansion. It is only when this string is used by a command that it will maybe trigger some globbing. Similarly, a value like$(wildcard *.c)
or$(shell ls *.c)
does not entail any expansion and is completely evaluated at definition time even if we used:=
in the variable definition.Try the following Makefile in directory where you have some C files:
Running
make
will trigger a rule that creates an extra (empty) C file, calledfoo.c
but none of the 6 variables hasfoo.c
in its value.得票最多的答案可以改进。
让我参考GNU Make手册“设置变量”和 "Flavors",并添加一些注释。
递归扩展变量
问题:
foo
每次都会扩展为$(bar)
的值foo< /code> 被评估,可能会产生不同的值。 当然不能称之为“懒”! 如果在午夜执行,这可能会让您感到惊讶:
简单扩展变量
没什么可补充的。 它会立即进行评估,包括递归扩展变量的递归扩展。
问题:如果
VARIABLE
引用ANOTHER_VARIABLE
:并且在此赋值之前未定义
ANOTHER_VARIABLE
,则ANOTHER_VARIABLE
将扩展为空值。Assign if not set
相当于
仅当变量根本未设置时,
$(origin FOO)
等于undefined
。 问题:如果FOO
设置为空字符串,无论是在 makefile、shell 环境还是命令行覆盖中,它将不会被赋值栏
。追加
追加:
因此,这将打印
foo bar
:但这将打印
foo
:问题是
+=
的行为不同取决于之前分配的变量VAR
类型。多行值
将多行值分配给变量的语法是:
或
赋值运算符可以省略,然后它创建一个递归扩展变量。
endef
之前的最后一个换行符被删除。奖励:shell 赋值运算符 '!='
相同
与Don't use it 。
$(shell)
调用更具可读性,并且强烈建议不要在 makefile 中同时使用这两者。 至少,$(shell)
遵循了 Joel 的建议和 使错误的代码看起来明显错误。The most upvoted answer can be improved.
Let me refer to GNU Make manual "Setting variables" and "Flavors", and add some comments.
Recursively expanded variables
The catch:
foo
will be expanded to the value of$(bar)
each timefoo
is evaluated, possibly resulting in different values. Surely you cannot call it "lazy"! This can surprise you if executed on midnight:Simply expanded variable
Not much to add. It's evaluated immediately, including recursive expansion of, well, recursively expanded variables.
The catch: If
VARIABLE
refers toANOTHER_VARIABLE
:and
ANOTHER_VARIABLE
is not defined before this assignment,ANOTHER_VARIABLE
will expand to an empty value.Assign if not set
is equivalent to
where
$(origin FOO)
equals toundefined
only if the variable was not set at all.The catch: if
FOO
was set to an empty string, either in makefiles, shell environment, or command line overrides, it will not be assignedbar
.Appending
Appending:
So, this will print
foo bar
:but this will print
foo
:The catch is that
+=
behaves differently depending on what type of variableVAR
was assigned before.Multiline values
The syntax to assign multiline value to a variable is:
or
Assignment operator can be omitted, then it creates a recursively-expanded variable.
The last newline before
endef
is removed.Bonus: the shell assignment operator ‘!=’
is the same as
Don't use it.
$(shell)
call is more readable, and the usage of both in a makefiles is highly discouraged. At least,$(shell)
follows Joel's advice and makes wrong code look obviously wrong.惰性设置
变量的正常设置,但
value
字段中提到的任何其他变量都会使用该变量使用时的值进行递归扩展,而不是声明该变量时的值。 Set
通过简单扩展内部值来设置变量 - 其中的值在声明时扩展。
如果不存在则延迟设置
仅当变量没有值时才设置该变量。 当访问
VARIABLE
时,value
始终会被求值。 它相当于有关更多详细信息,请参阅文档。
Append
将提供的值附加到现有值(如果变量不存在,则设置为该值)
Lazy Set
Normal setting of a variable, but any other variables mentioned with the
value
field are recursively expanded with their value at the point at which the variable is used, not the one it had when it was declaredImmediate Set
Setting of a variable with simple expansion of the values inside - values within it are expanded at declaration time.
Lazy Set If Absent
Setting of a variable only if it doesn't have a value.
value
is always evaluated whenVARIABLE
is accessed. It is equivalent toSee the documentation for more details.
Append
Appending the supplied value to the existing value (or setting to that value if the variable didn't exist)
使用
=
会为变量分配一个值。 如果变量已经有值,则将其替换。 该值在使用时会被扩展。 例如:使用
:=
与使用=
类似。 但是,该值不是在使用时扩展,而是在赋值期间扩展。 例如:使用
?=
为变量分配一个值 iff 该变量之前未分配过。 如果之前为变量分配了空白值 (VAR=
),则它仍然被视为已设置我认为。 否则,功能与=
完全相同。使用
+=
与使用=
类似,但不是替换值,而是将值附加到当前值,中间有一个空格。 如果变量之前使用:=
设置,那么它会被扩展我认为。 我认为使用时结果值会扩展。 例如:如果使用类似
HELLO_WORLD = $(HELLO_WORLD) world!
的内容,则会导致递归,这很可能会结束 Makefile 的执行。 如果使用A := $(A) $(B)
,结果将与使用+=
不完全相同,因为B
使用:=
展开,而+=
不会导致B
展开。Using
=
causes the variable to be assigned a value. If the variable already had a value, it is replaced. This value will be expanded when it is used. For example:Using
:=
is similar to using=
. However, instead of the value being expanded when it is used, it is expanded during the assignment. For example:Using
?=
assigns the variable a value iff the variable was not previously assigned. If the variable was previously assigned a blank value (VAR=
), it is still considered set I think. Otherwise, functions exactly like=
.Using
+=
is like using=
, but instead of replacing the value, the value is appended to the current one, with a space in between. If the variable was previously set with:=
, it is expanded I think. The resulting value is expanded when it is used I think. For example:If something like
HELLO_WORLD = $(HELLO_WORLD) world!
were used, recursion would result, which would most likely end the execution of your Makefile. IfA := $(A) $(B)
were used, the result would not be the exact same as using+=
becauseB
is expanded with:=
whereas+=
would not causeB
to be expanded.我建议你使用“make”做一些实验。 这是一个简单的演示,展示了
=
和:=
之间的区别。make test
打印:在此处查看更详细的解释
I suggest you do some experiments using "make". Here is a simple demo, showing the difference between
=
and:=
.make test
prints:Check more elaborate explanation here