当前位置: 首页 > ops >正文

Linux修炼:自动化构建make/Makefile

         Hello大家好!很高兴我们又见面啦!给生活添点passion,开始今天的编程之路!

我的博客:<但凡.

我的专栏:《编程之路》、《数据结构与算法之美》、《C++修炼之路》、《Linux修炼:终端之内 洞悉真理》

感谢你打开这篇博客!希望这篇博客能为你带来帮助,也欢迎一起交流探讨,共同成长。

目录

1、引入

2、基本概念

      理解

 3、推导

4、Makefile语法拓展


1、引入

        在上一期我们介绍了gcc来编译源文件,可是大家在未来写代码的时候,有可能会有多个源文件需要我们去编译,那么我们怎么样才能像在vs那样,自动化的编译形成可执行程序呢?

        我们可以通过这一期介绍的make/Makefile来实现自动化构建


2、基本概念

        make是Linux系统内置的命令,而Makefile是需要工程师自己建立的文件。

        那么我们先来简单看一下怎么操作:

        现在我们的目录中已经有了一个写好的code.c文件。

        第一步新建一个名为Makefile的文件(或者makefile);

        第二步,在文件中写入以下代码:

        

        注意,第二行必须是table而不是空格!

        第三步,输入命令 make,我们发现我们当前目录中生成了code文件:

        第四步,我们直接执行这个可执行程序code:

         接下来,我们在Makefile中写一下自动清理:

         现在,我们执行make clean命令,就能够自动删除我们刚才实现的可执行程序了。          


      理解

        现在我们来解释一下我们刚才都写了什么:

        文件的第一行,code:code.c 是依赖关系;紧接着第二行叫依赖方法。依赖方法表明了依赖关系。注意第二行开头必须是TAB键,对于缩进有严格要求。依赖关系和依赖方法缺一不可。依赖关系中,冒号前面的我们叫目标文件,也就是我们生成的文件。冒号后面的叫依赖文件列表。这个列表可以有多个文件。

        第三行.PHONY :clean声明 clean是一个伪目标,即它不代表实际要生成的文件名。第四行clean: 定义了一个名为 clean 的目标。当在命令行运行make  clean时,Make 会执行该目标下的命令。伪目标总是被执行的。 什么叫总是被执行的呢?我们多次执行make,会发现他不让你编译了,因为他检测到你的源代码没有变化。这就叫总是不被执行,本质上是为了提升效率。如果我们多次执行clean,发现他总是会被执行。因为他被.PHONY修饰了。

        那么系统是怎么知道我们的源文件有没有被更改呢?

        我们看一下code.c的文件属性:

        当我们的修改文件内容时,第一二个时间属性会更改,当访问时,后两个时间属性不会更改,但是第一个可能会更改,根据系统而定。当我们修改属性但是不修改内容时,只有第三个时间属性会改变。 系统根据我们code和code.c的Modify时间的新旧来判断是否需要重修编译。

        所以说,系统判断的并不是你内容是否被更改了,只要你编辑了code.c,就算你去掉一个字母,又加上去了,内容没有改变,在系统眼里,code.c的Modify时间比code的时间新,那么code.c就允许再次被执行。

        我们在执行make时,他是从上往下扫描的,默认都是实现遇到的第一个目标。所以说对于这两个目标的前后顺序是不能调换的。


 3、推导

        我们现在用一幅图来理解makefile是怎么推导的:

        我们想要生成code就需要code.o,想生成code.o就需要code.s。以此类推。直到我们想生成code.i需要code.c,我们是有code.c的,所以就能生成了code.i,接着反向执行刚才的每个命令。其实系统在检测到我们某一个指令没有前置文件时,先把他入栈。只要没法生成就入栈,知道可以执行了,就依次出栈执行指令。

         但是我们实际上不会这样写。往往我们习惯这样写:

code:code.o                                                                       gcc code.o -o code 
code.o:code.cgcc -c code.c -o code.o.PHONY:clean
#clean:rm -f code

4、Makefile语法拓展

        接下来我们适度拓展一下makefile的语法:

        在写makefile文件的时候,我们可以不直接把各种命令都写出来,而是以变量的形式来写。

