1.=,:=,+=区别
1 = 是最基本的赋值 2 := 是覆盖之前的值 3 ?= 是如果没有被赋值过就赋予等号后面的值 4 += 是添加等号后面的值 5 1、“=” 6 make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。看例子: 7 x = foo 8 y = $(x) bar 9 x = xyz 10 在上例中,y的值将会是 xyz bar ,而不是 foo bar 。 11 2、“:=” 12 “:=”表示变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。 13 x := foo 14 y := $(x) bar 15 x := xyz 16 在上例中,y的值将会是 foo bar ,而不是 xyz bar 了。
2.MAKEFLAGS += -rR --no-print-directory
1 MAKEFLAGS是make内置的环境变量,这些参数的含义,可以通过man make 获得详细解释. 2 以上”-rR“表示禁用内置的隐含规则和变量定义, 3 --no-print-directory 是 Turn off -w, even if it was turned on implicitly.
3.ifeq、ifneq、ifdef
1 使用条件判断,可以让make根据运行时的不同情况选择不同的执行分支。条件表达式可以是比较变量的值,或是比较变量和常量的值。 2 3 一、示例 4 5 下面的例子,判断$(CC)变量是否“gcc”,如果是的话,则使用GNU函数编译目标。 6 7 libs_for_gcc = -lgnu 8 normal_libs = 9 10 foo: $(objects) 11 ifeq ($(CC),gcc) 12 $(CC) -o foo $(objects) $(libs_for_gcc) 13 else 14 $(CC) -o foo $(objects) $(normal_libs) 15 endif 16 17 可见,在上面示例的这个规则中,目标“foo”可以根据变量“$(CC)”值来选取不同的函数库来编译程序。 18 19 我们可以从上面的示例中看到三个关键字:ifeq、else和endif。ifeq的意思表示条件语句的开始,并指定一个条件表达式,表达式包含两个参数,以逗号分隔,表达式以圆括号括起。else表示条件表达式为假的情况。endif表示一个条件语句的结束,任何一个条件表达式都应该以endif结束。 20 21 当我们的变量$(CC)值是“gcc”时,目标foo的规则是: 22 23 foo: $(objects) 24 $(CC) -o foo $(objects) $(libs_for_gcc) 25 26 而当我们的变量$(CC)值不是“gcc”时(比如“cc”),目标foo的规则是: 27 28 foo: $(objects) 29 $(CC) -o foo $(objects) $(normal_libs) 30 31 当然,我们还可以把上面的那个例子写得更简洁一些: 32 33 libs_for_gcc = -lgnu 34 normal_libs = 35 36 ifeq ($(CC),gcc) 37 libs=$(libs_for_gcc) 38 else 39 libs=$(normal_libs) 40 endif 41 42 foo: $(objects) 43 $(CC) -o foo $(objects) $(libs) 44 45 46 二、语法 47 48 条件表达式的语法为: 49 50 <conditional-directive>; 51 <text-if-true>; 52 endif 53 54 以及: 55 56 <conditional-directive>; 57 <text-if-true>; 58 else 59 <text-if-false>; 60 endif 61 62 其中<conditional-directive>;表示条件关键字,如“ifeq”。这个关键字有四个。 63 64 第一个是我们前面所见过的“ifeq” 65 66 ifeq (<arg1>;, <arg2>;) 67 ifeq '<arg1>;' '<arg2>;' 68 ifeq "<arg1>;" "<arg2>;" 69 ifeq "<arg1>;" '<arg2>;' 70 ifeq '<arg1>;' "<arg2>;" 71 72 比较参数“arg1”和“arg2”的值是否相同。当然,参数中我们还可以使用make的函数。如: 73 74 ifeq ($(strip $(foo)),) 75 <text-if-empty>; 76 endif 77 78 这个示例中使用了“strip”函数,如果这个函数的返回值是空(Empty),那么<text-if-empty>;就生效。 79 80 第二个条件关键字是“ifneq”。语法是: 81 82 ifneq (<arg1>;, <arg2>;) 83 ifneq '<arg1>;' '<arg2>;' 84 ifneq "<arg1>;" "<arg2>;" 85 ifneq "<arg1>;" '<arg2>;' 86 ifneq '<arg1>;' "<arg2>;" 87 88 其比较参数“arg1”和“arg2”的值是否相同,如果不同,则为真。和“ifeq”类似。 89 90 第三个条件关键字是“ifdef”。语法是: 91 92 ifdef <variable-name>; 93 94 如果变量<variable-name>;的值非空,那到表达式为真。否则,表达式为假。当然,<variable-name>;同样可以是一个函数的返回值。注意,ifdef只是测试一个变量是否有值,其并不会把变量扩展到当前位置。还是来看两个例子: 95 96 示例一: 97 bar = 98 foo = $(bar) 99 ifdef foo 100 frobozz = yes 101 else 102 frobozz = no 103 endif 104 105 示例二: 106 foo = 107 ifdef foo 108 frobozz = yes 109 else 110 frobozz = no 111 endif 112 113 第一个例子中,“$(frobozz)”值是“yes”,第二个则是“no”。 114 115 第四个条件关键字是“ifndef”。其语法是: 116 117 ifndef <variable-name>; 118 119 这个我就不多说了,和“ifdef”是相反的意思。 120 121 在<conditional-directive>;这一行上,多余的空格是被允许的,但是不能以[Tab]键做为开始(不然就被认为是命令)。而注释符“#”同样也是安全的。“else”和“endif”也一样,只要不是以[Tab]键开始就行了。 122 123 特别注意的是,make是在读取Makefile时就计算条件表达式的值,并根据条件表达式的值来选择语句,所以,你最好不要把自动化变量(如“$@”等)放入条件表达式中,因为自动化变量是在运行时才有的。 124 125 而且,为了避免混乱,make不允许把整个条件语句分成两部分放在不同的文件中。
4.origin
1 $(origin VARIABLE) 2 3 函数功能:函数“origin”查询参数“VARIABLE” (一个变量名)的出处。 4 函数说明: “VARIABLE”是一个变量名而不是一个变量的引用。因此通常它不 5 包含“$”(当然,计算的变量名例外)。 6 返回值:返回“VARIABLE”的定义方式。用字符串表示。 7 函数的返回情况有以下几种: 8 1. undefined 9 变量“VARIABLE”没有被定义。 10 2. default 11 变量“VARIABLE”是一个默认定义(内嵌变量) 。如“CC”、“MAKE”、“RM” 12 等变量(参考 10.3 隐含变量 一节)。如果在Makefile中重新定义这些变量, 13 函数返回值将相应发生变化。 14 3. environment 15 变量“VARIABLE” 是一个系统环境变量, 并且make没有使用命令行选项“-e” 16 (Makefile中不存在同名的变量定义,此变量没有被替代)。参考 10.7 make 17 的命令行选项 一节 18 4. environment override 19 变量“VARIABLE”是一个系统环境变量,并且make使用了命令行选项“-e”。 20 Makefile中存在一个同名的变量定义,使用“make -e”时环境变量值替代了 21 文件中的变量定义。 参考 9.7 make的命令行选项 一节 22 5. file 23 变量“VARIABLE”在某一个 makefile 文件中定义。 24 6. command line 25 变量“VARIABLE”在命令行中定义。 26 7. override 27 变量“VARIABLE”在 makefile 文件中定义并使用“override”指示符声明。 28 8. automatic 29 变量“VARIABLE”是自动化变量。 30 31 函数“origin”返回的变量信息对我们书写 Makefile 是相当有用的,可以使我们在 32 使用一个变量之前对它值的合法性进行判断。假设在 Makefile 其包了另外一个名为 33 bar.mk 的 makefile 文件。我们需要在 bar.mk 中定义变量“bletch”(无论它是否是一 34 个环境变量),保证“make –f bar.mk”能够正确执行。另外一种情况,当Makefile 包 35 含bar.mk,在Makefile包含bar.mk之前有同样的变量定义,但是我们不希望覆盖bar.mk 36 中的“bletch”的定义。一种方式是:我们在bar.mk中使用指示符“override”声明这 37 个变量。但是它所存在的问题时,此变量不能被任何方式定义的同名变量覆盖,包括命 38 令行定义。另外一种比较灵活的实现就是在bar.mk 中使用“origin”函数,如下: 39 40 ifdef bletch 41 ifeq "$(origin bletch)" "environment" 42 bletch = barf, gag, etc. 43 endif 44 endif 45 46 这里,如果存在环境变量“bletch”,则对它进行重定义。 47 48 ifneq "$(findstring environment,$(origin bletch))" "" 49 bletch = barf, gag, etc. 50 endif 51 52 这个例子实现了:即使环境变量中已经存在变量“bletch”,无论是否使用“make -e” 53 来执行 Makefile,变量“bletch”的值都是“barf,gag,etc”(在 Makefile 中所定义的) 。 54 环境变量不能替代文件中的定义。 55 如果“$(origin bletch)”返回“environment”或“environment override”,都将对 56 变量“bletch”重新定义。
5.DIR = $(CURDIR)
1 CURDIR是make的内嵌变量,自动设置为当前目录 2 3 测试 4 5 all: 6 7 @echo $(CURDIR) 8 9 10 11 make 后就显示当前路径
6.$(CURDIR)/Makefile Makefile: ;
1 这是一条"空指令",Makefile中使用它来阻止make使用隐含规则构建指定目标。 2 make 在执行时,需要一个命名为Makefile 的文件。在一个完整的Makefile 中,一般包含了5部分:规则(显示指定和隐含规则)、变量定义(同样包含显示变量和隐含变量)、指示符( include, define 等)和注释。 3 显 示规则是由作者显示写出的规则,而隐含规则则是内建在make 中,为make 提供了重建某一类目标文件(.o 等)的通用方法,同时这些隐含规则所用到的变量也就是所谓的隐含变量。隐含规则和隐含变量可以通过make -p -f /dev/null 查看。隐含规则的好处是在Makefile 中不需要明确给出重建某一个目标的命令,甚至可以不需要规则。make会为你自动搜寻匹配的隐含规则链。 4 这个世界上没有免费的午餐,隐含规则的代价之一就是低效,系统必须搜索可能的隐含规则链。同时隐含规则也有可能应用了不是你想要的规则而引入很难debug的错误。 5 Cancel implicit rules on top Makefile的意思就是取消上述makefile的隐含规则。 6 7 大家会奇怪为什么要定义一个没有命令的规则。其唯一的原因是,空命令行可以防止make在执行时试图为重建这个目标去查找隐含命令(包括了使用隐含规则中的命令 8 和“.DEFAULT”指定的命令。
7.if
1 $(if CONDITION,THEN-PART[,ELSE-PART]) 2 3 函数功能:第一个参数“CONDITION” ,在函数执行时忽略其前导和结尾空字 4 符,如果包含对其他变量或者函数的引用则进行展开。如果“CONDITION”的 5 展开结果非空,则条件为真,就将第二个参数“THEN_PATR”作为函数的计算 6 表达式;“CONDITION”的展开结果为空,将第三个参数“ELSE-PART”作为 7 函数的表达式,函数的返回结果为有效表达式的计算结果。 8 返回值:根据条件决定函数的返回值是第一个或者第二个参数表达式的计算结 9 果。当不存在第三个参数“ELSE-PART” ,并且“CONDITION”展开为空,函 10 数返回空。 11 函数说明:函数的条件表达式“CONDITION”决定了函数的返回值只能是 12 “THEN-PART”或者“ELSE-PART”两个之一的计算结果。
8.filter-out
1 $(filter-out PATTERN...,TEXT) 2 函数名称:反过滤函数—filter-out。 3 函数功能:和“filter”函数实现的功能相反。过滤掉字串“TEXT”中所有符合模式 4 “PATTERN”的单词,保留所有不符合此模式的单词。可以有多个模式。 5 存在多个模式时,模式表达式之间使用空格分割。。 6 返回值:空格分割的“TEXT”字串中所有不符合模式“PATTERN”的字串。 7 函数说明: “filter-out”函数也可以用来去除一个变量中的某些字符串, (实现和 8 “filter”函数相反)。 9 示例: 10 objects=main1.o foo.o main2.o bar.o 11 mains=main1.o main2.o 12 13 $(filter-out $(mains),$(objects)) 14 实现了去除变量“objects”中“mains”定义的字串(文件名)功能。它的返回值 15 为“foo.o bar.o”。
9.FORCE
1 FORCE 2 3 首先分析一下这个依赖,它的规则定式义在内核源码主目录的Makefile中: 4 5 PHONY += FORCE 6 FORCE: 7 8 这个规则没有命令也没有依赖,它的目标也不是一个存在的文件名。fu在执行此规则时,目标FORCE总会被认为是最新的。这样当它作为其它规则的依赖时,因为依赖总被认为被更新过的,所以那个规则的中定义的命令总会被执行。