1. make工具和Makefile文件的引入
当源码文件比较多的时候就不适合通过直接输入gcc命令来编译,这时候就需要一个自动化的编译工具.
- make:一般说GNU Make,是一个软件,用于将源代码文件编译为可执行的二进制文件,make工具主要用于完成自动化编译。make工具编译的时候需要Makefile文件提供编译文件。
- Makefile:make工具所使用的文件,Makefile指明了编译规则。
2. Makefile 语法
2.1 Makefile 规则格式
Makefile 里面是由一系列的规则组成的,这些规则格式如下:
目标…... : 依赖文件集合……
命令 1
命令 2
……
例如:
main : main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
这条规则的目标是 main,main.o、input.o 和 calcu.o 是生成 main 的依赖文件,如果要更新目标 main,就必须先更新它的所有依赖文件,如果依赖文件中的任何一个有更新,那么目标也必须更新,“更新”就是执行一遍规则中的命令列表。
命令列表中的每条命令必须以 TAB 键开始,不能使用空格!
make 命令会为 Makefile 中的每个以 TAB 开始的命令创建一个 Shell 进程去执行
总结一下 Make 的执行过程:
- make 命令会在当前目录下查找以 Makefile(makefile 其实也可以)命名的文件。
- 找到 Makefile 文件以后就会按照 Makefile 中定义的规则去编译生成最终的目标文件。
- 当发现目标文件不存在,或者目标所依赖的文件比目标文件新(也就是最后修改时间比目标文件晚)的话就会执行后面的命令来更新目标
2.2 Makefile 变量
Makefile 中的变量都是字符串,类似 C 语言中的宏
#Makefile 变量的使用
objects = main.o input.o calcu.o
main: $(objects)
gcc -o main $(objects)
“$(objects)”就是使用变量 objects。
Makefile 赋值符
1. 赋值符“=”
使用“=”在给变量的赋值的时候,不一定要用已经定义好的值,也可以使用后面定义的值
name = zzk
curname = $(name)
name = zuozhongkai
print:
@echo curname: $(curname)
结果:
赋值符=
:变量的真实值取决于它所引用的变量的最后一次有效值。
2. 赋值符“:=”
赋值符:=
不会使用后面定义的变量,只能使用前面已经定义好的
3. 赋值符“?=”
curname ?= zuozhongkai
如果变量 curname 前面没有被赋值,那么此变量就是“zuozhongkai”,如果前面已经赋过值了,那么就使用前面赋的值。
4. 变量追加“+=”
给前面已经定义好的变量添加一些字符串进
去,此时就要使用到符号+=
2.3 Makefile 模式规则
- 模式规则中,至少在规则的目标定定义中要包涵“%”,否则就是一般规则
- 目标中的“%”表示对文件名的匹配,“%”表示长度任意的非空字符串,比如“%.c”就是所有的以.c 结尾的文件,类似与通配符,a.%.c 就表示以 a.开头,以.c 结束的所有文件。
- 当“%”出现在目标中的时候,目标中“%”所代表的值决定了依赖中的“%”值
%.o : %.c
命令
2.4 Makefile 自动化变量
例子:
main: main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
main.o: main.c
gcc -c main.c
input.o: input.c
gcc -c input.c
calcu.o: calcu.c
gcc -c calcu.c
clean:
rm *.o
rm main
改为:
objects = main.o input.o calcu.o
main: $(objects)
gcc -o main $(objects)
%.o : %.c
gcc -c $<
clean:
rm *.o
rm main
2.5 Makefile 伪目标
- 一般的目标名都是要生成的文件,而伪目标不代表真正的目标名,在执行 make 命令的时候通过指定这个伪目标来执行其所在规则的定义的命令。
- 使用伪目标的主要是为了避免 Makefile 中定义的只执行命令的目标和工作目录下的实际文件出现名字冲突,有时候我们需要编写一个规则用来执行一些命令,但是这个规则不是用来创建文件的
声明方式如下:
.PHONY : clean
2.6 Makefile 条件判断
语法有两种如下:
<条件关键字>
<条件为真时执行的语句>
endif
<条件关键字>
<条件为真时执行的语句>
else
<条件为假时执行的语句>
endif
其中条件关键字有 4 个:ifeq、ifneq、ifdef 和 ifndef
ifeq 用来判断是否相等,ifneq 就是判断是否不相等:
ifeq (<参数 1>, <参数 2>)
ifeq ‘<参数 1 >’,‘ <参数 2>’
ifeq “<参数 1>”, “<参数 2>”
ifeq “<参数 1>”, ‘<参数 2>’
ifeq ‘<参数 1>’, “<参数 2>”
ifdef 和 ifndef :如果“变量名”的值非空,那么表示表达式为真,否则表达式为假。“变量名”同样可以是一个函数的返回值。ifndef 用法类似,但是含义用户 ifdef 相反
ifdef <变量名>
2.7 Makefile 函数使用
Makefile 中的函数是已经定义好的,不支持我们自定义函数。
$(函数名 参数集合)
#或者
${函数名 参数集合}
1. 函数 subst
函数 subst 用来完成字符串替换,调用形式如下:
$(subst <from>,<to>,<text>)
//是将字符串<text>中的<from>内容替换为<to>,函数返回被替换以后的字符
串
2. 函数 patsubst
函数 patsubst 用来完成模式字符串替换,使用方法如下:
$(patsubst <pattern>,<replacement>,<text>)
此函数查找字符串<text>
中的单词是否符合模式<pattern>
,如果匹配就用<replacement>
来替换掉,<pattern>
可以使用包括通配符“%”,表示任意长度的字符串,函数返回值就是替换后的字符串。如果<replacement>
中也包涵“%”,那么<replacement>
中的“%”将是<pattern>
中的那个“%”所代表的字符串
3. 函数 dir
函数 dir 用来获取目录
$(dir <names…>)
此函数用来从文件名序列<names>
中提取出目录部分,返回值是文件名序列<names>
的目录部分
4. 函数 notdir
去除文件中的目录部分,也就是提取文件名
$(notdir <names…>)
此函数用与从文件名序列<names>
中提取出文件名非目录部分
5. 函数 foreach
foreach 函数用来完成循环
$(foreach <var>, <list>,<text>)
把参数<list>
中的单词逐一取出来放到参数<var>
中,然后再执行<text>
所包含的表达式。每次<text>
都会返回一个字符串,循环的过程中,<text>
中所包含的每个字符串会以空格隔开,最后当整个循环结束时,<text>
所返回的每个字符串所组成的整个字符串将会是函数 foreach 函数的返回值
6. 函数 wildcard
通配符“%”只能用在规则中,只有在规则中它才会展开,如果在变量定义和函数使用时,通配符不会自动展开,这个时候就要用到函数 wildcard
$(wildcard PATTERN…)
评论区