一文入门Makefile

今天我们来玩玩Makefile。

这边是借鉴的陈皓老师的《跟我一起写 Makefile》

pdf下载链接如下。

链接:https://pan.baidu.com/s/1woRq2nEkgzLv1o5uE0FZHg?pwd=mhrh 
提取码:mhrh

我们之前已经算是入门了gcc,那我们的下一站就是Makefile,上一篇我们也发现了,当我们的main.c包含了自己写的头文件,那么编译命令会变得很长,如果包含的头文件很多,那么光是敲编译命令都够花我们半条命了。

所以也有下面这个说法。

会不会写 makefile ,从一个侧面说明了一个人是否具备完成大型工程的能力。

那么Makefile到底是做什么的呢?简单来说,Makefile通过定义一系列编译规则,指导make工具如何根据源文件的修改情况来执行增量编译,从而极大地提高了开发效率,Makefile写出来也就是一个脚本文件。

使用Makefile不仅使得编译过程自动化,还带来了诸多好处:

  • 自动化处理复杂的依赖关系:Makefile能够自动处理和解析项目中各文件之间的复杂依赖关系,确保只有必要的部分被重新编译。
  • 支持跨平台构建:通过编写与平台无关的Makefile,可以在不同操作系统间实现一致的构建过程。
  • 提高开发效率:开发者只需关注源代码的编写,编译过程的大部分操作都由Makefile自动完成,减少了手动操作的错误和时间消耗。

那么废话不多说,我们直接开始先写一个Makefile吧。

先别管这里的内容是什么意思,这内容我们写到Makefile里,Makefile就是这个脚本文件的名字,没有后缀,当然了也可以叫makefile和GNUmakefile(最好不要叫这个,因为只有GNU make才能识别)。

我们写好之后要执行Makefile,就直接执行一个make命令。

然后就可以看到执行了一堆命令,这些命令是我们写在Makefile里面的。

并且生成了下面一堆中间文件。

那其实大部分情况我们是不需要中间文件的,那么我们是不是也可以把删除中间文件的命令写进Makefile里呢?那当然是可以了,因为Makefile本质上就是脚本文件,自然是可以写的。

然后我们执行

make clean

可以看到执行了我们写在Makefile里面的最后的那个语句。

接下来我们开始揭秘Makefile。

我们先看第一行test:test.o,这实际上是一个规则。这段的含义是我们需要生成test(也就是目标文件),为了生成test首先需要拥有test.o(也就是依赖文件),通过执行下面首行缩进一个tab的那个命令来生成。

如果当前目录下没有依赖文件,那么就会在Makefile里找有没有目标文件是依赖文件的规则。

那么前四个规则大家应该就能看懂了。

但是第五个clean它不是简单的规则,它是一个特殊的目标,一般用来删除编译过程中产生的中间文件,并且我们看到它是没有依赖的。

执行的时候就是输入命令 make clean。

因为clean涉及到删除,而在Linux中删除就是真删除了,不像Window里还能从回收站里找到,因此编写clean的时候我们需要格外小心,但是保不齐我们会失误,那怎么办呢?

我们可以在make clean后面加个-n选项来模拟删除,然后再次检查是否出错,此时还不是真的删除,因此还有改正的机会。

如上可以看得出来当我们执行make clean命令加上-n选项之后,它会展示出执行的删除命令,但是并没有真正执行,这时我们就可以对make clean 进行检查了。

除了直接在Makefile里写clean,更稳健的写法是下面这样的。

 其中.PHONY表示后面的clean是一个伪目标,并不是正常的目标。并且在 rm 前面加上了一个 - ,这表示当我们删除某些不存在的文件的时候忽略报错,接着往后执行。

当然还有个潜规则就是clean放在Makefile的最后面。

接着再回到我们的第一版最简单的Makefile,它是由多个规则构成的,每个规则里有目标文件,依赖文件和执行命令。在Makefile里,它默认会把第一个规则中的目标文件当成是最终目标,也就是说它不一点会执行每个规则,而是只要能够生成最终目标就行。

要指定最终目标也是可以的,在Makefile开头加上ALL:最终目标即可。像下面这样,实际上不一定非得叫ALL,原理就是Makefile会以第一个规则为最终目标,那么我放在第一行的那就是最终目标。

上面就是Makefile最基础最基础的内容了。

那接下来我们就可以更进一步了。

既然Makefile是脚本文件,那么它有变量也是正常的对叭。

一般写在文件开头,格式就是  变量名 = 变量值 ,当我们使用时是这样的 $( 变量名 ),这边需要提的是Makefile中的变量比较接近于宏定义,也就是直接替换的,没有类型。

