Linux项目自动化构建工具---make/makefile
Posted 做1个快乐的程序员
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux项目自动化构建工具---make/makefile相关的知识,希望对你有一定的参考价值。
💦不知道大家有没有听说过这样的一句话,不会写makefile就不算一个程序员。这家伙好啊,直接把我程序员的饭碗砸了,这我能忍???为了保住大家的饭碗,我来给各位读者详细解读一下make/makefile。💦
小编奉劝各位不要轻易说一些不经过思考的话,毕竟我辉辉都说过,砸人饭碗,堪比杀生。要不然你预购的diss已经在路上了。废话不说了,让我们进入今天的主题。
1、make/makefile的引出
1.1 代码编写
今天我们通过一组测试用例来开始今天的话题,我们在一个csdn的目录下创建main.c、test.c、test.h三个文件。
使用vim工具对三个文件的内容进行编辑。
|
|
|
我们在test.h中放了test函数的声明,在test.c函数中实现了test函数,然后在main.c中调用该函数。这样我们就把三个文件的内容写好了。
1.2 代码编译
疑问一: 下面我们要进行编译,怎么进行编译呢?用哪几个文件进行编译呢?
答:我们使用gcc编译器,然后生成可执行程序,可执行程序的生成一定是编译源文件,即.c文件,所以我们:gcc -o mytest main.c test.c这样就会生成一个可执行程序。
[xd@VM-4-5-centos csdn]$ gcc -o mytest main.c test.c
[xd@VM-4-5-centos csdn]$ ll
total 24
-rw-rw-r-- 1 xd xd 57 Aug 5 20:21 main.c
-rwxrwxr-x 1 xd xd 8416 Aug 5 20:23 mytest
-rw-rw-r-- 1 xd xd 68 Aug 5 20:21 test.c
-rw-rw-r-- 1 xd xd 89 Aug 5 20:23 test.h
疑问二: 这里大家可能会有疑问,为什么我们的头文件不参与编译呢?难道头文件没有作用吗?
答:编译器在参与编译的时候,头文件展开是在预处理阶段,编译器在参与编译的时候,头文件展开是在预处理阶段,第一步就完成了,我们的gcc在编译源文件时,不需要显示的去指明我们需要那些头文件,但是必须要让编译器找到所需要的头文件。 在本例中,编译器是可以找到所需要的头文件的,因为头文件就在当前目录下,即我们在编译main.c和test.c两个源文件时,所需要的头文件test.h在和源文件同等目录的位置,所以gcc可以帮我们找到。我们把test.h剪切到上一层目录,重新gcc编译两个源文件,就会报错,显示没有test.h文件。
总结:我们的编译器需要头文件,在编译器看来,不用显示的告诉我头文件是谁,因为源文件中已经告诉我我要包含谁了。但是要帮我找到头文件,在默认的情况下,
a:编译器会去源文件同等位置目录寻找头文件;
b:标准库指定的头文件目录,像#include <stdio.h> 等头文件所在的目
录,/user/include/stdio.h就是标准库指定的目录。
我们在写C语言的时候学过,包含头文件的方式有两种,A:<>;B:””。<>表示去标准库指定目录寻找头文件,””表示去源文件所在同等目录去寻找头文件。
1.3 编译分类
我们将源文件编译成二进制目标文件有两种方法:
法一:gcc -o mytest main.c test.c直接生成二进制目标文件
法二:gcc -c main.c -o main.o和gcc -c test.c -o test.o,先生成两个目标文件,然后链接两个目标文件,gcc -o mytest main.o test.o
在上述两种方法中,我们常用和推荐的是法二,之所以推荐是因为:a:我们在写项目时有成千上百个.c源文件,我们有可能会用不同的源文件生成不同的可执行程序,我们如果先将其都转为.o二进制目标文件,想用那几个文件生成可执行文件,直接用命令行生成就可以。b:比如我们有100个源文件,我们每次都gcc -o mytest +100个.c文件,如果有一个.c文件更改了,我们都要全部重新编译链接,但是我们如果生成.o文件,那个文件更改了,只重新编译一下更改的那个源文件,让他生成一个.o文件即可。会提升编译效率。
那么问题又来了,我们有成千上百个源文件,总不能每次都,这样工作量无疑是巨大的,这就有了我们的make/makefile。
2、make/makefile是什么
make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
总结来说:make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
3、make/makefile的使用
对于make/makefile的使用我们也是通过一个测试用例来理解:
3.1 make/makefile简要示例
首先,我们创建一个test.c文件,里面有一个打印”hello make/makefile!”的代码,然后创建一个makefile或者Makefile的文件,m大写小写都可以,touch Makefile。Makefile文件中放的是一组我们所依赖的关系、依赖的方法,我们直接vim Makefile,里面写依赖方法和依赖关系,具体怎么写呢?
第一行写依赖关系,如:mytest:test.c(即mytest的生成依赖test.c文件)
第二行写依赖方法,必须以Tab开头,不能用空格代替,然后gcc -o mytest test.c
写完以后,如果我们想要编译test.c源文件,直接make,此时就会自动执行Makefile中的依赖关系,帮我们生成一个mytest可执行程序,以后我们不管对test.c文件做了何种修改,不需要再敲写gcc等一系列指令,直接make,就会帮我们编译。
3.2 make/makefile详细示例
通过对上面代码的分析,我们暂时了解了makefile中的依赖关系和依赖方法,其实3.1中的makefile的依赖关系是简略版,我们的mytest实际依赖的是mytest.o,而我们的mytest.o依赖的是mytest.s,mytest.s依赖的是mytest.i,mytest.i最终才是依赖test.c,那么我们重新修改一下makefile,看一下完整的makefile。(实际在真正应用中,我们并不会写的如此详细,这里是为了帮助大家理解。)
不管是详细版makefile和简要版makefile最终都会生成一个可执行程序,我们运行就会得到结果。
3.3 clean清理项目文件
生成项目的步骤我们会了,那么该怎么清理项目文件呢?在生成项目的过程中,产生了很多临时文件,这时候我们vim Makefile,再添加一些信息。
对于clean,它是没有依赖文件的,直接回车+tab写依赖方法,依赖方法就是我们要清理的项目文件。这里需要注意的是,我们在clean上面添加了这样的信息:.PHONY:clean。
我们可以将.PHONY这个理解为makefile中的某种关键字的概念,用它来修饰我们的clean,此时clean就是一个伪目标的概念;上面的mytest、test.o等都称为目标。伪目标也是目标,也是要根据依赖关系来执行依赖方法,clean没有依赖关系,直接执行依赖方法。
经过以上的修改,makefile就算写完了。我们make执行,会生成可执行程序及一些临时文件,make clean就会清理我们的临时文件,所以我们写好makefile命令后,直接make、make clean就可以了,不需要重复写gcc等一系列命令了。(make clean和make可以同时依次执行,输入指令:make clean;make即可)
|
|
3.4 伪目标
clean之前是目标,被.PHONY修饰后变为伪目标,伪目标的特点是: 它的依赖方法总是被执行,make一遍后再make,就会提示生成的mytest已经是最新的了,但是make clean之后,还可以一直make clean,所以一般我们将清理命令clean定义为伪目标,对于可执行程序没必要定义为伪目标。
|
|
4、make是如何工作的
- make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
- 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“mytest”这个文件,并把这个文件作为最终的目标文件。
- 如果mytest文件不存在,或是mytest所依赖的后面的mytest.o文件的文件修改时间要比mytest这个文件新(可以用 touch 测试),那么,他就会执行后面所定义的命令来生成mytest这个文件。
- 如果mytest所依赖的mytest.o文件不存在,那么make会在当前文件中找目标为mytest.o文件的依赖性,如果找到则再根据那一个规则生成mytest.o文件。(这有点像一个堆栈的过程)
- 当然,你的c文件和h文件是存在的啦,于是make会生成 mytest.o 文件,然后再用 mytest.o 文件声明make的终极任务,也就是执行文件mytest了。
- 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
- 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
- make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。
5、扩展知识(三种特殊符号)
三种特殊符号:
@
、
@、
@、^、$<
上图中,在对应位置替换上特殊符号后,make和make clean正常运行。
$@:依赖关系中的目标文件(即:左侧的文件)
$^: 依赖关系中的依赖文件列表(即:右侧的所有文件)
&<:依赖关系中的一个依赖文件
以上是关于Linux项目自动化构建工具---make/makefile的主要内容,如果未能解决你的问题,请参考以下文章
喵呜:Linux环境基础开发工具使用篇之Linux开发工具:Linux项目自动化构建工具-make/Makefile
Linux环境开发工具gdb调试工具+Makefile自动化构建工具