BIN=code.exe
CC=gcc 
SRC=code.c
OBJ=code.o
CFLAGS=-c
LFLAGS=-o
RM=rm -f$(BIN):$(OBJ)$(CC) $(LFLAGS) $(BIN) $(OBJ)   #或者写成$(CC) $(LFLAGS) $@ $^                                                                                                                      
$(BOJ):$(SRC)$(CC) $(CFLAGS) $(SRC) #默认生成.o结尾的同名文件.PHONY:clean 
clean:$(RM) $(BIN).PHONY:print 
print:#打印并关闭回显#使用@关闭回显@echo $(BIN)@echo $(CC)@echo $(SRC)@echo $(FLAGS)@echo $(RM)

        我们定义了一堆变量,我们的命令直接用变量代替就可以了,这类似于C语言中的宏或者全局变量,如果我们想换一些命令,比如把gcc换成g++,就直接切换这个变量就可以了。其中,$@代表上一行中冒号左边的内容,$^代表冒号右边所有内容。

        我们可以把代码继续"升级":

BIN=code.exe
CC=gcc 
SRC=$(whildcard *.c)
OBJ=$(SRC:.c=.o)
CFLAGS=-c
LFLAGS=-o
RM=rm -f$(BIN):$(OBJ)$(CC) $(LFLAGS) $(BIN) $(OBJ)   #或者写成$(CC) $(LFLAGS) $@ $^                                                                                                                      
%.o:%.c$(CC) $(CFLAGS) $<.PHONY:clean 
clean:$(RM) $(BIN).PHONY:print 
print:#打印并关闭回显#使用@关闭回显@echo $(BIN)@echo $(CC)@echo $(SRC)@echo $(FLAGS)@echo $(RM)

        whilecard是makefile内置的函数,可以实现查找当前目录下以.c为结尾的文件。当然我们也可以把.c改成.o或者其他的。第二行代码就是把SRC的所有文件中都换成同名的.o文件。%.o:%.c代表,冒号左侧有一百个文件,分别是code1.o,code2.o......,冒号右侧也有一百个文件,分别是code1.c,code2.c......,而$<代表着把以上的文件对应着,一个一个的交给.o文件。而&^代表把冒号右边的统一交给冒号左边的。因为最后我们只形成一个可执行程序。

        当然了我们日常练习也没必要写的这么复杂。

        好了,今天的内容就分享到这,我们下期再见!

http://www.xdnf.cn/news/15341.html

相关文章:

  • sshpass原理详解及自动化运维实践
  • 微软发布BioEmu模型
  • 【FPGA】AXI总线协议
  • 动态规划题解——单词拆分【LeetCode】
  • VScode链接服务器一直卡在下载vscode服务器,无法连接成功
  • 企业数字化资产管理安全、成本、协作困局难解?
  • MYSQL数据库----DCL语句
  • Linux进程状态实战指南:转换关系、监控命令与状态解析
  • 从代码学习深度强化学习 - DDPG PyTorch版
  • python赤道上空的大气环流剖面图(纬向-高度剖面)
  • 代理模式:控制对象访问
  • Spring AI 项目实战(十七):Spring Boot + AI + 通义千问星辰航空智能机票预订系统(附完整源码)
  • 无缝衔接直播流体验
  • 数据结构 单链表(1)
  • Acrobat 表单中的下拉菜单(附示例下载)
  • ESP-Timer入门(基于ESP-IDF-5.4)
  • 插入类排序的C语言实现
  • Java小白-设计模式
  • C#单例模式管理全局变量
  • OSPF与BGP的联动特性实验案例
  • OSPF与BGP的联动特性
  • Java设计模式之行为型模式(命令模式)
  • 单例模式:确保全局唯一实例
  • Vue文件上传实战指南
  • 【OpenGL 渲染器开发笔记】1 为什么要设计渲染器?
  • Dubbo-Admin 安装与使用指南:可视化管理 Dubbo 服务
  • 初识drag2框架,drag2注入的基本原理
  • 常用的docker命令备份
  • k8s:0/1 nodes are available: pod has unbound immediate PersistentVolumeClaims.
  • 论文Review 3DGSSLAM GauS-SLAM: Dense RGB-D SLAM with Gaussian Surfels