Makefile的使用

Makefile基础

当小伙伴们搜索Makefile怎么使用的时候,肯定事先对Makefile有一个大概的了解,所以Makfile是什么本篇文章就不做过多的解释,直接讲述详细操作。

C语言编译过程

在讲述Makefile使用之前,必须要先了解一下C语言编译的过程,以及对应的编译命令,这对接下来的Makefile的使用至关重要。

C语言从源代码生成可执行文件的过程有四步,分别是预处理、编译、汇编、链接,其过程如下图:
在这里插入图片描述
接下来的演示操作都以一个hello.c、hello.h文件为操作对象。
预处理阶段:
将编写好的.c和.h文件进行预处理,生成.i预处理文件。预处理过程主要操作有:头文件包含、宏定义的替换、条件编译、去除注释、添加行号。可以使用以下命令来完成预处理操作:

gcc -E hello.c hello.h -o hello.i

编译阶段:
编译就是把预处理完的.i文件进行一些列的词法分析、语法分析、语义分析以及优化后生成相应的.s汇编文件。编译是整个程序构建的核心部分,也是最复杂的部分之一,涉及到的算法较多,有兴趣的可以去看《编译原理》。可以使用以下命令来完成汇编操作:

gcc -S hello.i -o hello.s

汇编阶段:
汇编的过程就是将.s汇编文件转换成.o目标文件。过程中会将汇编代码转换成及其支流,大部分汇编语句对应一条机器指令,有的汇编语句对应多条机器指令。可以使用以下命令来完成汇编操作:

#此处的-c为小写,千万不要写成大写
gcc -c hello.s -o hello.o

链接阶段:
在上一步的汇编操作完成后,目标文件已经是二进制文件,与可执行文件的组织形式类似,只是有些函数和全局变量的地址还未找到,程序不能执行。链接的作用就是找到这些目标地址,将所有的目标文件组织成一个可以执行的二进制文件。可以使用以下命令完成链接操作:

#通常gcc会自动在标准库目录中寻找链接文件。因此当没有使用非标准库或者第三方库需要链接时,不需要指定链接文件或路径
gcc hello.o -o hello
#有非标准库或第三方库需要链接时,需要指定非标准库或第三方链接库,此时有三种操作:
	#第一种是使用-l指定标准库,例如<math.h>,此时-l后紧跟的是math.h库的缩写 m
	gcc hello.o -o hello -lm
	#第二种是直接指定链接文件的绝对路径,例如
	gcc hello.o -o hello /usr/lib/libm.a
	#第三种是使用-L指定链接文件的目录
	gcc hello.o -o hello -L/usr/lib -lm

其实,也可以一步实现从.c文件生成对应的可执行文件,或者从上述的任何一步直接生成对应的可执行文件,其命令如下:

#从.c文件生成可执行文件
gcc hello.c hello.h -o hello
#从.i文件生成可执行文件,以此类推
gcc hello.i -o hello

虽然最后这一个步骤比较简单,可以一步生成可执行文件,但仍需要对C语言的编译流程有一个详细的了解。

以上所讲述的命令仅为完成每个步骤的基础的命令,每个命令还有多个可以选择的选项,具体有关的更多更详细的知识请读者自行查阅。此处贴出我所参考的教程,具体可查看GCC教程中10-16章节,链接贴在此处:
点击此处,跳转到GCC教程

Makefile的规则

先来粗略的看下Makefile的规则:

target : prerequisites
command
target也就是一个目标文件(此处的目标文件是指你想要生成的文件,而非上述的.o目标文件),可以是Object File,可以是执行文件,也可以是一个标签(Label)。对于标签的特性,会在后续的”伪目标“知识中讲解。
prerequisites就是要生成的目标文件所需要的文件或者是目标,也称之为生成目标文件所依赖的文件。
command也就是make需要执行的命令。(是任意的shell命令,包括但不限于上一小节中讲述的C语言编译过程命令)。

这个规则讲述的是一个文件的依赖关系。也就是说,target这一个或多个目标文件依赖于prerequisites中的文件,其生成的规则定义在command中。说明白点的解释就是,从prerequisites中的文件生成target中的目标文件,而生成目标文件所使用的命令就是command命令。如果prerequistes中如果有一个以上的文件比target文件要新的话,说明工程中的某个或多个源文件就有被修改,此时command所定义的命令就会被执行,这就是Makefile的规则,也就是Makefile中最为核心的内容。因此,当我们在编写一个多文件项目的Makefile时,只需要将相关的编译规则和依赖文件给写清楚,后续的工程管理就可以省去很多麻烦。

接下来,就还以上述的hello.c和hello.h文件编写一个Makefile示例。首先创建一个名字为makefile或者Makefile的文件(注意:一个工程中或者说一个目录下只能有一个名为makefile的文件,大小写无所谓,但是只能有一个!!!)。在新建的makefile文件中写入如下代码,注意command命令前必须是一个tab键(而且这个tab键必须是4个空格,多一个少一个都不行,格式必须严格的控制)。

hello : hello.o
	gcc hello.o -o hello
hello.o : hello.c hello.h
	gcc hello.c hello.h -o hello

clean:
	rm -r hello.o hello

此处,对最后两行代码说明一下,clean不是一个文件,它是一个动作的名字,clean冒号后面什么都没有,所以Make不会主动去寻找文件的依赖性,即不会自动执行其后面定义的命令,而在需要使用后面定义的命令时,可以在make后面指出这个lable的名字。这种方法很有用,比如我们可以在makefile文件中定义不用的编译或者和编译无关的命令,例如程序的打包,程序的备份,工程中的中间文件的清理等等。
此时,当我们在终端中输入make,当前目录下的项目就会自动根据makefile文件中的依赖关系进行编译,生成对应的文件,而当编译出错或者修改过源文件后,就可以通过执行make clean命令删除修改源文件前的中间文件和目标文件,然后再次输入make命令即可生成新的可执行文件。

make是如何工作的

当我们输入make命令后,make会执行以下流程:
1、make会在当前目录下寻找名为”makefile“或者"Makefile"的文件。
2、如果找到文件,那么它就会找到文件中的第一个目标文件(target),在上面的例子中,它会找到hello文件,并把这个文件作为最终的目标文件
3、如果最终的目标文件hello不存在,或者说所依赖的后面的.o文件的文件修改时间比这个hello文件新,那么就会执行后面所定义的命令来生成这个文件。接下来,当hello.o文件的依赖文件不存在,或者所依赖的文件的文件修改时间比hello.o新,那么就会执行相应的命令。以此类推,直到最后一条命令(clean命令除外,它并不会自动去执行这条命令,而是需要用户使用make clean主动调用)。

这就是整个make的依赖性,它会一层一层的去寻找文件之间的依赖关系,直到最终编译出第一个目标文件。在寻找的过程中,如果出现错误,比如最后被依赖的文件找不到,make就会直接退出,并报错。而如果是相关的command命令出现语法错误,或者编译不成功,make根本不会理。因为make只管文件的依赖性。

至此,make的最基本的使用就已经差不多了。但是Make还有很多很灵活的用法,比如使用变量,make的自动推导,make中显式规则,隐式规则,伪目标,多目标,自动生成依赖性等。会makefile会使你的项目管理变得轻松,如果会makefile的高级使用方法,则会让你在编写大型的项目的makefile中更轻松,更灵活。接下来会在相关的后续文章中继续介绍更多的关于makefile的使用方法。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骑猫去洱海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值