自动化构建工具:makemakefile
在Windows中,我们写C代码或者C++代码都需要用先找到一款合适的编译器,用来方便我们更好的完成代码,比如说vs2019,这些工具的特点是集成了多种开发所需的功能,如代码编辑、编译、调试、版本控制等,无需在不同的工具之间切换。自动化和简化了许多常见的开发任务,减少了繁琐的操作和配置。像 Visual Studio 可以自动完成代码补全、语法检查,快速定位错误,节省了开发者的时间。
而在Linux中,我们也有一个工具不用再单纯的用gcc指令来运行代码,具体情况可以看上一篇博客。而这个工具就是make,虽然不像其他编译器那样快捷,美观。但是对于Linux系统开发来说,极大的提高了开发效率。
make和makefile概念
会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。现在我们就来学习这个工具。
make概念
在 Linux 中,make 是一个工具,用于自动化编译和构建软件项目,执行该命令需要当前操作目录下有一个名为makefile或者Makefile的文件,在makefile内部编写指令,随后就可以通过make快速执行一系列的指令了。
make 的核心概念是依赖关系和规则。它通过读取一个名为 Makefile 的文件来确定项目中各个文件之间的依赖关系,以及如何根据这些依赖关系执行相应的命令来生成目标文件。
依赖关系指的是某个目标文件(比如可执行文件或库文件)的生成依赖于其他的源文件或中间文件。例如,如果一个可执行文件依赖于多个 .c 源文件和 .h 头文件,make 会检查这些依赖文件的修改时间,如果依赖文件有更新,就会重新执行相应的编译命令来生成新的目标文件。
使用方法
我先在makefile中编写一段指令,然后跟着指令来学习。
mycode:mycode.cgcc mycode.c -o mycode
clean:rm -f mycode

我先创建了一个mycode.c文件,里面有一段C语言代码,然后生成的目标文件是mycode。在makefile文件中,发现了2段属性的代码,分别是gcc mycode.c -o mycode,该指令可以把源文件编译为可执行文件;rm -f mycode是删除mycode文件。编写完成之后,我们使用make工具就可以完成源代码的编译工作了。

C语言代码执行的结果是hello Linux,如果我再添加一段代码为printf("hello world\n");,不用像之前一样使用gcc mycode.c -o mycode这个指令,可以直接make后,再用./mycode就可以编译代码了,相比之前每次改变代码之后都需要执行gcc这条指令,让人感到很麻烦,所以make这个工具提高了我们的工作效率。

当我们执行完代码之后,想要删除mycode文件,只用使用make clean指令即可。

make原理
学会如何使用之后,我们来学习makefile文件中4条指令的作用都是什么。
mycode:mycode.cgcc mycode.c -o mycode
mycode:mycode.c:通过:把2个文件连接起来,叫做依赖关系。即mycode这个目标依赖于mycode.c文件。gcc mycode.c -o mycode:这是依赖方法。它指定了使用gcc编译器将mycode.c编译成可执行文件mycode。依赖方法前必须使用Tab键隔开,不能使用4个空格。
下面来看后2条指令
clean:rm -f mycode
该代码中,目标文件是clean,没有依赖文件列表,依赖关系是删除mycode指令,只用执行依赖方法中的代码。clean相当于vs中清理解决方案的操作。
现在我们有一个问题,
为什么执行
mycode:mycode.c只需要make指令即可,而要删除mycode文件,则需要使用make clean指令呢?
根据上篇博客所学到的知识,我们把生成可执行目标文件分成4个过程。把这4个过程写进makefile文件当中。
mycode:mycode.ogcc mycode.o -o mycode
mycode.o:mycode.sgcc -c mycode.s -o mycode.o
mycode.s:mycode.igcc -S mycode.i -o mycode.s
mycode.i:mycode.cgcc -E mycode.c -o mycode.i
clean:rm -f mycode.i mycode.s mycode.o mycode
该文件是一个完整的C语言程序的编译链接过程,但是执行编译的过程中,应该依次生成.i,.s,.o三个文件,最后再生成可执行目标文件mycode。当进行第一条依赖关系的时候,就没有.o文件,第二个依赖关系缺少.s文件,依次类推,整个过程都是反过来的,那么还能成功执行makefile文件吗?

可以看出执行成功了。这是因为make会自动推导makefile中的依赖关系,就算把顺序颠倒了,也可以成功运行。

这个过程有点像递归过程,最开始只有mycode.c文件,只有找到了源文件,才能依次生成其它文件。
如果我们把clean指令放在最前面,再使用make指令会发生什么情况呢?

由图片可以看出,会先执行clean指令,原因是:当make后面不接任何目标时,make会从上往下找,找到第一个依赖关系并执行。不过建议还是把clean指令放在最后面。
接下来还有一个问题,
[!question]
如果源代码没有发生改动,为什么只能编译一次,多次编译后就无效了呢?这是如何做到的呢?
如图所示:

答案就是为了提高编译效率。代码没有发生改动的话,编译器只需要执行一次就可以了,因为多次编译之后结果还是一样的。试想一下,如果有一个工程文件,里面的代码有几百万行,编译一次的时间就需要几十分钟,如果其他人再来编译一次,又会浪费很长时间,所以只需要执行一次就行。
接着回答第2个小问:如何做到的
答:我们知道一定是源文件(.c)形成可执行文件(.exe)。先有源文件,才有可执行,一般而言,源文件的最近修改时间比可执行文件是要老的!如果我们更改了源文件,历史上曾经还有可执行文件,那么源文件的最近修改时间,一定要比可执行程序要新的。所以只需要比较,可执行程序的最近修改时间和源文件的最近修改时间:
.exe 新与 .c :源文件是老的,不需要重新编译
.exe 老与 .c :源文件是新的,需要重新编译
那么如何进行验证呢?我们需要用到一个新指令:stat 文件名这条指令可以查看文件的时间。

- Access:访问时间。该文件最后一次被读取或执行的时间
- Modify:修改时间(针对的是文件内容)
- Change:更改时间(针对的是文件属性)
在之前的学习中,我们知道==文件 = 文件内容 + 文件属性==。文件属性指的是文件的名称、大小、权限、存储位置等。

由此可以得出结论:make会根据源文件和目标文件的新旧,判定是否需要重新执行依赖关系进行编译。如果想让对应的依赖关系总是被执行呢?那么就可以在makefile中添加.PHONY:文件名指令

不过不建议用.PHONY修饰可执行程序,一般用在清理工作当中。我们将它设置为伪目标,用 .PHONY 修饰,伪目标的特性是,总是被执行的。
.PHONY: clean
clean:rm -f mycode
makefile的特殊处理
mycode:mycode.cgcc -o $@ $^
.PHONY:clean
clean:rm -f mycode
$@等价于冒号左边,$^等价于冒号右边

