Makefile 的变量-2

来源:互联网 发布:航盛导航端口 编辑:程序博客网 时间:2024/06/06 09:03
轉載自 http://malihou2008.blog.163.com/blog/static/21182004520124157330988/
 
Makefile Variable

makefile 中的变量除了在 makefile 中自定义的之外,还可以来自 make 内置缺省变量(default variable)、make 内置自动化变量(automatic variable)、命令行变量(command line variable)、系统环境变量(environment variable)、目标指定变量(target-specific variable)、模式指定变量(pattern-specific variable)。

系统环境变量
make 在运行时,系统的所有环境变量对它都是可见的(variables in make can come from the environment in which make is run)。在 makefile 中,可以引用任何已定义的系统环境变量。

示例 20
Makefile 文件的内容如下

print:
@echo system SHELL=$(shell echo $$SHELL)
@echo make SHELL=$(SHELL)
@echo HOME=$(HOME)


测试结果如下

malihou@ubuntu:~$ make
system SHELL=/bin/bash
make SHELL=/bin/sh
HOME=/home/malihou
malihou@ubuntu:~$

 
在示例 20 中,make 内置缺省变量 SHELL 的值覆盖了系统环境变量 SHELL 的值。

系统环境变量总结
1 makefile 中定义的变量(an explicit assignment in the makefile)或者命令行参数变量(a command argument),都将覆盖同名的环境变量(它并不能改变系统环境变量的值,被修改的系统环境变量只在 make 执行过程有效)。
2 make 在执行时使用 -e 命令行选项,makefile 中定义的变量不会覆盖同名的系统环境变量。
3 make 在递归调用时,所有的系统环境变量会传递给下一级 make 进程。默认情况下,只有系统环境变量和命令行变量才会传递给下一级 make 进程(by default, only variables that came from the environment or the command line are passed to recursive invocations. You can use the export directive to pass other variables)。
4 系统环境变量 SHELL 在 makefile 中的值为 /bin/sh,其在 make 开始执行时就已改变。而不是默认的值。
5 在 makefile 中,非必须情况下不建议重置系统环境变量的值。

示例 21
test.mak 文件的内容如下

print:
@echo HOME2=$(HOME)
@echo var2=$(var)


Makefile 文件的内容如下

HOME =/home
var= test

ifeq ($(findstring override,$(origin HOME)),override)
exportvar
endif

print:
make -f test.mak
@echo HOME1=$(HOME)
@echo var1=$(var)


测试结果如下

malihou@ubuntu:~$ make -s
HOME2=/home
var2=
HOME1=/home
var1=test
malihou@ubuntu:~$ make --e
HOME2=/home/maxma
var2=test
HOME1=/home/maxma
var1=test
malihou@ubuntu:~$


示例 21 的结果表明,系统环境变量默认可以传递给下一级 make;makefile 中定义的变量默认不能传递给下一级 make;make 在执行时使用 -e 参数,makefile 中定义的同名变量不能覆盖系统环境变量的值。

目标指定变量
makefile 提供了一种目标指定变量(target-specific variables),其允许同一个变量根据目标的不同而指定不同的值。
目标指定变量的值只在指定它的目标的上下文(所有和目标有依赖关系的目标)中有效,对于其它的目标不产生影响。因此可以说目标指定变量的作用域具有局部性。

语法格式如下:

    target... : variable-assignment

目标指定变量总结
1 variable-assignment 可以使用任何一个有效的赋值方式(=、:=、?=、+=)。
2 目标指定变量和同名的全局变量属于两个不同的变量。
3 目标指定变量会作用到由这个目标所引发的所有的规则。
4 目标指定变量的值不会影响同名的那个全局变量的值。如果在 makefile 中已经定义了一个和目标指定变量同名的变量(非目标指定变量),那么目标指定变量值的改变只对指定的这些目标可见。
5 目标指定变量和普通变量具有相同的优先级。
6 目标指定变量常用于针对不同的目标文件执行不同的编译选项。

