Appearance
Make 简介
Makefile 是 make 命令对应的自动化任务配置文件,通常用在 C/C++。当然也可以用在其他语言,我看见过一些 go 项目也在使用。和 Gulpfile.js 等很类似,通过简单的配置,大大简化编译、构建过程,提高开发效率。
其他同类软件:
- C/C++:SCons, CMake, Bazel, Ninja...
- Java: Ant, Maven, Gradle...
Hello World
在当前目录下创建一个 Makefile 文件:
Makefile
hello:
echo "Hello World"运行 make 指令:
bash
~> make
echo "Hello World"
Hello World基本格式
Makefile
targets: prerequisites
command
command
command- targets: 构建目标文件名,用空格分隔,一般只有一个
- commands:构建指令,通常需要制表符缩进,而不是空格
- prerequisites:先决条件文件名,空格分隔,也称为依赖项
依照这个格式,我们可以通过 make hello 构建 hello 目标文件,只要 hello 不存在,构建指令永远可以运行。当我们 touch hello 以后,再次执行 make hello ,将会显示 make: 'hello' is up to date.。
编译单个 C 文件
Makefile
blah:
cc blah.c -o blahc
int main() { return 0; }通过运行 make blah ,make 将根据目录是否存在 blah 调用 cc 来编译 blah.c 文件。但是这样子,如果 blah.c 代码文件更新,重新运行 make blah,make 不会重新编译。此时可以把 blah.c 作为依赖项目:
Makefile
blah: blah.c
cc blah.c -o blah此时,修改 blah.c 后,make 会比较 balh 和 balh.c 的时间戳,依据时间戳判断 balh 是否为最新,如果 blah 的时间戳比 blah.c 早,说明代码已经更新,需要重新编译。
分步编译单个 C 文件
Makefile
blah: blah.o
cc blah.o -o blah # Runs third
blah.o: blah.c
cc -c blah.c -o blah.o # Runs second
# Typically blah.c would already exist, but I want to limit any additional required files
blah.c:
echo "int main() { return 0; }" > blah.c # Runs first此时执行 make :
- 如果 blah.c 不存在,执行三个任务
- 如果 blah.o 不存在,执行头两个任务
- 如果 blah 不存在,执行第一个任务
可以发现,任务会按照依赖项目进行递归地执行。
make clean
Makefile
clean:
rm -f *.o这是比较常见的清理目标文件的方式,它的原理同最上面的 hello world。
变量
Makefile
files := file1 file2
some_file: $(files)
echo "Look at this variable: " $(files)
touch some_file
file1:
touch file1
file2:
touch file2
clean:
rm -f file1 file2 some_file支持使用变量,使得更多行数的 Makefile 更容易维护
- 变量使用
=或者:=赋值 - 变量使用
${var}或者$()引用
make all
Makefile
all: one two three
one:
touch one
two:
touch two
three:
touch three
clean:
rm -f one two three和 make clean 类似,非常常见的方法,将 all 放在最上面,当运行 make 的时候会执行 all 的任务。
多目标文件
Makefile
all: f1.o f2.o
f1.o f2.o:
echo $@
# Equivalent to:
# f1.o:
# echo f1.o
# f2.o:
# echo f2.o上面提过支持多目标文件,用空格隔开,可以用 $@ 来指代列表中的一个文件,它和后面注释中的任务等价。
通配符
- Makefile 支持
*通配符,但是单独使用会被当作一般字符串,需要使用wildcard函数
Makefile
# Print out file information about every .c file
print: $(wildcard *.c)
ls -la $?*不能用在变量定义中- 当
*没有匹配到文件,将保持原样
自动变量
$@指代目标文件$?指代比目标更新的依赖文件$^指代依赖文件
Makefile
hey: one two
# Outputs "hey", since this is the target name
echo $@
# Outputs all prerequisites newer than the target
echo $?
# Outputs all prerequisites
echo $^
touch hey
one:
touch one
two:
touch two
clean:
rm -f hey one two默认规则
变量名:
CC:指代编译器,如不赋值直接调用则指代ccCXX:同上,默认指代g++CFLAGS:C编译参数标志CXXFLAGS:C++编译参数标志CPPFLAGS:C 预处理参数标志LDFLAGS:链接器参数标志
#TBD/LV2 :接着阅读 tutorial