任何人都可以清楚地解释变量赋值在Makefile中是如何工作的。
有什么区别:
VARIABLE = value
VARIABLE ?= value
VARIABLE := value
VARIABLE += value
我已经阅读了GNU Make手册中的section,但它对我来说仍然没有意义。
答案 0 :(得分:933)
VARIABLE = value
变量的正常设置 - 当使用变量时,递归扩展其中的值,而不是在声明它时
VARIABLE := value
通过简单扩展内部值来设置变量 - 其中的值在声明时间展开。
VARIABLE ?= value
仅当变量没有值
时才设置变量VARIABLE += value
将提供的值附加到现有值(如果变量不存在,则设置为该值)
答案 1 :(得分:238)
使用 =
会为变量分配值。如果变量已有值,则替换它。使用时,该值将被扩展。例如:
HELLO = world
HELLO_WORLD = $(HELLO) world!
# This echoes "world world!"
echo $(HELLO_WORLD)
HELLO = hello
# This echoes "hello world!"
echo $(HELLO_WORLD)
使用 :=
与使用=
类似。但是,在使用它时,不是在扩展值时,而是在赋值期间扩展它。例如:
HELLO = world
HELLO_WORLD := $(HELLO) world!
# This echoes "world world!"
echo $(HELLO_WORLD)
HELLO = hello
# Still echoes "world world!"
echo $(HELLO_WORLD)
HELLO_WORLD := $(HELLO) world!
# This echoes "hello world!"
echo $(HELLO_WORLD)
使用 ?=
为变量指定值 iff 以前未分配变量。如果先前为变量指定了空值(VAR=
),则仍将其视为我认为。否则,函数与=
完全相同。
使用 +=
就像使用=
一样,但不是替换值,而是将值附加到当前值,其间有空格。如果变量之前已使用:=
设置,则会扩展我认为。当使用我认为时,结果值会扩展。例如:
HELLO_WORLD = hello
HELLO_WORLD += world!
# This echoes "hello world!"
echo $(HELLO_WORLD)
如果使用HELLO_WORLD = $(HELLO_WORLD) world!
之类的东西,将导致递归,这很可能会结束Makefile的执行。如果使用A := $(A) $(B)
,则结果与使用+=
的结果不同,因为B
使用:=
展开,而+=
不会导致B
要扩展。
答案 2 :(得分:52)
我建议你使用“make”做一些实验。这是一个简单的演示,展示了=
和:=
之间的区别。
/* Filename: Makefile*/
x := foo
y := $(x) bar
x := later
a = foo
b = $(a) bar
a = later
test:
@echo x - $(x)
@echo y - $(y)
@echo a - $(a)
@echo b - $(b)
make test
打印:
x - later
y - foo bar
a - later
b - later bar
答案 3 :(得分:31)
当您使用VARIABLE = value
时,如果value
实际上是对另一个变量的引用,则仅在使用VARIABLE
时确定该值。最好用一个例子说明这一点:
VAL = foo
VARIABLE = $(VAL)
VAL = bar
# VARIABLE and VAL will both evaluate to "bar"
当您使用VARIABLE := value
时,您将获得value
的值,因为它现在是。例如:
VAL = foo
VARIABLE := $(VAL)
VAL = bar
# VAL will evaluate to "bar", but VARIABLE will evaluate to "foo"
使用VARIABLE ?= val
表示如果尚未设置 VARIABLE
,则只设置VARIABLE
的值。如果尚未设置,则推迟使用值设置,直到使用VARIABLE
为止(如示例1所示)。
VARIABLE += value
只需将value
追加到VARIABLE
即可。 value
的实际值是根据最初设置的时间确定的,使用=
或:=
。
答案 4 :(得分:6)
在上面的答案中,理解的含义非常重要"值在声明/使用时间扩展"。给出像*.c
这样的值并不需要任何扩展。只有当命令使用此字符串时,它才会触发某些通配。同样,$(wildcard *.c)
或$(shell ls *.c)
之类的值不需要任何扩展,即使我们在变量定义中使用:=
,也会在定义时进行完全评估。
在您有一些C文件的目录中尝试以下Makefile:
VAR1 = *.c
VAR2 := *.c
VAR3 = $(wildcard *.c)
VAR4 := $(wildcard *.c)
VAR5 = $(shell ls *.c)
VAR6 := $(shell ls *.c)
all :
touch foo.c
@echo "now VAR1 = \"$(VAR1)\"" ; ls $(VAR1)
@echo "now VAR2 = \"$(VAR2)\"" ; ls $(VAR2)
@echo "now VAR3 = \"$(VAR3)\"" ; ls $(VAR3)
@echo "now VAR4 = \"$(VAR4)\"" ; ls $(VAR4)
@echo "now VAR5 = \"$(VAR5)\"" ; ls $(VAR5)
@echo "now VAR6 = \"$(VAR6)\"" ; ls $(VAR6)
rm -v foo.c
运行make
将触发一条规则,该规则会创建一个名为foo.c
的额外(空)C文件,但6个变量中没有一个变量的值为foo.c
。
答案 5 :(得分:1)
最受好评的答案可以得到改善。
让我参考GNU Make手册"Setting variables"和"Flavors",并添加一些评论。
您指定的值是逐字安装的;如果它包含对其他变量的引用,则每当替换此变量时(在扩展其他字符串的过程中),这些引用就会被扩展。发生这种情况时,它称为递归扩展。
foo = $(bar)
捕获:foo
的值将扩展为$(bar)
的值,每次评估foo
,可能会导致不同的值。当然,您不能称其为“懒惰”!如果在午夜执行,这可能会让您感到惊讶:
# This variable is haunted!
WHEN = $(shell date -I)
something:
touch $(WHEN).flag
# If this is executed on 00:00:00:000, $(WHEN) will have a different value!
something-else-later: something
test -f $(WHEN).flag || echo "Boo!"
VARIABLE := value
VARIABLE ::= value
用“:=”或“ :: =”定义的变量只是扩展变量。
使用':='或':: ='[...]由行定义简单扩展的变量。两种形式在GNU make中是等效的;但是,POSIX标准[...] 2012仅描述“ :: =”形式。
定义变量后,将一次扫描简单扩展的变量的值,从而扩展对其他变量和函数的引用。
要添加的内容不多。立即对其进行评估,包括递归扩展变量以及递归扩展变量。
收获:如果VARIABLE
指向ANOTHER_VARIABLE
:
VARIABLE := $(ANOTHER_VARIABLE)-yohoho
并且ANOTHER_VARIABLE
在此分配之前未定义,ANOTHER_VARIABLE
将扩展为空值。
FOO ?= bar
等同于
ifeq ($(origin FOO), undefined)
FOO = bar
endif
其中$(origin FOO)
等于undefined
,只有在根本没有设置变量的情况下。
捕获:如果FOO
设置为空字符串,无论是在makefile,shell环境还是命令行替代中,都将不分配bar
。
VAR += bar
如果之前未定义相关变量,则'+ ='的作用与普通的'='相同:它定义了一个递归扩展的变量。但是,当有先前的定义时,“ + =”的作用取决于您最初定义的变量的样式。
因此,这将打印foo bar
:
VAR = foo
# ... a mile of code
VAR += $(BAR)
BAR = bar
$(info $(VAR))
但这会打印foo
:
VAR := foo
# ... a mile of code
VAR += $(BAR)
BAR = bar
$(info $(VAR))
要抓住的地方是,+=
的行为取决于之前分配的变量VAR
的类型。
syntax to assign multiline value to a variable是:
define VAR_NAME :=
line
line
endef
或
define VAR_NAME =
line
line
endef
可以省略赋值运算符,然后创建一个递归扩展的变量。
define VAR_NAME
line
line
endef
endef
之前的最后一个换行符已删除。
HASH != printf '\043'
与
相同HASH := $(shell printf '\043')
请勿使用。 $(shell)
调用更具可读性,强烈建议不要在makefile中使用二者。至少$(shell)
遵循Joel的建议和makes wrong code look obviously wrong。
答案 6 :(得分:0)
这是我的问题:
ULB=/usr/local/bin/
PGM1=myprogram
Install:
sudo /usr/bin/cp ${PGM1} ${ULB} #works just fine,
# I need to do the following which does not work (extra spaces and
# catenation of ${ULB}{PGM1} does not work.
sudo chown root:root ${ULB}${PGM1}
# I need as a conclusion
sudo chown root:root /usr/local/bin/myprogram
I tried make's join, strip,
make 在不需要的地方添加空格字符,并且 make 可能不会连接程序和目录字段。