Linux: make指令与Makefile文件

news2024/11/25 11:28:16

目录

1. 场景介绍

2. make指令与Makefile文件

3. 依赖关系和依赖方法

4. 项目清理

5. 原理

5.1 识别文件是否需要编译

5.2 make原理

6. 扩展

总结


 

1. 场景介绍

Linux操作系统中,我们每编写一个C/C++代码,都要手动使用gcc/g++指令,对代码进行编译并生成可执行程序。如果对该代码有所改动,需要再次使用指令,形成新的可执行程序,删除之前的可执行程序。

如下面的场景,创建一个code.c文件,写了一个简单的打印程序,通过gcc指令直接生成code可执行程序,执行该程序,打印出一句话。如果对该份代码还有改动,就要像下面一样删除刚生成的可执行程序,并重复刚刚的操作。

这样的操作十分麻烦,有什么解决办法吗?此时就要使用make指令,搭配上MakeFile文件。

2. make指令与Makefile文件

Linux中,make指令是一个工具,它用于自动化软件构建过程,特别是用于编译大型程序。它通过读取一个名为Makefile的文件来确定如何构建一个或多个目标,完成自动化编译。

  • 工程中的文件不计其数,分别放在若干个目录中,Makefile文件有相应的语法规则,可以指定哪些文件需要先编译,哪些文件可以后编译,哪些文件需要重新编译,甚至是进行更复杂的功能操作。
  • make是一个解释Makefile中指令的的命令工具。
  • make是一条命令,Makefile是一个文件,两个搭配使用,完成项目自动化构建。

3. 依赖关系和依赖方法

在doc目录下,创建一个Makefile文件。下面是C语言代码编译的详细步骤,从下到上,先进行预处理(进行宏替换,展开头文件,删除注释),生成纯C语言文件,其次由C语言代码转换成汇编代码,再生成二进制目标代码(机器可识别代码),最后进行链接操作生成可执行程序。

你会发现每次编译生成不同文件,语法格式大致相同。第一行不留空格,冒号前面是目标文件名,冒号后面是所依赖文件。第二行需要用Tab键隔开几个空格,然后写下编译指令。

一般来说,Makefile中编写指令时,需要有依赖关系依赖方法

  • 依赖关系是指一个目标文件(通常是最终要生成的文件,比如可执行文件或库文件)与它所依赖的文件(通常是源文件、头文件或其他目标文件)之间的关系。且目标文件在冒号之前,依赖文件列表再冒号之后。依赖文件列表可以有多个文件,需要用空格隔开。
  • 如下图中,code依赖code.o,code.o依赖code.s,code.s依赖code.i,code.i依赖code.c。
  • 依赖方法就是下图中编译的指令。

 Makefile文件内容就是上图的八行文本。我们使用make指令,就会自动进行编译,生成各个阶段的文件,运行code可执行程序,打印出最开始写的一句话。

其中需要注意,Makefile中先写生成可执行程序,然后慢慢推导到code.c文件,不可以颠倒过来。如果颠倒过来只会执行上图中最下面的雨具,生成code.i文件。

不过一般来说,不会像我刚刚那样生成一系列的中间文件,可以一步到位。由code.c文件直接生成code可执行程序。如下图所示:

4. 项目清理

既然有自动化编译,那么重新编译时,需要清理项目生成的文件。

  • 如清理项目这种指令,目标文件没有依赖文件,我们要声明一个伪目标,用.PHONY进行修饰。
  • 像clean这种,没有跟第一个目标文件直接或间接关联,那么它后面对应的方法就不会被执行。不过,可以显示用make执行,即用“make clean”指令执行。也就是说,用“make”+“目标文件名”格式的指令,可以执行对应的方法。

下面是操作示意图:

那么为什么要用.PHONY进行修饰呢?

观察上图操作,一开始没有生成可执行程序,我们使用make指令进行自动化编译,生成了一个code可执行程序。之后再使用make指令时,都会弹出一句话“ 'code' is up to date”,这是说明源文件没有更新,code可执行程序已经是最新的。

