Makefile:项目的代码管理工具,用于管理工程编译。通过把所有源代码的编译命令写入makefile来达到多文件统一编译。
一、初识Makefile
1、在公司中,架构师负责把各模块集中起来做成makefile提供给公司内部人员使用。
2、Makefile实质:写好的makefile其实就是一个文件,内部写好了各个分模块的编译规则。
3、Makefile文件两种命名规则:全小写(makefile) 或者 首字母大写(Makefile);
4、Makefile写法规则中的三要素:目标、依赖、命令;
//格式:
//目标:依赖条件
//[tab]命令
//举例如下:
app:main.c add.c sub.c mul.c
gcc main.c add.c sub.c mul.c -o app
5、Make是一个命令工具,它用于解释Makefile中的指令(具体说是规则);在Makefile文件中描述了整个工程的所有文件的编译顺序、编译规则。
注:一般把 .c 和 makefile 放在同一目录下。
6、Makefile优化
上方所写makefile依赖项是 .c 文件,当其中一个 .c 文件发生变化时,其余的 .c 文件也需要跟着它重新编译,显然效率不高,为了提高效率,让单个文件发生变化后,仅编译发生变化的 .c 文件,需要将各个模块分开编译,此时依赖项需要编程 .o 文件
app:main.o add.o sub.o mul.o
gcc main.o add.o sub.o mul.o -o app
main.o:main.c
gcc -c main.c
add.o:add.c
gcc -c add.c
sub.o:sub.c
gcc -c sub.c
mul.o:mul.c
gcc -c mul.c
各模块分开编译好处:避免了一个 .c 修改后,所有的 .c 都需要跟着重新编译的缺陷,提高了程序编译的效率。
此时,先执行终极目标app,查找终极目标的依赖项,若某项没有则执行下方的子目标以生成该项依赖,最后集齐所有终极目标的依赖项后,执行终极目标下方的命令已完成最终编译。
二、Makefile工作原理剖析
1、Makefile工作原理叙述:先执行终极目标app,查找终极目标的依赖项,若某项没有则执行下方的子目标以生成该项依赖,最后集齐所有终极目标的依赖项后,执行终极目标下方的命令已完成最终编译。
2、Makefile:目标生成原理
Makefile目标生成规则:首先检查以来的条件是否存在,存在通过命令直接生成对应的目标,若不存在,向下寻找对应的子目标,根据其规则生成依赖条件,最终集齐各依赖项后执行下方命令生成对应的目标。流程详见下图:
3、Makefile:目标更新机制
每次生成目标前,检查目标和依赖项之间是否一致,若依赖项修改了,则重新编译此项目;
三、Makefile变量介绍及使用
Makefile中也支持变量的使用,但弱化了变量的类型,即随定义随时用;同时Makefile也维护了一批内置变量和自动变量(只能在规则中的命令中使用)
Makefile常用的三个自动变量:
1、$< : 代表规则中的第一个依赖
2、$@ : 代表规则中的目标
3、$^ : 代表规则中所有的变量
注:自动变量只能在规则中的命令中使用
Makefile的模式规则:
% : 此处代表所有的项,谁符合条件件是谁的值(类似于shell中的 *)
Makefile中自己维护的变量:
CC=cc (小写cc代表gcc)
注:用户也可以修改内置变量的默认值
Makefile用户自定义变量:
如:obj=main.o add.o sub.o mul.o
注:使用时需要加 $ 表示提取变量内容 如:gcc $(obj) -o app
四、使用Makefile变量再优化上面的Makefile
obj=main.o add.o sub.o mul.o
target=app
$(target):$(obj)
gcc $(obj) -o $(target)
%.o:%.c
gcc -c $< -o $@
五、Makefile常用函数及Makefile继续优化
1、Makefile函数:任意Makefile中的函数均有返回值
2、Makefile常用函数
注:Makefile函数的参数不需要写在括号内,直接在函数名后加空格间隔,紧接着写参数
wildcard函数:显示指定路径下指定文件类型的所有文件
使用:src=$(wildcard ./*.c)
解释:从当前路径下查找所以有以 .c 结尾的文件名作为参数回传给src变量
patsubst函数:模式字符串替换函数
使用:obj=$(patsubst ./%.c,./%.o,$(src))
解释:把src中以 .c 结尾的值变为以 .o 结束
3、Makefile伪目标的声明及定义
伪函数声明语句
.PHONY:clean
定义语句:
clean:
rm -f $(obj)
注:把clean声明成伪目标的好处:每个Makefile执行后,每个目标都会生成对应的文件,此处clean目标无依赖项,所以不需要做改变项的检查,因此声明成伪目标,每次都执行它
4、Makefile继续优化
target=app
src=$(wildcard ./*.c)
obj=$(patsubst ./%.c, ./%.o, $(src))
CC=gcc
$(target):$(obj)
$(CC) $(obj) -o $(target)
%.o:%.c
$(CC) -c $< -o $@
.PHONY:clean //把clean声明成伪目标
clean:
rm -f $(obj) //-f选项:强制执行
此次Makefile的编写加入了Makefile函数的使用,同时加入了新的目标clean,它用于在执行makefile的同时删除生成的用于过渡的 .o 文件;
此时执行makefile时,需要做到:
make && make clean
注:这里显示生成了 clean 目标,因为clean目标没有依赖项,但需求是生成clean目标,所以需要显示指定生成 clean 目标
5、Makefile语句细节优化案列
“-” :在命令前加“-”号,忽略不可执行的命令,不中断Makefile执行
如:简单写一个目标
1、clean:
mkdir /aaa
rm -f $(obj)
此时,执行到mkdir命令行会终止后续项的执行,因为普通用户权限不足;这样就会影响Makefile整体的容错能力
2、clean:
-mkdir /aaa
rm -f $(obj)
此时,执行到mkdir命令行是不会终止,makefile只是忽略它无权限或不能执行的命令,继续执行后续项