Makefile tutorial
总结一下makefile tutorial里的教程,总不能一直拿bash做构建系统
Makefile rules
rules
是makefile最基本的内容,当运行make
时,其实就是在执行对应rule下面的命令
1 | target: prerequirement |
一个rule由以上结构组成,target
是rule的目标文件名称,prerequirement
是rule的依赖文件,只有这些文件都存在才会执行对应的rule,command
是make命令或者shell命令,前面有一个tab
缩进
rule之间可以互相依赖
1 | test: test.o |
比如上面这个,test
的依赖是test.o
,运行make时会先运行test.o
,再执行test
变量
makefile变量只能是纯文本,引号之类的也不会转义,有三种给变量赋值的方式
1 | a:= 1 |
:=
是立刻赋值,=
是当使用到了才赋值(延迟赋值),?=
是未初始化则赋值
使用+=
实现变量字符串的拼接
变量通过$()
来使用
1 | a:= test1 test2 test3 |
target
rule可以设置多个prerequirement
1 | all: one two three |
这个经典的例子就是make all
,等价于make one two three
rule同时也可以设置多个target
,等价于执行好多遍
1 | f1.o f2.o: |
预设变量
下面是几个常用的预设变量
$@
target
名$?
所有时间戳比target
新的prerequirement
$^
所有的prerequirement
$<
第一个prerequirement
正则匹配
只有*
和%
两种匹配符,*
正则匹配只建议由wildcard
函数包裹使用
*
的功能是匹配任意字符,比如$(wildcard *.c)
就是目录下所有后缀为.c
的文件%
的功能是匹配并替换,通常用在模式固定的rule或者字符串替换中
1 | %.o : %.c |
这里就是匹配目录下所有.c
文件的名称作为pattern
然后生成对应名字的.o
文件
1 | objects = foo.o bar.o all.o |
这个则是从objects
中提取符合%.o
的模式,然后替换到%.c
中,等于是为每个.o
寻找对应的.c
文件并编译
c/cpp
makefile会自动对目录下的与目标同名的c/cpp
文件生成编译命令,不建议使用这个技巧
n.o会以n.c作为源被以下命令编译
$(CC) -c $(CPPFLAGS) $(CFLAGS) $^ -o $@
如果是n.cc或n.cpp则是如下
$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $^ -o $@
n会以n.o默认以以下命令链接
$(CC) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@
命令
在命令前加@
可以静默执行,make -s
可以让所有命令静默执行
每行命令的shell环境是独立的,但是可以用;
在一行连接多个命令,然后用\
连接多个行
1 | all: |
shell变量
shell环境变量和makefile变量是两种不同的东西,要使用shell环境变量,则要在变量名前加$$
且不用括号包裹(这里类似转义)
1 | make_var = I am a make variable |
递归调用make
如果需要在子文件夹中递归调用make
则使用$(MAKE)
命令而不是shell命令,因为前者会帮助传递makefile变量
export
由export命令设置成环境变量的makefile变量可以被所有的rule和子makefile访问
1 | shell_env_var=Shell env var, created inside of Make |
这里输出的两行都是一样的
override
带override修饰的变量会忽略来自命令行的传参override option_one = did_override
option_one
永远是did_override
target特化的变量
1 | all: one = cool |
变量可以为不同的target设置不同的值,这里make all
时one
的值为cool
,否则为空
这里的target
也可以用正则
1 | %.c: one = cool |
条件表达式
1 | foo = ok |
函数
函数通过这两种模式的任意一种调用${fn,arguments}
,$(fn,arguments)
第一个参数的参数前不要带空格,否则空格会被识别成参数字符串的一部分
字符串替换
$(patsubst pattern,replacement,text)
patsubst
函数从text
中筛选符合pattern
的空格分隔的字符串并替换成replacement
,这里通常结合正则使用
1 | foo := a.o b.o l.a c.o |
批量修改
$(foreach var,list,text)
foreach
函数把list
中按空格分隔的每个字符串修改成新的,var
是遍历时的变量,在text
中使用,text
是目标字符串
1 | foo := who are you |
过滤
$(filter pattern,objects)
filter
从objects
中按空格为分隔符筛选出符合pattern
的字符串filter-out
则是筛掉符合的
vpath
vpath <pattern> <directories, space/colon separated>
vpath
是为指定pattern
的文件添加搜索路径,pattern
可以是%
正则vpath %.h ../headers ../other-directory
比如这个就会在headers
里搜索.h
文件
.PHONY
.PHONY
是伪目标宏,听起来很难懂,其实就是带.PHONY
修饰的rule不管target状态如何都会执行
1 |
|
Makefile tutorial