Makefile文件(五)_使用变量

时间:2021-05-28 12:51:04

参考原文http://blog.csdn.net/liang13664759/article/details/1771246/

Makefile中变量如C\C++中宏一样执行时候自动原模原样展开在使用的地方,与C/C++不同得失,Makefile中可以改变其值。Makefile中变量可以使用在“目标”,“依赖目标”,“命令”或其他部分。

变量名可以包含字符数字下划线(可以数字开头),但是不应该含有“:”、“#”、“=”或是空字符,区分大小写。

一、变量的基础

声明时需要给予初始值,使用时加上“$”符号,最好用“()”或者“{}”把变量包括起来。而使用真是的“$”需要“$$”表示。

变量可以用在许多地方,如规则中的目标、依赖、命令以及新的变量。

二、变量中的变量

①使用“=”,左侧是变量,右侧是变量的值,右侧变量的值可以定义在文件的任何一处,也就是说右侧变量不一定是一已定义好的值,也可以使用后面定义的值。

例如:

foo = $(bar)

bar = $(ugh)

ugh = huh?

all:

  echo $(foo)

执行make all会打印出变量$(foo)的值“Huh?”。所以,变量是可以用后面的变量来定义的。

注:这样可能会产生递归定义:

A= $(B)

B=$(A)

这会让make陷入无限的变量展开过程中去,当然,make有检测这样的能力,并会报错。

如果变量中使用函数,这也会让make运行时非常慢。他会使用make的“wildcard”和“shell”发生不可预知的错误。

②“:=”,前面的变量不能使用后面的变量,只能使用已定义好的变量。

x:=foo

y:=$(x) bar

x:=later

等价于

y := foo bar

x := later

 

y := $(x) bar

x := foo

那么y的值是“bar”,而不是“foo, bar”

系统变量“MAKELEVEL”表示,如果make有一个嵌套执行的动作,则该变量会记录当前的Makefile调用层数.

(以下的我也还没懂,先标记)

nullstring :=
space := $(nullstring) # end of the line

nullstring是一个Empty变量,其中什么也没有,而我们的space的值是一个空格。因为在操作符的右边是很难描述一个空格的,这里采用的技术很管用,先用一个Empty变量来标明变量的值开始了,而后面采用“#”注释符来表示变量定义的终止,这样,我们可以定义出其值是一个空格的变量。请注意这里关于“#”的使用,注释符“#”的这种特性值得我们注意,如果我们这样定义一个变量:

dir := /foo/bar # directory to put the frobs in

dir这个变量的值是“/foo/bar”,后面还跟了4个空格,如果我们这样使用这样变量来指定别的目录——“$(dir)/file”那么就完蛋了。

③、另外的赋值法,“?=”表示如果没有被定义过,则赋值。如果定义过,则什么也不做。

FOO ?= bar

等价于:

ifeq ($(origin FOO), undefined)

FOO = bar

endif

三、变量高级用法

①变量值的替换

替换变量中的共有部分,格式“$(var:a=b)”或是“${var:a=b}”,表示吧变量var中的所有以“a”结尾的“a”替换成“b”

例如:

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

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

把“$(foo)”中的所有“.o”结尾全部替换为“.c”,所以“$(bar)”的值就是“a.c b.c c.c”。

另外一种前面记录过得静态模式,

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

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

②、“把变量的值在当成变量”

x = y

y = z

a:=$($(x))

例子中,$(x)=y, 所以$($(x))就是$(y),于是$(a)的值就是z

“函数”于“条件语句”一同使用的例子:

ifdef do_set

  func := sort

else

  func := strip

endif

bar := a b d g q c

foo := $($(func) $(bar))

示例中如果定义了"do_sort",foo:=$(sort a d b g q c),于是$(foo)就是“a b c d g q”。如果没有定义“do_sort”,则foo:=$(strip a d b g q c),调用strip函数。

“把变量的值当成变量”同样可以用在操作符的左边:

dir = foo

