Linux - make命令 和 makefile

news2025/2/23 21:56:45

make命令和 makefile

 如果之前用过 vim 的话,应该会对 vim  又爱又恨吧,刚开始使用感觉非常的别扭,因为这种编写代码的方式,和在 windows 当中用图形化界面的方式编写代码的方式差别是不是很大。当你把vim 用熟悉的之后,虽然没有刚开始那么别扭了,但是当你在编写 一些大型项目的时候,vim 怎么用都不习惯。

而 makefile,就是一个可以定义一系列规则,来指定那个文件先编译,那个文件后编译,哪些文件需要重新编译,甚至进行更复杂的操作。

makefile 相对与 vim来说,他可以实现--“自动化编译”,一旦把 makefile 当中的各个文件的执行过程写好只好,只需要一个 make 命令,就可以让  由makefile 实现的各个文件的编译顺序 的整个工程 进行 完全自动的编译,这极大的提高了软件开发的效率


makefile 编写链接关系 和 链接方法 

首先要明确的是, make 是一个命名,它会默认在 本目录下寻找 名字叫做 "makefile" 或者 "Makefile" 也就是说,首字母大不大写其实是无所谓的。

一般情况下,makefile是创建在 源文件的 同级目录(当前目录)下创建的,我们用一个小例子来看 makefile和 make 的使用过程:

我们新建立一个文件夹(mk),在这个文件夹当中进行操作:

此时这个文件夹当中什么都没有,是空的,我们创建一个 text.c 文件:

 然后 在其中简单些一些代码:

 此时,就有了源代码文件,然后,我们建立的 makefile 文件要和 这个 源代码文件(text.c)文件在同级目录下

 然后我们使用 vim 打开编译 makefile 文件,在 makefile 文件当中进行以下书写

 在 " : " 的右边是 与 makefile同级目录之下的某一个 源代码文件;而在 " : " 的左边 是由右边的源代码文件 即将 生成的可执行文件(这个在外部使用make 名字之后才会生成)。

 由上述过程,我们就编译好了, text.c 这个源代码文件 由 makefile 生成可执行文件的过程。

此时我们只需要在 makefile 的同级目录下,使用 make 命令就可以在 同级目录之下生成一个 text 的可执行文件

 由上述结果可知,使用 make 之后,还会再屏幕上打印 编译过程。

我们把上述的 用 " : " 把源文件 和 对应可执行文件连接在一起的关系,叫做链接关系。关于链接关系我们下述在具体说明。


但是,上述我们只是写了 一个 链接关系,并没有指定这个源代码要使用什么样的编译方式,我们可以在 " : " 说明之后,在下面把 编译规则写上

 向上述就表示买吧 text.c 源代码文件 以 gcc 的方式编译成 text 可执行文件。我们把这个中方式叫做依赖方法。

注意:此处的依赖方法我们可以看到前面是 空格开头的,这里不能是空格分割,必须使用 tab 键进行分割:

 往后,我们先要编译 text.c 这个源代码文件的时候,就可以不用再使用 gcc 命令来编译这个文件了,直接在 上述同级目录之下,使用 make 命令就可以直接生成 text 可执行文件。(具体方式和上述演示是一样的,这里就不演示了)

 makefile 编写 删除源文件 规则

 当我们不想使用上述的 text 这个可执行文件时,我们当然可以 用 rm 删掉 这个 text 可执行文件,但是,用 rm 删除文件的风险太大,很容易写错文件名,而导致删错文件,要知道,在 linux 当中可是没有 像 windows 当中的 回收站一样的东西,在linux 当中删除某一个文件就是真的删除掉了。

所以,在 makefile 当中不能只提供 编写 源代码文件 链接关系 和 链接方法,还应该提供 删除的方式

 我们可以在 其中写一个 类型 make 的命名,向上述我就写了一个 make clean 的命令(这个命令的名字是自定义的),然后在后边写上 删除 text 这个可执行文件:

 在使用 make clean 这个命令之后,在目录当中就没有 text 可执行文件了。

 依赖关系 和 依赖方法

 如上所示:text:text.c 是一个依赖关系, gcc -o text text.c 是一个依赖方法,那么这里的 依赖关系 和 依赖方法是什么呢?

