文章目录
- 1. MakeFile 的作用
- 2. 背景知识说明
- 2.1 程序的编译与链接
- 2.2 常见代码的文档结构
- 3. MakeFile 的内容
- 4. Makefile的基本语法
- 5. 变量定义
- 5.1 一般变量赋值语法
- 5.2 自动化变量
- 6. 通配符
参考:
Makefile教程:Makefile文件编写1天入门
Makefile由浅入深–教程、干货
Makefile详解(超级好) 陈皓
1. MakeFile 的作用
Makefile 文件描述了 Linux 系统下 C/C++ 工程的编译规则,它用来自动化编译 C/C++ 项目。一旦写编写好 Makefile 文件,只需要一个 make 命令,整个工程就开始自动编译,不再需要手动执行 GCC 命令。
2. 背景知识说明
2.1 程序的编译与链接
编译(compile)是将源文件编译成中间目标文件的过程。对于C、C++,在Windows下是.obj
文件,在UNIX下是.o
文件。
链接(link)是将目标文件合成执行文件。
正确的编译要求语法正确,函数与变量的声明正确。一般来说每个源文件(头文件+cpp文件)都对应于一个中间目标文件。 链接是链接函数和全局变量,可以使用中间目标文件来链接。链接时需要支出中间目标文件名称。
在源文件较多的情况下(此时中间目标文件也多),可以给中间目标文件打包,这种包文件就“库文件”(Library FIle),也就是.lib
文件或.a
文件。
2.2 常见代码的文档结构
src
:源码incl
:头文件bin
:执行码lib
:静态/动态库
3. MakeFile 的内容
Makefile 文件中主要包含了五项内容:
- 变量定义:在Makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点像C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
- 显式规则:显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile 的明显指出,要生成的文件,文件的依赖文件,生成的命令。 .
- 隐晦规则:make有自动推导的功能,隐晦规则指导我们如何简略地书写Makefile的同时又让
make
命令能够顺利执行。 - 文件指示:其包括了三个部分,一个是在一个 Makefile 中引用另一个 Makefile,就像C语言中的 include 一样;另一个是指根据某些情况指定 Makefile 中的有效部分,就像C语言中的预编译 #if 一样;还有就是定义一个多行的命令。
- 注释:Makefile 中只有行注释,和 UNIX 的 Shell 脚本一样,其注释是用“#”字符。
4. Makefile的基本语法
一般的 Makefile 语句的形式如下:
targets:prerequisitescommand
或
targets:prerequisites;commandcommand
其中:
targets
是目标,可以是中间文件,也可以是可执行文件或标签;prerequisites
是依赖的文件,要生成 targets 需要的文件或者是目标。可以是多个,也可以是没有;command
是make 需要执行的命令(任意的 shell 命令)。可以有多条命令,每一条命令占一行。
注意:目标和依赖文件之间要使用冒号分隔开,命令的开始要使用Tab键。
以此规则可以写出如下代码:
test:test.cgcc -o test test.c
上述代码实现的功能就是编译 test.c 文件,通过这个实例可以详细的说明 Makefile 的具体的使用。其中 test 是的目标文件,也是我们的最终生成的可执行文件。依赖文件就是 test.c 源文件,重建目标文件需要执行的操作是gcc -o test test.c
。
5. 变量定义
5.1 一般变量赋值语法
MakeFile中变量定义的基本语法:
valname = valuelist
- MakeFile中的变量没有数据类型(或者理解为是字符数组?)。
- 值列表可以是零项,也可以是一项或者多项。
调用变量的格式:$(valname)
或${valname}
,如
OBJ=main.o test.o test1.o test2.o
test:$(OBJ)gcc -o test $(OBJ)
变量的赋值
Makefile 有四种基本赋值方式:
- 简单赋值 ( := ) 编程语言中常规理解的赋值方式,只对当前语句的变量有效。
- 递归赋值 ( = ) 赋值语句可能影响多个变量,所有目标变量相关的其他变量都受影响(如使用该变量赋值的变量)。
- 条件赋值 ( ?= ) 如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。
- 追加赋值 ( += ) 原变量用空格隔开的方式追加一个新值。
案例:
简单赋值
x:=foo
y:=$(x)b
x:=new
test:@echo "y=>$(y)"@echo "x=>$(x)"
在 shell 命令行执行make test
我们会看到:
y=>foob
x=>new
递归赋值
x=foo
y=$(x)b
x=new
test:@echo "y=>$(y)"@echo "x=>$(x)"
在 shell 命令行执行make test
我们会看到:
y=>newb
x=>new
条件赋值
x:=foo
y:=$(x)b
x?=new
test:@echo "y=>$(y)"@echo "x=>$(x)"
在 shell 命令行执行make test
我们会看到:
y=>foob
x=>foo
追加赋值
x:=foo
y:=$(x)b
x+=$(y)
test:@echo "y=>$(y)"@echo "x=>$(x)"
在 shell 命令行执行make test
我们会看到:
y=>foob
x=>foo foob
5.2 自动化变量
自动化变量是Makefile 自动产生的变量。
自动化变量 | 说明 |
---|---|
$@ | 表示规则的目标文件名。如果目标是一个文档文件(Linux 中,一般成 .a 文件为文档文件,也成为静态的库文件),那么它代表这个文档的文件名。在多目标模式规则中,它代表的是触发规则被执行的文件名。 |
$% | 当目标文件是一个静态库文件时,代表静态库的一个成员名。 |
$< | 规则的第一个依赖的文件名。如果是一个目标文件使用隐含的规则来重建,则它代表由隐含规则加入的第一个依赖文件。 |
$? | 所有比目标文件更新的依赖文件列表,空格分隔。如果目标文件时静态库文件,代表的是库文件(.o 文件)。 |
$^ | 代表的是所有依赖文件列表,使用空格分隔。如果目标是静态库文件,它所代表的只能是所有的库成员(.o 文件)名。一个文件可重复的出现在目标的依赖中,变量$^ 只记录它的第一次引用的情况。就是说变量“$^”会去掉重复的依赖文件。 |
$+ | 类似$^ ,但是它保留了依赖文件中重复出现的文件。主要用在程序链接时库的交叉引用场合。 |
$* | 在模式规则和静态模式规则中,代表“茎”。“茎”是目标模式中“%”所代表的部分(当文件名中存在目录时,“茎”也包含目录部分)。 |
6. 通配符
通配符 | 使用说明 |
---|---|
* | 匹配0个或者是任意个字符 |
? | 匹配任意一个字符 |
[] | 我们可以指定匹配的字符放在 “[]” 中 |
% | 匹配任意字符 |
通配符可以使用在规则的命令和规则中,但不能直接用于变量声明。如:
# 使用在命令中
.PHONY::clean
clean:rm -rf *.o test
# 使用在规则中
test:*.cgcc -o $@ $^
```我们可以在 Makefile 中这样写
如果我们就是相要通过引用变量的话,我们要使用一个函数 `wildcard`:
```shell
OBJ=$(wildcard *.c)
test:$(OBJ)gcc -o $@ $^