发布网友 发布时间:2024-10-24 17:35
共2个回答
热心网友 时间:2024-11-04 12:43
:= 就是简单的赋值, 比如
foo := $(bar)
将bar的值赋给foo
?= 是条件赋值, 比如
foo ?= $(bar)
只有当foo变量还没有被定义的时候,才会将bar的值赋给foo。 注意,如果foo已经被定义过,但是是空值了话,?=不会给他赋值。比方说你的makefile是
foo = hello
foo ?= new
则最终foo的值是hello
如果你的makefile是
foo =
foo ?= new
foo的值是空
热心网友 时间:2024-11-04 12:44
GNU make支持另外一种风格的变量,称为“直接展开”式。这种风格的变量使用“:=”定义。在使用“:=”定义变量时,变量值中对其他量或者函数的引用在定义变量时被展开(对变量进行替换)。所以变量被定义后就是一个实际需要的文本串,其中不再包含任何变量的引用。因此
x := foo
y := $(x) bar
x := later
就等价于:
y := foo bar
x := later
和递归展开式变量不同:此风格变量在定义时就完成了对所引用变量和函数的展开,因此不能实现对其后定义变量的引用。如:
CFLAGS := $(include_dirs) -O
include_dirs := -Ifoo -Ibar
由于变量“include_dirs”的定义出现在“CFLAGS”定义之后。因此在“CFLAGS”的定义中,“include_dirs”的值为空。“CFLAGS”的值为“-O”而不是“-Ifoo -Ibar -O”。这一点也是直接展开式和递归展开式变量的不同点。注意这里的两个变量都是“直接展开”式的。大家不妨试试将其中某一个变量使用递归展开式定义后看一下又会出现什么样的结果。
下边我们来看一个复杂一点的例子。分析一下直接展开式变量定义(:=)的用法,这里也用到了make的shell函数和变量“MAKELEVEL”(此变量在make的递归调用时代表make的调用深度)。
其中包括了对函数、条件表达式和系统变量“MAKELEVEL”的使用:
ifeq (0,${MAKELEVEL})
cur-dir := $(shell pwd)
whoami := $(shell whoami)
host-type := $(shell arch)
MAKE := ${MAKE} host-type=${host-type} whoami=${whoami}
endif
第一行是一个条件判断,如果是顶层Makefile,就定义下列变量。否则不定义任何变量。第二、三、四、五行分别定义了一个变量,在进行变量定义时对引用到的其它变量和函数展开。最后结束定义。利用直接展开式的特点我们可以书写这样一个规则:
${subdirs}:
${MAKE} cur-dir=${cur-dir}/$@ -C $@ all
它实现了在不同子目录下变量“cur_dir”使用不同的值(为当前工作目录)。
在复杂的Makefile中,推荐使用直接展开式变量。因为这种风格变量的使用方式和大多数编程语言中的变量使用方式基本上相同。它可以使一个比较复杂的Makefile在一定程度上具有可预测性。而且这种变量允许我们利用之前所定义的值来重新定义它(比如使用某一个函数来对它以前的值进行处理并重新赋值),此方式在Makefile中经常用到。尽量避免和减少递归式变量的使用。
“?=”操作符
GNU make中,还有一个被称为条件赋值的赋值操作符“?=”。被称为条件赋值是因为:只有此变量在之前没有赋值的情况下才会对这个变量进行赋值。例如:
FOO ?= bar
其等价于:
ifeq ($(origin FOO), undefined)
FOO = bar
endif
含义是:如果变量“FOO”在之前没有定义,就给它赋值“bar”。否则不改变它的值。