当需要编译很的c文件数量很大时,使用gcc逐个进行编译就变得十分困难,所以自动化编译工具就需要被使用
1. 介绍
- make是软件,而不是一个编译器
- makefile是描述哪些文件需要编译的文件,类似脚本文件(现在已经不用区分分大小写了makefile/Makefile都可以)
- 只对作出修改的源文件进行重新编译
- 若头文件被修改,则重新编译所有所有包含该头文件的源文件
2. makefile编写
2.1 举例
使用gcc编译时需要对每个c文件进行编译汇编生成对应的目标文件(.o),当只改变部分文件时只用对其c文件编译重新生成练目标文件后,再进行链接。这些就是可以写进makefile中用来自动编译的,例如:
规则:
目标文件: 依赖的文件
执行命令
如上main所依赖的是main.o文件,没有这个文件就会再makefile中寻找生成这个文件的指令,找到main.o依赖于文件main.c文件,就运行指令生成main.o文件,同理最后生成main可执行文件
在文件最后可以添加以下代码,用来清除当前生成的所有.o目标文件,或者删除生成的可执行文件
clean:
rm *.o
rm "可执行文"
2.2 语法说明
2.2.1 规则格式
- 目标:需要实现的目标,如目标生成文件
第一条规则的目标为默认目标,是makefile工作最终目的,需要放在第一个规则,其他规则顺序不影响 - 依赖的所有文件:生成目标文件所需要的相关文件,如需要用.c生成.o文件
- 执行的命令: 根据需要执行相关的命令如gcc -c a.c 来生成.o文件,命令前面要用tab键,不可以使用空格缩进
目标: 依赖的所有文件
执行命令
......
- 一个完整的目标文件,依赖文件集合以及所有执行命令称为一条规则
- 当目标不存在时,规则就会执行
- 当依赖文件不存在时就会再文档中寻找以当前依赖文件作为目标的规则,然后执行该规则
- 当依赖文件更行时,目标文件也会进行更新
- 没有依赖的目标使用时总是会执行
2.2.2 变量
- makefile中只有一种变量:字符串类型
- 变量的赋值使用“=”进行,(=号赋值,左值等于右值在文档中最终的值,而不是在定义左值前的值)
- 对于大工程,某个目标的依赖文件可能很多,所以可以使用一个字符串变量来代替这些文件
- 调用方式:
$(变量名)
例如:
objectives = main.o input.o calcu.o
main: $(objectives)
gcc $(objectives) -o main
2.2.3 模式规则和自动化变量
在上述图片中的代码,从第2条规则到最后一条都是将.c文件编译成.o目标文件,重复操作可以使用模式规则和自动化变量
- 通过模式规则将重复的操作通过一条规则执行
- 模式规则%用来表示文件名的匹配,类似于Linux *通配符
- 自动化变量使得完成相同操做不同的依赖文件生成其对应的目标
*引用自正点原子
上方图片的代码段可变成
```
objectives = main.o input.o calcu.o
main: $(objectives)
gcc $(objectives) -o main
%.o:%.c
gcc -c $<
```
2.2.4 伪目标
如例代码中的clean目标;伪目标并不会生成目标,其依赖集合一般为空,当当前文件夹下有一个与目标相同的文件且依赖集合为空,则表示目永远为罪行的,执行命令就不会执行,为了防止这种情况,需要对伪目标进行声明
- 伪目标声明:
.PHONY:伪目标名
声明后就不再考虑当前路径是否有同名的文件
其他指令,关键字和标识符
- #:注释
- 赋值符
- =
左值真实值等于右值最终有效值a = aa b = $(a) a = cc #最终b的值为cc
可用来实现对某变量的定义简介改变
- :=
左值真实值等于右值在左值前定义好的值a = aa b = $(a) a = ccc #最终b的值为aa
- ?=
若左值在之前有赋值则为之前的值,否则为当前所赋值的值 - +=
给当前变量在当前值的前提下,加入新的值objectives = a.c b.c objectives += c.c #objectives 等于a.c b.c c.c
- echo:打印字符串或者变量的值
print: @echo objectives : $(objectives) #(@表示不打印出这条指令本身)
3 文件执行
编写好makefile文件后,通过指令make
来执行makefile文件,效果如下。
清除指令用来执行文档中编写的代码块中的内容,如清除目标文件或者可执行文件等:make clean
(这里的clean取决于makefile中定义的名字)