光讲可能比较抽象,我们直接看下面的例子。

上面例子把目标文件直接赋值给了变量targetFile,我们在规则中可以使用$(targetFile)的方式取出test的这个值去使用,当然了上面只是简单地做个示范,我们还可以拿变量去装一些更复杂的东西,比如说一堆的文件(没错,一个变量能装的可不止一个文件,用空格隔开可以装多个)

那我们要给变量赋值赋上一堆文件,除了一个个手敲上去,还有别的更省力的方式那就是通配符。

比如说我们需要给一个变量赋值当前目录下所有的 .c 文件,那么我们用通配符就可以非常方便的赋值。

大家想的是下面这样的对叭。

cfile = *.c

但是实际上这样是不行的,这样在Makefile中,cfile这个变量的值就是 *.c ,而不是我们想要的所有 .c 文件,这时候就需要用上函数了,既然Makefile是脚本文件,那么有个函数也是很正常的对叭。

正确的写法是下面这样的。

cfile = $(wildcard *.c)

这个函数就是 $(wildcard  ),在括号里,wildcard后写的通配符就会被展开,就会是我们想要的效果了。

除了上面我们自己去写变量,Makefile里有一些自动化变量我们可以直接去使用的,我们挑几个常用的来说。

$@ : 本条规则中的目标

$< : 本条规则中第一个依赖,如果第一个依赖代表多个文件(后面会说怎么实现),那么$<就表示为将这多个文件一个个取出来。

$^ :本条规则中的所有依赖,用空格分隔。

$* : 可以简单理解成目标文件的名字但是不含后缀名。

$? :比目标更新的依赖,也就是最后修改时间比目标更晚的依赖。

用了上面的自动化变量,那么我们第一版的Makefile可以写成下面这样了。

现在我们改一改我们的test.c,像下面这样。包含了自己写的头文件,用了里面的方法。

对应的在Makefile里也需要修改。我们添加了对于mytool1的编译。

是可以正常make的。

然后我们发现,后面两个规则中的命令是一样的,那么实际上我们是可以对他们进行一个合并操作的,也就是说在一个规则里,可以有多个目标。可以像下面这样改写,但是由于gcc -o选项只能输出一个文件,因此在命令里不能使用 $@,但是还好-c选项可以不指定输出文件,默认就是输入文件的后缀改成 .o当输出文件了。

也是可以正常make的。

这个例子主要是想说在Makefile中,在一个规则里可以有多个目标。然后同一个目标也可以有多个规则(这边不演示了)。

然后实际上我们还有种更简单的写法,那就是模式规则。

这边直接贴出怎么写的。

看不懂什么意思没关系,我们make一下,make之后会显示出它执行的命令,然后我们再分析分析。

看的出来Makefile直接帮我们把我们需要的依赖都执行了。

这是因为上面的%可以看成是任意的东西(类似于通配符中的*),当我们的目标的依赖不存在的时候,Makefile就会在规则中寻找是否目标的依赖和哪个规则的目标一致,找到就会执行这个规则中的命令。就比如说我们上面的Makefile,需要寻找目标为test.o以及目标为mytool1.o的依赖,最终都找到了 %.o:%.c 这个规则,因为%代表任意东西,那么自然是可以匹配上的,这就是模式规则强大的地方,我们可以少写很多东西了。

不过上面这种写法有一个可以改进的点,那就是将$^改成$<,我们来看看二者的区别。

我们上面的例子简单,所以没什么差别,但是当我们的依赖变多之后,依赖嵌套依赖之后,我们就得用$<了。

使用模式规则也有个弊端,那就是模式规则会匹配所有符合条件的,因为%可以匹配任意东西,因此只要后缀符合,都会被我们的模式规则匹配到,如果我只有一部分的文件需要用模式规则中的命令怎么办呢?

这就要用到我们的静态模式规则了。

在模式规则的基础上,在前面加上需要匹配到的目标即可。

可能有小伙伴会说,这样不就又绕回去了嘛,还是要把目标的名字都写出来。那其实我们可以再静态模式规则的后面再写个模式规则,而只在静态模式规则中写上需要特殊处理的目标即可,剩下的可以都丢给后面的模式规则去兜底。

一般情况下我们不会将工具文件和我们的主文件放在同一级目录下,因此我新建个文件夹my_tools,然后将工具文件放进去,接着我们就毫不意外地发现Makefile找不到库文件了。

我们可以在Makefile中指定头文件目录,指定的方式也很简单,就像下面这样。

