0. 简介

Makefile 关系到了整个工程的编译规则。一个工程中的源文件不计其数,并且按类型、功能、模块分别放在若干个目录中,Makefile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个 Shell 脚本一样,其中也可以执行操作系统的命令。

Makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。 make是一个命令工具,是一个解释Makefile中指令的命令工具。

1. 语法规则

1.1 基本语法

# rules1
target1: prerequisites1
command1
command2
# rules2
target2: prerequisites2
command3
command4
command5

注意:

  • command 必须以Tab(\t)键开头
  • Makefile有隐含时间戳逻辑
    • target timestamp > prerequisites timestamp, 不执行 command
    • target timestamp < prerequisites timestamp, 执行 command
    • target 缺失,执行 command

1.2 自动推导

自动推导:用命令 make 编译扩展名为.c 的 C 语言文件的时候,源文件的编译规则可不显示编写。 make 进行编译的时会有默认的编译规则(即按照默认规则完成对.c文件的编译,生成对应的.o 文件)
它使用命令cc -c来编译.c 源文件。在 Makefile 中只要给出需要构建的目标文件名(一个.o 文件),make 会自动为这个.o 文件寻找合适的依赖文件(对应的.c 文件),并且使用默认的命令来构建这个目标文件。

# 当前目录仅有a.c/b.c/c.c
app:a.o b.o c.o
gcc a.o b.o c.o -o app

通过上面的 Makefile ,会自动推导使用 cc -c a.c 编译 a.c 文件,生成 a.o 文件(b.c/c.c 同理)

2. 变量

2.1 普通变量

变量的命名字可以包含字符、数字,下划线(可以是数字开头),但不应该含有 : # = 或空字符(空格、回车等)。且变量名区分大小写

# 定义变量
VAR1 = a.c
VAR2 = a.o

# 使用变量
$(VAR2): $(VAR1)
cc -o $(VAR2) $(VAR1)

2.2 预定义变量

  • CC C 语言编译器的名称 cc
  • CFLAGS C 语言编译器的编译选项 无默认值
  • CPP C 语言预编译器的名称 $(CC) -E
  • CXXFLAGS C++语言编译器的编译选项 无默认值

2.3 自动变量

  • $@ target,包含扩展名
  • $* target,不包含扩展名
  • $< 表示 prerequisites 中第一个依赖
  • $+ 所有的 prerequisites ,这些 prerequisites 之间以空格分开,按照出现的先后为顺序,可能重复
  • $^ 去重 prerequisites 之间以空格分开
  • $? prerequisites 中,所有比 target 时间戳晚的 prerequisites ,prerequisites 之间以空格分开

2.4 模式变量

给定一种“模式”,可以把变量定义在符合这种模式的所有目标上。

# prerequisites, 后缀为.c, target 是 .o , % 是一个通配符, 匹配的是文件名
# 这里就会将 a.c b.c c.c 编译成 a.o b.o c.o
%.o:%.c
gcc $< -c

3. 函数

用法:$(function, arg1, arg2, ...)

3.1 字符串处理函数

patsubst 模式字符串替换

$(patsubst <pattern>,<replacement>,<text>)

  • 功能:查找 <text> 中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式 <pattern> ,如果匹配的话,则以 <replacement> 替换。这里, <pattern> 可以包括通配符 % ,表示任意长度的字串。如果 <replacement> 中也包含 % ,那么, <replacement> 中的这个 % 将是 <pattern> 中的那个 % 所代表的字串。(可以用 \ 来转义,以 % 来表示真实含义的 % 字符)
  • 返回:函数返回被替换过后的字符串。

3.2 文件名处理函数

wildcard 获取指定目录下指定类型的文件名

$(wildcard <pattern1> <pattern2> ...)

  • 功能:获取指定目录下的所有符合条件的文件名列表
  • 返回:若干个文件的文件列表, 文件名之间使用空格间隔

4. 伪目标

在删除Make安装的所有文件时,通常使用make clean命令。

.PHONY:
clean:
# - 表示强制这个指令执行, 如果执行失败也不会终止
-rm $(obj) $(target)

5. 相关引用

[1] 跟我一起写Makefile