这里写目录标题
起因
自己半个月之前学习了makefile,编译c/c++程序方便很多
而最近又正好使用到了Linux系统,Linux系统不像Windows系统一样,基本上都是命令行编程
一个文件还好说,可是多个文件一起编译,就会很麻烦,甚至浪费时间
这个时候makefile管理项目就很方便了,明白其原理后,一旦需要使用,写好模板后,可以直接移植,而且我发现,这个适合于Linux平台,也适合于Windows平台。
而且只要你把规则写好,一个make命令就直接编译完成,自己只需要查看可执行文件就可以了
那就结合之前看过的视频对学习过的知识进行一个总结吧!!!
放出视频链接:
今天复习了一遍,收获良多
makefile项目管理
一、用途:
项目代码编译管理 节省编译项目时间
二、 makefile的基础规则
1 个规则:
目标:依赖条件
(一个TAB缩进)命令
使用命令借助依赖条件去生成目标
目标的生成时间应该比依赖条件的生成目标晚
Makefile文件
出现错误原因及解决方式
运行hello,成功运行!
注意:
- 目标的时间必须晚于依赖条件的时间,否则,更新目标
- 依赖条件如果不存在,找寻新的规则去产生依赖条件。
依赖规则:如下 Makefile文件
执行make命令 成功生成hello.o hello
运行成功,木有问题
1.多文件联合编译
makefiletest目录下有以下文件
hello.c修改如下
此时编译,则需要多文件联合编译
对于当前文件,Makefile文件修改如下
执行make命令,成功生成a.out
执行a.out
修改add.c
再次make运行a.out
可以看到,只修改add.c,但是编译的时候,其他.c文件也重新编译了
明明只改了一个,全部都重新编译了
解决方法:
- 使用命令的方式进行编译
- 修改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函数
src = $(wildscard *.c)
匹配当前工作用户下的所有.c文件。将文件名组成列表,赋值给变量src。
找到当前目录下所有后缀为.c的文件,赋值给src
eg: src = add.c sub.c div.c hello.c
匹配当前目录下所有后缀为.c的文件,赋值给src
$(wildcard arguments)函数 arguments表示函数的参数
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命令 运行结果
- 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文件
执行make命令,运行成功
这样可移植性可扩展性就很强,比如再来一个mul乘法函数,下图可见成功make,成功运行
继续优化Makefile,静态模式规则
六、 静态模式规则
使用静态模式规则,就是指定模式规则给谁用,这里指定模式规则给obj用
以后文件多了,文件集合会有很多个,就需要指定哪个文件集合用什么规则
$(obj):%.o:%.c
gcc -c $< -o $@
Makefile文件优化如下
make成功,又一次优化
七、 扩展
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. 修改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)命令
- 如果想生成目标,检查规则中的依赖条件是否存在,不存在,则寻找是否有规则用来生成该依赖文件(创造依赖条件) ----- 依赖条件如果不存在,则找寻新的规则去产生依赖条件
- 目标的时间必须晚于依赖条件的时间,否则更新目标
- ALL指定makefile的终极目标
2个函数
-
src = $(wildcard *.c)
匹配当前工作目录中所有的.c文件 -
obj = $(patsubst %.c,%.o,$(src))
将参数3中,包含参数1的部分,替换成参数2 把src中的所有的.c文件替换成.o文件 clean:(无依赖) (tab) -rm -rf $(obj) a.out #强制删除所有的.o文件和a.out文件
3个自动变量
-
$@
:表示规则中的目标 -
$<
:表示规则中的第一个依赖条件,如果将该变量用在模式规则中,它可以将依赖条件列表中的依赖依次取出,套用模式规则 -
$^
:表示规则中所有的依赖条件
小tips
大家学习完makefile后,可以做出自己的一个模板,下次在Linux系统中编写程序时可以直接复制这个模板,就不用去写重复的Makefile了。
然后编译c++程序也是一样的,只不过gcc编译变成了g++编译
一样的是
.c文件/.cpp文件 ---> .o 文件 ---> 可执行文件
噢,关于c和c++不同的地方就是,要添加指定c++的标准(是c++11还是c++14标准),其他大体不差,还有对应的规则要修改一下,makefile也适用于c++
大家只需要换相应的参数就可以啦!!!!