VPATH = 路径1:路径2……

可以指定多个路径,用冒号:隔开即可。

指定完之后仍然报错,但这就是链接阶段报的错误了。

我们需要在规则的命令中添加头文件路径。

最终是下面这样的。

可以正常运行,在Makefile执行规则命令的时候也帮我们把头文件路径加上去了。

VPATH是一个特殊变量,指明了这个特殊变量,当Makefile找不到依赖文件,也没有目标是依赖的规则,那么Makefile就会到VPATH指明的路径去寻找。

除了VPATH还有vpath,也就是小写的,但是vpath不是变量,而是关键字,使用可以参考下面这样。

看的出来vpath一次只能添加一条路径,但是和VPATH相比的话,vpath可以更细致地指定路径,可以给不同后缀的文件指定不同的路径。

至此我们就算是入门Makefile成功了,相信各位小伙伴已经能够给自己以前写的小项目编写(相对)高效的Makefile了。

如果想进一步了解Makefile的话,最好的方法是去看官方文档,当然了,也可以看看陈皓老师写的《跟我一起写 Makefile》,下载链接在本文的开头。

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

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

相关文章

嵌入式学习(Day 51:ARM指令/汇编与c语言函数相互调用)

1.Supervisor模式与SVC模式 Supervisor模式是ARM处理器的一个特权工作模式&#xff0c;允许执行特权指令和访问特权资源。SVC模式&#xff08;Supervisor Call&#xff09;是与Supervisor模式相关的一个功能或指令&#xff0c;用于从用户模式切换到Supervisor模式&#xff0c;…

大模型应用研发基础环境配置(Miniconda、Python、Jupyter Lab、Ollama等)

老牛同学之前使用的MacBook Pro电脑配置有点旧&#xff08;2015 年生产&#xff09;&#xff0c;跑大模型感觉有点吃力&#xff0c;操作起来有点卡顿&#xff0c;因此不得已捡起了尘封了快两年的MateBook Pro电脑&#xff08;老牛同学其实不太喜欢用 Windows 电脑做研发工作&am…

从零开始做题:老照片中的密码

老照片中的密码 1.题目 1.1 给出图片如下 1.2 给出如下提示 这张老照片中的人使用的是莫尔斯电报机&#xff0c;莫尔斯电报机分为莫尔斯人工电报机和莫尔斯自动电报机&#xff08;简称莫尔斯快机&#xff09;。莫尔斯人工电报机是一种最简单的电报机&#xff0c;由三个部分组…

SelfReg-UNet:解决UNet语义损失,增强特征一致性与减少冗余的优化模型

SelfReg-UNet&#xff1a;解决UNet语义损失&#xff0c;增强特征一致性与减少冗余的优化模型 提出背景拆解类比&#xff1a;整理书架语义一致性正则化内部特征蒸馏为什么 UNet 会有语义损失&#xff1f; 提出背景 论文&#xff1a;https://arxiv.org/pdf/2406.14896 代码&…

c++内存管理_复习

new与placement new new&#xff1a; 先调用operator new(大小)&#xff0c;而operator new()会调用malloc尝试分配内存&#xff0c;失败则调用_callnewh()来释放内存&#xff0c;直至分配成功 可以设置分配失败的处理函数&#xff1a;将写好的处理函数作为参数传入set_new_han…

Vue3 使用 Vue Router 时,params 传参失效

前言&#xff1a; 在写项目的时候&#xff0c;使用了 vue-router 的 params 进行传参&#xff0c;但是在详情页面中一直获取不到参数。原因&#xff1a;Vue Router 在2022-8-22的那次更新后&#xff0c;使用这种方式在新页面上无法获取&#xff01; 正文&#xff1a; 在列表页进…

虚拟机装入kali linux

VMware 首先需要先安装VMware Workstation Pro可以根据这篇文章来下载VMware 下载kali linux Installer Images VS Virtual Machines Installer Images&#xff08;安装镜像&#xff09;Virtual Machines&#xff08;虚拟机&#xff09; 直接访问硬件&#xff0c;定制内核…

Matlab|【防骗帖】考虑时空相关性的风电功率预测误差建模与分析

目录 1 主要内容 2 部分程序 3 下载链接 1 主要内容 这个程序《考虑时空相关性的风电功率预测误差建模与分析》画的图片非常漂亮&#xff0c;和原文献基本一致&#xff0c;但是实际上内容并未实现出来&#xff0c;主要就是利用现有的风电预测的数据和结果做了相关的图&#…

【数据结构】(C语言):链表

