ILD

make学习笔记:variables
作者:Yuan Jianpeng 邮箱:yuanjp89@163.com
发布时间:2019-5-19 站点:Inside Linux Development

6 How to user Variables

变量在读取makefile的过程中被扩展,除了:recipes,=定义变量的右边,define语法定义变量的body。


变量名字不能包含:: # = whitespace,这4种字符,其它都可以。


变量名字是大小写敏感的。


6.1 basic of variable references

为了替换一个变量的值,有两种写法:$(foo) 或 ${foo}


variable references可以发生在任何context:targets,prerequisites,recipes,most directives,new variable values。


$跟一个非 $ ( { 字符,那么这个单字符被解析为变量名,如$x,但是这种方法不推荐。


6.2 The two flavors of variables

recursively expanded variable 递归扩展变量。

使用=,或者define定义的变量


simply expanded variables 简单扩展变量。

使用:=,或者::=定义,这二者是一样的,后者是POSIX的标准。


递归扩展变量的值是按字面量安装的(installed verbatim),如果它引用其它变量,当这个变量被引用时,都会扩展这些变量。


foo = $(bar)

bar = $(ugh)

ugh = Huh?

all:;echo $(foo)

输出Huh?,解析过程:$(foo)扩展成$(bar),$(bar)被扩展成$(ugh),然后被扩展成Huh?


递归扩展变量如果引用它自己,将是一个死循环,make将给出出错信息:

1
2
3
4
5
6
7
8
9
10
$ cat Makefile 
 
a := 2
a = $(a) 3
 
all: $(a)
        echo all
 
$ make
Makefile:3: *** Recursive variable 'a' references itself (eventually).  Stop.


由于是按字面量安装的,上述依赖使用$(a)时,a的值已经是 "$(a) 3"了,因此这里会导致死循环。


递归扩展变量的缺点是引用的时候每次都会扩展。


简单扩展变量,对于所有引用的其它变量,只会扫描扩展一次,且变量的值是简单扩展变量处变量的值。


个人观点:

递归扩展,简单扩展和deferred,immediate是两个概念,但是又有一定关联。

后者指变量引用的时候,是立即的,还是延后的,这依赖与变量使用的context,比如对于target和prerequisite,变量引用是立即的。

前者指扩展方式。


6.3 Advanced Features for Reference to Variables

6.3.1 Substitution References

格式 $(var:a=b) 或 ${var:a=b)

将var中的end of word的a替换为b。

at the end of a word,意味着a要么出现空白字符的前面,或者在值的最后,其它地方的不会被替换。


得到变量的一个变种,一个例子足以说明问题:

foo := a.o b.o c.o

bar := $(foo:.o=.c)


上述a和b不能含%,也支持含%的,这是Another type of substitution reference

bar := $(foo:%.o=%.c)


6.3.2 Computed Variable Names

Variables may be referenced inside the name of a variable. This is called a computed

variable name or a nested variable reference

x = y

y = z

a := $($(x))


References to recursively-expanded variables within a variable name are re-expanded in

the usual fashion

变量名中引用recursively-expanded variables是按正常的方法重新扩展

1
2
3
4
x = $(y)
y = z
z = Hello
a := $($(x))

$($(x))成为$($(y)),成为$(z),最终扩展为Hello


6.4 How Variables Get Their Values

环境变量中的变量,成为make变量


6.5 setting variables

变量名跟一个赋值符 = := ::= ,后面跟变量的值

objects = main.o foo.o bar.o utils.o


变量名周边的和等号后边的whitespace被忽略。


没有设置的变量,默认是空字符串。


如果你想设置一个变量的值,除非它还没有被设置,可以使用 ?=


shell assignment operator !=

file_list != find . -name '*.c'

shell执行的结果放到变量中,结尾的换行符被替换为移除,中间的换行符被替换为空格,注意变量是recursively-expanded类型的。


6.6 appending more text to variables

+=

如果变量未定义过,那么+=的类型是recursively-expanded的,否则它和原来的类型相同。


6.7 The override directive

如果一个变量在命令行中设置,那么makefile中的赋值都将被忽略。如果你想改写命令行中的变量,那么可以使用override语法:

override variable = value

override variable := value

override variable += more text


override有最高的优先级,后面没有使用override的赋值都将被忽略。

1
2
3
4
5
6
7
8
9
10
11
$ cat Makefile 
 
override a :=  2
a += 3
 
all:
        echo "$(a)"
 
$ make
echo "2"
2

可以看到a的值是2


6.8 defining multi-line varriables

define语法,它允许换行符出现在变量的值中,主要用在canned sequences of commands和eval函数。


define variable =

echo foo

echo $(bar)

endef


赋值符可以是 = := += 等,赋值符可以省略,默认为=


define可以嵌套


6.9 undefining variables

如果你想清除一个变量,把它们定义成empty足够了,它们和未定义变量的扩展结果是一样的。但是如果使用origin那么它和未定义变量有区别。这种情况下,可以使用undefine 语法:

undefine foo


如果你想undefine一个命令行变量

override undefine CFLAGS


6.10 Variables from the Environment

环境变量会变转成make变量,但是make中的变量赋值和命令行变量会覆盖环境变量。


-e选项,环境变量覆盖make中赋值的变量。


调用子make时,环境变量会传递给子make。


6.11 Target-specific Variable Values

make中的变量通常是全局的,一个例外是自动变量,另外一个例外是target-specific variable


其作用域,仅在target所在的rule。


语法:

target ... : variable-assignment


可以使用 override, export, private等语法


注意:依赖继承 target-specific variable


6.12 Pattern-specific Variable Values

GNU make还支持pattern-specific variable


语法:

pattern ... : variable-assignment


pattern是一个% pattern


例子:

%.o : CFLAGS = -O


6.13 Suppressing Inheritance

前面讲到target-specific variable会被依赖继承,如果不想让依赖继承,可以使用private修饰符。

prog: private EXTRA_CFLAGS = -L/usr/local/lib


6.14 Other Special Variables

MAKEFILE_LIST,当前被解析的所有makefile,按照被包含的顺序。

.VARIABLES,扩展成当前定义的所有全局变量



Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.