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

Linux - make命令 和 makefile

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

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

相关文章:

Linux - make命令 和 makefile

make命令和 makefile 如果之前用过 vim 的话,应该会对 vim 又爱又恨吧,刚开始使用感觉非常的别扭,因为这种编写代码的方式,和在 windows 当中用图形化界面的方式编写代码的方式差别是不是很大。当你把vim 用熟悉的之后&#xff0…...

FPGA复习(功耗)

减小功耗 就得减小电流 电流和CF有关( C: 电容(被门数目和布线长度影响) F:时钟频率) 方法大纲 减小功耗:1 时钟控制 2输入控制 3减小供电电压 4双沿触发器 5修改终端 同步数字电路降低动态功耗:动态禁止…...

element ui el-table表格复选框,弹框关闭取消打勾选择

//弹框表格复选框清空 this.$nextTick(()>{this.$refs.table.clearSelection();})<el-table ref"table" v-loading"crud.loading" :header-cell-style"{ color: #FFF, background: #333 }":cell-style"{ color: #FFF, background: #3…...

数据结构——队列

1.队列元素逆置 【问题描述】 已知Q是一个非空队列&#xff0c;S是一个空栈。仅使用少量工作变量以及对队列和栈的基本操作&#xff0c;编写一个算法&#xff0c;将队列Q中的所有元素逆置。 【输入形式】 输入的第一行为队列元素个数&#xff0c;第二行为队列从首至尾的元素…...

【Unity引擎核心-Object,序列化,资产管理,内存管理】

文章目录 整体介绍Native & Managed Objects什么是序列化序列化用来做什么Editor和运行时序列化的区别脚本序列化针对序列化的使用建议 Unity资产管理导入Asset Process为何要做引擎资源文件导入Main-Assets和 Sub-Assets资产的导入管线Hook&#xff0c;AssetPostprocessor…...

Generics/泛型, ViewBuilder/视图构造器 的使用