我们举一个例子:小明 和 他的爸爸,是一种依赖关系,当小明向他的爸爸要零花钱的时候,小明说:“爸,给我打100 块钱”,类似的话语,那么 小明 只有管他的爸爸叫爸,这是一种依赖关系,如果他问 他的室友的 爸爸,给他打钱,小明 和 他室友的爸爸 没有依赖关系,那么 室友的 爸爸为什么要给 小明打钱呢?

只有 小明 和 他父亲,是一种依赖关系,所以 ,小明 的爸爸 才会给他打钱;

但是,确定依赖关系之后,已经确定是要打钱的了,但是,如何打钱,微信还是支付宝,还是 打 银行卡,就要 有人去确定,所以这时候 就有了打钱的方法,也就是依赖方法

 那么,换到 makefile 当中也是一样的,text 和 text.c 是一种依赖关系,只有通过 text.c 才能生成 text 可执行文件,对于如何生成可执行文件,如上述:使用 gcc -o 的方式生成可执行文件。

 当前的 text 依赖的是 text.c 这个一个源文件来生成的,如果有 两个,那么后面就跟两个,三个就跟三个,是依靠 这 text.c 一个源文件 生成的 text 可执行文件(目标文件)。所以,就告诉 makefile, 目标文件是 text,这个text 依赖的文件是 text.c。但是光有依赖关系是不够的,makefile还需要知道如何根据 text.c 文件生成 text 目标文件,他也是需要知道的,所以,才有了 依赖方法

关于make 指令

上述是有 text.c 文件一步到位生成的 text 可执行文件,我们还可以写得更复杂一点,把 c 源代码文件 生成可执行文件的整个过程都是 意义列举出来:
 

 此时 make 命令打印:

 而且,发现,此时在文件夹当中不止有 text 可执行文件了,还有 上述生成的所有的中间文件:

 其实是因为,在上述当中,我们要想 从 text.o 文件 生成 text 可执行文件,makefile 就要从当前目录之下来寻找 text.o 文件,但是此时目录当中是没有 text.o 文件的,所以他就会接着走链接关系,发现 text.o 是由 text.s 生成的,但是此时目录当中还是有 text.s,他又会继续寻找链接关系,发现是 text.i 生成的 text.s········一次类推。

最后找到 text.c ,生成了text.i ,然后逆向的一直生成到 最终的 目标文件 text 可执行文件

也就是说,makefile 的最终目的是要生成 目标文件,而 目标文件的依赖关系 的 源文件,他会先去看目录当中有没有,有就直接生成,没有的话,就会去寻找 这个号源文件的依赖关系,然后递归式的 去生成 目标文件的 依赖文件。 

这个特征(过程),就特别像一个函数递归的过程。而上述的目标文件就是这个递归的 出口(结束条件),整个的结构,在保存这些依赖关系的时候,是一种栈式的结构。

 而且,上述过程,不是需要按照 顺序来 书写 链接关系的,就算是乱序,都是可以 编译出来的

make 指令:

当然,虽然能 打乱顺序,但是不能缺胳膊少腿,一个工程当中的文件编译顺序,缺一个他肯定是不能自动推导的
 

 输出:

 总结:make 命令 可以自动推导 makefile 的链接关系,就算其中的顺序是打乱的,只要存在,就会自动推导。其中的依赖关系是利用栈式的结构进行存储的。

 在上述你也发现了,我们的 clean 指令,写的是删除了4 个文件,当我们在外部输入 make clean 的时候,这个 4 个文件就都会删除,非常的方便


注意make 的默认动作是 ,把 makefile 当中的第一个目标文件作为 make 的默认动作

比如上述,把 clean 放到 text 目标文件的第一行的话,那么我们使用 make 指令是不会执行 text 的,而是执行 clean:
 

 使用 make 指令:
 

 如上述所示,我们直接使用 make 指令,直接执行的是 clean 指令,而不是 生成 text 可执行文件。

而 make + 目标文件名(如上述的 make clean),就是执行 在makefile当中的 目标文件。