链表&#xff1a; 基本单位是节点。节点至少两部分&#xff1a;数据&#xff0c;下一个数据的地址。头指针head&#xff0c;始终指向链表的第一个节点。若没有节点&#xff0c;则headNULL。链表在内存中是非连续的。不能使用索引&#xff08;下标&#xff09;查找元素。只能从…

解决:Xshell通过SSH协议连接Ubuntu服务器报“服务器发送了一个意外的数据包,received:3,expected:20”

下图所示&#xff1a; 日志也基本看不出来问题在哪&#xff0c;只是说断开了连接大概是验证失败。有幸在某论坛评论区找到了原因&#xff0c;是因为我的xshell版本太低了而服务器的ssh版本太高&#xff0c;高版本的ssh默认屏蔽了一部分不太安全的算法导致建立连接的时候验证失败…

C++ 14新特性个人总结

variable templates 变量模板。这个特性允许模板被用于定义变量&#xff0c;就像之前模板可以用于定义函数或类型一样。变量模板为模板编程带来了新的灵活性&#xff0c;特别是在定义泛化的常量和元编程时非常有用。 变量模板的基本语法 变量模板的声明遵循以下基本语法&am…

解决Vue+Vite打包后Leaflet的marker图标不显示的问题

前言 用Leaflet写关于WebGIS的开发&#xff0c;用Vite或者webpack打包&#xff0c;打包后会找不到图标&#xff0c;如下所示。 直言的说&#xff0c;笔者去网上搜了搜&#xff0c;其实收到一个比较好是答案。网址如下。 &#xff08;完美解决~&#xff09;关于VueLeaflet添加…

eslint 与 prettier 的一些常见的配置项(很详细)

目录 1、eslint 常见配置项&#xff08;语法规范&#xff09; 2、 prettier 常见的配置项&#xff08;格式规范&#xff09; 代码规范相关内容看小编的该文章&#xff0c;获取对你有更好的帮助 vsCode代码格式化&#xff08;理解eslint、vetur、prettier&#xff0c;实现格式…

IDEA启动报错:Abnormal build process termination...

一、问题描述 因为项目需要&#xff0c;同时打开了两个idea&#xff0c;突然发现一个启动的时候报错&#xff0c;有点莫名其妙&#xff0c;刚还好好的&#xff0c;为啥就不能用了&#xff0c;一顿百度找方法&#xff0c;试了各种方法&#xff0c;像重新安装jdk、重启系统发现都…

TensorFlow开源项目

欢迎来到 Papicatch的博客 文章目录 &#x1f349;TensorFlow介绍 &#x1f349;主要特点和功能 &#x1f348;多语言支持 &#x1f348;灵活的架构 &#x1f348;分布式训练 &#x1f348;跨平台部署 &#x1f348;强大的工具链 &#x1f348;丰富的社区和生态系统 &a…

Vue3基础使用

目录 一、创建Vue3工程 (一)、cli (二)、vite 二、常用Composition API (一)、setup函数 (二)、ref函数 (三)、reactive函数 (四)、setup注意事项 (五)、计算属性 (六)、watch (七)、watchEffect函数 (八)、生命周期 1、以配置项的形式使用生命周期钩子 2、组合式…

【机器学习-10】 | Scikit-Learn工具包进阶指南:Scikit-Learn工具包之支持向量机模块研究

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

高考填报志愿攻略,5个步骤选专业和院校

在高考完毕出成绩的时候&#xff0c;很多人会陷入迷茫中&#xff0c;好像努力了这么多年&#xff0c;却不知道怎么规划好未来。怎么填报志愿合适&#xff1f;在填报志愿方面有几个内容需要弄清楚&#xff0c;按部就班就能找到方向&#xff0c;一起来了解一下正确的步骤吧。 第…

入局AI手机 苹果公布Apple Intelligence

日前&#xff0c;苹果WWDC 2024如期召开。在这持续1个小时44分钟的开发者大会上&#xff0c;苹果在前一个小时里更新了iOS、iPadOS、MacOS等操作系统&#xff0c;而且还首次更新了visionOS。余下的时间全部留给了苹果的“AI大礼包”——Apple Intelligence&#xff08;苹果智能…

mysql是什么

mysql是什么 是DBMS软件系统&#xff0c;并不是一个数据库&#xff0c;管理数据库 DBMS相当于用户和数据库之间的桥梁&#xff0c;有超过300种不同的dbms系统 mysql是关系型数据库&#xff0c;关系型数据库存储模型很想excel&#xff0c;用行和列组织数据 sql是一门编程语言…