Makefile 中的变量
在 Makefile 中定义的变量,就像是C/C++语言中的宏一样,他代表了一个文本字串,在
Makefile 中执行的时候其会自动原模原样地展开在所使用的地方。与C/C++所不同的是,你
可以在 Makefile 中改变其值。在 Makefile 中,变量可以在“目标”,“依赖目标”,
“命令”或是 Makefile 的其它部分中使用。
可以把每个 recipe 当作字符串理解,通过各种方法组成一个字符串,然后交给 shell 执行。
注意:文中的“命令”一词表示以上语法中的 recipe。
本文主要说自动变量,如有疏漏,还请大方指教。(可是现在没有评论,怎么指教呢?)
规则语法:
1 | targets : prerequisites |
或者是:
1 | targets : prerequisites ; recipe |
静态模式规则 (Static Pattern Rules):
1 | targets …: target-pattern: prereq-patterns … |
可以使用模式规则来定义一个隐含规则。一个模式规则就好像一个一般的规则,只是在规则
中,目标的定义需要有”%”字符。”%”的意思是表示一个或多个任意字符。在依赖目标中同样
可以使用”%”,只是依赖目标中的”%”的取值,取决于其目标。
有一点需要注意的是,”%”的展开发生在变量和函数的展开之后,变量和函数的展开发生在
make载入Makefile时,而模式规则中的”%”则发生在运行时。
我也不知道为什么叫静态模式,也许还有一个动态的吧。
模式规则中,至少要在规则的目标定义中包含”%”,否则,就是一般的规则。目标中的”%”定
义表示对文件名的匹配,”%”表示长度任意的非空字符串。
$@
先看官方文档里的说明:
The file name of the target of the rule. If the target is an archive member,
then ‘$@’ is the name of the archive file. In a pattern rule that has multiple
targets, ‘$@’ is the name of whichever target caused the rule’s recipe to be
run.
所以,$@表示一条规则中目标的名字。
看一个例子:
1 | output: |
执行结果为:
1 | make output |
可以看出$@表示的就是目标名字,而且目标是单独列出还是和其他一起列出也不影响。
另一个例子:
1 | objects = foo.o bar.o |
执行结果为:
1 | make all |
可以看到在目标是一个变量表示的集合时,$@的值仍为规则展开后的对应的目标名字。
但文档里说的并不是规则名字,而是 the file name of the target of the rule。但第一
个例子中output 也并非是一个文件名,所以此处有些疑问。
$<
The name of the first prerequisite. If the target got its recipe from an
implicit rule, this will be the first prerequisite added by the implicit rule.
变量 $<
表示依赖文件(就是 target 冒号后面的文件集合)中的第一个。先看一个简单的例子:
1 | noinput: |
输出为:
1 | touch empty.c main.c |
如果把 empty.c t main.c 调换位置的话:
1 | output: main.c empty.c |
这时的输出结果为:
1 | make output |
再复杂一点的话:
1 | objects = foo.o bar.o |
输出为:
1 | make all |
从例子中确实可以看出,$<
表示的是第一个依赖的名字。
$^ 和 $+
$^
表示所有的依赖的集合。以空格分隔。如果在依赖中有多个重复的,那个这个变量会
去除重复的依赖,只保留一份。
$+
与 $^
十分类似,只是它不去除重复的依赖。
还是看一个简单的例子:
1 | noduplicate: main.c empty.c main.c |
执行一下:
1 | make noduplicate |
注意其中重复的文件 main.c 的出现次数。
$%
变量$%
是专门用来处理库文件的自动变量,文档中的解释是:
The target member name, when the target is an archive member. See Archives.
For example, if the target is foo.a(bar.o) then ‘$%’ is bar.o and ‘$@’ is
foo.a. ‘$%’ is empty when the target is not an archive member.
因为库文件的打包方式几乎只有一种,似乎 Makefile 为它单独做了处理,有特别的语法。例子:
1 | libfoo.a(foo.o): foo.o |
1 | make lib.a |
可以看出$%
和$@
的不同,其中 lib.a: libfoo.a(foo.o)
不是 archive(member)
的形式,即文档中说的“not an archive member”,所以$%
的值为空。
$*
变量$*
表示%
匹配到的字符串。例如:
1 | %: |
如果在 shell 里执行 $ make test
,make 命令就会执行 gcc -o test test.c
。
再例如:
1 | bigoutput littleoutput : %output : test.c |
这里的$*
会被展开为 ‘big’ 或者 ‘little’
1 | touch test.c |
tip: echo 命令前面的@
表示不回显命令, 如果不理解可以尝试删除它。
以下是 linux kernel 中的一个例子:
1 | .c.s: |
其中的.c.s:
等可以理解为%.s: %.c
。
References
GNU make manual
跟我一起写 Makefile(五)
跟我一起写 Makefile(十三)
Advanced Makefile Tricks