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.pswp.cn/diannao/91138.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/91138.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/91138.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GaussDB 分布式部署下创建表方法

1、问题现象 分布式集群采用水平分表的方式,将业务数据表的元组/行打散存储到各个节点内。 2、技术背景 通过全并行数据处理技术和快速定位到数据存储位置等手段可极大提升数据库性能,GaussDB分布式部署下可以创建俩种类型表,在做实际业务系统开发时根据业务场景创建不同表。…

Padavan路由器设置DNSmasq的DHCP Option

是下文的拓展&#xff1a;由于更换路由器为Padavan&#xff0c;需要配置DHCP option才能使得AC能够纳管AP 爱快路由器下水星&#xff08;Mercury&#xff09;无线管理器AC跨三层发现AP_爱快管理第三方ap-CSDN博客 DNSmasq全部配置请参考&#xff1a;Man page of DNSMASQ dhcp-…

Ubuntu 22.04 Server 虚拟机初始化配置与优化指南

✅ Ubuntu 22.04 本地/通用服务器初始化配置清单 1. 设置时区 sudo timedatectl set-timezone Asia/Shanghai2. 防火墙配置&#xff08;UFW&#xff09; sudo ufw enable sudo ufw default deny # 可选放通SSH或其他端口 sudo ufw allow 22/tcp # 查看状态 sudo ufw status # 禁…

如何在服务器上运行一个github项目

一、事情的缘起 今天一个朋友向我推荐了小红书上的一个视频&#xff0c;我看了一下这是一个在演示TypeWords项目的视频。这个项目是Github上采用vue来编写的一个开源项目。我进入该项目后看到了给出的样例网址2study.top&#xff0c;然后到上面看了一下。我发现这是一个通过打…

7.14 Java基础|String 和StringBuilder

补充注意&#xff1a;1、StringBuilder 的 append 方法可以接收整数类型的参数&#xff0c;并将其自动转换为字符串后添加到 StringBuilder 中2、该方法适用于所有基本数据类型&#xff08;如 long、double 等&#xff09;和对象&#xff08;通过调用其 toString() 方法&#x…

React 第六十九节 Router中renderMatches的使用详解及注意事项

前言 renderMatches 是 React Router 的一个高级实用函数&#xff0c;用于根据路由匹配结果渲染对应的组件树。它提供了对路由渲染过程的底层控制能力&#xff0c;特别适用于自定义路由渲染逻辑的场景。 一、基本概念和功能 renderMatches 函数的作用是将路由匹配结果转换为 Re…

esp8266-01S实现PPM波形

esp8266-01虽然小众&#xff0c;但是功能可不能少。因航模需要让ESP8266-01生成PPM波形。#include <ESP8266WiFi.h> #include <Ticker.h> // 仅用于延时函数替代#define PPM_PIN 2 // 使用 GPIO2 (需断开串口上传时的连接) #define CHANNELS 4 // PPM通道数量…

使用 pytest 测试框架构建自动化测试套件之一

pytest 是一个非常灵活且强大的测试框架&#xff0c;它支持简单的单元测试到复杂的功能测试。显著特点是其简洁的语法&#xff0c;可以无需继承 TestCase 类直接使用函数来编写测试用例&#xff0c;并通过 assert语句 进行断言。还支持参数化测试、丰富的插件系统。 pytest自动…

nacos docker 配置

docker.io/nacos 项目中国可用镜像列表 | 高速可靠的 Docker 镜像资源 1、Docker 拉取镜像 docker pull nacos/nacos-server:v2.1.0 2、创建宿主机挂载目录 mkdir -p /mydata/nacos/logs/ mkdir -p /mydata/nacos/conf/ AI写代码 3、启动nacos并复制文件到宿主机&#xff0…

Django 模板(Template)

1. 模板简介 作为 Web 开发框架,Django 提供了模板,可以很便利的动态生成 HTML。模版系统致力于表达外观,而不是程序逻辑。 模板的设计实现了业务逻辑(view)与显示内容(template)的分离,一个视图可以使用任意一个模板,一个模板可以供多个视图使用。 模板包含: HTM…

