(8)Linux Makefile | 依赖关系,依赖方法

news2024/12/23 1:38:49

💭前言:

本篇文章会着重讲解Linux中的自动化构建代码工具: make/makefile的介绍与使用。

在Linux下编译代码时,每次都会输入

gcc code.c -o code.exe

 在删除可执行程序时,每次都会输入

rm -rf code.exe

这样非常的不方便,很麻烦,于是乎学习自动化构建代码是很重要的,它可以提高我们之后在Linux下编程的效率!

初识 Makefile 

首先,make是一条指令,而makefile是一个文件,makefile是需要自己创建的一个文件,并且makefile是一个具有特定格式的文本文件。

 在当前目录创建Makefile文件

现在有了 makefile 文件,下一步就是编写这个文件!

即在这个文件中添加对应的 "依赖关系" 和 "依赖方法"。

依赖关系与依赖方法

makefile:是在当前路径下的一个普通文件,它会包含两个东西

  • 依赖关系(Dependency Relationship)
  • 依赖方法(Dependent Method)

我们首先弄清楚一个概念,依赖是什么意思?什么是依赖?

假如你是个在校大学生,快要到月底了,这时候你可能就要打电话给你爸要生活费了。你打电话给你爸爸,说 "爸,我是你儿子。",这就是表明依赖关系。你打电话告诉你爸你是他儿子的时候,实际上你的潜台词就是 "我要依赖你"。你给你爸打电话说:"爸我是你儿子",说完就把电话一挂,对于你爸来说会一脸懵逼 —— "这孩子今天怎么了,这是被绑架了?",你爸就不太清楚了。也就是说,你在打电话时只是表明了依赖关系,但你并没有达到你想要做的目的(要下个月的生活费),所以正确的方法应该是:"爸,我是你儿子,我要下个月的生活费。",你表达了你是谁,并且要求给你打钱。

我是你儿子 —— 表明了 "依赖关系",因为依赖关系的存在,所以才能给你打钱。

打钱 —— 就是 "依赖方法",当你把依赖关系和依赖方法表明时,你就能达到要钱的目的。

依赖关系不对,依赖方法再对也没有用,比如你的舍友给你爸打电话,说:"我是你儿子的舍友,给我打钱!",你爸绝对不会打钱的。

依赖方法表明了,依赖方法不正确同样没有用,比如你打电话给你爸:说:"我是你儿子,给我打钱我要充游戏!",你爸也不会给你打钱的!

通过上面的比喻,相信你已经知道什么是依赖关系和依赖方法了,他们必须都为真。

依赖关系和依赖方法都要为真,才能达成要钱的目的!

(\textrm{DR} \, \, \wedge \textrm{ DM}) \rightarrow \textrm{makefile}

makefile 里面表明的就是依赖关系和依赖方法。

写一个最简单的 Makefile

演示:写一个最基本的 Makefile

第一行的意思是mytest依赖于test.c。依赖关系写好后要写依赖方法(必须以Tab键开头)

gcc编译test.c形成一个mytest的可执行程序

mytest:test.c
    gcc test.c -o mytest

至此,我们就把一个最基本的 Makefile 写完了。

我们来 cat 看一下我们写的 Makefile,第一行是依赖关系,紧接着第二行是依赖方法。

注意:依赖关系后面紧跟依赖方法时前面要空一个 tab,再写依赖方法。

此时我们就有了一个最基本的 Makefile 了,我们编译 mytest.c 文件就可以不用再敲 gcc 命令了!

直接在命令行中输入:

$ make

 

 输入 make,这里就自动形成了可执行程序,会帮我们从 Makefile 去找依赖关系和依赖方

我们看看发生了什么:

"这不还是要输 gcc 命令吗?这和我在命令行有什么区别?" 

当前让你产生这种感觉,主要是因为:

① 上面我们写的 makefile 是最简单的 makefile 了,自然和命令行没什么差别。

② 我们目前的项目结构简单,如果后面遇到大的项目结构你就知道 Makefile 有多香了。

最最最重要的是 ——

以后我们在 Linux 下编译代码就不需要敲 gcc 命令了,直接 make 就可以了。

它会给我们带来很多便捷,如果是第一次接触,现在可能还体会不到,后面慢慢就能体会到了。

 项目的清理

刚才我们说的 make 就相当于 VS 下的 "生成解决方案" :

但是 VS 下好像还有 "清理解决方案" 这样的功能,那我在 Linux 下也想拥有,怎么办?

💭 举个例子: 

我们现在不想要这个可执行程序了,放在之前我们会直接 rm 掉这个文件。

但是假设有这样的一个场景:一个程序生产了大量的临时文件,你岂不是要疯狂的 rm?

