变量与宏2

转自  http://blog.csdn.net/todd911/article/details/44237959

1.何时扩展变量

当make在处理递归变量或define指令的时候,会将变量里的每一行或宏的主体存储起来,包括换行符号,但不会予以扩展。

宏定义里的最后一个换行符号并不会被存储称宏的一部分,否则,宏被扩展时make会读进一个额外的换行符号。

当宏被扩展时,make会立即扫描被扩展的文本中是否存在宏或变量的引用,如果存在就予以扩展,如此递归进行下去。如果

宏是在命令脚本的语境中被扩展的,则宏主体的每一行都会被插入一个前导的跳格符。

下面是用来处理makefile中元素何时被扩展的准则:

1.对于变量的赋值,make会在第一阶段读进该行时,立即扩展赋值运算符左边的部分。

2.=和?=的右边部分会被延后到它们被使用的时候扩展,并且在第二阶段进行。

3.:=的右边部分会被立即扩展。

4.如果+=的左边部分原来被定义成一个简单变量,+=的右边部分就会被立即扩展,否则,它的求值动作会被延后。

5.对于宏定义,宏的变量名称会被立即扩展,宏的主体会被延后到使用的时候扩展。

6.对于规则,工作目标的必要条件总是被立即扩展,然而命令总是会延后扩展。

2.工作目标与模式的专属变量

在makefile运行期间,变量通常只有一个值,对需要经过两个处理阶段的makefile来说是这样没错。第一个阶段,make读取

makefile之后,会对变量进行赋值的扩展的动作并建立依存图。第二阶段,make会分析以及遍历依存图。所以等到make执行

命令脚本的时候,所有变量都已经处理完毕。但是如果我们想为特定的规则或模式重新定义变量,该怎么办?

现在,我们想要编译一个需要额外命令行选项-DUSE_NEW_MALLOC=1的文件,但是其他的编译项目并不需要这个额外的

命令行选项:

gui.o:gui.h

        $(COMPILE.c) -DUSE_NEW_MALLOC=1 $(OUTPUT_OPTION) $<

我们必须复制编译命令脚本以及为它加入这个必要的选项。如果有许多文件需要经过类似的特别处理,整个工作会变得冗长

乏味。

为解决此类问题,make提供了工作目标的专属变量,这些变量的定义会附在工作目标之上,且只有该工作目标以及相应的

任何必要条件被处理的时候,它们才会发生作用。通过使用此功能,我们可以改写成如下:

gui.o:CPPFLAGS += -DUSE_NEW_MALLOC=1

gui.o:gui.h

        $(COMPILE.c) $(OUTPUT_OPTION) $<

变量CPPFLAGS内置在默认在C编译规则里,用来保存供C预处理器使用的选项,通过使用+=附加运算符,我们可以把这个

新的选项附加到任何已存在的值里。

 

工作目标的专属变量的语法如下:

target...:variable = value

target...:variable := value

target...:variable += value

target...:variable ?= value

以上的语法只能用来定义工作目标的专属变量,此类变量在被赋值之前,并不需要事先存在。

此外,这类变量的赋值动作会延后到开始处理工作目标的时候进行,所以赋值运算符右边赋值的值,可由另一个目标的

专属变量来设定。同样地,此变量只有必要条件的处理期间,才会发生作用。

 

3.变量来自何处

make的变量可以有以下几个来源:

文件:

变量被定义在makefile中,或是被makefile引入。(include指令)

 

命令行:

直接在make命令行上定义或重新定义变量:

$make CFLAGS=-g CPPFLAGS='-DBSD -DDEBUG'

每个命令行参数中所包含的等号,都是一个变量赋值运算符。在命令行上,每个变量赋值运算符的右边部分必须是一个单独

的shell参数。如果变量的值包含空格,则必须为参数加上括号或者规避空格。

 

环境:

当make启动时,所有来自环境的变量都会被自动定义成make的变量。这些变量具有非常低的优先级,所以makefile文件

或命令行参数的赋值结果将会覆盖掉环境变量的值。不过,可以使用--environment-overrides(或-e)命令选项,让环境变量

覆盖掉相应的makefile变量。

 

自动创建:

make会在执行一个规则的命令脚本之前立即创建自动变量。

 

4.条件指令

当make所读进的makefile使用了条件处理指令时,makefile文件中有些部分会被省略,有些部分会被挑选处理,用来控制

是否选择的条件具有各种形式。

条件指令的基本语法如下所示:

if-condition

  text if the condition is true

endif

或:

if-condition

  text if the condition is true

else

  text if the condition is false

endif

 

if-condition可以是以下之一:

ifdef variable-name

ifndef variable-name

ifeq test

ifneq test

进行ifdef/ifndef的测试时,不应该以$()括住variable-name,test可以表示成下面这样:

"a" "b"

或:

(a,b)

ifeq和ifneq条件指令可用来测试其参数是否相等。条件指令里空格的处理有些微妙。举例来说,如果参数采用小括号的

形式,那么逗号之后的空格将会被忽略,除此之外所有其他的空格都是有意义的:

ifeq (a,a)

    #these are equal

endif

 

ifeq ( b, b )

    #these are not equal - ' b' != 'b '

endif

我比较喜欢使用等效的引号形式:

ifeq "a" "a"

    #these are equal

endif

 

ifeq 'b' 'b'

    #so are these

endif

 

5.include指令

一个makefile可以引入其他文件。此功能常用来引入make头文件中所存放的共同的make的定义,或是用来自动产生依存

关系的信息,include指令的用法如下:

include definitions.mk

你可以为这个指令提供任意多个文件,shell通配符以及make变量。

 

当make看到include指令时,会事先对通配符以及变量引用进行扩展的动作,然后试着读进引用文件(include file)。如果

这个文件存在,则整个处理过程会继续下去,然而,如果这个文件不存在,则make会汇报此文件并且继续读取其余的makefile。

当所有的读取动作皆已完成以后,make会从规则数据库中找出任何可用来更新引入文件的规则。如果找到一个相符的规则,

make就会按照正常的步骤更新工作目标。如果任何一个引入文件被规则更新,make接着会清除它的内部数据库并且重新

读取整个makefile。如果完成读取、更新和重新读取的过程之后,仍有include指令因为文件不存在而执行失败,那么make

就会显示错误状态并终止执行。

 

6.标准的make变量

除了自动变量,make还会为“自己的状态以及内置规则的定义”提供变量,一边对外提供相关信息:

MAKE_VERSIN:GNU make的版本编号。

CURDIR:正在执行make进程的当前工作目录,此变量的值将会时shell变量PWD的值,除非make在运行时用到了--directory

(或-C)选项。--directory选项会使得make在搜索任何makefile之前变更到不同的目录。这个选项的 完整形式是:

--directory=directory-name 或 -C directory-name。

MAKEFILE_LIST:make所读进的每个makefile文件的名称所构成的列表,包括默认的makefile以及命令行或include指令

所指定的makefile。每个makefile被读进make之前,其文件名会被附加到该变量里。

MAKECMDGOALS:对当前所运行的make而言,make运行时命令行上指定了那些工作目标。

.VARIABLES:到目前为止,make从各个makefile文件所读进的变量的名称所构成的列表,不含工作目标的专属变量,此

变量仅供读取,对它所进行的任何赋值动作都会被忽略掉。

posted @ 2015-06-29 14:44  neteasefans  阅读(297)  评论(0编辑  收藏  举报