示例 21
Makefile 文件的内容如下
test : targets := test
1.o : targets += 1.o
test.o : targets += test.o

test : 1.o test.o
    echo test targets = $(targets)

1.o : 1.c
    echo 1.o targets = $(targets)

test.o : test.c 1.h
    echo test.o targets = $(targets)

在命令提示符下输入 “make -s”,执行结果如下:
1.o targets = test 1.o
test.o targets = test test.o
test targets = test

模式指定变量
makefile 提供了一种模式指定变量(pattern-specific variables),它将一个变量值指定到所有符合特定模式的目标。而目标指定变量是将变量指定到某个具体目标和由它所引发的规则的目标。

语法格式如下:

    pattern... : variable-assignment

模式指定变量的目标是一个或多个符合模式的目标,模式字符串中通常都会包含模式字符 %。在模式指定变量定义时,目标文件除了模式字符 % 以外还需要包含某种文件名的特征字符。当单独使用模式字符 % 作为目标时,指定的变量会对任何类型的目标文件都有效。

示例 22
Makefile 文件的内容如下
test : targets += test
1.o : targets += 1.o
test.o : targets += test.o
% : targets += all
%.o : targets += object

test : 1.o test.o
    echo test targets = $(targets)

1.o : 1.c
    echo 1.o targets = $(targets)

test.o : test.c 1.h
    echo test.o targets = $(targets)

在命令提示符下输入 “make -s”,执行结果如下:
1.o targets = all test all object 1.o
test.o targets = all test all object test.o
test targets = all test

示例 22 的结果表明,同一个变量如果使用追加方式,目标的局部变量值的顺序是: 所有规则定义的全局值(模式指定)+引发它所在规则被执行的目标指定值(目标指定)+它所符合的模式指定值(模式指定)+此目标指定值(目标指定)。
 

 override 指示符
在执行 make 时,如果通过命令行定义了一个变量,那么它将替代在 makefile 中出现的同名变量。就是说在 makefile 中定义的变量(通过 =、:=、?=、+=、define 定义),我们可以在执行 make 时通过命令行方式重新指定这个变量的值,命令行指定的值将替代出现在 makefile 中同名变量的值。

示例 23
Makefile 文件的内容如下
i2c_support = yes

print :
 
   echo i2c_support=$(i2c_support)

在命令提示符下输入 “make -s”,执行结果如下:
i2c_support=yes

在命令提示符下输入 “make -s i2c_support=no”,执行结果如下:
i2c_support=no

为了在 makefile 中修改命令行定义的变量,需要在 makefile 中使用 override 指示符来声明这个变量,表示将覆盖同名的命令行变量。

语法格式如下:

    override variable = value
    override variable := value
    override variable ?= value
    override variable += more
    override define variable
    value
    ...
    endef

变量在定义时使用了 override,则后续对它的值进行追加时,也需要使用 override 指示符声明,否则对此变量值的追加不会生效。

示例 24
Makefile 文件的内容如下
override i2c_support = yes

print :
    echo i2c_support=$(i2c_support)

在命令提示符下输入 “make -s i2c_support=no”,执行结果如下:
i2c_support=yes

示例 25
Makefile 文件的内容如下
override i2c_support += yes

print :
    echo i2c_support=$(i2c_support)

在命令提示符下输入 “make -s i2c_support=no”,执行结果如下:
i2c_support=no yes

override 指示符并不是调整 makefile 定义的变量和命令行定义的变量之间的冲突,而是为了使用户可以改变命令行定义的变量的值。也就是实现了在 makefile 中修改命令行变量的一种机制。
可能会有这样的需求,通过命令行参数来指定一些附加的编译参数,而对一些通用的或者必需的编译参数在 makefile 中指定。这样我们就可以使用 override 来实现。

