小伙伴们大家好,本片文章将会讲解
Linux
中项目自动化构建工具make/makefile
的相关内容。
如果看到最后您觉得这篇文章写得不错,有所收获,麻烦点赞👍、收藏🌟、留下评论📝。您的支持是我最大的动力,让我们一起努力,共同成长!
文章目录
- 1. 何为make/makefile
- 2. make/makefile的原理
- 3. makefile中的变量以及自动显示问题
- 4. makefile 目标文件的生成顺序
1. 何为make/makefile
当谈到在
Linux
中进行项目构建时,make
和makefile
是两个非常重要的工具。它们提供了一种自动化构建的方法,使得开发者能够轻松地编译和构建复杂的软件项目。下面我会分别介绍一下make
和makefile
。
⏳ make 简介⌛
make
是一个命令行工具(指令),用于自动化构建程序或项目。它通过读取一个称为makefile
的文件来确定构建项目所需的步骤。make
工具的核心理念是根据文件之间的依赖关系以及每个文件的修改时间,决定哪些文件需要重新编译,从而实现高效的构建。
⏳ makefile 简介⌛
makefile
是一个文本文件,其中包含了一系列规则和命令,用于指导make
工具如何构建项目。makefile
定义了项目中的各种组件(例如源文件、目标文件和依赖关系),以及如何将它们组合在一起以生成最终的可执行文件或库文件。
2. make/makefile的原理
⏳ 我们先来看一个例子:⌛
- 首先新建一个名为
code.c
的文件,并写入一段简单的代码:
# 新建名为code.c的文件 [dsj@alicloud-dsj lesson11]$ touch code.c # code.c中所输入的代码 #include <stdio.h> int main() { int i = 0; for (i = 0;i < 10; ++i) { printf("%d\n",i); } return 0; }
- 新建一个名为
makefile
或者Makefile
的文件,并在其中输入以下代码:
code.exe:code.c gcc -o code.exe code.c .PHONY: clean clean: rm -f code.exe
- 退出,并依次输入
make
和make clean
指令:
输入
make
指令:
[dsj@alicloud-dsj lesson11]$ ll total 20 -rw-rw-r-- 1 dsj dsj 116 May 9 21:33 code.c -rwxrwxr-x 1 dsj dsj 8360 May 9 21:38 code.exe -rw-rw-r-- 1 dsj dsj 79 May 9 21:36 makefile
输入
make clean
指令:
⏳ 原理解释⌛
看完之后我们可能对
make/makefile
有以下几点疑问:
1.
makefile
文件中的代码是什么意思;
2. 为什么输入make
就能生成code.exe
的文件,而不是make code.exe
;
接下来我来一一解释这几个问题:
问题1:makefile文件中的代码是什么意思:
我们把
code.exe
称为目标文件,code.c
称为依赖关系,下面的指令gcc -o code.exe code.c
称为依赖方法。
目标文件(targets):指定要构建的文件或操作的名称。这可以是可执行文件、目标文件、清理操作等。
依赖关系(Dependencies ):指定每个目标所依赖的文件或操作。如果某个目标的依赖文件发生了变化,那么该目标就需要重新构建。有时,依赖关系可以省略。依赖关系也可以有多个。
依赖方法(Commands):指定 make 工具执行的操作步骤。这些操作通常是编译源代码、链接目标文件、复制文件等。有时可以有多个依赖方法。
这个搞明白了,那clean
这个目标文件前面一行的.PHONY
又是什么意思呢?
我们先了解一个概念:
makefile
中的操作默认是只执行一次的,因为这样可以提高编译的效率。
.PHONY:.PHONY 是告诉 make 工具,该目标不是实际的文件,而是一个动作或操作,并且这个操作总是要被执行的。
总是要执行的意思就是只要你输入了指令
make clean
这个指令那么对应的操作方法就要被执行。
那么问题又来了,只执行一次是怎么做到的呢?
- 首先我们可以用命令
stat [filename]
来查看一个文件的修改时间;- 其次,对于每个要生成的目标文件要依赖于依赖关系,而我们也可以查看这些依赖关系中的文件的修改时间,也可以查看目标文件的修改时间;
- 如果 目标文件修改时间 先于 依赖文件的修改时间,说明依赖文件在编译后进行了修改,那么执行make指令,就 会 重新生成一个目标文件。
- 反之,如果 目标文件修改时间 晚于 依赖文件的修改时间,说明依赖文件并没有进行修改,那么执行make指令 就 不会 重新生成一个目标文件。
那我们来验证一下,看一下下面的例子吧:
目标文件 修改时间 晚于 依赖文件 修改时间的例子:
目标文件 修改时间 早于 依赖文件 修改时间的例子:
问题2: 为什么输入make
就能生成code.exe
的文件,而不是make code.exe
:
因为
make
指令会默认生成makefile
中的第一个目标文件。但是输入make code.exe
也是可以的。
3. makefile中的变量以及自动显示问题
在
makefile
中我们可以用$@
来代替目标文件,$^
来代替依赖关系文件,例如:
也是可以编译通过的😁!
在
makefile
中也是可以出现变量的,但是这里的变量和其他编程语言有些不同,先看个例子吧:
注意定义变量的时候不能出现空格,除非依赖多个文件!
也是可以编译通过的😁!
我们发现在每次输入
make
指令的时候都会打印出他所执行的指令,例如:
我们可以修改相关的`makefile`代码,只需要在每个依赖方法之前加上`@`符号即可,使得它不出现:
不加
@
符号:
make
一下会发现他把他所执行的指令和我们要让他打印的东西一起打印了:
加@
符号:
make
一下会发现他并没有把他所需要执行的指令打印出来,只打印了我们让他打印的东西:
4. makefile 目标文件的生成顺序
看一下这个makefile
文件:
源码:
code.exe: code.s
gcc -o $@ $^
code.o: code.s
gcc -o $@ -c $^
code.s: code.i
gcc -o $@ -S $^
code.i: code.c
gcc -o $@ -E $^
.PHONY:clean
clean:
rm -f code.i code.s code.o code.exe
如果我们直接
make
,由于找不到依赖文件code.s
,但是此时不会停止执行,会继续向下寻找,但是向下找到了code.o
文件,但是它的依赖文件是code.s
文件,因为此时没有code.c
文件,会继续向下寻找……
可以发现,这类似于递归的一个过程,没找到就会继续递归,直到找到为止。
当然如果最后还是找不到需要的依赖文件就会报错。
报错示例:
🤔当然,由于
make
指令默认生成的是第一个目标文件,所以指挥生成和第一个目标文件相关的内容,我们可以改一下顺序来验证一下,咱们将.o
放在第一个:
🤔那如果咱们再改一下顺序,把.o
需要的.s
文件不放在直接顺序上的下一个会怎么样呢?
🤔可以发现还是可以的,不会报错。
🐼所以说,只要
makefile
文件中给出了所需要的依赖文件,make
都能帮你找到,不会报错🎋