起因


自己半个月之前学习了makefile,编译c/c++程序方便很多
而最近又正好使用到了Linux系统,Linux系统不像Windows系统一样,基本上都是命令行编程
一个文件还好说,可是多个文件一起编译,就会很麻烦,甚至浪费时间
这个时候makefile管理项目就很方便了,明白其原理后,一旦需要使用,写好模板后,可以直接移植,而且我发现,这个适合于Linux平台,也适合于Windows平台。
而且只要你把规则写好,一个make命令就直接编译完成,自己只需要查看可执行文件就可以了
那就结合之前看过的视频对学习过的知识进行一个总结吧!!!
放出视频链接:视频链接
makefile项目管理


一、用途:


项目代码编译管理 节省编译项目时间


二、 makefile的基础规则


1 个规则:
目标:依赖条件
(一个TAB缩进)命令
使用命令借助依赖条件去生成目标
目标的生成时间应该比依赖条件的生成目标晚
Makefile文件



出现错误原因及解决方式



运行hello,成功运行!



注意:
1.目标的时间必须晚于依赖条件的时间,否则,更新目标
2.依赖条件如果不存在,找寻新的规则去产生依赖条件。



依赖规则:如下 Makefile文件



执行make命令 成功生成hello.o hello



运行成功,木有问题



1.多文件联合编译


makefiletest目录下有以下文件



hello.c修改如下



此时编译,则需要多文件联合编译



对于当前文件,Makefile文件修改如下



执行make命令,成功生成a.out



执行a.out



修改add.c



再次make运行a.out



可以看到,只修改add.c,但是编译的时候,其他.c文件也重新编译了
明明只改了一个,全部都重新编译了


解决方法:
1.使用命令的方式进行编译



2.修改Makefile文件



执行make,成功生成a.out文件



2. makefile检测原理


修改div.c后,再次执行make
可以看到只重新编译了修改后的文件,而其他文件并没有编译



再次修改add.c,再次执行make
除法的结果没有改变,表明只编译了add.c,而div.c和其他文件并没有编译



Makefile文件中
使用命令借助依赖条件去生成目标
目标的生成时间应该比依赖条件的生成目标晚
当依赖条件比目标时间晚,目标就要被更新
makefile检测原理:
修改文件后,文件的修改时间发生变化,会出现目标文件的时间早于作为依赖的时间,出现这种情况的文件会重新编译。
修改div.c后,div.o的时间就早于div.c ,a.out的时间也早于div.o的时间了,于是重新编译这俩文件了。


3. ALL来指定终极目标


ALL来指定终极目标
makefile的依赖是从上至下的,换句话说就是目标文件是第一句里的目标,如果不满足执行依赖,就会继续向下执行。如果满足了生成目标的依赖,就不会再继续向下执行了。
make会自动寻找规则里需要的材料文件,执行规则下面的行为生成规则中的目标。
修改Makefile文件,把生成a.out放在其他下面



执行make,可以看到只生成了hello.o,其他文件的.o并没有生成



同样,修改Makefile文件后,再次执行make,只执行了



这就说明了make命令会检查所写的Makefile文件,把它碰到的第一组规则中的目标,作为终极任务


解决方法:
ALL:终极目标


ALL存在的意义就是用来告诉make命令,当前Makefile文件中,不管碰到的第一组规则的目标是谁,最终要生成的目标一定是a.out



这样再执行make命令,文件都编译成功!



三、 makefile的两个函数和clean


makefile文件的变量类型只有一种,字符串类型
wildcard函数和patsubst函数

  1. src = $(wildscard _.c)
    匹配当前工作用户下的所有.c文件。将文件名组成列表,赋值给变量src。
    找到当前目录下所有后缀为.c的文件,赋值给src
    eg: _*src = add.c sub.c div.c hello.c__
    匹配当前目录下所有后缀为.c的文件,赋值给src
    $(wildcard arguments)函数 arguments表示函数的参数
  2. obj=$(patsubst %.c , %.o , $(src))
    将参数3中,包含参数1的部分,替换成参数2
    把src变量里所有后缀为.c的文件替换成.o
    eg:obj = add.o sub.o div.o hello.o
    把src变量里所有后缀名为.c的文件替换成.o
    这样Makefile文件就可以更新了



执行make命令 运行结果



  1. clean:(没有依赖)
    clean:
    (TAB缩进) rm -rf $(obj) a.out
    循环删除所有.o和a.out文件
    在执行make clean命令时,一定要加-n 去模拟执行
    make clean -n



自己在查看-n命令后,认为无问题了,再执行,所有的.o文件和a.out文件都被删除了



Makefile文件里clean中的命令
clean:
-rm -rf $(obj) a.out
这里rm前面的”-“表示出错依然执行,作用是删除不存在文件时,不报错,顺序执行结束。


四、 makefile中的三个自动变量


3个自动变量
$@:在规则命令中,表示规则中的目标
$<:在规则命令中,表示规则中的第一个依赖条件
如果将该变量用在模式规则中,它可以将依赖条件列表中的依赖依次取出,套用模式规则
%.o:%.c
(tab)gcc -c $< -o $@
$^:在规则命令中,表示规则中的所有依赖条件,组成一个列表,以空格隔开,如果这个列表中有重复项,则去重
由此,更新makefile文件



