Make命令和makefile工程管理
文章目录
- Make和Makefile的基本概念
- Makefile的基本结构
- Makefile中的变量
- makefile变量特征
- makefile中的自动变量
- makefile规则机制
- 隐式规则
- 模式规则
- 运行make
- make 命令常用选项
这一小节主要讲解在 Linux 编程开发中如何使用
make
工具及
makefile
文件来管理多文件项目,提升编译效率
Make和Makefile的基本概念
为什么需要 Make 和 Makefile:
-
小项目(如只有 1~2 个
.c
文件):可以手动输入gcc
命令编译 -
大项目(含多个模块、多个目录):手动编译效率低、容易出错
解决方案:使用 GNU 的
make
工具 +makefile
配置文件,自动化管理工程构建过程make
工具:通过解释一个称为makefile
的文件来完成整个工程的完全自动编译,极大的提高了软件开发的效率makefile
:定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译。makefile
就像一个 Shell 脚本一样,也可以执行操作系统的命令
Makefile的基本结构
target: dependency_files
<TAB> commands
- target(目标):最终生成的文件,如
.o
、可执行程序,或伪目标 - dependency(依赖):生成目标所需的源文件或头文件
- command(命令):生成目标所需执行的命令,前面必须是
Tab
,不能是空格!
【举例】
sum: ex_sum.o mysum.ogcc ex_sum.o mysum.o -o sumex_sum.o: ex_sum.cgcc -c ex_sum.cmysum.o: mysum.c mysum.hgcc -c mysum.c
Makefile中的变量
makefile
中定义的变量,与 C 语言中的宏一样,代表一个文本字串,在 makefile
被执行时候变量会自动地展开在所使用的地方
makefile
中的变量可以使用在“目标”,“依赖目标”,“命令”或 makefile
的其它部分中
makefile变量特征
makefile
中变量和函数的展开(除规则的命令行以外),是在make
读取makefile
文件时进行的,这里的变量包括了使用 “=” 定义和使用指示符 “define” 定义的makefile
中变量的命名字可以包含字符、数字,下划线(可以是数字开头),但不应该含有 “:”、“#”、“=” 或是空字符(空格、回车等)makefile
中变量是大小写敏感的,“test”、“Test” 和 “TEST” 是三个不同的变量名- 变量在声明时需要给予初值,而在使用时,需要在变量名前加上“
$
”符号,如$(var)
【举例】在 makefile 中使用变量的实例:
OBJS = main.o mytool1.o mytool2.o
CC = gcc
main: $(OBJS)$(CC) $(OBJS) -o main
main.o: main.c$(CC) -c main.c
mytool1.o: mytool1.c mytool1.h$(CC) -c mytool1.c
mytool2.o: mytool2.c mytool2.h$(CC) -c mytool2.c
makefile中的自动变量
自动变量也是系统预先定义的变量,编写 makefile 文件时可以直接使用
自动变量通常出现在目标文件和依赖文件中
自动变量 | 含义 |
---|---|
$* | 不包含扩展名的目标文件名称 |
$+ | 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件 |
$< | 第一个依赖文件的名称 |
$? | 所有时间戳比目标文件晚的依赖文件,并以空格分开 |
$@ | 目标文件的完整名称 |
$^ | 所有不重复的依赖文件,以空格分开 |
$% | 如果目标是归档成员,则该变量表示目标的归档成员名称 |
makefile规则机制
在 Makefile 中,规则是 make 工具决定如何构建目标文件(通常是可执行程序或中间目标,例如 .o 文件)的基本单位
一个典型规则包含三部分:
target: prerequisitescommands
target:要生成的目标文件
prerequisites(依赖):生成目标所依赖的文件
commands:当目标需要更新时执行的命令
除了显式写出的规则,Makefile 还支持两种非常强大的规则机制:隐式规则 和 模式规则。
隐式规则
隐式规则是 make
预定义的一些默认规则,当用户使用它们时就不必详细指定编译的具体细节,而只需把目标文件列出即可
特点:
- 你不需要写出编译的细节,Make 会自动推断
- 适合常见场景,比如
.c
编译为.o
【举例】在没有使用隐式规则时,Makefile文件内容如下:
main: main.o mytool1.o mytool2.ogcc -o main main.o mytool1.o mytool2.omain.o: main.cgcc -c main.cmytool1.o: mytool1.c mytool1.hgcc -c mytool1.cmytool2.o: mytool2.c mytool2.hgcc -c mytool2.c
使用隐式规则后Makefile文件内容可简化如下:
OBJS = main.o mytool1.o mytool2.o
CC = gccmain: $(OBJS)$(CC) $^ -o $@
【解释】省略了后6句,因为 make
的隐式规则指出:所有 .o
文件都可自动由 .c
文 件使用命令 $(CC) -c <file.c> -o <file.o>
生成,这样 main.o
、mytool1.o
和 mytool2.o
就会分别调用 $(CC) -c $< -o $@
来生成
模式规则
模式规则是用户自己定义的一种通用规则,使用通配符 %
来匹配多个文件名,类似 shell 中的通配符(“%
” 的意思是表示一个或多个任意字符,与文件名匹配),模式规则更加通用,因为可以利用模式规则定义更加复杂的依赖性规则
【举例】%.c
表示以 .c
结尾的文件名,而 s.%.c
则表示以 s.
开 头、以 .c
结尾的文件名
对于上面的 Makefile 文件,若使用模式规则,其代码如下:
OBJS = main.o mytool1.o mytool2.o
CC = gccmain: $(OBJS)$(CC) $^ -o $@%.o: %.c$(CC) -c $< -o $@
说明:
%
代表文件名中共有的部分$<
表示第一个依赖文件$@
表示目标文件
这样可以让一条规则适配多个文件,简化 Makefile 内容
【对比】
项目 | 隐式规则 | 模式规则 |
---|---|---|
定义方式 | make 内置 | 用户自定义 |
使用方式 | 自动匹配,不显式书写 | 使用 % 模式通配符 |
灵活性 | 适合常规简单情况 | 适合复杂或统一构建逻辑 |
运行make
一般来说,最简单的就是直接在命令行下输入 make 命令,GNU make 找寻默认的 makefile 的规则是在当前目录下依次找 “makefile
” 和 “Makefile
” (“makefile
” 更优先)
一旦找到,就开始读取这个文件并执行,也可以给 make 命令指定一个特殊名字的makefile,要达到这个功能,要求使用 make 的 “-f
” 或是 “--file
” 参数,例如:
make -f Hello.makefile
make 命令常用选项
命令行选项 | 含义 |
---|---|
-C dir | 在读取 makefile 之前改变到指定的目录 dir |
-f file | 以指定的file文件作为makefile |
-h | 显示所有的 make 选项 |
-i | 忽略 make 过程中的所有命令执行错误 |
-I dir | 当包含其他 makefile 文件时,可利用该选项指定搜索目录 |
-n | 只打印要执行的命令,但不执行这些命令 |
-p | 显示 make 变量数据库和隐含规则 |
-s | 在执行命令时不显示命令 |
-w | 在处理 makefile 之前和之后,显示工作目录 |
-W file | 假定文件 FILE 已经被修改 |