1. Generics 泛型的定义及使用 1.1 创建使用泛型的实例 GenericsBootcamp.swift import SwiftUIstruct StringModel {let info: String?func removeInfo() -> StringModel{StringModel(info: nil)} }struct BoolModel {let info: Bool?func removeInfo() -> BoolModel…...

数据结构之手撕顺序表(增删查改等)

0.引言 在本章之后&#xff0c;就要求大家对于指针、结构体、动态开辟等相关的知识要熟练的掌握&#xff0c;如果有小伙伴对上面相关的知识还不是很清晰&#xff0c;要先弄明白再过来接着学习哦&#xff01; 那进入正题&#xff0c;在讲解顺序表之前&#xff0c;我们先来介绍…...

进阶JAVA篇- ZoneId 类与 ZoneDateTime 类、Instant类的常用API(七)

目录 API 1.0 ZoneId 类的说明 1.1 如何创建 ZoneId 类的对象呢&#xff1f; 1.2 ZoneId 类中的 getAvailableZoneIds() 静态方法 2.0 ZoneDateTime 类的说明 2.1 如何创建 ZoneDateTime 类的对象呢&#xff1f; 3.0 Instant 类的说明 3.1 如何创建 Instant 类的对象呢…...

bat脚本字符串替换:路径中\需要替换,解决一些文件写入路径不对的问题

脚本 set dir_tmp%~dp0 set dir%dir_tmp:\\\\\% set dir_tmp%~dp0 新建一个变量dir_tmp&#xff0c;存储获取的脚本当前路径 set dir%dir_tmp:\\\\\% 新建一个变量dir &#xff0c;存储字符串替换之后的路径 其中黄色的\\实际上代表的是一个\...

python一行命令搭建web服务,实现内网共享文件

python一行命令搭建web服务&#xff0c;实现内网共享文件 有时候我们在本地电脑访问自己的虚拟机的时候&#xff0c;可能因为某些原因无法直接CV文件到虚拟机。但此时我们又想上传文件到虚拟机&#xff0c;如果虚拟机和本地电脑可以互通。那么我们可以直接通过python来启动一个…...

RK3562开发板:升级摄像头ISP,突破视觉体验边界

RK3562开发板作为深圳触觉智能新推出的爆款产品&#xff0c;采用 Rockchip 新一代 64 位处理器 RK3562&#xff08;Quad-core ARM Cortex-A53&#xff0c;主频最高 2.0GHz&#xff09;&#xff0c;最大支持 8GB 内存&#xff1b;内置独立的 NPU&#xff0c;可用于轻量级人工智能…...

数据结构与算法-队列

队列 &#x1f388;1.队列的定义&#x1f388;2.队列的抽象数据类型定义&#x1f388;3.顺序队列&#xff08;循环队列&#xff09;&#x1f52d;3.1循环队列&#x1f52d;3.1循环队列类定义&#x1f52d;3.2创建空队列&#x1f52d;3.3入队操作&#x1f52d;3.4出队操作&#…...

腾讯云轻量2核4G5M可容纳多少人访问?

腾讯云2核4G5M服务器支持多少人在线访问&#xff1f;卡不卡&#xff1f;腾讯云轻量2核4G5M带宽服务器支持多少人在线访问&#xff1f;5M带宽下载速度峰值可达640KB/秒&#xff0c;阿腾云以搭建网站为例&#xff0c;假设优化后平均大小为60KB&#xff0c;则5M带宽可支撑10个用户…...

【分布式计算】九、容错性 Fault Tolerance

分布式系统应当有一定的容错性&#xff0c;发生故障时仍能运行 一些概念&#xff1a; 可用性Availability&#xff1a;系统是否准备好立即使用 可靠性Reliability&#xff1a;系统连续运行不发生故障 安全性&#xff1a;衡量安全故障的指标&#xff0c;没有严重事件发生 可维护…...

The SDK location is inside Studio install location 解决

The SDK location is inside Studio install location 解决 安装 Android Studio SDK 时提示&#xff1a;The SDK location is inside Studio install location 解决 问题&#xff1a; 由于 SDK 与 编辑器(Android Studio)的安装在同一目录下所以报错。 解决 你需要在 Andro…...

【蓝桥】数树数

一、题目 1、题目描述 给定一个层数为 n n n 的满二叉树&#xff0c;每个点编号规则如下&#xff1a; 具体来说&#xff0c;二叉树从上往下数第 p p p 层&#xff0c;从左往右编号分别为&#xff1a;1,2,3,4&#xff0c;…, 2p-1。 给你一条从根节点开始的路径&#xff0…...

2、Windows下安装

目录 一.安装 1、双击下载的程序&#xff1a; 2、加载完成后&#xff0c;会进入如下界面&#xff08;选第一个Developer Default&#xff09; 3、然后点击Next 点击Execute 然后Next 4.继续next注意端口为3306 5.继续next&#xff0c;输入账户密码&#xff08;要有大小写…...

vue中transition的使用

Vue中的<transition>组件用于在元素或组件添加/移除时应用过渡动画。它能够包裹需要进行过渡效果的元素或组件&#xff0c;通过设置相应的CSS样式来实现过渡动画效果。 <transition name"过渡效果名称" before-enter"beforeEnter" enter"…...

性能测试中如何使用RunnerGo还原混合并发场景

我们在进行软件开发时经常需要进行性能测试、压力测试和负载测试。其中有一类测试场景叫做混合并发测试&#xff0c;需要模拟多个接口下不同数量的用户使用场景&#xff0c;检查同时处理多个并发任务的能力&#xff0c;本文将展示如何使用开源的RunnerGo还原混合并发场景。 在…...

KanziStudio described using object-oriented design patterns(持续更新...)

1.绑定-mvc mvc&#xff0c;model数据与view控件分离。...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

LangFlow技术架构分析

&#x1f527; LangFlow 的可视化技术栈 前端节点编辑器 底层框架&#xff1a;基于 &#xff08;一个现代化的 React 节点绘图库&#xff09; 功能&#xff1a; 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...