我们要知道.PHONY的作用,我们可以在Makefile文件中加上伪目标的修饰。观察下面的操作,你会发现加上.PHONY修饰之后,不管源文件有没有更新,都会一直执行编译操作。说明伪目标的特性是总是执行目标文件对应的方法

5. 原理

5.1 识别文件是否需要编译

前面说不用.PHONY修饰的目标文件,编译C语言代码成可执行程序时,会识别代码内容是否被修改过,如果没有被修改,就不会再次编译,反之进行编译操作。

仔细一想,这样子处理是十分合理的。因为当你面对的不是一两个文件,而是十几个甚至上百个文件的工程。每修改工程中的一个文件,就要对整个工程进行重新编译,是十分耗时的。

那么这是如何做到的呢,原理是什么?

  • 解析原理之前,我们首先要了解一个结论,文件由文件内容文件属性这两部分组成的。文件属性中有访问时间和修改时间。我们可以使用stat这条指令获取文件当前状态。
  • 下面就是code.c文件的当前状态,下面有三行显示不同类型的时间。Acess表示最近一次访问该文件的时间,有些不是显示最近一次访问的时间,可能需要积累到一定次数才进行更新;Modify表示该文件内容最近一次被修改的时间;Change表示该文件属性最近一次被修改的时间。

  • 我们复制printf代码,多粘贴几句,修改一下code.c文件内容。查看code.c文件的状态,会发现Modify这一栏的时间更新了。可是Change这一栏的时间怎么也更新了呢?那是因为修改文件内容会引起文件大小发生变化,文件大小也是属性中的一种。

  • 如果仅仅修改文件权限,只会改变Change这一栏的时间,Modify的时间保持不变。

我们通过上面的讲解,知道每个文件都有最近一次文件内容被修改的时间。

  • 下面的横轴表示文件的Modify时间,从左到右时间更新。其中一开始的Modify时间就表示创建该文件的时间。
  • 正常来说,我们都是先创建一个源文件code.c。然后,编译产生一个可执行程序文件。如下图红色部分所示,该文件的Modify时间一定比源文件的Modify时间更新,此时执行make指令,不会重新编译。
  • 除非code.c文件内容被修改,随之Modify时间更新,比code.exe文件更新,这样执行make指令之后才会进行编译。

那么.PHONY关键字修饰后的目标文件,为什么可以总是执行其对应的方法呢?因为.PHONY可以让依赖方法忽略掉时间的对比。

5.2 make原理

  • make会在当前目录下找名为“Makefile”或者“makefile”的文件。
  • 如果文件存在,它会找文件中的第一个目标文件。在上面的例子中,它会找到code文件,把它当做最终的目标文件。
  • 如果code文件不存在,或者其所依赖的code.c文件的Modify时间比code文件新。此时就会执行依赖方法中的指令,来生成code文件。

  • 如果是code所依赖的code.o文件不存在,那么make就会在makefile文件中寻找code.o文件依赖的code.s文件。会这样一直找下去,直到依赖的文件存在于当前目录下,并逆向执行指令,有点像栈的结构,先将一开始指令存进去。

  • 在寻找的过程,如果中出现错误,如最后的被依赖文件找不到,那么make就会直接退出,并报错。make只管文件的依赖性。

6. 扩展

一般,我们不会像上面一样生成.i和.s文件。我们会直接让源文件编译成一个.o目标文件,且.o文件与源文件同名,有助于最后链接的操作。其中code.o文件的依赖方法表示生成跟源文件同名的.o文件。

  • %是makefile文件中的一种通配符,如%.c表示以.c结尾的文件。依赖方法中的$<表示将依赖列表中的所有文件一个一个给gcc指令编译生成同名的.o文件。如果有什么code1.c,code2.c文件,就会生成三条gcc指令。
  • makefile文件中也是可以定义变量的,但是不需要声明变量类型。第一行和第二行分别定义bin和src变量,表示目标文件和所依赖文件。
  • 其中$()符号中加上变量名,表示获取变量中的内容,相当于指针的解引用。这样写的好处是,如果所依赖文件有许多个,都可以存在一个变量中,然后使用$()符号即可。
  • $^表示所依赖文件列表中的所有文件,全部拿过来给gcc编译到目标文件中。$@就表示所有的目标文件。

