Makefile项目管理-----在Linux下编译c/c++程序

时间:2021-04-08 01:14:51

起因

自己半个月之前学习了makefile编译c/c++程序方便很多

而最近又正好使用到了Linux系统,Linux系统不像Windows系统一样,基本上都是命令行编程

一个文件还好说,可是多个文件一起编译,就会很麻烦,甚至浪费时间

这个时候makefile管理项目就很方便了,明白其原理后,一旦需要使用,写好模板后,可以直接移植,而且我发现,这个适合于Linux平台,也适合于Windows平台

而且只要你把规则写好一个make命令就直接编译完成自己只需要查看可执行文件就可以了

那就结合之前看过的视频对学习过的知识进行一个总结吧!!!

放出视频链接:

视频链接

今天复习了一遍,收获良多

makefile项目管理

一、用途:

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

二、 makefile的基础规则

1 个规则:

目标:依赖条件
(一个TAB缩进)命令

使用命令借助依赖条件去生成目标
目标的生成时间应该比依赖条件的生成目标晚

Makefile文件
Makefile项目管理-----在Linux下编译c/c++程序

出现错误原因及解决方式
Makefile项目管理-----在Linux下编译c/c++程序
运行hello,成功运行!
Makefile项目管理-----在Linux下编译c/c++程序


注意

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

Makefile项目管理-----在Linux下编译c/c++程序
依赖规则:如下 Makefile文件
Makefile项目管理-----在Linux下编译c/c++程序

执行make命令 成功生成hello.o hello
Makefile项目管理-----在Linux下编译c/c++程序
运行成功,木有问题
Makefile项目管理-----在Linux下编译c/c++程序

1.多文件联合编译

makefiletest目录下有以下文件
Makefile项目管理-----在Linux下编译c/c++程序
hello.c修改如下
Makefile项目管理-----在Linux下编译c/c++程序
此时编译,则需要多文件联合编译
Makefile项目管理-----在Linux下编译c/c++程序

对于当前文件,Makefile文件修改如下
Makefile项目管理-----在Linux下编译c/c++程序
执行make命令,成功生成a.out
Makefile项目管理-----在Linux下编译c/c++程序
执行a.out
Makefile项目管理-----在Linux下编译c/c++程序


修改add.c
Makefile项目管理-----在Linux下编译c/c++程序
再次make运行a.out
Makefile项目管理-----在Linux下编译c/c++程序
可以看到,只修改add.c,但是编译的时候,其他.c文件也重新编译了
明明只改了一个,全部都重新编译了

解决方法

  1. 使用命令的方式进行编译

Makefile项目管理-----在Linux下编译c/c++程序

  1. 修改Makefile文件

Makefile项目管理-----在Linux下编译c/c++程序
执行make,成功生成a.out文件
Makefile项目管理-----在Linux下编译c/c++程序


2. makefile检测原理

修改div.c后,再次执行make
可以看到只重新编译了修改后的文件,而其他文件并没有编译
Makefile项目管理-----在Linux下编译c/c++程序
再次修改add.c,再次执行make
除法的结果没有改变,表明只编译了add.c,而div.c和其他文件并没有编译
Makefile项目管理-----在Linux下编译c/c++程序

Makefile文件中
使用命令借助依赖条件去生成目标
目标的生成时间应该比依赖条件的生成目标晚

当依赖条件比目标时间晚,目标就要被更新

makefile检测原理

  • 修改文件后,文件的修改时间发生变化,会出现目标文件的时间早于作为依赖的时间,出现这种情况的文件会重新编译。
  • 修改div.c后,div.o的时间就早于div.c ,a.out的时间也早于div.o的时间了,于是重新编译这俩文件了

3. ALL来指定终极目标

ALL来指定终极目标

  • makefile的依赖是从上至下的,换句话说就是目标文件是第一句里的目标,如果不满足执行依赖,就会继续向下执行。如果满足了生成目标的依赖,就不会再继续向下执行了。
  • make会自动寻找规则里需要的材料文件,执行规则下面的行为生成规则中的目标。

修改Makefile文件,把生成a.out放在其他下面
Makefile项目管理-----在Linux下编译c/c++程序
执行make,可以看到只生成了hello.o,其他文件的.o并没有生成
Makefile项目管理-----在Linux下编译c/c++程序
同样,修改Makefile文件后,再次执行make,只执行了
Makefile项目管理-----在Linux下编译c/c++程序

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

解决方法

ALL : 终极目标

ALL存在的意义就是用来告诉make命令,当前Makefile文件中,不管碰到的第一组规则的目标是谁,最终要生成的目标一定是a.out
Makefile项目管理-----在Linux下编译c/c++程序
这样再执行make命令,文件都编译成功!
Makefile项目管理-----在Linux下编译c/c++程序
:::

三、 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表示函数的参数

  1. 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文件就可以更新了
