makefile变量和宏变量和宏其实说的是同一件事。变量的内容是一个字符串,从变量名中获取变量内容的过程称为变量扩展。只需使用$()或${}来扩展变量名。而不是像在编程语言中那样使用变量名来引用变量的值。变量类型make中有两种类型的变量:简单变量和递归扩展变量。变量的定义是一个赋值动作,将等号右边的内容赋值给左边。等号可以有很多种::=、=、?=,它们决定了如何赋值。等号两边的东西可以只是字面值,也可以包含变量。赋值时变量名需要明确,等号左边的内容立即展开(没有变量则保持不变),右边的内容根据等号决定什么时候展开赋值符号。用:=或::=赋值运算符定义的简单变量是简单扩展变量。一旦make读取到变量的定义语句,赋值运算符右边的部分会立即展开,展开后的文本作为变量的值存储。变量名和变量内容被添加到数据库中。MAKE_DEPEND:=$(CC)-M这个变量一般展开为gcc-M但是,如果CC变量没有被定义,展开为:-MVariablenotdefined不报错。递归变量是用=定义的变量。或者定义已定义的变量。make只会读取赋值运算符之后的部分,并将其存储为变量的值,而不会执行任何扩展动作,该动作会延迟到使用变量时。其他赋值类型make还提供了另外两个赋值运算符:?=和+=。?=运算符被称为条件变量赋值运算符。只有当变量的值尚不存在时,此运算符才会复制。+=运算符称为追加运算符。此运算符将文本附加到变量。对递归变量仍然有用。对于简单变量,相当于simple:=$(simple)newstuff但是,对于递归变量,表达式recursive=$(recursive)newstuff是非法的,会被无限展开。要将一段文本附加到递归变量,需要附加运算符。作业目标和模式特定变量make提供作业目标特定变量。这些变量的定义会附加到作业目标上,只有当作业目标和相应的必要条件被处理时,它们才会生效。工作目标的独占变量语法如下:file单独指定一个宏定义,但是文件在一个patternrule中:gui.o:CPPFLAGS+=-DUSE_NEW_MALLOC=1gui.o:gui.h当make处理gui.o的worktarget时,会追加变量CPPFLAGS-DUSE_NEW_MALLOC=1,CPPFLAGS会在处理完gui.o目标后恢复原来的值。可变源文件变量可以在makefile中定义,也可以通过makefile引入(include命令)。命令行可以在make命令行直接定义或重新定义变量:$makeCFLAG=-gCPPFLAGS='DBSD-DDEBUG'every每个命令行参数中包含的等号是一个变量赋值运算符。在命令行上,每个变量赋值运算符的右侧部分必须是单个shell参数。如果变量的值包含空格,则参数必须括在括号或引号中。命令行对变量的赋值会覆盖环境变量和makefile的赋值结果。如果想让makefile中的变量覆盖命令行中的变量,可以在makefile中的变量前加上override指令。环境当make启动时,来自环境的所有变量都被定义为make变量。这些变量的优先级很低,makefile或命令行参数的赋值结果会覆盖环境变量的值。但是,您可以使用--environment-overrides(或-e)命令行选项让环境变量覆盖相应的makefile变量。递归调用make时,上层make的几个变量会通过环境传递给下层make。默认情况下,只有最初来自环境的变量才会导出到底层环境。可以使用导出指令导出任何变量。自动创建make在执行常规命令脚本之前立即创建自动变量。注意自动创建变量的时间。makefile中定义变量variable:=valuevariable=valuevariable?=valuedefinevariable=......endefdefinevariable:=......endefdefine的特点是可以定义多行内容的变量。变量的值由赋值符号右侧的所有字符组成,不包括前导空格。不会删除所有单词后面的空格。这有时会导致问题。宏宏是变量的另一个旧名称。可以通过define指令创建称为宏的“封装命令序列”。在make中,宏只是定义变量的另一种形式,它也可以包含换行符。一般用define定义的变量称为宏,用赋值运算符定义的变量称为变量。define后跟变量名和换行符。变量的主体是以制表符开头并以endef结尾的命令行。定义创建jar@echo创建$@...$(RM)$(TMP_JAR_DIR)$(MKDIR)$(TMP_JAR_DIR)$(CP)-r$^$(TMP_JAR_DIR)cd$(TMP_JAR_DIR)&&$(JAR)$(JARFLAGS)$@的函数。$(JAR)-ufm$@$(MANIFEST)$(RM)$(TMP_JAR_DIR)endef@:Make会打印出每个命令,然后将其交给shell执行。命令前加上@可以使make不这样做。如果将宏应用于命令,使用@将导致整个宏扩展命令都以@开头。当make运行时,它分两个阶段完成工作。在第一阶段,make读取makefile和包含的任何其他makefile。此时,其中定义的变量会被加载到make内部的数据库中,构建依赖图。第二阶段,make分析依赖图,确定需要更新的目标,然后执行脚本。make在处理递归变量或define指令时,会将每一行存储在变量或宏体中,包括换行符,但不会展开。宏定义的最后一个换行符不会成为宏的一部分,否则在展开宏时会额外添加一个换行符。当一个宏被展开时,make会立即扫描展开后的文本以查找对宏或变量的引用,如果存在则展开,以此类推。如果在命令脚本中展开宏,则将在宏主体的每一行插入一个制表符。下面是makefile中的元素展开时的原则:对于变量赋值,make在第一阶段读到一行时,会立即展开赋值运算符左边的部分。=和?=的右侧会一直展开,直到被使用,并在第二阶段运行。:=的右侧立即展开。如果+=的左侧定义为简单变量,则+=的右侧立即展开。否则,评估会延迟。对于宏定义,宏的变量名立即展开,宏体稍后展开。对于规则,作业目标和先决条件总是立即展开,而命令总是稍后展开。延迟扩展发生在它所在的表达式需要扩展时,例如在规则的目标和先决条件中,在要执行的命令中,或者出现在简单变量赋值的右侧等。OUTPUT_DIR:=/tmp$(OUTPUT_DIR)/very_big_file:$(free-space)definefree-space$(PRINTF)"Freediskspace"$(DF).|$(AWK)'NR==2{print$$4}'endefBIN:=/usr/binPRINTF:=$(BIN)/printfDF:=$(BIN)/dfAWK:=$(BIN)/awk解释:第一个stage:make逐行读取makefile,将变量添加到数据库,构建依赖图。OUTPUT_DIR是一个简单的变量,它的值是一个普通的字面量值(如果有$引用的变量,会被展开),放到数据库中。接下来是规则,规则的目标和条件都立即展开,而命令稍后展开并保持不变。所以这条规则就变成了:/tmp/very_big_file:$(free-space)后面是一个宏定义,宏名立即展开,这里只是一个字面值,不需要展开。宏体是延迟展开的,只有在使用宏时才会展开。最后四个简单变量直接展开,变量值加入数据库。第二阶段:后序遍历规则树,执行规则。这时候就应该利用规则中的命令部分来展开命令中的变量和宏,执行命令。自动变量自动变量是在处理规则时自动分配的变量。变量名描述$@作业目标的文件名$%存档成员结构中的文件名元素$<第一个要求的文件名$?在作业目标之后为所有先决条件添加时间戳,以空格分隔。$^所有必要条件的文件名,以空格分隔。$+和$^一样,代表所有必要条件的文件名,以空格隔开。但是$+包含重复的文件名。$*作业目标的主文件名。文件名由主文件名和扩展名组成。解释:档案中的个别成员可以用作工作目标或先决条件。可以通过诸如archive(member)的语法在归档文件archive中指定名为member的成员。如果作业目标是foo.a(bar.o),则$%是bar.o,$@是foo.a。当作业目标不是存档时,$%为空。