Skip to content
On this page

Makefile


标签:linux/软件  

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 blah
c
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 :指代编译器,如不赋值直接调用则指代 cc
  • CXX:同上,默认指代 g++
  • CFLAGS :C编译参数标志
  • CXXFLAGS:C++编译参数标志
  • CPPFLAGS:C 预处理参数标志
  • LDFLAGS:链接器参数标志

#TBD/LV2 :接着阅读 tutorial

学习资料

Last updated: