【Linux】项目自动化构建工具-make/Makefile 详解


文章目录
- 前言
- 1. 什么是make和Makefile?
- 2. Makefile的基本结构
- 3. Makefile的高级特性
- 4. 使用make的优势
- 5. 总结
前言
在Linux及类Unix系统中,自动化构建项目是提高开发效率、减少重复劳动的关键环节。make工具及其配置文件Makefile是实现这一目标的重要工具组合。它们通过定义一系列规则和依赖关系,自动执行编译、链接等构建过程,确保软件项目能够高效、准确地构建。
1. 什么是make和Makefile?
make 是一种控制程序生成的工具,它读取一个名为Makefile(或makefile,不区分大小写)的文件,并根据文件中的指令执行相应的命令。这些命令通常包括编译、链接等,用于生成最终的可执行文件或库文件。一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
Makefile 是一个文本文件,其中包含了一系列的规则(rules)、目标(targets)、依赖(dependencies)和命令(commands)。每个规则定义了一个目标文件(通常是编译或链接的结果),以及生成该目标文件所需的依赖文件和要执行的命令。
一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
2. Makefile的基本结构
Makefile的基本结构由规则组成,每个规则通常包含以下部分:
- 目标(target):通常是要生成的文件名,如可执行文件或对象文件。
- 依赖(dependencies):生成目标所依赖的文件列表。
- 命令(commands):生成目标需要执行的Shell命令,前面通常需要一个制表符(Tab)开头。
示例:
首先,这里有一个hello.c源文件:

hello.c的内容如下:

然后我们就可以通过创建一个Makefile文件来控制该代码生成程序(当然我们也可以直接使用gcc命令来生成可执行程序,但是随着源文件个数的增加,我们每次重新生成可执行程序时,所需输入的gcc指令的长度与个数也会随之增加,所以这时我们就需要使用make和Makefile了,这将大大减少我们的工作量),Makefile内容如下:

✨✨这里hello和clean就是我们的目标,hello.c就是要生成hello目标文件的依赖,而clean由.PHONY修饰,是一个伪目标,所以不需要依赖,伪目标的特性是,总是被执行的;
gcc -o hello hello.c
和rm -f hello
就是生成目标需要执行的Shell命令
然后我们就可以使用make来创建可执行程序hello:

在这个例子中,hello是最终的目标,它依赖于hello.c。为了生成hello,需要执行gcc -o hello hello.c命令,如上图绿色划线部分,这样我们直接使用make命令,它就可以帮我们在Makefile文件中找到生成hello的命令,自动执行。
此外在Makefile中clean是一个用.PHONY声明伪目标(不生成文件),用于清理构建过程中产生的文件,我们直接使用make clean
指令即可删除对应的文件:
.PHONY:clean
clean: rm -f hello

可以看到之前make指令生成的可执行程序hello被删除了,其原因也是因为make clean命令使得它去Makefile文件中找到相关的指令
rm -f hello
进行删除
如果你想要删除多个文件,直接在rm -f
后面加文件名即可,例如我们可以将hello.c文件也删除:

结果如下:

可以看到已经没有hello和hello.c文件了
- 我们发现使用clean命令时需要写
make clean
但是创建hello文件时只需要写make
即可,这是因为如果只输入make命令,make会在当前目录下找名字叫“Makefile”或“makefile”的文件,如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“hello”这个文件,然后执行生成它的Shell命令,所以make后面的hello可以省略,只写一个make命令即可; - 如果找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错。
3. Makefile的高级特性
变量:Makefile中可以使用变量来存储文件名、编译器选项等,以提高灵活性和可维护性。
示例:
CC=gcc
CFLAGS=-Wall -g
hello: hello.o $(CC) $(CFLAGS) -o hello hello.o
上述例子使用变量CC和CFLAGS来代替gcc和-Wall -g ,使用时需要使用括号并在前面加上$
自动变量:在规则中的命令里,可以使用一些特殊变量来表示依赖文件和目标文件等,如:
- $@:表示依赖关系中的目标文件(冒号左侧)。
- $^:表示依赖关系中的依赖文件列表(冒号右侧全部)。
- $<:表示依赖关系中的第一个依赖文件(冒号右侧第一个)。
模式规则:允许为符合特定模式的文件指定构建规则,从而减少重复代码。
示例:
%.o: %.c $(CC) $(CFLAGS) -c $< -o $@
条件判断:基于不同的条件执行不同的命令。
示例:
ifeq ($(OS),Windows_NT)
CFLAGS += -DWIN32
endif
函数:Makefile支持多种内置函数,用于处理文件名、字符串等。
4. 使用make的优势
- 自动化:自动根据依赖关系执行必要的命令,减少手动操作。
- 可维护性:通过清晰的规则和依赖关系,提高项目的可维护性。
- 灵活性:支持变量、条件判断等高级特性,满足不同项目的构建需求。
- 高效性:只重新构建已更改的部分,避免不必要的编译和链接。
5. 总结
make和Makefile是Linux及类Unix系统中不可或缺的自动化构建工具。它们通过定义清晰的规则和依赖关系,极大地提高了软件项目的构建效率和可维护性。掌握make和Makefile的使用,对于开发者来说,是提升开发效率、保证项目质量的重要一步。
相关文章:

【Linux】项目自动化构建工具-make/Makefile 详解
🔥 个人主页:大耳朵土土垚 🔥 所属专栏:Linux系统编程 这里将会不定期更新有关Linux的内容,欢迎大家点赞,收藏,评论🥳🥳🎉🎉🎉 文章目…...
嵌入式开发中学习C++的用处?
这个问题一直有同学在问,其实从我的角度是一定是需要学的,最直接的就是你面试大厂的嵌入式岗位或者相关岗位,最后一定会问c,而很多人是不会的,这就是最大的用处,至于从技术角度考量倒是其次,因为…...
基于SAM大模型的遥感影像分割工具,用于创建交互式标注、识别地物的能力,可利用Flask进行封装作为Web后台服务
如有帮助,支持一下(GitHub - Lvbta/ImageSegmentationTool-SAM: An interactive annotation case developed based on SAM for remote sensing image annotation, which can generate corresponding segmentation results based on point, multi-point, …...
Selenium入门
Selenium 是一个用于自动化 web 应用程序测试的工具,它支持多种浏览器和编程语言。 下载驱动程序:根据你的浏览器类型和版本,下载相应的 WebDriver。例如,Chrome 浏览器需要 ChromeDriver。 安装 Selenium 库 pip install sele…...

USB 3.1 Micro-A 与 Micro-B 插头,Micro-AB 与 Micro-B 插座,及其引脚定义
连接器配对 下表列出 USB 插座可接受的插头: USB 3.1 Micro-B 连接器 USB 3.1 Micro-B 插头和 USB 3.1 Micro-B 插座连接器是为小型手持设备和其他可能使用小尺寸连接器的应用而定义的。其定义使得 USB 3.1 Micro-B 插座既可以接受 USB 3.1 Micro-B 插头ÿ…...

MySQL多版本并发控制MVCC实现原理
MVCC MVCC 是多版本并发控制方法,用来解决读和写之间的冲突,比如脏读、不可重复读问题,MVCC主要针对读操作做限制,保证每次读取到的数据都是本次读取之前的已经提交事务所修改的。 概述 当一个事务要对数据库中的数据进行selec…...
【并查集】[ABC372E] K-th Largest Connected Components 题解
题意 前置阅读:并查集算法介绍 洛谷链接 Atcoder 链接 给定 n ( 1 ≤ n ≤ 2 1 0 5 ) n(1 \leq n \leq 2\times 10^5) n(1≤n≤2105) 个点,初始没有边,您要进行以下操作: 1 a b,表示连接一条 ( a , b ) (a,b) …...
HarmonyOS面试题(持续更新中)
1、用过线程通信吗,线程是怎么进行通信的? emitter 和 eventHub 相同: 都是基于事件总线的 区别是: ① eventHub当前线程内通信 ② emitter是同一进程不同线程或者同一进程和同一线程也可以通信 2、页面和组件的生命周期 …...
QT中QWidget和QObject的区别与联系是什么
在Qt框架中,QWidget和QObject是两个核心类,它们各自扮演着不同的角色,但又紧密相连。以下是关于它们区别与联系的详细解释: 区别 基类和功能定位: QObject是Qt中所有类的基类,包括几乎所有的Qt对象。它提供…...

解决macOS安装redis以后不支持远程链接的问题
参考文档:https://blog.csdn.net/qq_37703224/article/details/142542179?spm1001.2014.3001.5501 安装的时候有个提示, 使用指定配置启动: /opt/homebrew/opt/redis/bin/redis-server /opt/homebrew/etc/redis.conf那么我们可以尝试修改这个配置文件: code /opt/homebrew/…...

2024年研究生数学建模“华为杯”E题——肘部法则、k-means聚类、目标检测(python)、ARIMA、逻辑回归、混淆矩阵(附:目标检测代码)
文章目录 一、情况介绍二、思路情况二、代码展示三、感受 一、情况介绍 前几天也是参加了研究生数学建模竞赛(也就是华为杯),也是和本校的两个数学学院的朋友在网上组的队伍。昨天(9.25)通宵干完论文(一条…...

绝了,自从用了它,我每天能多摸鱼2小时!
大家好,我是可乐。 俗话说的好:“摸鱼一时爽,一直摸鱼一直爽”。 作为一个程序员,是否有过调试代码熬到深夜?是否有过找不到解决方案而挠秃头顶? 但现在你即将要解放了,用了这款工具——秘塔…...

C语言指针系列1——初识指针
祛魅:其实指针这块儿并不难,有人说难只是因为基础到进阶没有处理好,大家要好好跟着一步一步学习,今天我们先来认识一下指针 指针定义:指针就是内存地址,指针变量是用来存放内存地址的变量,在同一…...

传神论文中心|第26期人工智能领域论文推荐
在人工智能领域的快速发展中,我们不断看到令人振奋的技术进步和创新。近期,开放传神(OpenCSG)传神社区发现了一些值得关注的成就。传神社区本周也为对AI和大模型感兴趣的读者们提供了一些值得一读的研究工作的简要概述以及它们各自…...
NLP基础1
NLP基础1 深度学习中的NLP的特征输入 1.稠密编码(特征嵌入) 稠密编码(Dense Encoding):指将离散或者高纬的稀疏数据转化为低纬度的连续、密集向量表示 特征嵌入(Feature Embedding) 也称…...

001.docker30分钟速通版
docker简介 docker就是一个用于构建(build),运行(run),传送(share)应用程序的平台做一个不恰当的类比,就是外卖平台,如果你自己做华莱士不一定好吃࿰…...
Kafka 在 Linux 下的集群配置和安装
Kafka 在 Linux 下的集群配置和安装 Apache Kafka 是一个流行的分布式流处理平台,广泛用于实时数据管道和流处理应用。本文将详细讲解如何在 Linux 环境中配置和安装 Kafka 集群,并包括通过 Docker 安装和配置 Kafka 的步骤。每个步骤都将提供详细的解释…...

Python--操作列表
1.for循环 1.1 for循环的基本语法 for variable in iterable: # 执行循环体 # 这里可以是任何有效的Python代码块这里的variable是一个变量名,用于在每次循环迭代时临时存储iterable中的下一个元素。 iterable是一个可迭代对象,比如列表(…...
JMeter(需要补充请在留言区发给我,谢谢)
一、学习工具 1、CinfigElement(HTTP Request Defaults、HTTP Header Manager、HTTP Authorization、CSV Data Set Config、User Defined Variables、JDBC Connection Configuration、HTTP Cookie Manager、Random Variable) 二、协议 1、HTTP协议(消息体数据&am…...

线程池的执行流程和配置参数总结
一、线程池的执行流程总结 提交线程任务;如果线程池中存在空闲线程,则分配一个空闲线程给任务,执行线程任务;线程池中不存在空闲线程,则线程池会判断当前线程数是否超过核心线程数(corePoolSize)…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...

push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...

【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...

Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...