无脑删又很容易把源代码删掉,这个时候我们就可以在 Makefile 里实现 "清理解决方案" 的功能!

.PHONY:clean
clean:

我们再次打开:vim Makefile

 clean  没有依赖文件,也是存在依赖关系的,只不过这个  clean  没有依赖列表。

它后面的相当于是个孤儿,而  clean  被 ​.PHONY

 修饰成伪目标(这个我们下面会说)。

后面的  rm -f mytest  为依赖方法,我们现在来用一下看看效果如何!

刚才我们编译用的是 make,清理我们用 make clean:

输入效果如下:

 

可执行程序没了-----清理成功

注意事项:再次强调,依赖方法前面必以 tab 键开头

 多文件的 makefile

我们来演示一下多文件的 makefile。

我们先创建 3 个文件,分别是 main.c,test.c 和 test.h :

vim 分别打开这三个文件,我们写一点东西进去:

 此时如果我们 gcc,我们可以:

gcc -o hello main.c test.c

我们把 test.c 跟在 main.c 后面,这里不放 test.h 的原因是因为头文件在预处理阶段就已经展开到源文件中了。

现在我们开始写 makefile:

我们想生成的 hello 文件需要依赖于 main.o 和 test.o

但我们没有 .o,所以我们还需要进一步解释一下 main.o 和 test.o 是依赖谁的。

值得一提的是,下面两种写法都是可以的:

# 写全是这样的
gcc -c main.c -o main.o   
# 实际上,如果你不写后面的,makefile也会自动给你形成同名.o
gcc -c main.c   

制作好 makefile 之后,我们 make 一下看看效果如何:

效果很好,我们再把清理功能写一下:

 

这里我们需要删除 *.o 文件,星号代表的是通配符,意思为 " . " 左边所有的内容我不关心,

只要它以 .o 结尾的,就删掉。此外,* 和 .o 之间没有空格!

看看效果如何:

make 就相当于 VS 中的构建项目,而 make clean 就相当于是清理项目。

除此之外,在makefile中还可以定义变量

这样写你还认识之前的代码吗?在要替换的内容前加上$和()即可,像C语言定义变量一样编辑代码

依然正常:

对比一下:

并且,可以用$^代表依赖关系的左边,可以用$@代表依赖关系的右边

这里的$^就代表test.c

如果你不想一条指令被打印在显示器
可以在指令前加上@符号

PHONY 伪目标

PHONY 定义伪目标 

.PHONY是将clean指令修饰成了伪目标

不知道你有没有观察到,我们的 makefile 有两个目标文件:

我们在 make 的时候,默认只帮我们生成 makefile 中的 test.c 目标文件。

而 make clean 是制作指定名称的目标文件,做清理的工作,我们首先来思考一个问题:

❓ 思考:为什么 make 的时候它总是执行第一个呢?

makefile 在自顶而下进行形成目标文件时,它可以根据你的需求形成多个目标文件。

我们这里有两个目标文件,一个是 test 一个是 clean,凭什么我 make 执行的是 test 而不是 clean?答案很简单,就凭我 test 是在前面写的!

 如果我们把它们两的顺序换一下:

然后我们再来进行 make 看看:

此时make就是clean的操作了,如果要生成test.c,自然要make test了,和钢材的make clean一样

所以 makefile 在形成文件时会自顶而下扫描,默认只会形式第一个目标文件,执行该依赖关系的依赖方法。 

但是我们一般还是喜欢把形成可执行程序放在前面,也就是让 makefile 默认去形成

那这个  .PHONY到底是干什么的呢?现在我们正式介绍一下这个东西。

​.PHONY 是 makefile 语法格式的一个关键字,表明 "总是被执行的" 。

  • 比如 clean 被 .PHONY
  •  修饰时,表明 clean 是总是被执行的。

这个 "总是被执行" 这句话真的非常的莫名其妙,我们先通过代码来看看什么是 "总是被执行" !

总是不被执行 

现象演示:总是不被执行

我们多次 make 之后它仍然是会提示 “make: `mytest` is up to date.”  这段话。

貌似只有第一次 make 的时候才会才会帮我们形成一个全新的 mytest ,再之后多次进行 make,

就会告知你 mytest 已经是一个可执行程序了,不能再生成了。
这种现象就叫做 "总是不被执行的" ,你已经是最新的可执行程序了,干嘛要再去形成呢。

总是被执行 

我们用.PHONY修饰test.c,现在test也变成了总是被执行了,

现象演示:总是被执行

被 ​ .PHONY 标记后,我们每次 make 都会执行 gcc mytest.c -o mytest

总是被执行:无论目标时间是否新旧,照样执行依赖关系。

而我们一般不太建议、喜欢把我们形成的目标文件定义成伪目标,而是喜欢把清理定义成伪目标。