export & unexport 指示符
在 makefile 中定义的变量默认是不能传递到下一级 makefile。默认情况下只有系统环境变量和命令行变量才可以传递到下一级 makefile。通过使用 export 指示符对变量进行声明可以将变量传递到下一级 makefile。
变量使用 export 指示符进行声明,变量将被加入到当前工作的环境变量列表中,下一级 makefile 就可以使用这些变量。
没有使用 export 指示符进行声明,上层 makefile 只将那些已经初始化的系统环境变量和命令行变量传递给下一级 makefile。

语法格式如下:

    export variable...
    export variable-assignment

当不希望将一个变量传递给下一级 make 时,可以使用 unexport 指示符来声明这个变量。

语法格式如下:

    unexport variable...

1 unexport 指示符只对系统环境变量和 makefile 中定义的变量有效,而对命令行变量无效。
2 不带任何参数的 export 指示符表示将此 makefile 中定义的所有变量传递给下一级 makefile。
3 虽然不带任何参数的 export 指示符具有特殊的含义,但是一个不带任何参数的 unexport 指示符却是没有任何意义的,它不会对 make 的执行过程(变量的传递)产生任何影响。

示例 26
test.mak 文件的内容如下
print :
    echo test.mak
    echo env_variable=$(DESKTOP_SESSION)
    echo cmd_variable=$(cmd_variable)
    echo com_variable=$(com_variable)

Makefile 文件的内容如下
com_variable = makefile

print :
    make -f test.mak
    echo Makefile
    echo env_variable=$(DESKTOP_SESSION)
    echo cmd_variable=$(cmd_variable)
    echo com_variable=$(com_variable)

在命令提示符下输入 “make -s cmd_variable=cmd”,执行结果如下:
test.mak
env_variable=ubuntu-2d
cmd_variable=cmd
com_variable=
Makefile
env_variable=ubuntu-2d
cmd_variable=cmd
com_variable=makefile

示例 27
test.mak 文件的内容如下
print :
    echo test.mak
    echo env_variable=$(DESKTOP_SESSION)
    echo cmd_variable=$(cmd_variable)
    echo com_variable=$(com_variable)

Makefile 文件的内容如下
export com_variable = makefile
unexport cmd_variable DESKTOP_SESSION

print :
    make -f test.mak
    echo Makefile
    echo env_variable=$(DESKTOP_SESSION)
    echo cmd_variable=$(cmd_variable)
    echo com_variable=$(com_variable)

在命令提示符下输入 “make -s cmd_variable=cmd”,执行结果如下:
test.mak
env_variable=
cmd_variable=cmd
com_variable=makefile
Makefile
env_variable=ubuntu-2d
cmd_variable=cmd
com_variable=makefile

示例 26 的结果表明系统环境变量和命令行变量默认可以传递到下一级 makefile。
示例 27 的结果表明 unexport 指示符只对系统环境变量和 makefile 定义的变量有效,而对命令行变量无效。

undefine 指示符
如果想要清除一个变量,将其变为未定义的状态,可以使用 undefine 指示符。
注意:只有 V3.82 及以上的 make 版本才支持 undefine 指示符。

语法格式如下:

    undefine variable

undefine 指示符常用于在无法确定变量是否有定义的情况下,先移除此变量,然后在重新定义。类似于 c 语言的预编译指令 undef。

示例 28
Makefile 文件的内容如下
i2c_support =

$(info $(origin i2c_support))
$(info $(flavor i2c_support))

undefine i2c_support

$(info $(origin i2c_support))
$(info $(flavor i2c_support))

ifndef i2c_support
    output_str = i2c_support is not define
endif

print :
    echo $(output_str)

在命令提示符下输入 “make -s”,执行结果如下:
file
recursive
undefined
undefined
i2c_support is not define

private 指示符
目标指定变量和模式指定变量会作用到指定目标和由该目标所引发的所有规则中。也就是说具有可继承性。有时我们不希望变量继承,makefile 提供了 private 指示符来实现此功能。
注意:只有 V3.82 及以上的 make 版本才支持 private 指示符。