在 本目录下 有 make + 目标文件  的 目标文件时,就不能再次 make 了:

 发现,当目录当中没有目标文件的时候,可以用 make 编译,但是当有目标文件的时候,就不能再次编译了但是,当上述情况发生之后,我们又去修改了 text.c 的代码,发现make 有可以进行编译了

因为,如果在第一次编译之后,源代码没有进行修改,那么是没有必要进行再次编译的(提升效率)。

我们在 ,windows 当中编写代码的时候,有时候报错了,但是我们已经进行修改了,但是修改之后还是报错,当我们重新生成解决方案之后,程序又好了,在期间我们没有修改过代码。其实原因就和上述是一样的,有些编译器会帮我们去 辨别 当前代码有没有被修改过,如果没有,那么也就没有再次编译的必要了,但是有的时候,可能编译器判断不是很灵敏,需要我们手动编译一下。


那,上述的 不给继续编译,和 判断源代码文件是否进行修改是如何做到呢

  我们都知道,可执行文件 是 在源文件的基础之上生成的,先有源文件,才有可执行文件,所以,一般而言,源文件的最近一次修改时间 是要比 可执行文件的。

 如果,我们修改了源文件,此时在目录当中还是有 可执行文件的,那么源文件的实现一定要比可执行文件的

 所以,只需要比较 可执行文件 的最近修改时间 和 源文件的最近修改时间:

  • 如果.exe 新于 .c 说明源文件是老的,不需要重新编译。
  • 如果.exe 于旧 .c 说明源文件是新的,需要重新编译。

对于 可执行 文件 和 源文件的 修改时间,一般是不会一样的,除非是用一些修改文件时间的命令。 

 stat命令(验证make 利用 文件时间 差异 实现 新老文件判断)(文件的三个时间)

 stat命令 用于访问某一个文件的 时间问题,那么,可以使用 stat命令 来查看 源文件和 可执行文件的一些时间:

  • 最近访问时间就是访问了这个文件的最近一次时间,比如 cat ,vim 都算是访问了这个文件。不管是你要 查看 还是 修改这个文件当中的内容,都是要访问这个文件的,所以 最近访问时间,几乎是 你 对这个文件任何操作的 最近时间。这个 时间 更改的频率是非常高的。
  •  文件内容修改时间,就是文件当中存储的内容,最近一次的修改时间。
  • 文件属性改变时间,就是文件当中存储的文件的属性,最近一次的修改时间。

 上述的三个时间可能不是割裂的,比如 修改了文件内容,不仅是 Modify 会改变,可能 Access 也会改变,系统可能判定为当前一次操作就是 一个 文件的访问操作,而且修改文件的内容 可能 会修改到 文件属性,所以,都不是割裂的。

 现在,我们修改一下文件的属性:

发现文件的 Change 时间已经被修改了。 

 此时 Modif 和 Access 都没有被修改,说明在当前系统下,认为 chmod 命令不算做是一次文件的访问。

其实在早期的linux 当中 access 在上述情况是要被修改的,但是也正是 Access 被修改的频率太高了,所以,如果有多个用户在修改访问这个文件,那么 Access 都要被修改,而 Access 被修改是要写进日志的,文件还是在磁盘上保存的,要修改 磁盘当中 Access 被修改的日志的话,就是要频繁的修改磁盘当中的内容 ,这效率就太低了。

所以,现在就减少了Access 修改的次数,来变相修改操作系统的效率。

如果实在想要 修改这个文件的当中的所有的时间,可以使用 touch  (要修改的文件)文件名 来实现。touch +  目录当中不存在的文件名,就是创建一个文件,如果 touch +  目录当中已经有的文件,就是更新这个文件的 所以时间。


make 命令 就是把 两个文件 各种各样的时间,转化成时间戳,然后按照时间戳的大小,来比较谁新谁旧。

验证:

首先我们先用 make 编译一次,打印出 源文件时间 和 可执行文件的文件内容时间:
 

 如上所示,我们进行第二次编译是不行的,此时 两个文件的时间如上所示:
现在,我们使用 touch 命令给 源文件更新时间,使得 源文件的时间 比 可执行文件的时间要新:

此时就可以进行 make 编译了。 


 makefile 当中的 .PHONY: 的使用

make 指令 会根据源文件 和 目标文件 的新旧,判定是否需要重新执行依赖关系,进行编译。编译不总是执行的。

 如果想要,在不能编译的情况下一定编译的话,也就是让对应的依赖关系总是被执行就可以在 makefile当中操作

 我们把 .PHONY 修饰的 目标文件称之为 伪目标

 我们不建议把 你需要的 生产的 目标文件修饰为 伪目标,因为 有些编译器不是很友好,重新编译的时候 可能不是删掉原本的可执行文件,然后重新生成新的可执行文件,可能是 不删除直接新增一个新的可执行文件。可能就会导致老的问题依旧还有。

 我们一把 把上述写的 清理操作,比如 clean ,写成 伪目标。

 makefile当中的特殊符号

 在链接方法当中的:

  • "$@" : 代表目标文件。如上述的 text
  • "$^" : 代表 : 右侧所属内容。如上述的 text.c

 在 链接方法前 加  “@” 符号可以让这个目标文件在生成的时候,不答应生成过程

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

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

相关文章

专业韩语论文翻译,论文中译韩哪里比较专业?

据了解,论文翻译是翻译工作中较常见的一种翻译题材,论文翻译的主要目的是在国外期刊上发表,加强国际学术交流。那么,如何做好论文翻译,论文中译韩哪里比较专业? 业内人士指出,翻译韩语论文&…

pycharm2020无法打开,点击无反应

pycharm 2020 无法打开,点击无反应,今天我碰到这现象,总结大体原因 C:\Users\ygw\AppData\Roaming\JetBrains (删除该目录即可,一般由于升级安装 或 安装两个不同版本 会存在老旧文件影响导致)

了解什么是JWT的原理及实际应用

目录 一、介绍&讲述 ( 1 ) 什么是JWT ( 2 ) 为什么要学 二、结构 三、Jwt的工具类的使用 1. 依赖 2. 工具类 3. 过滤器 4. 控制器 5. 配置 6. 测试类 用于生成JWT 解析Jwt 复制jwt,并延时30分钟 测试JWT的有效时间 测试过期JWT的解析 四、…

智能制造优化,RFID生产线管理系统解决方案

一、背景介绍 随着全球经济的发展,传统制造业面临着越来越高的成本和低利润的挑战,为了提升企业的整体利润率,优化管理流程成为必要的手段之一,在传统的制造企业中,生产线通常采用单件流生产模式,但这种模…

成立 15 年的美图分享,AI 视觉大模型的核心能力是什么?

出品 | CSDN 云计算 国民级美颜修图软件美图秀秀,从移动互联网时代火到现在,而它背后的美图公司也走过了十五年的发展,旗下拥有众多的专业影像与设计产品。最近,美图公司举办 15 周年生日会,生日会上美图还发布了自研 …

深度学习基础知识数据 数据预处理transforms流程讲解

深度学习基础知识数据 数据预处理transforms流程讲解 1、数据预处理2、使用节点2、transform.RandomResizedCrop 随机尺寸裁剪缩放3、水平翻转 与 垂直翻转4、ColorJitter变换5、ToTensor6、Normalization 归一化7、transforms.Compose8、重写transforms1、分类任务2、目标检测…

“Jwt认证在前后端分离架构中的应用与优化“

目录 引言1. JWT的简介1.1 什么是JWT1.2 JWT的优势 2. JWT工具类2.1 JWT生成与解析2.2 JWT与安全性 3. JWT案例演示后台改动前台改动 总结 引言 在当今互联网应用开发中,前后端分离架构已经成为一种主流的开发模式。而身份验证和授权是保证系统安全性的重要环节之一…

Unity 快捷键的一些记录

1.Unity Prefab Apply All 设置快捷键,修改预设体之后快捷键应用 打包会出问题:The type or namespace name ‘EditorWindow‘ could not be found EditorWindow类无法打包出EXE 添加unity关键字定义如下文所示: #if UNITY_EDITOR using Uni…

「五度情报站」网罗全量企业情报,找客户、查竞品、寻商机!