Word 文字编辑状态下按回车换行后是非正文格式

在Word里编辑时&#xff0c;按回车后新段落突然变成标题1、标题2这类格式&#xff0c;不再是正文样式&#xff0c;这通常是因为「正文」的样式设置出了问题——可能被默认设置成“后续段落自动应用标题1/标题2格式”了。 修改方法很简单&#xff1a; 找到并打开「正文」样式的修…

PySide6 UI 灵活性:QToolBar 的浮动与停靠及 QSplitter 的可调整面板

PySide6 UI 灵活性&#xff1a;QToolBar 的浮动与停靠及 QSplitter 的可调整面板 在现代桌面应用程序开发中&#xff0c;提供灵活且用户友好的界面至关重要。PySide6&#xff08;Qt for Python&#xff09;提供了强大的工具来构建这样的界面。本文将深入探讨两个关键的 PySide6…

B4016 树的直径

B4016 树的直径 - 洛谷 题目描述 给定一棵 n 个结点的树&#xff0c;树没有边权。请求出树的直径是多少&#xff0c;即树上最长的不重复经过一个点的路径长度是多少。 输入格式 第一行输入一个正整数 n&#xff0c;表示结点个数。 第二行开始&#xff0c;往下一共 n - 1 行…

【一维 前缀和+差分】

一、一维前缀和 1.1 定义 给定一个数组 a[1..n]&#xff0c;其前缀和数组 pre[1..n] 定义为&#xff1a; pre[i]a[1]a[2]⋯a[i] pre[i] a[1] a[2] \dots a[i] pre[i]a[1]a[2]⋯a[i] 即 pre[i] 表示原数组从第 1 项到第 i 项的和。 1.2 构建 int a[N], pre[N]; for (int i …

Spring Boot 双数据源配置

文章目录什么是双数据源&#xff1f;为什么需要双数据源&#xff1f;核心实现原理完整示例注意什么是双数据源&#xff1f; 双数据源是指在一个应用程序中同时配置和使用两个不同的数据库连接。比如&#xff1a; 一个连接订单数据库&#xff0c;处理业务数据一个连接用户中心…

【Java】【力扣】102.二叉树层序遍历

思路一个辅助队列&#xff08;初始化队列&#xff1a;根节点入队&#xff09;一个节点 出队&#xff0c;他的左右孩子入队循环 直到队列为空举例代码public List<List<Integer>> levelOrder(TreeNode root) {if (rootnull){return new ArrayList<List<Intege…

为什么有些PDF无法复制文字?原理分析与解决方案

在日常办公和学习中&#xff0c;我们经常会从PDF文件中复制文字&#xff0c;用于编辑、引用、整理笔记。但你是否也遇到过这样的情况&#xff1a;有些PDF中的文字根本无法选中&#xff0c;更无法复制粘贴&#xff1f; 看起来像是“文字”&#xff0c;但操作上却完全无效——这…

LabVIEW浏览器ActiveX事件交互

​程序围绕 WebBrowser ActiveX 控件&#xff0c;借 “Reg Event Callback” 注册标题变更回调&#xff0c;“Callback - Title Change.vi” 处理标题数据&#xff0c;“Monitor...” 响应 URL 变更&#xff0c;“Unregister...” 清理资源&#xff0c;实现浏览器事件交互与管控…

C++后端面试八股文

一、C 语言基础与底层原理请解释 new / delete 和 malloc / free 的区别和联系&#xff0c;以及使用它们时需要注意什么new 和 delete 是C的​​运算符&#xff08;Operator&#xff09;​​。这意味着它们可以被类&#xff08;通过 operator new 和 operator delete&#xff0…

基础分类模型及回归简介(一)

一、先搞懂两个核心任务&#xff1a;分类和回归咱们生活中总遇到要 “判断” 或 “预测” 的事&#xff1a;比如看到一个水果&#xff0c;判断是苹果还是橘子 —— 这就是分类&#xff08;结果是 “类别”&#xff09;&#xff1b;比如根据西瓜的大小、颜色&#xff0c;猜它能卖…