当前位置: 首页 > news >正文

Linux下的项目自动化构建-make\makefile详解

文章目录

  • 1. 背景知识
  • 2.基本使用
    • 2.1make/makefile的初识
    • 2.2 make命令和Makefile的依赖关系和依赖方法
      • 依赖关系
      • 依赖方法(语法要求)
    • 2.3 项目清理(伪目标依赖)
        • PHONY解析(伪目标)
        • 文件时间细节(加餐)
    • 2.4 Makefile编辑语法细节
      • @(禁止命令回显)
      • 变量替换
      • 多文件替换
      • 替换进阶内容(命令包装)
    • 2.5 $< 和 $^ 的区别(加餐)
      • 一、核心区别总结表
      • 二、示例(基于 test.exe 多文件场景)
        • 项目文件结构
        • Makefile 规则示例
  • 求三连!!

1. 背景知识

  • 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力
  • 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作
  • -makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
  • make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
  • make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
    在这里插入图片描述
    假如一个项目一共有1w个源文件,难道一个一个gcc编译吗?这显然是不可能的,这里就需要我们项目的自动化构建

2.基本使用

2.1make/makefile的初识

  1. 创建一个在当前目录下的Makefile或者makefile 首字母大小写都行,然后打开Makefile
    请添加图片描述
  2. 在内部写下以下内容,保存退出在这里插入图片描述
  3. 然后 输入make 发现自动执行了gcc命令
    请添加图片描述
    这就是最简单的Makefile

2.2 make命令和Makefile的依赖关系和依赖方法

什么是依赖关系、依赖方法?
比如月底,你没钱了,你和你爸是父子关系,所以你找他打电话要钱,这层关系叫依赖关系,而打电话要钱的行为就叫依赖方法。只有依赖关系依赖方法同时存在且合理,你才能达到你要钱的目的。

依赖关系

  • make 命令依赖 Makefilemake 命令是一个解释执行工具,它需要读取 Makefile 文件中的规则来确定如何编译、链接项目中的文件。如果没有 Makefilemake 命令无法执行自动化构建操作。
  • Makefile 定义依赖规则:Makefile 中通过一系列规则来定义文件之间的依赖关系(如目标文件依赖于源文件、头文件等),以及对应的构建命令。make 命令根据这些依赖规则来判断哪些文件需要重新编译、链接,从而实现增量构建,提高开发效率。

依赖方法(语法要求)

格式:目标文件: 依赖文件列表

test.exe: test.cgcc -o test.exe test.c   #单行缩进使用Table键

这里声明test.exe依赖于test.c,当test.c或有更新时,make 会执行后面的编译命令重新生成test.exe

同时依赖关系依赖方法可以多重定义书写
请添加图片描述
请添加图片描述
这里make会形成推导栈,通过依赖方式的入栈,直到找到突破口(这里的突破口就是test.c文件的存在),从而进行栈返回,类似于函数递归的方式一步步生成可执行文件。

以下为流程图:
请添加图片描述

2.3 项目清理(伪目标依赖)

工程是需要被清理的 这里就提到一个新的概念伪目标依赖.
格式:.:PHONY :核心伪目标
请添加图片描述
这样项目就被清理了
在这里插入图片描述
细节解析:

  1. 依赖关系必须存在,但是依赖列表可以为空。
    请添加图片描述
  2. 依赖方法(Makefile文件内的内容)可以是任何shell命令(可以gcc也可以rm)。
  3. clean目标,只是利用make的自动推导能力,让他执行了rm命令,在构建工程视角,看起来就是清理项目。清理项目,本质就是删除不需要的临时文件。
  4. make命令,后面可以跟“目标名”,后面跟谁,就解析谁的依赖关系和依赖方法,同时make默认只会推导一条完整的推导链路!当make后面没有跟目标名字的时候默认推导第一个依赖关系对应的推导链。
    默认推导:
    请添加图片描述
    当修改顺序:
    在这里插入图片描述
    此时:
    请添加图片描述
PHONY解析(伪目标)

.PHONY是用来修饰目标文件是一个伪目标,本质就是总是被执行
什么叫总是被执行
当我每次make 生成可执行程序时候,发现只有第一次可以成功。
请添加图片描述
只有当源文件发生改变以后我们才能再次执行。