在当下严峻的市场经济环境下,准确、及时的情报信息,就如同指引企业前行的明灯,能够让企业在风起云涌的市场大潮中保持敏锐的洞察力,掌握最新的市场动态,洞悉竞争对手的一举一动,先知先动,保持竞…

多域名SSL数字证书是什么呢

多域名SSL数字证书是众多SSL数字证书中最灵活的一款SSL证书产品。一般一张SSL证书只能保护一个域名,即使能保护多个域名站点,证书保护的域名类型也有限制(通配符SSL数字证书)。多域名SSL数字证书既能用一张SSL证书保护多个域名网站,又不限制域…

时序数据库InfluxDB了解

参考:https://blog.csdn.net/u014265785/article/details/126951221

【分享】如何让压缩包里的文件“限制编辑”?

在压缩文件的时候,有时候希望压缩包里的文件,只可以查看,不能修改,那要怎么实现呢?这里有两种方法可以试试,来看看具体怎么用吧! 方法1: 在压缩文件之前,给需要压缩的文…

蓝桥杯每日一题2023.10.13

组队 - 蓝桥云课 (lanqiao.cn) 题目描述 方法一:由肉眼观察找到在一至五号位的不同编号成员的最大的值 #include<bits/stdc.h> using namespace std; int main() {cout << 98 99 98 97 98;return 0; } 方法二&#xff1a;由dfs一一找寻 #include<bits/st…

保护您的Shopify站点免受封禁和关联

Shopify是一种流行的电商平台&#xff0c;但要确保您的Shopify站点不被封禁和关联&#xff0c;需要采取一些预防措施。本文将介绍一些方法&#xff0c;帮助您保护和维护您的Shopify站点的稳定性和安全性。 一、避免被封禁的方法 遵守平台政策&#xff1a;Shopify有一系列规定和…

python可视化分析之印度中国人口分析

前言 印度和中国是世界上人口最多的两个国家&#xff0c;它们的人口变化对全球经济、社会和环境都有重要影响。根据联合国《2022 年世界人口展望》报告&#xff0c;印度人口将在今年4月中旬超过中国&#xff0c;增至14.1亿&#xff0c;成为全球人口第一大国。到2023年底&#…

drone如何发布docker服务

上篇主要实现了drone在物理机上进行发布程序&#xff0c;这次介绍drone如何发布docker类型的服务。 一 drone.yml文件配置 前提&#xff1a;需要提前在drone里添加文件里面所引用的密钥 kind: pipeline # 定义对象类型&#xff0c;还有secret和signature两种类型 type: dock…

联盟链学习笔记-网络的创建

联盟链学习笔记 初始网络 下图是初始网络网络N的参考图 排序服务 在定义 网络 N 的时候&#xff0c;第一件事情就是定义一个 排序服务O4。O4 最初被配置并且由组织 R4 的一个管理员来启动&#xff0c;并且由 R4 管理。配置 NC4 包含了描述网络管理能力初始集合的规则。最初…

计算机专业学生实习的一条明路

当计算机专业的学生毕业后学习嵌入式开发优势也会非常的明显。计算机专业提供了坚实的编程基础、数据结构和算法知识&#xff0c;这些都是嵌入式开发所需要的基本技能。视频后方有免费的嵌入式学习资料&#xff0c;按需自取。此外&#xff0c;对操作系统和系统编程的了解也为嵌…

大语言模型之十七-QA-LoRA

由于基座模型通常需要海量的数据和算力内存&#xff0c;这一巨大的成本往往只有巨头公司会投入&#xff0c;所以一些优秀的大语言模型要么是大公司开源的&#xff0c;要么是背后有大公司身影公司开源的&#xff0c;如何从优秀的开源基座模型针对特定场景fine-tune模型具有广大的…

python 如何获取url的名称

一、使用os模块 os模块是Python内置的一个操作系统接口模块&#xff0c;提供了许多与操作系统相关的函数和变量。其中&#xff0c;os.path模块用于处理路径相关的操作&#xff0c;包括文件名、目录名等。 os.path.basename()函数可以用来获取路径中的文件名部分 imp…