执行结果如下:

 


总结

在Linux操作系统中,手动编译C/C++代码并生成可执行程序的过程较为繁琐,尤其是在代码修改后需要重复编译和删除旧程序。为了解决这个问题,可以使用make工具和Makefile文件来自动化编译过程。

Makefile文件是一个包含编译指令和依赖关系的文件,它指导make工具如何构建目标文件。。依赖关系指明了目标文件与源文件之间的关系,而依赖方法则包含了编译指令。

创作不易,希望这篇文章能给你带来启发和帮助,如果喜欢这篇文章,请留下你的三连,你的支持的我最大的动力!!!

ee192b61bd234c87be9d198fb540140e.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2092900.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ffmpeg源码分析(六)内存管理

系列文章目录 FFmpeg源码解析系列&#xff08;一&#xff09;目录和编译 FFmpeg源码解析系列&#xff08;二&#xff09;主要结构体 ffmpeg源码解析系列&#xff08;四&#xff09;结构体之AVIOContext 、URLContext、URLProtocol ffmpeg源码解析系列&#xff08;五&#xff0…

phpstudy怎么用

启动Apache 这是你的默认网站域名。点击物理路径 进入到目录&#xff0c;将你的php文件项目拖进去。如test.php 打开浏览器

python 天气与股票的关系--第2部分,清洗数据

先看一下股票信息 合并天气信息 合并2个数据 合并之后&#xff0c;会自动删除 周六和周日 节假日 下一篇&#xff0c;尝试建立数学模型

生产环境变态开启devtools(redux篇)

