目录
- 一、自动化构建
- 二、make/Makefile
- 2.1 见识一个简单的make/Makefile
- 2.2 Makefile的基本语法
- 2.3 Makefile的语法细节
个人主页<—请点击
Linux专栏<—请点击
一、自动化构建
自动化构建是指通过构建工具(如make
)解析构建脚本(如Makefile
),自动执行一系列步骤(编译、链接等)以将源代码生成可执行程序或库的过程。
想象一下你要编译一个大型C++
项目,比如一个游戏引擎,它有成千上万个源文件.cpp
和头文件.h
。
如果没有自动化构建,你会怎么做?你可能会在终端里输入一条巨长的命令:g++ main.cpp renderer.cpp physics.cpp audio.cpp network.cpp ...(列出所有文件) -o MyGameEngine -lSDL2 -lOpenGL ...
,这种方法效率低下、容易出错、无法复用,并且依赖管理困难。自动化构建就是为了解决这些问题而生的。
所以会不会写Makefile
,从侧面说明了一个人是否具备完成大型工程的能力。在Windows
下vs
帮我们做了自动化构建,而在Linux
下我们需要使用make/Makefile
完成对自动化项目的构建。
上述我们所说的make
和Makefile
,其中前者是一条命令,而后者是一个文件。后者也可以写成makefile
。
二、make/Makefile
2.1 见识一个简单的make/Makefile
现在我们在我们的当前目录下准备了一份文件code.c
,里面写了一些代码,现在我要使用make
对它进行编译。我们开始创建Makefile
文件,并在其中写入以下指令:
我们执行make
命令对code.c
进行编译。
如上图,make
命令自动执行了我在Makefile
文件中写入的指令生成了可执行文件!
那么Makefile
中写的那两行究竟是什么意思呢?接着往下看。
如上图,形成code.exe
目标文件需要依赖code.c
文件,而解决依赖关系需要依赖下面的依赖方法gcc -o code.exe code.c
,所以依赖关系和依赖方法共同构成了形成可执行程序的语义。
2.2 Makefile的基本语法
其中上面的 依赖方法一行必须以Tab键
开头,且对应的依赖方法可以是多条,接下来我们依据上期博客讲解的编译的详细过程进行编写Makefile
文件。注意:Makefile
里面想要注释是#
。
执行make
命令:
如上图,make
命令会解析Makefile
文件,解析过程中会形成推导栈,这个栈中是依赖方法的集合,直到找到存在的依赖文件时就会执行相应的依赖方法,然后依次出栈,就形成了上图中依次运行的指令。如果make
推导失败了它就会报错。
Makefile
其实就是一种脚本语言,make
要从最终目标code.exe
开始,递归地向下检查依赖,再向上决定是否构建。这个过程是深度优先的。
当然我们实际的写法可不会这样写,太麻烦了。
接下来我们学习一个新的语法,我们在vs
下不仅要能够生成可执行程序,我们还需要能够清理呀,所以接下来清理可执行程序。
其中.PHONY
的作用是声明一个符号clean
是伪目标。 clean
的依赖方法是清理可执行程序,这样就可以清理了。
从上面clean
的执行操作,我们可以知道 make
命令后面可以直接跟“目标名” 。
如上图,make
命令后面跟谁就会解析谁的依赖关系和依赖方法,并且make
命令默认只会推导一条完整的链路。
现在我把.PHONY:clean
部分放在前面,再执行make
命令。
所以单独执行make
指令,默认只推导第一个依赖关系对应的推导链。
.PHONY
:用来修饰一个目标文件是伪目标,这个我们刚讲过。伪目标的本质是总是被执行的。像我们的形成code.exe
的命令通常情况下只能被执行一次。
而当我们对code.exe
进行修饰后就可以一直执行了。
不建议.exe
被.PHONY
修饰,这样能够加快编译的效率,而且当你的源文件再次被修改后,就又可以进行编译操作了。
那么无法二次编译老项目是如何做到的呢? 答案是通过比较创建时间的新旧。
在Linux
下有一个stat
命令,可以查看文件的相关时间信息。
当源文件code.c
文件内容被更改时间比code.exe
的文件内容被更改时间新,make
就允许进行重新编译。而被.PHONY
修饰能够总是执行,是让make
工具忽略了时间对比。
扩充:上图中,文件内容被更改时Modify
时间会更改,文件属性被更改时Change
时间会更改,文件被访问特定次数后,Access
时间会更改。
2.3 Makefile的语法细节
我们在了解基本语法的时候,我们发现编译、清理的过程,make
会将执行命令回显出来,为了不让它回显出来,可以在命令前加上@
。
现在假设我要对生成的文件名进行修改,我还要一个名称一个名称更改,太麻烦了吧,所以我们使用变量对Makefile
做出大的更改!
如上图所示,我对Makefile
文件进行了更改,接下来我们逐行分析。首先定义了两个变量名BIN
和SRC
分别代表目标文件和源文件,注意=
两侧不要加空格。下面的$()
的作用相当于提取变量名对应的文件。第五行中的$@
和$^
是自动变量,前者代表目标文件,后者代表依赖文件。
很好,现在我们能够编译一个源文件了,那如果源文件有100
个呢?
如上图,创建了100
个源文件,现在我们要将他们编译性成一个可执行程序。我们要按照下图的方式进行编译:
首先,如何获取这100
个源文件就是一个问题,一个个写吗? 当然不行,这里我们可以使用shell
命令ls
进行获取,或者使用Makefile
中自带的wildcard
函数获取。
这就是两种获取源文件的方法,第一个是执行ls
命令将列出的源文件提取写入到SRC
中,第二个是使用指定函数获取源文件。
接下来完成Makefile
的编写。
为了获取.o
文件,我们还要定义一个变量OBJ
,其中SRC:.c=.o
是将SRC
的所有同名.c
替换成为.o
形成目标文件列表。接下来又对gcc、rm -rf、echo
命令进行了包装。然后在编译的过程将每个文件的.c
变.o
的过程和.o
变可执行程序的过程使用echo
打印了出来。
另外%.c
展开当前目录下所有的.c
,%.o
: 同时展开当前目录下所有的.o
。gcc -c code.c -o code.o
这个命令的-o code.o
部分也可以去掉,所以就变成了上图中这样,%<
是将展开的依赖.c
文件,⼀个⼀个的交给gcc
。
如上图执行make
命令,它就自动将100
个源文件先编译成.o
,然后再进行链接编译成了可执行程序code.exe
。我们试着运行一下。
如上图再make clean
它就自动将形成的.o
及可执行程序清除了!
总结:
以上就是本期博客分享的全部内容啦!如果觉得文章还不错的话可以三连支持一下,你的支持就是我前进最大的动力!
技术的探索永无止境! 道阻且长,行则将至!后续我会给大家带来更多优质博客内容,欢迎关注我的CSDN账号,我们一同成长!
(~ ̄▽ ̄)~