做网站用什么浏览器,集团响应式网站建设,欧美专业牙科医院网站网页源码,做物流用哪个网站好Linux操作系统从入门到实战#xff08;十#xff09;Linux开发工具#xff08;下#xff09;make/Makefile的推导过程与扩展语法前言一、 make/Makefile的推导过程1. 先看一个完整的Makefile示例2. make的工作流程#xff08;1#xff09;寻找Makefile文件#xff08;2十Linux开发工具下make/Makefile的推导过程与扩展语法前言一、 make/Makefile的推导过程1. 先看一个完整的Makefile示例2. make的工作流程1寻找Makefile文件2确定最终目标3 检查最终目标是否需要更新4 从最终目标到中间文件5 反向执行命令从源文件到最终目标6 遇到错误立即停止7 核心逻辑只做“必要的事”二、make/Makefile的扩展语法1. 变量的妙用2. 自动变量3. 批量处理1模式规则一键编译所有 .c 文件2通配符函数自动找文件、改名字4. 高级小技巧5. 完整示例前言
前面的博客里我们讲解了Linux开发工具自动化构建-make/Makefile里的基础知识接下来我们继续讲解Linux开发工具自动化构建-make/Makefile里的细节make/Makefile的推导过程与扩展语法 我的个人主页欢迎来阅读我的其他文章 https://blog.csdn.net/2402_83322742?spm1011.2415.3001.5343 我的Linux知识文章专栏 欢迎来阅读指出不足 https://blog.csdn.net/2402_83322742/category_12879535.html?spm1001.2014.3001.5482 一、 make/Makefile的推导过程
1. 先看一个完整的Makefile示例
假设我们有一个名为myproc的程序对应的Makefile内容如下 # 最终目标生成可执行文件myproc依赖于中间文件myproc.o
myproc: myproc.ogcc myproc.o -o myproc # 通过链接myproc.o生成可执行文件myproc# 中间目标生成目标文件myproc.o依赖于汇编文件myproc.s
myproc.o: myproc.sgcc -c myproc.s -o myproc.o # 将汇编文件myproc.s编译为目标文件myproc.o# 中间目标生成汇编文件myproc.s依赖于预处理文件myproc.i
myproc.s: myproc.igcc -S myproc.i -o myproc.s # 将预处理文件myproc.i转换为汇编文件myproc.s# 中间目标生成预处理文件myproc.i依赖于源文件myproc.c
myproc.i: myproc.cgcc -E myproc.c -o myproc.i # 对源文件myproc.c进行预处理生成myproc.i# 伪目标清理所有编译过程中产生的中间文件和可执行文件
.PHONY: clean
clean:rm -f *.i *.s *.o myproc # 删除所有.i、.s、.o文件及myproc执行make命令的输出
当我们在终端输入make后会看到如下执行过程
$ make
gcc -E myproc.c -o myproc.i # 第一步预处理
gcc -S myproc.i -o myproc.s # 第二步生成汇编
gcc -c myproc.s -o myproc.o # 第三步生成目标文件
gcc myproc.o -o myproc # 第四步链接生成可执行文件整个过程就像“剥洋葱”——从最终目标出发逐层拆解依赖直到找到最原始的源文件再反向执行编译命令。 下面我们详细解释make是如何一步步完成这个过程的。
2. make的工作流程
在默认情况下即直接输入make命令工具的执行逻辑可以拆解为以下8个核心步骤
1寻找Makefile文件
make首先会在当前目录下搜索名为Makefile或makefile的文件注意大小写敏感推荐统一使用Makefile。如果找不到这两个文件会直接报错“没有规则可制作目标”。 2确定最终目标
找到Makefile后make会将文件中第一个目标作为“最终目标”。
在上面的例子中第一个目标是myproc可执行文件。因此make的最终任务就是生成myproc。 3 检查最终目标是否需要更新
确定最终目标后make会通过两个条件判断是否需要生成/更新myproc
若myproc不存在直接执行后续命令生成它若myproc已存在比较myproc和它的依赖文件myproc.o的修改时间。如果myproc.o的修改时间比myproc晚即myproc.o被更新过则需要重新生成myproc反之若myproc比myproc.o新说明myproc已是最新无需操作。 小技巧可以用touch 文件名命令手动更新文件的修改时间比如touch myproc.o测试make是否会重新执行命令。 4 从最终目标到中间文件 如果myproc需要更新或不存在make会检查它的依赖myproc.o
若myproc.o不存在在Makefile中寻找以myproc.o为目标的规则即myproc.o: myproc.s这一行然后根据规则生成myproc.o若myproc.o已存在同样比较myproc.o和它的依赖myproc.s的修改时间判断是否需要重新生成myproc.o。
这个过程会逐层递归
检查myproc.s是否存在/需要更新 → 依赖myproc.i检查myproc.i是否存在/需要更新 → 依赖myproc.c源代码文件。
直到找到最底层的依赖myproc.c——这是我们手动编写的源文件必须存在如果myproc.c缺失make会直接报错退出。
5 反向执行命令从源文件到最终目标
当确认所有依赖都已处理后make会按照依赖链的反向顺序执行命令
先执行gcc -E myproc.c -o myproc.i将源文件myproc.c预处理为myproc.i再执行gcc -S myproc.i -o myproc.s将myproc.i编译为汇编文件myproc.s接着执行gcc -c myproc.s -o myproc.o将myproc.s汇编为目标文件myproc.o最后执行gcc myproc.o -o myproc将myproc.o链接为可执行文件myproc。
整个过程就像“链式反应”——只有前一个中间文件生成后才能执行下一个步骤。
6 遇到错误立即停止
在依赖检查或命令执行过程中若出现以下情况make会直接退出并报错
某个依赖文件如myproc.c不存在命令执行失败如编译错误返回非0状态码。
但需要注意make只负责检查“依赖是否存在”和“命令是否执行”不负责检查命令的语法正确性比如把gcc写成gmake会执行命令但因错误退出。
7 核心逻辑只做“必要的事”
make的高效性体现在“增量编译”——它只会重新生成“过时”的文件。例如
若只修改了myproc.cmake会重新生成myproc.i、myproc.s、myproc.o和myproc若只修改了myproc.smake只会重新生成myproc.o和myproc无需处理myproc.i和myproc.c若所有文件都未修改make会直接提示“myproc已是最新”不执行任何命令。
二、make/Makefile的扩展语法
刚开始写 Makefile 时我们可能会像下面这样写
code: code.ogcc code.o -o code # 链接把 .o 变成可执行文件code.o: code.sgcc -c code.s -o code.o # 汇编.s 变 .ocode.s: code.igcc -S code.i -o code.s # 编译.i 变 .scode.i: code.cgcc -E code.c -o code.i # 预处理.c 变 .iclean:rm -f *.i *.s *.o code # 清理垃圾文件这看起来还行但问题大了
如果你把 code.c 改名叫 main.c上面所有提到 code 的地方都得改漏一个就报错。要是我们加了个新文件 tool.c又得复制粘贴一堆规则累得慌。
1. 变量的妙用
如果把经常用的文件名、命令起个外号改的时候只改外号是不是就方便了
这就是变量的作用。
比如下面这样
BINcode # 给可执行文件起个外号叫 BIN
CCgcc # 给编译器起个外号叫 CC
SRCcode.c # 给源文件起个外号叫 SRC
FLAGS-o # 给输出参数起个外号叫 FLAGS
RMrm -f # 给删除命令起个外号叫 RM$(BIN):$(SRC) # 用外号代替具体名字$(CC) $(FLAGS) $(BIN) $(SRC) # 相当于 gcc -o code code.cclean:$(RM) $(BIN) # 相当于 rm -f code现在如果要改文件名比如把 code.c 改成 main.c只需要改 SRCmain.c 就行其他地方不用动。
2. 自动变量
有时候规则里的文件名会重复。
比如 gcc -o code code.o 里code 出现了两次。要是文件名很长写起来超麻烦。这时候“自动变量”就派上用场了它们能自动代表规则里的目标或依赖文件。
常用的有三个
$代表当前规则的“目标文件”比如上面的 code。$^代表当前规则的“所有依赖文件”比如上面的 code.o。$代表当前规则的“第一个依赖文件”比如只有一个依赖时和 $^ 一样。
举个例子
$(BIN):$(OBJ) $(CC) -o $ $^ # 相当于 gcc -o code code.o$ 是 code$^ 是 code.oecho 正在把 $^ 变成 $ # 会打印正在把 code.o 变成 code%.o:%.c # 后面会讲这个先关注自动变量$(CC) -c $ # 相当于 gcc -c code.c$ 是 code.cecho 正在把 $ 变成 $ # 会打印正在把 code.c 变成 code.o是不是像用了“占位符”不用手写具体文件名Makefile 自动帮你填少写好多字。
3. 批量处理
如果你的项目有多个 .c 文件比如 a.c、b.c、c.c总不能每个都写一条编译规则吧这时候就需要“模式规则”和“通配符”来批量干活。
1模式规则一键编译所有 .c 文件
模式规则用 % 当通配符比如 %.o: %.c 表示“所有 .o 文件都由对应的 .c 文件生成”。
%.o: %.c # 只要有 x.c就自动生成 x.o$(CC) -c $ -o $ # 对每个 .c 文件执行gcc -c x.c -o x.o%.o: %.c # 只要有 x.c就自动生成 x.o现在不管你有 a.c、b.c 还是 c.c这条规则都能自动处理不用一个一个写
2通配符函数自动找文件、改名字
还有两个超实用的工具
wildcard帮你找出所有符合条件的文件。比如 SRC$(wildcard *.c)它会自动收集当前文件夹里所有 .c 文件不管有多少个。patsubst帮你批量改文件名。比如 OBJ$(patsubst %.c,%.o,$(SRC))意思是“把 SRC 里所有 .c 结尾的文件改成 .o 结尾”。
举个例子如果当前有 a.c、b.c那么
SRC$(wildcard *.c) # SRC 就等于 a.c b.c
OBJ$(SRC:.c.o) # 这是上面那句的简写OBJ 就等于 a.o b.o这下不用手动列所有文件了Makefile 会自动帮你找齐。
4. 高级小技巧
命令前的 和 -
命令前加 只显示命令的结果不显示命令本身。比如 echo 编译中...只会打印“编译中…”不会显示 echo 编译中...看起来更清爽。命令前加 -就算命令执行失败也继续往下跑。比如 -rm -f *.o就算没有 .o 文件也不会报错中断。
5. 完整示例
最后来看一个能应付大多数小项目的 Makefile我们一步步拆开看
BINproc # 可执行文件名叫 proc
CCgcc # 用 gcc 编译
SRC$(wildcard *.c) # 自动找所有 .c 文件
OBJ$(SRC:.c.o) # 把 .c 换成 .o比如 a.c → a.o
LFLAGS-o # 链接时的输出参数
FLAGS-c # 编译时的参数-c 表示只编译不链接
RMrm -f # 删除命令# 第一步链接所有 .o 文件生成可执行文件 proc
$(BIN):$(OBJ) $(CC) $(LFLAGS) $ $^ # 相当于 gcc -o proc a.o b.o自动找所有 .oecho 链接完成把 $^ 变成了 $ # 第二步编译每个 .c 文件成 .o 文件
%.o:%.c $(CC) $(FLAGS) $ # 相当于 gcc -c a.c自动处理每个 .cecho 编译中$ → $# 声明伪目标
.PHONY: clean test
clean: # 清理垃圾文件$(RM) $(OBJ) $(BIN) # 删除所有 .o 和 procecho 清理完毕test: # 测试变量内容echo 源文件列表$(SRC) echo 目标文件列表$(OBJ)这个 Makefile 会干以下事情
自动找出当前文件夹所有 .c 文件比如 a.c、b.c。自动算出需要生成的 .o 文件a.o、b.o。逐个把 .c 编译成 .o不用手动写每个规则。把所有 .o 链接成可执行文件 proc。提供 make clean 清理垃圾make test 查看文件列表。 以上就是这篇博客的全部内容下一篇我们将继续探索Linux的更多精彩内容。 我的个人主页 欢迎来阅读我的其他文章 https://blog.csdn.net/2402_83322742?spm1011.2415.3001.5343 我的Linux知识文章专栏 欢迎来阅读指出不足 https://blog.csdn.net/2402_83322742/category_12879535.html?spm1001.2014.3001.5482 非常感谢您的阅读喜欢的话记得三连哦