Makefile
介绍
Makefile 的基本规则:
|
target
:可以是一个 object file(目标文件),也可以是一个可执行文件,还可以是一个标签(label)prerequisites
:生成该 target 所依赖的文件和/或 targetrecipe
:该 target 要执行的命令(任意的 shell 命令)
简单来说就是指定了一个依赖关系
输入 make
命令时,是这么工作的:
make
会在当前目录下找名字叫Makefile
或makefile
的文件- 如果找到,它会找文件中的第一个目标文件(target),并把这个文件作为最终的目标文件
- 如果该文件不存在,或其所依赖的后面的
.o
文件的文件修改时间要比这个文件新,则执行后面所定义的命令来生成这个文件 - 如果所依赖的
.o
文件也不存在,那么 make 会在当前文件中找目标为.o
文件的依赖性,如果找到则再根据那一个规则生成.o
文件 - 最后用
.o
文件生成可执行文件
在 Makefile 中可以声明变量并使用变量:
|
事实上,make 可以自动推导文件及依赖关系后的命令,如
|
可以简化为:
|
每个 Makefile 都应该在最后写一个清空目标文件的规则,如:
|
当然,Makefile 可以为任意的文件名,但在使用时必须指定:make -f Make.Solaris
还可以把其他 Makefile 包含进来,如:
|
其寻找的位置是:
- 当前目录
-I
参数指定的目录<prefix>/include
书写规则
make 支持三个通配符:*
,?
和 ~
VPATH
变量指定了 make 寻找文件的目录,还有 vpath
功能类似,但是更灵活:
vpath <pattern> <directories>
:为符合模式<pattern>
的文件指定搜索目录<directories>
vpath <pattern>
:清除符合模式<pattern>
的文件的搜索目录vpath
:清除所有已被设置好了的文件搜索目录
可以连续使用 vpath
语句
因为不生成 clean
文件,故这是一个伪目标,如:
|
Makefile 的规则中的目标可以不止一个,如
|
静态模式可以更加容易地定义多目标的规则:
|
targets
定义了一系列的目标文件,可以有通配符target-pattern
是指明了targets
的模式,也就是的目标集模式prereq-patterns
是目标的依赖模式,它对target-pattern
形成的模式再进行一次依赖目标的定义
大多数的 C/C++ 编译器都支持一个 -M
的选项,即自动找寻源文件中包含的头文件,并生成一个依赖关系
利用这个特性,我们可以为每一个 name.c
的文件都生成一个 name.d
的 Makefile 文件, .d
文件中就存放对应 .c
文件的依赖关系
书写命令
通常,make 会把执行的命令显示到屏幕上,如果不想显示,则加上 @
,如:
|
当然,加上参数 -s
会全面禁止命令的显示
如果要让上一条命令的结果应用在下一条命令上,则应该使用 ;
分割这两条命令,如:
|
make 默认使用的 shell 是 /bin/sh
make 会检测每个命令的返回码,如果失败,则会终止执行当前规则;为了让其忽略出错,可以在命令前加 -
,如:
|
相应的全局方法是加上参数 -i
可以嵌套执行 Makefile 文件,如总控 Makefile 可以这样写:
|
其作用是执行 subdir
目录下的 Makefile 文件
默认情况下总控中定义的变量不会传递给下级的 Makefile,如果想要传递,可以:
|
如果要传递所有的变量,则直接使用 export
加上 -w
参数可以看到当前的工作目录
我们可以为相同的命令序列定义一个变量:
|
使用变量
定义变量的方法:
|
注意到上面那种定义顺序是合法的,当然还有另一种方法避免了这种情况:
|
一种定义一个空格的变量的方法:
|
?=
表示如果没有定义过,则定义;反之,则什么都不做
$(var:a=b)
:把变量 var
中所有结尾的 a
替换成 b
。这里的“结尾”意思是“空格”或是“结束符”。
可以使用 +=
给变量追加值
如果有变量是 make 的命令行参数设置的,则 Makefile 中对这个变量的赋值会被忽略,如果想设置,可以在前面加 override
之前定义的变量都是“全局变量”,也可以为某个目标设置局部变量,其作用范围只在这条规则以及连带规则中:
|
还支持模式变量,即可以把变量定义在所有符合该模式的目标上:
|
使用条件判断
|
除了 ifeq
以外,还有 ifneq
、ifdef
、ifndef
使用函数
函数调用类似于变量使用:
|
字符串替换函数 subst
:
|
把字串 <text>
中的 <from>
字符串替换成 <to>
还有相应的模式版本 patsubst
:
|
去空格函数 strip
:
|
去掉 <string>
字串中开头和结尾的空字符
查找字符串函数 findstring
:
|
sort
排序(升序),注意同时会去重
取单词串函数 wordlist
|
名称 | 功能 | 名称 | 功能 |
---|---|---|---|
filter |
过滤 | filter-out |
反过滤 |
word |
单词个数统计 | firstword |
首单词 |
dir |
取目录 | notdir |
取非目录 |
suffix |
取后缀 | basename |
取前缀 |
addsuffix |
加后缀 | addprefix |
加前缀 |
连接函数 join
:
|
功能:把 <list2>
中的单词对应地加到 <list1>
的单词后面
用来做循环的 foreach
:
|
把参数 <list>
中的单词逐一取出放到参数 <var>
所指定的变量中,然后再执行 <text>
所包含的表达式
if
函数
|
call
可以用来创建新的参数化:
|
origin
告诉你变量是从哪里来的
shell
函数参数是 shell 命令,和反引号功能一致,注意其会影响性能
还有控制函数:
|
make 的运行
make
的时候可以指定目标
隐含规则
make 中有一些隐含规则,不必写出来,例如编译 C 语言的:
<n>.o
的目标的依赖目标会自动推导为 <n>.c
,并且其生成命令是 $(CC) –c $(CPPFLAGS) $(CFLAGS)
隐含规则使用的变量:
AR
:函数库打包程序,默认命令是ar
AS
:汇编语言编译程序,默认命令是as
CC
:C 语言编译程序,默认命令是cc
CXX
:C++语言编译程序,默认命令是g++
相关命令的参数:
CFLAGS
: C 语言编译器参数CXXFLAGS
: C++语言编译器参数CPPFLAGS
: C 预处理器参数LDFLAGS
: 链接器参数
模式规则:使用 %
通配
自动化变量及其说明:
$@
:表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,$@
就是匹配于目标中模式定义的集合$%
:仅当目标是函数库文件中,表示规则中的目标成员名$<
:依赖目标中的第一个目标名字。如果依赖目标是以模式(即%
)定义的,那么$<
将是符合模式的一系列的文件集。注意,其是一个一个取出来的$?
:所有比目标新的依赖目标的集合$^
:所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那么这个变量会去除重复的依赖目标,只保留一份$+
:这个变量很像$^
,也是所有依赖目标的集合。只是它不去除重复的依赖目标
使用 make 更新函数库文件
一个函数库文件由多个文件组成,可以用如下格式指定函数库文件及其组成:
|