浅析 Makefile
Makefile逻辑
Makefile就是将一系列的工作流串在一起自动执行,构成Makefile最基本的要素是目标、依赖、命令。也就是为了实现目标需要哪些依赖并执行什么样的命令。
target: dependences1 dependences2 ... command1 command2 ...
其中,target表示要生成的目标,dependences表示生成target需要的依赖,而command就是生成target要执行什么命令。在格式上,命令所在行行首都有一个。
比如对于c语言来讲,生成.o文件需要.c源文件,而生成目标二进制文件又需要.o文件。
test: test.o gcc -o test test.o
test.o: test.c gcc -c test.c -o test.o
通过上面的例子我们隐约可以感觉到Makefile的解析过程,有点类似函数的递归调用。总是触及到最里层的规则之后,后面的每一次返回实际上都是依赖了上一次的调用。如下图:

当然,在编写代码的时候target相互之间的顺序有可能是打乱的,这里不要太死板。
Makefile的核心逻辑就是上面这点东西,而Makefile的创建有两种方式。
第一,将文件名命令为"Makefile",然后在Makefile文件所在的目录直接使用make命令就可以自动解析"Makefile"文件的内容。比如下面是我自己的一个c语言项目的Makefile。

第二,任意命名,比如我们使用一个叫makefile_test的文件来编写Makefile内容。在执行make的时候使用-f参数指定文件名。如下:
$ make -f makefile_test
当然,Makefile还支持引用其它的Makefile,格式如下:
include <filename>
伪目标
有些时候,我们希望不生成具体的目标文件,只想执行命令,比如在Linux通过源码安装经常会使用make clean来清除安装产生的额外的中间文件,比如:
test: test.o gcc -o test test.o
clean: rm -rf *.o test
按照Makefile的规则clean也是一个目标,但我们不希望生成clean目标文件,就可以使用.PHONY将其声明为伪目标,表示只执行命令,不生成目标文件。例如:
.PHONY: clean
test: test.o gcc -o test test.o
clean: rm -rf *.o test
当一个Makefile有多个目标的时候,可以通过参数来指定要执行哪个目标,比如上面的clean:
$ make clean
Makefile变量
Makefile也支持变量,使用上和Shell中的变量很相似,比如:
BUILDDIR=./build
...
build: mkdir -p $(BUILDDIR)
...
上面声明了一个变量BUILDDIR,然后在build目标中使用$(BUILDDIR)来引用变量。Makefile中变量可以分为三大类:默认变量、自定义变量和自动变量。\
1. 默认变量
默认变量是Makefile的约定,比如:
test: $(CC) -o test test.c
其中CC就是一个默认变量,在linux下就是编译器cc。其它比较常用的默认变量如下:
关于命令相关的变量
AR: 函数库打包程序。默认命令是arAS: 汇编语言编译程序。默认命令是asCC: C语言编译程序。默认命令是ccCXX: C++语言编译程序。默认命令是g++CO: 从 RCS文件中扩展文件程序。默认命令是coCPP: C程序的预处理器(输出是标准输出设备)。默认命令是$(CC) –EFC: Fortran 和 Ratfor 的编译器和预处理程序。默认命令是f77GET: 从SCCS文件中扩展文件的程序。默认命令是getLEX: Lex方法分析器程序(针对于C或Ratfor)。默认命令是lexPC: Pascal语言编译程序。默认命令是pcYACC: Yacc文法分析器(针对于C程序)。默认命令是yaccYACCR: Yacc文法分析器(针对于Ratfor程序)。默认命令是yacc –rMAKEINFO: 转换Texinfo源文件(.texi)到Info文件程序。默认命令是makeinfoTEX: 从TeX源文件创建TeX DVI文件的程序。默认命令是texTEXI2DVI: 从Texinfo源文件创建TeX DVI 文件的程序。默认命令是texi2dviWEAVE: 转换Web到TeX的程序。默认命令是weaveCWEAVE: 转换C Web 到 TeX的程序。默认命令是cweaveTANGLE: 转换Web到Pascal语言的程序。默认命令是tangleCTANGLE: 转换C Web 到 C。默认命令是ctangleRM: 删除文件命令。默认命令是rm –f
关于命令参数的变量
ARFLAGS: 函数库打包程序AR命令的参数。默认值是rvASFLAGS: 汇编语言编译器参数。(当明显地调用.s或.S文件时)CFLAGS: C语言编译器参数。CXXFLAGS: C++语言编译器参数。COFLAGS: RCS命令参数。CPPFLAGS: C预处理器参数。( C 和 Fortran 编译器也会用到)。FFLAGS: Fortran语言编译器参数。GFLAGS: SCCS “get”程序参数。LDFLAGS: 链接器参数。(如:ld)LFLAGS: Lex文法分析器参数。PFLAGS: Pascal语言编译器参数。RFLAGS: Ratfor 程序的Fortran 编译器参数。YFLAGS: Yacc文法分析器参数
2. 自定义变量
前面我们声明的BUILDDIR就是一个自定义变量,要注意的是,如果声明了一个和默认变量一样的变量就会覆盖默认变量,这也给我们提供了一个改变默认规则的入口。
自定义变量要注意的是赋值方式,在Makefile中有以下几种赋值方式:
=延迟赋值,在Makefile运行时才会被赋值:=立即赋值,立即赋值是在真正运行前就会被赋值?=空赋值,如果变量没有设置过才会被赋值+=追加赋值,可以理解为字符串的加操作
延迟赋值指的是在Makefile运行时再赋值。
立即赋值和我们的直觉一致
空赋值,是指如果变量没有设置的情况下才会赋值,空赋值只会在变量没有设置的时候才有效
3. 自动变量
Makefile有很多自动变量,这里只介绍几个常用的,分别是<、<、^、$@,其它的可以去参考Makefile文档。
$< 表示第一个依赖的文件,例如:
test: test.o test2.o echo $<
test.o:
test2.o:
最终结果是test.o,也就是test第一个依赖。
$^ 表示所有依赖,还是上面的例子,例如:
test: test.o test2.o echo $^
test.o:
test2.o:
最终结果是test.o test2.o,是test全部的依赖。
$@ 表示目标,上面的例子:
test: test.o test2.o echo $@
test.o:
test2.o:
最终结果是test,也就是Makefile中的test。
Makefile规则
在Makefile中有一些约定俗成的规则,正是这些规则的存在可以大大减少Makefile代码长度,这里我只列出了我认为比较重要的四个规则。
1. 隐含规则
这里以c语言的规则举例,先来看一段Makefile:
main: main.o test.o cc -o main main.o test.o
在当前目录下,只有main.c和test.c两个文件,并没有.o文件,上面的Makefile之所以能运行,是因为它的隐含规则。对于c语言来讲,如果有地方依赖.o文件,会自动去寻找相同名称的.c文件,并构建出.o文件。
当然隐含规则远没有这么简单,比如Makefile还支持多个步骤的隐形规则链,但这里我们只需要了解到这一步,后面可以查看理详细的文档去深入了解。
2. 通配符
Makefile中支持*、?、三个通配符,其意义和shell中的通配符基本一致。比如表示宿主目录。例如在make clean的时候清除编译中产生的.o中间文件,如下:
clean: rm -rf *.o
3. 模式匹配
在Makefile中模式匹配使用%来实现,表示匹配任意多个非空字符,相当于shell中的*。模式匹配有什么用呢?假如现在有非常多的.c源文件要生成目标.o文件,我们可以像下面这样写:
%.o: %.c cc -c %^ -o $@
上面的意思是将所有.c文件都经过编译器编译生成.o文件,其中表示的是所有的依赖,在上面的场景中就是当前目录下所有.c文件。而^表示的是所有的依赖,在上面的场景中就是当前目录下所有.c文件。而表示的是所有的依赖,在上面的场景中就是当前目录下所有.c文件。而@表示目标文件。也就是%.o所代表的所有文件。可以看到模式匹配可以大幅减少Makefile的代码量。
4. 文件搜索
在比较大的工程中,程序可能会有特别多的依赖,Makefile默认会在当前目录下搜索依赖,但是绝大多数情况依赖可能分布在多个目录中,Makefile的VPATH变量可以帮助我们解决依赖搜索的问题,比如:
VPATH=src:../headers
表示Makefile会从src和…headers目录去搜索依赖文件。
VPATH还支持模式匹配,比如
VPATH <pattern> <directories>
比如,下面就表示在headers目录找所有.h文件
vpath %.h headers
还可以通过模式匹配清除搜索目录。注意,这里说的是清除。
VPATH <pattern>
或者清除所有已设置好的目录。
VPATH
Makefile条件分支
Makefile条件分支比较简单,就ifeq和ifneq。比如:
ifeq ($(ARCH), x86) CC=gcc
else CC=arm....gcc
endif
这个比较好理解,而ifneq的使用和ifeq几乎是一样的,可以自己试一下。
Makefile函数
Makefile提供了很多内置函数,但这里我只讲其中我认为比较重要的4个函数,分别是:
1. patsubst : 模式匹配与替换
patsubst的原型如下:
$(patsubst <pattern>,<replacement>,<text>)
其语义是,在text中寻找符合pattern模式的内容替换成replacement的模式。这个函数非常有用,还是以c语言为例,在没有生成.o文件之前我们可以通过.c格式的原文件替换最终得到一组.o文件名。比如:
OBJECTS=$(patsubst %.c,%.o, main.c test.c)
最终main.c和test.c会被分别替换成main.o和test.o,然后将结果赋值给变量OBJECTS。
2. notdir : 去掉路径中的目录
notdir的原型如下:
$(notdir <text>)
有时候我们拿到的是一个文件的全路径,但我们只想要文件名,就可以使用notdir函数,比如src/foo.c,我们只想要foo.c,就可以这样写:
FOO=$(notdir src/foot.c)
3. wildcard : 匹配文件
如果我们要从一堆文件里面挑出符合条件的那部分就可以使用wildcard,它的原型如下:
$(wildcard <pattern>)
比如我们想找出所有.h文件
INCLUDES=$(wildcard *.h)
注意,这里使用的通配符是"*",这里表示在当前目录找到所有.h文件。
4. foreach : 批量处理
foreach可以重复相同的逻辑去处理一批数据,它的原型如下:
$(foreach <var>,<list>,<text>)
比如我们要一次性找到a、b、c三个目录下的所有.c文件,就可以这样写:
DIRS:=a b c
FILES=$(foreach dir, $(dirs), $(wildcard $(dir)/*.c))
foreach的参数有三个,我们分别来看一下
- 表示从中遍历出来的每一项
- 是被遍历的原数据列表,可以类比c语言中的数组
在text中是可以引用的也可以使用其它函数, 就是foreach函数处理之后的结果,如果 中有函数就是函数运行之后的结果。
好了,到这里我们所需要的前置知识都有了。下面来通过一个实际项目将上面的知识点串在一起,实现一个相对比较复杂的Makefile。
C++后端开发学习教程:https://ke.qq.com/course/417774?flowToken=1031343
相关文章:
浅析 Makefile
Makefile逻辑 Makefile就是将一系列的工作流串在一起自动执行,构成Makefile最基本的要素是目标、依赖、命令。也就是为了实现目标需要哪些依赖并执行什么样的命令。 target: dependences1 dependences2 ... command1 command2 ...其中,target表示要生…...
保护品牌线上声誉的5种方法
我们如今生活在一个搜索便捷的世界,对于一个企业和个人来说,品牌的线上声誉也尤为重要。在客户考虑与您的公司开展业务之前,他们理所当然会先使用众多软件和平台搜索相关信息,以帮助他们了解和做决定。 因此,您的品牌…...
Java多重选择结构,超详细整理,适合新手入门
目录 一、什么是多重选择结构? 二、if 语句的语法 1、什么是嵌套if语句? 2、if 语句循环基本用法: 3、案例: 二、if...else多重选择结构语法 1、什么是if-else语句? 2、if...else 循环基本用法 3、案例&#…...
SCI写作,一定要避开这些“雷点”!
SCI论文写作中,除了要符合各部分的写作要求,还有许多细节问题需要我们注意,不然可能一不小心就会“踩雷”。 今天我们就来和大家分享SCI各个部分写作时的注意事项。 下面就进入正题! SCI写作注意事项 01 标题的拟定 1.避免使用无…...
3GPP-NR Band14标准定义频点和信道(3GPP V17.7.0 (2022-12))
Reference test frequencies for NR operating band n14 Table 4.3.1.1.1.14-1: Test frequencies for NRoperating band n14 and SCS 15 kHz CBW [MHz]carrierBandwidth...
分库分表索引设计:分布式环境下的 主键索引、二级索引、全局索引的最佳设计实践
文章目录主键选择索引设计全局表唯一索引总结结语主键选择 对主键来说,要保证在所有分片中都唯一,它本质上就是一个全局唯一的索引。如果用大部分同学喜欢的自增作为主键,就会发现存在很大的问题。 因为自增并不能在插入前就获得值…...
2023年全国最新保安员精选真题及答案
百分百题库提供保安员考试试题、保安职业资格考试预测题、保安员考试真题、保安职业资格证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 一、单选题(1-480题)以下备选答案中只有一项最符合题目要求&a…...
计算机网络之http07 http2,http3
HTTP1.2 http1.2都做了哪些优化 (1)头部压缩 使用HPACK压缩头部 头部冗长,大量重复字段 (2)二进制帧 将报文头部和内容字符编码改为二进制格式 字符编码未压缩 (3)并发传输 解决h1.1 队头阻塞问题,多车道 …...
内网渗透(二十五)之Windows协议认证和密码抓取-使用Hashcat和在线工具破解NTLM Hash
系列文章第一章节之基础知识篇 内网渗透(一)之基础知识-内网渗透介绍和概述 内网渗透(二)之基础知识-工作组介绍 内网渗透(三)之基础知识-域环境的介绍和优点 内网渗透(四)之基础知识-搭建域环境 内网渗透(五)之基础知识-Active Directory活动目录介绍和使用 内网渗透(六)之基…...
TongWeb8防止System.exit代码导致的进程停止
现象:当应用中存在System.exit 、Runtime.exit代码执行时,会导致TongWeb进程停止,从而产生如下日志:2023-02-14 09:47:36 [WARN] - The web application [webtest01] is still processing a request that has yet to finish. This…...
PMP每年考几次,费用如何?
一,PMP每年考几次,怎么准备? PMP项目管理证书是美国PMI发起的在全球200多个国家进行的项目管理专业人士资格认证,它的含金量和给认证者带来的作用已经很明显。 PMP考试是项目管理专业人士资格认证考试,通过PMP考试是…...
【Kubernetes】【一】Kubernetes介绍
Kubernetes介绍 应用部署方式演变 在部署应用程序的方式上,主要经历了三个时代: 传统部署:互联网早期,会直接将应用程序部署在物理机上 优点:简单,不需要其它技术的参与 缺点:不能为应用程序定…...
C语言:结构体
往期文章 C语言:初识C语言C语言:分支语句和循环语句C语言:函数C语言:数组C语言:操作符详解C语言:指针详解 目录往期文章前言1. 结构体的声明2. 结构体变量的定义和初始化3. 结构体成员的访问3. 结构体传参…...
搭建pclpy环境与读取pandaset数据并转换为pkl格式为pcd格式
1.搭建pclpy环境 问题:需要处理pcd文件,于是开始摸索搭建环境,有python-pcl,但是安装过程频频出现问题,于是转向pclpy。 参考链接:GitHub - davidcaron/pclpy: Python bindings for the Point Cloud Libr…...
别在用scroll去做懒加载了,交叉观察器轻松搞定
Ⅰ、前言 「懒加载」是网页中非常 常见的;为了减少系统的压力,对于一些电商系统出场频率非常高;那么大家一般用什么方式去实现 「懒加载」 呢 ? ① 通过 scroll 的形式: 通过 滚动「scroll」事件,然后去判…...
工欲善其事,必先利其器,分享5款Windows效率软件
工欲善其事,必先利其器。作为全球最多人使用的桌面操作系统,Windows 的使用效率与我们的工作学习息息相关。今天,小编就为大家整理了5款提高效率的利器,让你的 Windows 更具生产力。 1.桌面自定义——Rainmeter Rainmeter是一款…...
机器学习笔记之生成模型综述(四)概率图模型 vs 神经网络
机器学习笔记之生成模型综述——概率图模型vs神经网络引言回顾:概率图模型与前馈神经网络贝叶斯网络 VS\text{VS}VS 神经网络表示层面观察两者区别推断、学习层面观察两者区别引言 本节将介绍概率图模型与神经网络之间的关联关系和各自特点。 回顾:概率…...
微信小程序 组件与页面交互 无反应的问题
使用组件 声明组件 1.在目录中右键,新建components 2.在页面的json,属性中加入"component": true, 编写组件 父 声明: "usingComponents": {"address": "../../components/address/address"},…...
maven相关概念以及no dependency information available错误修改
一,相关概念 1,Maven坐标 Maven定义了这样一组规则:世界上任何一个构件都可以使用Maven坐标唯一标识,Maven坐标元素包括groupId、artifactId、version、packaging、classifier,现在只要我们提供正确的元素坐标&#x…...
QML- 属性绑定
QML- 属性绑定一、概述二、 QML绑定使用三、从JavaScript创建属性绑定1. 调试绑定的覆盖2. 属性绑定使用 this一、概述 QML对象的属性可以被赋一个静态值,该值保持不变,直到显式地赋一个新值。但是,为了充分利用QML及其对动态对象行为的内置…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...
相关类相关的可视化图像总结
目录 一、散点图 二、气泡图 三、相关图 四、热力图 五、二维密度图 六、多模态二维密度图 七、雷达图 八、桑基图 九、总结 一、散点图 特点 通过点的位置展示两个连续变量之间的关系,可直观判断线性相关、非线性相关或无相关关系,点的分布密…...
Linux操作系统共享Windows操作系统的文件
目录 一、共享文件 二、挂载 一、共享文件 点击虚拟机选项-设置 点击选项,设置文件夹共享为总是启用,点击添加,可添加需要共享的文件夹 查询是否共享成功 ls /mnt/hgfs 如果显示Download(这是我共享的文件夹)&…...
Redis上篇--知识点总结
Redis上篇–解析 本文大部分知识整理自网上,在正文结束后都会附上参考地址。如果想要深入或者详细学习可以通过文末链接跳转学习。 1. 基本介绍 Redis 是一个开源的、高性能的 内存键值数据库,Redis 的键值对中的 key 就是字符串对象,而 val…...
HTML中各种标签的作用
一、HTML文件主要标签结构及说明 1. <!DOCTYPE html> 作用:声明文档类型,告知浏览器这是 HTML5 文档。 必须:是。 2. <html lang“zh”>. </html> 作用:包裹整个网页内容,lang"z…...