Makefile项目管理-----在Linux下编译c/c++程序
执行make命令 运行结果
Makefile项目管理-----在Linux下编译c/c++程序
Makefile项目管理-----在Linux下编译c/c++程序

  1. clean:(没有依赖)

clean:
(TAB缩进) rm -rf $(obj) a.out
循环删除所有.o和a.out文件

在执行make clean命令时,一定要加-n 去模拟执行

make clean -n
Makefile项目管理-----在Linux下编译c/c++程序
自己在查看-n命令后,认为无问题了,再执行,所有的.o文件和a.out文件都被删除了
Makefile项目管理-----在Linux下编译c/c++程序

Makefile文件里clean中的命令

clean:
-rm -rf $(obj) a.out

这里rm前面的”-“表示出错依然执行,作用是删除不存在文件时,不报错,顺序执行结束

四、 makefile中的三个自动变量

3个自动变量
$@:在规则命令中,表示规则中的目标
$<:在规则命令中,表示规则中的第一个依赖条件
如果将该变量用在模式规则中,它可以将依赖条件列表中的依赖依次取出,套用模式规则

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

$^:在规则命令中,表示规则中的所有依赖条件组成一个列表,以空格隔开,如果这个列表中有重复项,则去重

由此,更新makefile文件
Makefile项目管理-----在Linux下编译c/c++程序
执行make命令,运行成功
Makefile项目管理-----在Linux下编译c/c++程序

五、模式规则

上面的Makefile可扩展型不强
比如,要添加一个乘法函数,就需要在Makefile里添加乘法的规则
解决方法:模式规则

%.o:%.c
	gcc -c $< -o $@

更新Makefile文件
Makefile项目管理-----在Linux下编译c/c++程序
执行make命令,运行成功
Makefile项目管理-----在Linux下编译c/c++程序

这样可移植性可扩展性就很强,比如再来一个mul乘法函数,下图可见成功make,成功运行
Makefile项目管理-----在Linux下编译c/c++程序
Makefile项目管理-----在Linux下编译c/c++程序

继续优化Makefile,静态模式规则

六、 静态模式规则

使用静态模式规则,就是指定模式规则给谁用,这里指定模式规则给obj用
以后文件多了,文件集合会有很多个,就需要指定哪个文件集合用什么规则

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

Makefile文件优化如下
Makefile项目管理-----在Linux下编译c/c++程序
make成功,又一次优化
Makefile项目管理-----在Linux下编译c/c++程序

七、 扩展

1. 扩展1 伪目标

当文件夹下有ALL文件或者clean文件时,会导致makefile瘫痪,如下所示,make clean没有工作
用伪目标来解决,添加一行
伪目标的目的 不管条件满足与否,这个目标都要被执行

.PHONY: clean ALL

Makefile项目管理-----在Linux下编译c/c++程序
Makefile文件优化如下:
Makefile项目管理-----在Linux下编译c/c++程序
成功删除
Makefile项目管理-----在Linux下编译c/c++程序

2. 扩展2 可添加常用的参数

编译时的参数,-g,-Wall, ... 这些,可以放在makefile里面
再次优化Makefile
Makefile项目管理-----在Linux下编译c/c++程序

八、makefile最终形态

m1和Makefile最终形态

左边是第一版Makefile

右边是终极版本
Makefile项目管理-----在Linux下编译c/c++程序

九、练习

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

Makefile项目管理-----在Linux下编译c/c++程序
Makefile项目管理-----在Linux下编译c/c++程序

inc/mymath.h
Makefile项目管理-----在Linux下编译c/c++程序
src/hello.c

这里一定要添加头文件噢,千万不要忘了,我就是在复习一遍的时候,将这里遗忘了,导致错误。
Makefile项目管理-----在Linux下编译c/c++程序

1. 修改Makefile文件

%的匹配理解,只匹配文件名
注意这里,也有错误噢,小坑,大家注意!!!!!
Makefile项目管理-----在Linux下编译c/c++程序
Makefile项目管理-----在Linux下编译c/c++程序

这样才是正确的Makefile,注意%的含义

% 只匹配文件名 而目录位置参数要自己主动设置

Makefile项目管理-----在Linux下编译c/c++程序

2. 执行make命令

成功运行,生成了a.out和其他.o文件
Makefile项目管理-----在Linux下编译c/c++程序
Makefile项目管理-----在Linux下编译c/c++程序

3. 使用make clean

删除.o文件和a.out文件
Makefile项目管理-----在Linux下编译c/c++程序

4. 注意

  • 如果makefile的名字变化一下,比如,叫m6

用m6执行makefile, make -f m6
用m6执行clean make -f m6 clean

5.我的项目结构

Makefile项目管理-----在Linux下编译c/c++程序

总结

大前提命名: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++

大家只需要换相应的参数就可以啦!!!!