语法格式如下:

    private variable-assignment

1 private 指示符必须使用在变量定义时,不能单独对变量进行声明。
2 private 指示符声明的变量在 makefile 中非规则的部分是可见的,而在规则中不可见。
3 在规则中引用 private 指示符声明的变量,其值将为空。
4 变量在定义时引用了 private 指示符声明的变量,该变量也会成为 private。
5 规则指定变量和模式指定变量使用 private 指示符进行声明,其只能使用在当前规则中。

示例 29
Makefile 文件的内容如下
private i2c_support = yes

smbus_support = $(strip $(i2c_support))

$(info $(i2c_support))
$(info $(smbus_support))

ifeq '$(strip $(i2c_support))' 'yes'
ouput_str = i2c is support
endif

print :
    echo i2c_support=$(i2c_support)
    echo smbus_support=$(smbus_support)
    echo $(ouput_str)

在命令提示符下输入 “make -s”,执行结果如下:
yes
yes
i2c_support=
smbus_support=
i2c is support

示例 30
Makefile 文件的内容如下
targets += all
test : private targets += test

test : 1.o test.o
    echo test targets = $(targets)

1.o : 1.c
    echo 1.o targets = $(targets)

test.o : test.c 1.h
    echo test.o targets = $(targets)

在命令提示符下输入 “make -s”,执行结果如下:
1.o targets = all
test.o targets = all
test targets = all test

示例 29 的结果表明,使用 private 指示符声明的全局变量,在整个文件范围内是可见的,但是在规则中是不可见的,不能被任何目标所继承。
示例 30 的结果表明,使用 private 指示符声明的局部变量(目标指定变量、模式指定变量),在当前目标是可见的,在其依赖的目标中不可见。

变量的取值
1 将变量设置为系统环境变量,make 可以使用所有的系统环境变量。
2 在执行 make 时通过命令行选项的方式设置变量。
3 在不同的规则中自动变量会被赋予不同的值。
4 内置变量具有固定的值。
5 在 makefile 中通过赋值的方式或者使用 define 的方式给一个变量赋值。

变量的作用域
makefile 存在很多类型的变量,系统环境变量、命令行变量、自动变量、内置变量、makefile 文件变量(包括全局文件变量、目标指定变量、模式指定变量)。
自动变量、目标指定变量、模式指定变量都是一种规则型变量,只在规则的范围内有效(局部变量)。
系统环境变量、命令行变量、内置变量、全局文件变量的作用域是整个文件,因此它们都是全局变量。

变量的优先级关系
1 系统环境变量被同名的 makefile 文件变量覆盖。
2 在 make 执行时使用 -e 命令行选项,系统环境变量将覆盖 makefile 文件变量。
3 命令行变量将覆盖同名的 makefile 文件变量和系统环境变量(无论是否使用 -e 命令行选项) 。
4 makefile 文件变量使用 override 指示符声明,将覆盖同名的命令行变量和系统环境变量。

变量的优先级关系图

Makefile 的变量-2 - 马哥 - 我的奋斗

示例 31
Makefile 文件的内容如下
USER = administrator

print :
    echo USER=$(USER)

在命令提示符下输入 “make -s”,执行结果如下:
USER=administrator

在命令提示符下输入 “make -s -e”,执行结果如下:
USER=root

在命令提示符下输入 “make -s USER=guest”,执行结果如下:
USER=guest

在命令提示符下输入 “make -s -e USER=guest”,执行结果如下:
USER=guest

示例 32
Makefile 文件的内容如下
override USER = administrator

print :
    echo USER=$(USER)

在命令提示符下输入 “make -s”,执行结果如下:
USER=administrator

在命令提示符下输入 “make -s -e”,执行结果如下:
USER=administrator

在命令提示符下输入 “make -s USER=guest”,执行结果如下:
USER=administrator

在命令提示符下输入 “make -s -e USER=guest”,执行结果如下:
USER=administrator
0 0