如果在依赖方法前面加个@符合,作用是不用显示gcc指令。
相关文章:
自动化构建工具:makemakefile
在Windows中,我们写C代码或者C代码都需要用先找到一款合适的编译器,用来方便我们更好的完成代码,比如说vs2019,这些工具的特点是集成了多种开发所需的功能,如代码编辑、编译、调试、版本控制等,无需在不同的…...
刷题 | 牛客 - js中等10题(更ing)1/54知识点解答
知识点汇总: Array.from(要转换的对象, [mapFn], [thisArg ]):将类数组对象(Array-like)/可迭代对象(Iterable)转为真正的数组。 第二参 mapFn 是 类似 Array.prototype.map 的回调函数,加工…...
Ubuntu 20.04.6编译安装COMFAST CF-AX90无线网卡驱动
目录 0 前言 1 CF-AX90无线网卡驱动 1.1 驱动下载 1.2 驱动准备 2 编译安装驱动 2.1 拷贝驱动依赖到系统 2.2 驱动安装编译 3 重启 0 前言 COMFAST CF-AX90或者说AIC8800D80的Linux版本驱动不支持高版本的linux内核,实测目前仅支持最高5.15的内核。Ubuntu2…...
将python项目打包成Windows后台服务
前文,我开发了一个基于windows11与本地deepseek实现的语音助手,之前是通过CMD直接执行项目的main.py文件。但是这样不适合移植,现在想将其生成一个exe文件,以及部署成windows的后台服务。 关于语音助手的开发与发布,可以看的CSDN文章:一个基于windows11与本地deepseek实…...
PPT无法编辑怎么办?原因及解决方法全解析
在日常办公中,我们经常会遇到需要编辑PPT的情况。然而,有时我们会发现PPT文件无法编辑,这可能由多种原因引起。今天我们来看看PPT无法编辑的几种常见原因,并提供实用的解决方法,帮助你轻松应对。 原因1:文…...
安全用电基础知识及隐患排查重点
安全用电是电气安全的一个重要方面,作为普通人员,必须学会基础的用电知识和技巧,才能保障自己和家庭的安全。 以下是安全用电的基础知识及隐患排查重点: 一、基础知识 1.电压:单位为伏特(V)&a…...
Laravel 使用通义灵码 - AI 辅助开发提升效率
一、引言 Laravel 是 PHP 常用的一种后端开发框架,遵循 MVC(模型 - 视图 - 控制器)架构,以简洁、优雅的语法和强大的功能著称,旨在提升开发效率并简化复杂任务的实现。然而,它的开发习惯可能与传统的 PHP …...
签到功能---实现签到接口
文章目录 概要整体架构流程技术细节小结 概要 需求分析以及接口设计 由KEY的结构可知,要签到,就必须知道是谁在哪一天签到,也就是两个信息: 当前用户 当前时间 这两个信息我们都可以自己获取,因此签到时ÿ…...
JavaScript爬虫基础篇:HTTP 请求与响应
在互联网的世界里,数据无处不在。无论是新闻资讯、商品信息,还是社交媒体动态,这些数据都以各种形式存储在服务器上。而爬虫,就是我们获取这些数据的得力助手。今天,我们就来聊聊爬虫的基础——HTTP 请求与响应&#x…...
Python中的count()方法
文章目录 Python中的count()方法基本语法在不同数据类型中的使用1. 列表(List)中的count()2. 元组(Tuple)中的count()3. 字符串(String)中的count() 高级用法1. 指定搜索范围2. 统计复杂元素 注意事项 Python中的count()方法 前言:count()是Python中用于序列类型&a…...
LWIP_MQTT连接ONENET
前言: 使用正点原子STM32F407, LWIP,MQTT demo,验证LwIP的MQTT连接ONENET物联网平台,测试整个链路是否畅通,后面再详细分析LWIP移植和MQTT协议的使用。 26 基于 MQTT 协议连接 OneNET 服务器 本章主要介绍 lwIP 如何通过 MQTT 协议将设备连接到 OneNET…...
代码随想录刷题|Day20(组合总数,组合总数2、分割回文串)
回溯算法 Part02 组合总数 力扣题目链接 代码随想录链接 视频讲解 题目描述: 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你…...
文件描述符(File Descriptor, FD)详解及利用方法
文件描述符(FD)是 Linux/Unix 系统中用于访问文件、管道、套接字等 I/O 资源的整数标识符。每个进程默认打开 3 个标准文件描述符: FD名称默认绑定设备用途0stdin键盘标准输入(读取数据)1stdout终端屏幕标准输出&…...
Minecraft盔甲机制详解(1.9之后)
Minecraft的盔甲有很多种,但是评判盔甲的好坏,通常玩家会使用一个变量来评判——护甲值 护甲值的机制很简单,一格护甲值 (半个灰色的衣服图标)最多能提供4%的防御 护甲值在不开作弊的生存模式理论上限是20点…...
ArcGIS Desktop使用入门(四)——9版本与10版本区别
系列文章目录 ArcGIS Desktop使用入门(一)软件初认识 ArcGIS Desktop使用入门(二)常用工具条——标准工具 ArcGIS Desktop使用入门(二)常用工具条——编辑器 ArcGIS Desktop使用入门(二&#x…...
R语言之环境清理
有时候 R 环境中残留的变量可能会导致警告,可以尝试清理工作空间并重新加载数据。 警告信息: In mget(objectNames, envir ns, inherits TRUE) : 重新评估被中断的许诺 # 观察前6行 head(iris)# 观察数据结构 str(iris)# 探知数据的极值和分位数,以及…...
javaSE————网络编程套接字
网络编程套接字~~~~~ 好久没更新啦,蓝桥杯爆掉了,从今天开始爆更嗷; 1,网络编程基础 为啥要有网络编程呢,我们进行网络通信就是为了获取丰富的网络资源,说实话真的很神奇,想想我们躺在床上&a…...
FreeRTOS二值信号量详解与实战教程
FreeRTOS二值信号量详解与实战教程 📚 作者推荐:想系统学习FreeRTOS嵌入式开发?请访问我的FreeRTOS开源学习库,内含从入门到精通的完整教程和实例代码! 1. 二值信号量核心概念解析 二值信号量(Binary Semaphore)是Fre…...
Java命名规则
在 Java 项目中,命名规则遵循一定的约定俗成规范,目的是提高代码可读性和团队协作效率。以下是 Java 项目命名的核心规则和常见实践: 一、项目整体命名 项目名 使用小写字母 短横线(kebab-case)…...
赛灵思 XCVU440-2FLGA2892E XilinxFPGA Virtex UltraScale
XCVU440-2FLGA2892E 属于 Xilinx Virtex UltraScale 系列,是面向高端应用的旗舰 FPGA 器件。该系列产品以出色的高并行处理能力、丰富的逻辑资源和高速互联能力闻名,广泛用于 高性能计算、数字信号处理等对计算能力和带宽要求极高的场景。采用先进的 20n…...
Spring Cloud Alibaba微服务-微服务介绍和搭建
1. 课程介绍 单体服务中有订单,用户,库存, 两个缺陷: a. 是以应用的维度进行负载均衡,资源占用大 b. 当其中一个模块宕机,整个应用就不能用了; nacos;ribbon,loadBa…...
KALI安装JAVA8和切换JDK版本
一、安装JDK1.8 1、直接使用下面的地址下载java 1.8: https://repo.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz 2、建立目录,将下载的jdk的安装包复制过去并进行解压 sudo mkdir -p /usr/local/java cp jdk-8u202-linux-x64.t…...
C语言中冒泡排序和快速排序的区别
冒泡排序和快速排序都是常见的排序算法,但它们在原理、效率和应用场景等方面存在显著区别。以下是两者的详细对比: 一、算法原理 1. 冒泡排序 原理:通过重复遍历数组,比较相邻元素的大小,并在必要时交换它们的位置。…...
今日行情明日机会——20250417
指数目前在区间内缩量震荡 2025年4月17日涨停主要行业方向分析 一、核心主线方向 化工(产能优化涨价预期) • 涨停家数:11家(最强方向)。 • 代表标的: ◦ 红宝丽(2连板)ÿ…...
C# 对列表中的元素的多个属性进行排序
目录 前言一、OrderBy、OrderByDescending、ThenBy、ThenByDescending二、Sort 前言 在开发过程中,我们经常需要 根据列表中的元素的某个属性进行排序,下面我们将简单介绍常用的排序函数。 例如此处有一个类,拥有的元素为编号和值 public …...
QML 信号与槽
QML 信号与槽 QML 是 Qt 框架中用于构建现代化、流畅用户界面的声明式语言,其信号与槽(Signals and Slots)机制是实现组件间通信和交互的核心特性。与 C 的信号与槽类似,QML 的信号与槽提供了一种松耦合的方式,允许界…...
一篇讲完自动化测试基础-Python【万字详细讲解】12
✨博客主页: https://blog.csdn.net/m0_63815035?typeblog 💗《博客内容》:.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 📢博客专栏: https://blog.csdn.net/m0_63815035/cat…...
极限编程(XP)简介及其价值观与最佳实践
目录 一、什么是极限编程(XP)二、极限编程的核心价值观1. 沟通2. 简单3. 反馈4. 勇气 三、极限编程的12个最佳实践1. 结对编程2. 40小时工作制3. 简单设计4. 代码规范5. 测试驱动开发(TDD)6. 系统隐喻7. 持续集成8. 重构9. 客户在…...
四层板的蛇形走线技巧:原理、策略与应用
在四层板的设计过程中,蛇形走线是一种常见且重要的布线方式。它能够满足特定的设计需求,如调整信号线长度、实现等长布线等,但如果使用不当,也可能会带来一些负面影响,如增加信号衰减、引入电磁干扰等。以下将详细探讨…...
面向对象—有理数类的设计
目录 1.代码呈现 1.1编写toString、equals方法 1.2测试代码 1.3有理数类的代码 2.论述题 3.有理类设计 1.代码呈现 1.1编写toString、equals方法 (1)toString方法 Overridepublic String toString(){if(this.v20){return "Undefined";}return this.v1 "/…...