这也正是为什么我们每次 make clean 都能帮我们执行清理的根本原因。

思考:那 makefile 是如何识别我的 exe/bin 文件是新的还是旧的呢?

ACM 时间包含 Access 时间、Modify 时间 与 Change 时间。

这个 Modify 和 Change 有什么区别呢?

我们知道,"文件 = 内容 + 属性"

如果是内容发生改变,就是 Modify;如果是属性发生改变,就是 Change。

修改内容也有可能引发 Change 的改变,因为修改内容可能会引起 change time 的变化

我们打开文件修改,Access 应不应该改变呢?我们读取 Access 变不变?

要变的!但是现在不会变!因为访问文件的频率是最高的,Modify 和 Change 是不得不变的,不变的化文件就不对了。但是我们大多数情况修改文件属性和修改文件内容是很低频的事情,但打开文件是非常高平的事情,Linux 后期内核对 Access 进行了优化,将文件打开访问,打开时间不会变化,累计一段时间后他才会变化。如果不这样,打开文件这种高频率的事情,一旦更新 Access 时间,就要将数据刷新到磁盘上,这实际上一个很没效率的事情。

具体 Access 的调整策略取决于 Linux 的版本。

💡 答案:通过对比你的源文件和可执行程序的更改时间 (modify time) 识别的新旧。 根据原文件和可执行程序的最近修改时间,评估要不要重新生成。

现在我们再回头看刚才的问题:什么是 "总是被执行呢" ?

"总是被执行" 就是 忽略对比时间 (modify time),不看新旧,我让你执行你就给我执行。


谢谢~~

 

 

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

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

相关文章

Netty Review - ByteBuf 读写索引 详解

文章目录 概念Pre概述ByteBuf简介ByteBuf的主要特性结构APIByteBuf的创建读写操作示例引用计数操作其他常用操作 Code 演示 概念 Pre Netty Review - 探索ByteBuf的内部机制 概述 Netty的ByteBuf是一个强大的字节容器,用于处理字节数据。它提供了比Java标准库中的…

for命令语句

命令说明: 在批处理中,for是最为强大的命令语句,它的出现,使得解析文本内容、遍历文件路径、数值递增和递减等操作更加简单,配合if、call、goto等流程控制语句,更是可以实现脚本复杂的自动化、智能化操作。…

js基础入门

先来一点js基础&#xff0c;其实js大部分的时候都在处理对象或者数组。 对象四个基本操作&#xff1a;增删改查 掌握元素的增删改查&#xff0c;了解如何拷贝&#xff0c;深拷贝和浅拷贝的区别。详情见代码 <script>//创建对象一共有三种赋值声明的语法let obj{} //赋值…

Relocations for this machine are not implemented,IDA版本过低导致生成汇编代码失败

目录 1、问题描述 2、安卓app发生崩溃&#xff0c;需要查看汇编代码上下文去辅助分析 3、使用IDA打开.so动态库文件&#xff0c;提示Relocations for this machine are not implemented 4、IDA版本较老&#xff0c;不支持ARM64的指令集&#xff0c;使用7.0版本就可以了 5、…

【数据结构】二叉树的模拟实现

前言:前面我们学习了堆的模拟实现&#xff0c;今天我们来进一步学习二叉树&#xff0c;当然了内容肯定是越来越难的&#xff0c;各位我们一起努力&#xff01; &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:数据结构 &#x1f448; &…

创建个人网站(二)前端主页设计和编写一(太阳移动)

前言 以下内容纯纯当乐子来看就行&#xff0c;知识分享一下这样设计的原因&#xff0c;想看正文直接见下一节 为什么创建个人网站一之后几天没有动静了呢&#xff0c;一个是家里有事实在比较忙&#xff0c;第二个原因是没想到主页要设计成什么样&#xff0c;知道前两天问我姐什…

0基础学java-day22(多用户即时通信系统)

一、QQ 聊天项目演示 聊天通讯系统 在运运行过程出现的异常&#xff0c;应该是类的序列化不一致导致的 1 项目 QQ 演示 2 为什么选择这个项目 只做核心部分&#xff0c;界面相对弱化 3 项目开发流程 3.1 需求分析 3.2 界面设计 3.2.1 用户登录 3.2.2 拉取在线用户列表 …

对偶问题笔记(1)