但是make clean确能一直执行请添加图片描述
当我们为我们的命令加上.PHONY
请添加图片描述
此时就能总是执行
在这里插入图片描述


为什么我们可用执行程序往往不.PHONY修饰,gcc为什么无法二次编译老代码???
源代码如果在没有修改的情况下可以一直编译,这不是一个极度浪费资源的行为吗?假如一共有一万个源文件,哪怕你只改了一个源文件,也要全部重新编译。所以make默认只会重新编译你修改过的文件不会重复编译!

那么gcc如何做到的?
我们可以通过stat命令查看文件ACM时间信息
请添加图片描述
Access:访问内容时间。
Modify:文件内容修改时间。
Change:文件属性修改时间。
Birth:文件创建时间。
在这里插入图片描述
判断文件是否要被重新编译,靠的就是.exe文件和源文件的Mod时间的对比!当源文件比可执行文件旧,就无法进行重新编译,当你修改源文件内容,Mod时间就会更新,这样你就可以重新编译了。

那么我们touch直接修改文件时间是不是又可以重新编译了?
答案是:是的。
请添加图片描述
当然文件时间还有更多细节部分。

文件时间细节(加餐)

当我们修改文件内容的时候 为什么文件属性时间也发生了改变?
请添加图片描述
修改文件内容,会影响文件大小,同时Mod时间也会改变,但是文件内容大小和Mod时间本身也是文件属性,所以也会修改Change时间。


assess时间修改细节
我们多次使用cat命令访问文件
在这里插入图片描述
在这里插入图片描述
我们发现两次access时间都没有改变,这个是为什么呢?
文件内容发生更改是会从内存刷新到磁盘上的,文件的属性也是数据,每次更改也会刷新到磁盘上面。

我们修改文件和查看文件属性内容的频率是大大不一样的,明显查看文件比重更高。

而查看文件就会->更新时间->修改文件属性->刷新磁盘!

而每次查看文件就要刷新磁盘,就会导致增加访问磁盘的次数,而这种外设本身就效率低下,最终就会导致OS整体效率低下。

所以,就规定访问文件内容,特定次数后,才会刷新一次!

2.4 Makefile编辑语法细节

@(禁止命令回显)

请添加图片描述
我们发现此时命令被回显出来
请添加图片描述
我们可以利用@符号禁止命令回显请添加图片描述
效果:
请添加图片描述

变量替换

我们同样可以这么写
在这里插入图片描述
类似于宏一样定义变量,这样可以方便修改,$表示为内容提取符号。

依赖方法同样可以替换成符号:请添加图片描述
这里@和^都是定义好的内置变量 $@表示对应依赖关系中的目标文件 $^表示对应依赖关系中的依赖列表

多文件替换

假如一共有199个源文件我们不可能写一百九十九个依赖关系和依赖方法吧。

我们先创建199个文件 这里的{1..199}表示1~199
在这里插入图片描述
test.c改名为main.c作为主函数文件
请添加图片描述
我们把先前写得备份起来 #就是shell语句中的注释
请添加图片描述
做法一:采用 shell命令行方式,获取当前所 有.c文件名
格式:$(shell 命令)
在这里插入图片描述
测试:
请添加图片描述

做法二:使用wildcard(通配符),获取当前所有.c文件名
这里wildcard XXX表示获取当前所有XXX文件名字
在这里插入图片描述
测试:
请添加图片描述


然后将 SRC的所有同名 .c 替换成为.o 形成目标文件列表 语法如下:
请添加图片描述
测试:
请添加图片描述
结果:
在这里插入图片描述


接下来 书写他们的依赖关系和方式
前置知识:

当我们gcc -c xxx.c 会自动生成对应的.o文件

在这里插入图片描述

这里的%.c\%.o表示文件里所有的XXX.c和XXX.o文件 %是一种通配符。
同时$< 指代规则中 “第一个依赖文件” 即 .c 文件 然后生成对应的 .o 文件 相当于将其展开成200行gcc -c XXX代码:
请添加图片描述
展示:
在这里插入图片描述


有了创建 肯定还要有清理
在这里插入图片描述
展示:
在这里插入图片描述