$(dir)_sources := $(wildcard $(dir)/*.c)

define $(die)_print

  lpr $($(dir)_sources)#该命令表示把文件发送给打印机

endef

四、追加变量

使用“+=”给变量追加值,如:

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

objects += another.o

于是,$(objects)值就变成:“main.o foo.o bar.o utils.o another.o"

等价于:

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

objects := $(objects) another.o

但“+=”更为简洁,且如果前面没有定义过该变量。“+=”自动变成“=”,如果 有定义过,“+=”汇集成前次操作的赋值符。如果前一次的是“:=”,那么“+=”会以“:=”为其赋值符,如:

variable := value

variable += more

等价于:

variable := value

variable := $(variable) more

但是“=”情况却不一样,例如:

variable = value

variable += more

由于前次的赋值符是“=”,所以“+=”也会以“=”作为赋值,那么岂不会发生变量的递补归定义,这是很不好的,所以make会自动为我们解决这个问题,我们不必担心这个问题。(没懂)

五、override指示符

如果有变量是通常的make命令行参数设置,那么Makefile中对这个变量的赋值会被忽略。如果想在Makefile中设置这类参数的值,可使用“override”指示符。

override <variable>=<value>

override <variable>:=<value>

还可以追加

override <variable>+=<more text>

对于多行的变量定义,可以使用define指示符,而define指示符前,也同样可以使用override,如:

override define foo

bar

endef

定义变量foo bar

六、多行变量

使用define关键字设置变量的值可以有换行,有利于一系列的命令。(命令包就是利用该关键字)

define指示符后面跟变量的名字,重起一行定义变量的值,定义以关键字endef结束。工作方式和“=”操作符一样。变量的值可以包含函数、命令、文字或是其他变量。define定义的命令变量中同样要以【Tab】键开头

define two-lines

  echo foo

  echo $(bar)

endef

七、环境变量

make运行时的系统环境变量可以在make开始运行时被载入到Makefile文件中,但是如果Makefile中定义了这个变量,或是这个变量由make命令行带入,那么系统的环境变量的值将被覆盖(如果make指定了“-e”参数,那么系统环境变量将覆盖Makefile中定义的变量,-e, --environment-overrides环境变量覆盖Makefile文件)

因此,如果我们在环境变量中设置了“CFLAGS”环境变量,那么我们就可以在所有的Makefile中使用这个变量。这对于使用统一的编译参数很方便。如果Makefile中定义了CFLAGS,那么会使用Makefile中的这个变量,如果没有定义则使用系统的环境变量。

当make嵌套调用时,上层Makefile中定义的变量会以系统环境变量的方式传递到下层的Makefile中。默认情况下,只有通过命令行设置的变量会被传递。定义在文件中的变量传递需要export。

不推荐许多的变量定义在系统环境中,这样执行不用的Makefile拥有同一套系统变量,可能会有麻烦。

八、目标变量

前面所述的Makefile中定义的变量都是“全局变量”,整个文件中都可以访问这些变量。当然“自动化变量”除外("$<"、“$@”、“$^”)属于“规则型变量”,这种变量的值依赖于规则的目标和依赖目标的定义。

 当然,也可以为某个目标设置局部变量,成为“Target-specific Variable”,它可以和“全局变量”同名,因为他的作用范围只在这条规则以及连带规则中,其值也只在作用范围内有效,不会影响规则链以外的全局变量的值。如下:

<target...>:<variable-assignment>

<target...>:overide<vatiable-assignment>

<vatiable-assignment>可以是前面的各种赋值表达式。“=”、“:=”、“+=”、“?=”。第二条是make命令行带入的变量或是系统环境变量。

示例:

prog:CFLAGS=-g

prog:prog.o foo.o bar.o

  $(CC) $(CFLAGS) prog.o foo.o bar.o

prog.o:prog.c

  $(CC) $(CFLAGS) prog.c

foo.o:foo.c

  $(CC) $(CFLAGS) foo.c

bar.o:bar.c

  $(CC) $(CFLAGS) bar.c

实例中,不管全局的$(CFLAGS)的值是什么,在prog以及所引发的所有规则中(prog.o foo.o bar.o),$(CFLAGS)的值都是“-g”

九、模式变量

在GNU的make中,还支持模式变量(Pattern-speific Variable),通过前面,变量可以定义在某个目标上,模式变量的好处就是可以给定一种“模式”,可以把变量定义在符合这种模式的所有目标上。

示例:%.o:CFLAGS=-o

<pattern...>:<variable-assignment>

<pattern...>:override<variable-assignment>

make命令行指定变量override针对系统环境传入变量。