目录 1 从 Lagrange 函数引入对偶问题2. 强对偶性与 KKT 条件3. 对偶性的鞍点特征 1 从 Lagrange 函数引入对偶问题 考虑如下优化问题 { min ⁡ f 0 ( x ) s . t f i ( x ) ≤ 0 , i 1 , ⋯ , p , h j ( x ) 0 , j 1 , ⋯ , q , x ∈ Ω , \begin{align} \begin{cases}\min…

Mimikatz 的使用(黄金票据的制作)

#江南的江 #每日鸡汤&#xff1a;孤独没有什么反义词&#xff0c;但他的近义词是自由&#xff0c;人生成功的道路上充满了孤独&#xff0c;那么也同样告诉你&#xff0c;你离成功后的自由不远了。 #初心和目标&#xff1a;在网络安全里高出名堂。。。 Mimikatz 本文分为两种…

kafka启动报错“输入行太长。 命令语法不正确“

下午想试一下本地安装启动一下 kafak&#xff0c;参考网上的安装文档&#xff0c;结果一直报错&#xff0c;最开始报的是这个错误&#xff1a; Classpath is empty. Please build the project first e.g. by running gradlew jarAll参考了很多网上的解决办法&#xff0c;最后…

科创金融的向善力量:浙商银行多措并举赋能科创企业,打造科技金融服务生态圈

近日&#xff0c;浙商银行科技金融服务发布会在杭州举行。 发布会以“智汇科创&#xff0c;善行未来”为主题&#xff0c;围绕科技金融服务“向善”新生态&#xff0c;浙商银行重磅推出科创企业全图景服务方案&#xff0c;正式发布科创积分贷&#xff0c;与浙江大学联合发布人…

【开源软件】最好的开源软件-2023-第五名 JHipster

自我介绍 做一个简单介绍&#xff0c;酒架年近48 &#xff0c;有20多年IT工作经历&#xff0c;目前在一家500强做企业架构&#xff0e;因为工作需要&#xff0c;另外也因为兴趣涉猎比较广&#xff0c;为了自己学习建立了三个博客&#xff0c;分别是【全球IT瞭望】&#xff0c;【…

翻译: LLMs大语言模型影响到高工资的的白领知识工作者 加速各行各业的自动化潜力 Automation potential across sectors

我们已经探讨了生成人工智能可能对您的工作有用&#xff0c;也讨论了分析其对企业的影响。现在&#xff0c;让我们拉远镜头&#xff0c;看看它对不同公司的工作角色以及对不同行业部门的影响。这个视频的结果对特定企业可能不那么直接可行&#xff0c;但也许这会帮助您思考并尝…

IDEA tomcat内存不足

-Xms256m -Xmx256m -XX:MaxNewSize256m -XX:MaxPermSize256m

LLMs推理框架总结

总结一下这些框架的特点&#xff0c;如下表所示&#xff1a; LLM推理有很多框架&#xff0c;各有其特点&#xff0c;下面分别介绍一下表中七个框架的关键点&#xff1a; vLLM&#xff1a;适用于大批量Prompt输入&#xff0c;并对推理速度要求高的场景&#xff1b;Text generat…

14、Kafka 请求是怎么被处理的

Kafka 请求是怎么被处理的 1、处理请求的 2 种常见方案1.1、顺序处理请求1.2、每个请求使用单独线程处理 2、Kafka 是如何处理请求的&#xff1f;3、控制类请求和数据类请求分离 无论是 Kafka 客户端还是 Broker 端&#xff0c;它们之间的交互都是通过 “请求 / 响应” 的方式完…

二叉搜索树第大K节点,剑指offer,力扣

目录 题目地址&#xff1a; 题目&#xff1a; 我们直接看题解吧&#xff1a; 解题方法&#xff1a; 难度分析&#xff1a; 审题目事例提示&#xff1a; 解题分析&#xff1a; 解题思路&#xff1a; 代码实现&#xff1a; 代码补充&#xff1a; 代码实现&#xff08;非递归&…

20倍压缩比!微软提出大模型提示压缩框架LLMLingua

近期&#xff0c;越来越多研究在探索大型语言模型&#xff08;LLM&#xff09;在实际应用中的推理和生成能力。随着 ChatGPT 等模型的广泛研究与应用&#xff0c;如何在保留关键信息的同时&#xff0c;压缩较长的提示成为当前大模型研究的问题之一。 为了加速模型推理并降低成本…

ViewBinding与DataBinding(视图绑定与数据双向绑定)

前言&#xff1a;心中纵是有所盼 严寒没有减 风很冷 我的手已渐蓝 前言 控件查找对于Android开发来说也是一部血泪史&#xff0c;一直为更有效的方案进行了多种方案的研究和探讨。findViewById() 过于繁琐&#xff0c;强制转换不安全&#xff1b;butterkniife 会存在众多臃肿的…

【【UART 传输数据实验】】

UART 传输数据实验 通信方式在日常的应用中一般分为串行通信&#xff08;serial communication&#xff09;和并行通信&#xff08;parallel communication&#xff09;。 我们再来了解下串行通信的特点。串行通信是指数据在一条数据线上&#xff0c;一比特接一比特地按顺序传…