执行make命令,运行成功



五、模式规则


上面的Makefile可扩展型不强
比如,要添加一个乘法函数,就需要在Makefile里添加乘法的规则
解决方法:模式规则
```
%.o:%.c
gcc -c $< -o $@

更新Makefile文件
![](https://guyueju.oss-cn-beijing.aliyuncs.com/Uploads/Editor/202308/20230809_52686.jpg)
执行make命令,运行成功
![](https://guyueju.oss-cn-beijing.aliyuncs.com/Uploads/Editor/202308/20230809_47255.jpg)
这样可移植性可扩展性就很强,比如再来一个mul乘法函数,下图可见成功make,成功运行
![](https://guyueju.oss-cn-beijing.aliyuncs.com/Uploads/Editor/202308/20230809_15753.jpg)
![](https://guyueju.oss-cn-beijing.aliyuncs.com/Uploads/Editor/202308/20230809_34156.jpg)
**六、 静态模式规则**
使用静态模式规则,就是指定模式规则给谁用,这里指定模式规则给obj用
以后文件多了,文件集合会有很多个,就需要指定哪个文件集合用什么规则

$(obj):%.o:%.c
gcc -c $< -o $@

Makefile文件优化如下
![](https://guyueju.oss-cn-beijing.aliyuncs.com/Uploads/Editor/202308/20230809_25926.jpg)
make成功,又一次优化
![](https://guyueju.oss-cn-beijing.aliyuncs.com/Uploads/Editor/202308/20230809_24225.jpg)
**七、 扩展
1. 扩展1 伪目标**
当文件夹下有ALL文件或者clean文件时,会导致makefile瘫痪,如下所示,make clean没有工作
用伪目标来解决,添加一行
伪目标的目的 不管条件满足与否,这个目标都要被执行

.PHONY: clean ALL

```



Makefile文件优化如下:



成功删除



2. 扩展2 可添加常用的参数
编译时的参数,-g,-Wall, … 这些,可以放在makefile里面
再次优化Makefile



八、makefile最终形态


m1和Makefile最终形态
左边是第一版Makefile
右边是终极版本



九、练习


源码add.c,sub.c这些在src目录下,.o文件要放在obj目录下,头文件mymath.h在inc目录下。
将hello.c中的头文件单独拿出来




inc/mymath.h



src/hello.c
这里一定要添加头文件噢,千万不要忘了,我就是在复习一遍的时候,将这里遗忘了,导致错误。



  1. 1. 修改Makefile文件
    %的匹配理解,只匹配文件名
    注意这里,也有错误噢,小坑,大家注意!!!!!



这样才是正确的Makefile,注意%的含义
% 只匹配文件名 而目录位置参数要自己主动设置



2. 执行make命令
成功运行,生成了a.out和其他.o文件




3. 使用make clean


删除.o文件和a.out文件



4. 注意


如果makefile的名字变化一下,比如,叫m6
用m6执行makefile, make -f m6
用m6执行clean make -f m6 clean


5.我的项目结构



总结


大前提:命名:makefile Makefile — make 命令(只有这两个命名才能使用make命令)
记住1个规则,2个函数,3个自动变量
1个规则
目标:依赖
(tab)命令


1.如果想生成目标,检查规则中的依赖条件是否存在,不存在,则寻找是否有规则用来生成该依赖文件(创造依赖条件) ——- 依赖条件如果不存在,则找寻新的规则去产生依赖条件
2.目标的时间必须晚于依赖条件的时间,否则更新目标
3.ALL指定makefile的终极目标


2个函数
1.src = $(wildcard _.c) 匹配当前工作目录中所有的.c文件
2.obj = $(patsubst %.c,%.o,$(src)) 将参数3中,包含参数1的部分,替换成参数2 把src中的所有的.c文件替换成.o文件
3.clean:(无依赖) (tab) -rm -rf $(obj) a.out #强制删除所有的.o文件和a.out文件
3个自动变量


1.$@:表示规则中的目标
2.$<:表示_*规则中的第一个依赖条件__,如果将该变量用在模式规则中,它可以将依赖条件列表中的依赖依次取出,套用模式规则
3.$^:表示规则中所有的依赖条件
小tips
大家学习完makefile后,可以做出自己的一个模板,下次在Linux系统中编写程序时可以直接复制这个模板,就不用去写重复的Makefile了。
然后编译c++程序也是一样的,只不过gcc编译变成了g++编译
一样的是
.c文件/.cpp文件 —-> .o 文件 —-> 可执行文件
噢,关于c和c++不同的地方就是,要添加指定c++的标准(是c++11还是c++14标准),其他大体不差,还有对应的规则要修改一下,makefile也适用于c++
大家只需要换相应的参数就可以啦!!!!

原文作者:藕粉-

原文链接:https://blog.csdn.net/cyaya6/article/details/129771224?spm=1001.2014.3001.5502