替换进阶内容(命令包装)

如果我们不光想编译C语言 而是别的语言呢? 所以 我们这里的Makefile还可以再次优化
在这里插入图片描述

至此 意味着我们可以把该Makefile放入任何目录 我们只需要改变”别名“就可以编译清除任何项目程序了。

2.5 $< 和 $^ 的区别(加餐)

Makefile 中,$^$< 都是 自动变量(预定义变量),核心区别在于 指代的依赖文件范围不同,适用场景完全不同,以下是清晰对比和实战示例:

一、核心区别总结表

自动变量核心含义关键特点适用场景
$<指代 第一个依赖文件只取依赖列表的「第一个」,忽略后续所有依赖1. 隐式规则(如 .c→.o 编译);
2. 核心依赖明确的场景(如链接时只需要第一个 .o 触发)
$^指代 所有依赖文件(自动去重)包含依赖列表中所有文件,重复依赖会合并1. 链接多个 .o 文件生成可执行程序;
2. 需用到所有依赖的场景(如打包、多文件编译)

二、示例(基于 test.exe 多文件场景)

假设项目有 2 个源文件(test.cutils.c)和 1 个头文件(common.h),最终生成 test.exe,通过示例看两者区别:

项目文件结构
test.c    # 主程序源码
utils.c   # 工具函数源码
common.h  # 公共头文件(两个 .c 文件都依赖)
Makefile  # 编译规则
Makefile 规则示例
# 定义变量:所有源文件、目标文件、可执行文件
SRC = test.c utils.c
OBJ = $(SRC:.c=.o)  # 推导目标文件:test.o、utils.o
BIN = test.exe# 规则1:生成可执行文件(依赖所有 .o 文件 + 头文件)
$(BIN): $(OBJ) common.hgcc $^ -o $@  # 这里必须用 $^,需链接所有 .o 文件# 展开后:gcc test.o utils.o common.h -o test.exe(头文件不影响编译,仅用于判断是否重新编译)# 规则2:生成目标文件(每个 .o 依赖对应的 .c 文件 + 头文件)
%.o: %.c common.hgcc -c $< -o $@  # 这里用 $<,仅需编译第一个依赖(.c 文件)# 对 test.o 展开:gcc -c test.c -o test.o# 对 utils.o 展开:gcc -c utils.c -o utils.o

求三连!!

http://www.dtcms.com/a/598980.html

相关文章:

  • 闵行区网站开发网站开发总体设计
  • 氧os哪个网站做的最好杭州互联网企业
  • 开课吧前端面试训练营
  • 宜春网站开发可以做c语言任务的网站
  • 青岛网站权重提升为什么不建议去外包公司
  • C#8、有哪些访问修饰符
  • 西安 h5网站建设ui培训完找工作没人要
  • 做外汇需要了解的网站中国企业500强全部名单
  • php后台网站开发企业宣传报道模板范文
  • 建站公司新闻资讯做自己的网站不是免费的
  • unique_ptr和shared_ptr的引用计数机制有何不同?
  • 用c# 制作一个扑克牌小游戏
  • 买了域名如何做网站南昌有哪些做网站的公司
  • 京东商品详情接口深度解析:从反爬绕过到数据结构化重构
  • 微网站制作电话做的网站被注销
  • @Transactional失效的几种情况
  • 一般什么行业做网站的多袜子技术支持深圳网站建设
  • 网站策划书撰写流程河北seo推广系统
  • Java 全栈 Devs【应用】:[特殊字符] Java 异常处理最佳实践
  • 在线一键建站系统禹城做网站
  • Yolo中的检测头
  • 张家界建设局网站电话号码模板建站费用
  • 走进Linux的世界:进程状态
  • 毕设做网站需要买域名么网站建设方案之目标
  • 交叉熵损失函数(Cross-Entropy Loss)个人理解
  • 结对编程:提升编程效率与团队协作的最佳实践 | 如何通过结对编程实现高效协作和代码质量提升
  • 缓存优化(SpringCache、XXL-JOB)
  • 网站建设长期待摊费用个人网站的留言板怎么做
  • 优惠劵网站怎么做srm系统
  • Hugging Face Gated 模型下载全攻略:解决 401/403 和访问受限问题