OriginBot OriginCar 智能车竞赛 ROS探索总结 ROS2探索总结 ROS入门教程 ROS 建图导航 运动控制 自动驾驶 机器视觉 机器学习 建模仿真 机器人学 ROS2入门教程 硬件电路 创客DIY教程 智能机器人创意大赛 ROS史话36篇 学习笔记 ROS2 技术前沿 行业资讯 古月居社区公告 RDK开发套件 机械臂控制 嵌入式开发 Linux


自己半个月之前学习了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函数

  • 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文件
    ![](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. 修改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

    linuxC++CMakefile编译链接 转载原出处:https://blog.csdn.net/cyaya6/article/details/129771224?spm=1001.2014.3001.5502