前言:
在前边的文章中我们提到了GCC编译器如何去使用,但是在编译的时候都是一条的指令对已知的文件进行编译,但是对于工程文件数目较大的项目,如果修改了多个文件就需要对多个文件进行预编译、编译、汇编、链接,需要执行多条gcc命令尤其麻烦,这里引出makefile文件帮助我们轻松的组织代码编译,可以将多条编译命令转换为一条命令。
Makefile编译过程:
Makefile文件中的命令有一定的规范,一旦该文件编写好以后在Linux命令中执行一条make命令即可自动编译整个工程。
Makefile语法规则
规则:
我的这边博客意在会用会看,对一些深入的内容请参考下边分享的Makefile中文文档
链接: https://pan.baidu.com/s/1vz2PD-NhZ8zYF5qfCX2V8A?pwd=crw8 提取码: crw8
目标:依赖 命令1 命令2 …………
Makefile并不关心命令是怎么命令是怎么执行的,仅仅只会去执行所有定义的命令,命令的执行仍是编译器进行的,和直接输入命令行的效果是一样的。
- 目标是要生成的文件,如果目标文件的更新晚于依赖文件的更新时间,则说明依赖文件没有进行改动,目标文件不需要重新编译。否则会进行重新编译并且更新目标文件。
- 默认情况下,Makefile执行第一个目标
- 依赖:即目标文件由哪些文件组成。
- 命令:通过执行命令有依赖文件生成目标文件。注意每条命令之前都必须有一个tab保持缩进,这是语法要求。
- all:Makefile文件默认只生产第一个目标文件即编译完成。但是我们可以通过all指定索要生成的目标文件
实验1:第一个Makefile文件
将下述三个命令写成简单的Makefile
如果文件
编译:
gcc -o a.o a.c
gcc -o b.o b.c
链接:
gcc -o test a.o b.o
文件:Makefile
test :a.o b.o //test是目标,它依赖于a.o b.o文件,一旦a.o或者b.o比test新的时候, 就需要执行下面的命令,重新生成test可执行程序。
gcc -o test a.o b.o
a.o : a.c //a.o依赖于a.c,当a.c更加新的话,执行下面的命令来生成a.o
gcc -c -o a.o a.c
b.o : b.c //b.o依赖于b.c,当b.c更加新的话,执行下面的命令,来生成b.o
gcc -c -o b.o b.c
执行效果:
a.c文件修改了,重新编译生成a.o, b.c修改了重新编译生成b.o,a.o,b.o都更新了重新链接生成test可执 行程序,makefile的规则其实还是比较简单的。规则是Makefie的核心, 执行make命令的时候,就会在当前目录下面找到名字为:Makefile的文件,根据里面的内容来执行里 面的判断/命令。
通配符:
假如一个目标文件所依赖的依赖文件很多,那样岂不是我们对应的要写很多规则,这个显然不符合道理。于是有了通配符。
可以对上边的Makefile中的代码改写成
test: a.o b.o gcc -o test $^ %.o : %.c gcc -c -o $@ $<
%.o:表示所用的.o文件
%.c:表示所有的.c文件
$@:表示目标
$<:表示第1个依赖文件
$^:表示所有依赖文件
加一个类似的c.c文件
执行效果:
假想目标:.PHONY
我们想清除文件,我们在Makefile的结尾添加如下代码就可以了:
clean: rm *.o test .PHONY: clean
我们之前说,一个规则能过执行的条件:
*1)目标文件不存在
*2)依赖文件比目标新
现在我们的目录里面有名为“clean”的文件,目标文件是有的,并且没有依赖文件,没有办法判断依赖文件的时间。这种写法会导致:有同名的"clean"文件时,就没有办法执行 make clean操作。解决办法:我们需要把目标定义为假象目标,用关键子PHONY
.PHONY: clean //把clean定义为假象目标。他就不会判断名为“clean”的文件是否存在,
执行效果:
变量:
在makefile中有两个变量:
1、简单变量(即使变量)
A := xxx # A的值即刻确定,在定义时即确定
对于即使变量使用 “:=” 表示,它的值在定义的时候已经被确定了
2、延时变量
B = xxx # B的值使用到时才确定 对于延时变量使用“=”表示。它只有在使用到的时候才确定,在定义/等于时并没有确定下来。
变量的使用:
使用$()进行引用,例如:$(A)
:= # 即时变量
= # 延时变量
?= # 延时变量, 如果是第1次定义才起效, 如果在前面该变量已定义则忽略这句
\+= # 附加, 它是即时变量还是延时变量取决于前面的定义
?=: 如果这个变量在前面已经被定义了,这句话就会不会起效果。
实例:
效果显示:
1) A := $(C): A为即使变量,在定义时即确定,由于刚开始C的值为空,所以A的值也为空。 2) B = $(C): B为延时变量,只有使用到时它的值才确定,当执行make时,会解析Makefile里面的所用变量,所以先 解析C= abc,然后解析C += 123,此时,C = abc 123,当执行:\@echo B = $(B) B的值为 abc 123。
3) D ?= weidongshan: D变量在前面没有定义,所以D的值为weidongshan,如果在前面添加D = 100ask,最后D的值为 100ask。
我们还可以通过命令行存入变量的值
例如: 执行:make D=123456 里面的 D ?= weidongshan 这句话就不起作用了。
函数:
makefile里面可以包含很多函数,这些函数都是make本身实现的,下面列出我们来几个常用的函数。其他函数有需要的直接去查文档即可
foreach函数
举个例子来说:
A = a b c B = $(foreach f,$(A),$(f).o) all: @echo A = $(A) @echo B = $(B)
效果显示:
我理解的就是把LIST中的以空格分割的元素,放到分别放到VAR中,然后在拓展成TEXT格式
filter/filter-out函数
Wildcard函数
可以用wildcard函数来判断,真实存在的文件
patsubst函数
patsubst 函数是从TEXT变量里面取出每一个值,如果这个符合 pattern 格式,把它替换成 replacement 格式,
实例:
Makefile实例
这里就参考韦东山老师对Makefile实例的讲解把,我感觉非常棒,在我绑定的资源里边