前沿 默认都安装了谷歌的redux-devtools插件哦 没有亮,说明关闭了生产环境的redux devtools工具, 接下来跟着博主一起变态启用它 如果看了我上一篇的小伙伴,应该会很熟练了,如果没有看上一篇的,也没关系,博主会手摸手的教你们打开它。 正常的解决方案(适用内部开发人员…

【c++】日期类相关实践:计算日期到天数转换、日期差值

相关文章&#xff1a;日期类&#xff08;运算符重载应用&#xff09;详细版 目录 前言 实践1&#xff1a;计算日期到天数转换 题目 方法 关键代码 完整代码 实践2&#xff1a;日期差值 题目 方法 关键代码 完整代码 &#x1f497;感谢阅读&#xff01;&#x1f49…

python网络爬虫(四)——实战练习

0.为什么要学习网络爬虫 深度学习一般过程:   收集数据&#xff0c;尤其是有标签、高质量的数据是一件昂贵的工作。   爬虫的过程&#xff0c;就是模仿浏览器的行为&#xff0c;往目标站点发送请求&#xff0c;接收服务器的响应数据&#xff0c;提取需要的信息&#xff0c…

Python 算法交易实验85 QTV200日常推进-钳制指标与交易量

说明 继续保持思考与尝试 最近挺有意思的&#xff0c;碰到很多技术上的问题&#xff0c;其解决方案都类似“阴阳两仪”的概念。 "阴阳两仪"是中国古代哲学中的一个重要概念&#xff0c;源自《易经》&#xff08;又称《周易》&#xff09;。它是对宇宙间最基本对立统一…

数据结构与算法 第5天(树和二叉树)

树形结构 一对多 只有一个前驱 可以有多个后继 树的定义 基本术语 有序树&#xff1a;树中结点的各子树从左至右有次序(最左边的为第一个孩子) 森林&#xff1a;是 m(m≥0)棵互不相交的树的集合。 一棵树可以看成特殊的森林 二叉树 每个节点最多有两个…

【王树森】BERT:预训练Transformer模型(个人向笔记)

前言 BERT&#xff1a;Bidirectional Encoder Representations from TransformerBERT是用来预训练Transformer模型的encoder的本节课只讲述主要思想BERT用两个主要思想来训练Transformer的encoder网络&#xff1a;①随机遮挡单词&#xff0c;让encoder根据上下文来预测被遮挡的…

2024年9月1日 十二生肖 今日运势

小运播报&#xff1a;2024年9月1日&#xff0c;星期日&#xff0c;农历七月廿九 &#xff08;甲辰年壬申月戊辰日&#xff09;&#xff0c;法定节假日。 红榜生肖&#xff1a;鸡、猴、鼠 需要注意&#xff1a;龙、兔、狗 喜神方位&#xff1a;东南方 财神方位&#xff1a;正…

【系统架构设计师-2015年】综合知识-答案及详解

【第1~2题】 某航空公司机票销售系统有n个售票点&#xff0c;该系统为每个售票点创建一个进程Pi&#xff08;i1&#xff0c;2&#xff0c;…&#xff0c;n&#xff09;管理机票销售。假设Tj&#xff08;j1&#xff0c;2&#xff0c;…&#xff0c;m&#xff09;单元存放某日某…

2025届必看:如何用Java SpringBoot+Vue打造免费体育馆场地预约系统?

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

异常与使用

异常 一、C语言传统的错误处理机制二、异常1、概念2、关键字3、示例 三、异常的使用1、异常的抛出和匹配原则2、在函数调用链中异常栈展开匹配原则3、栈展开示意图4、示例代码5、运行结果 四、异常的重新抛出1、作用2、示例代码3、运行结果 五、异常安全六、异常规范1、概念2、…

CSS-浮动【看这一篇就够了】

目录 浮动布局 浮动是如何工作的 浮动的本质和要点 如何产生浮动 元素浮动的特性 1.元素添加浮动后&#xff0c;脱离文档流 2.如果父元素的宽度不够 3.浮动的顺序贴靠特性 4.元素浮动后&#xff0c;具有行内块级元素特性 5.浮动的元素会造成父元素高度塌陷 6.浮动对…

“无法连接打印机0X0000011B”原因分析及多种解决方法

在日常办公和生活中&#xff0c;打印机是不可或缺的重要设备。然而&#xff0c;有时在连接打印机的过程中&#xff0c;我们可能会遇到错误代码0x0000011b的提示。有更新补丁导致的、有访问共享打印机服务异常、有访问共享打印机驱动异常等问题导致的&#xff0c;针对访问共享打…

MySQL场景测试题

第一题 软件环境描述&#xff1a; Mysql V5.7.30 Innodb RR隔离级别 表结构以及数据描述&#xff1a; &#xff08;1&#xff09;t_user用户表&#xff0c;表格如下&#xff1a; CREATE TABLE t_user ( id int(10) NOT NULL, name varchar(100) DEFAULT NULL, PRIMARY KEY (id)…

240831-Gradio之RAG文档对话工具Kotaemon的安装与配置

A. 用户界面 该项目既可以作为功能性 RAG UI&#xff0c;既可以用于对文档进行 QA 的最终用户&#xff0c;也可以用作想要构建自己的 RAG 管道的开发人员。对于最终用户&#xff1a; - 一个干净且简约的用户界面&#xff0c;用于基于RAG的QA。 - 支持 LLM API 提供程序&#xf…

gethub-rrsf

一.FastCGI协议 1.来到127.0.0.1下发现404报错 2.这一关我们要借助一个叫Gopherus的工具&#xff0c;我这里是在kali虚拟机里面克隆的 git clone https://github.com/tarunkant/Gopherus.git 3.运行命令 由于一句话木马无法写入&#xff0c;所以我们使用base64编码&#xf…

将Google Chrome或Microsoft Edge浏览器的地址栏隐藏的方法

将Google Chrome或Microsoft Edge浏览器的地址栏隐藏的方法 目标效果示范 我们以百度首页为例&#xff0c;普通模式启动的页面通常会显示地址栏&#xff0c;如下图所示&#xff1a; 而本文要实现的效果是隐去地址栏和书签栏&#xff08;如果有的话&#xff09;&#xff0c;无…

重生奇迹MU 敏捷流梦幻骑士 真正的平民PK王

“梦幻骑士”这个职业已经存在于重生奇迹MU中很长时间了&#xff0c;虽然现在已经不算是新职业了&#xff0c;但玩家们对于梦幻骑士的研究和开发一直没有停止过。它作为一个特殊的职业&#xff0c;与传统职业截然不同&#xff0c;拥有着许多独特的玩法。其中&#xff0c;有一种…