Linux之make的⽤法讲解
在 Linux环境下使⽤ GNU 的 make⼯具能够⽐较容易的构建⼀个属于你⾃⼰的⼯程,整个⼯程的编译只需要⼀个命令就可以完成编译、连接以⾄于最后的执⾏。不过这需要我们投⼊⼀些时间去完成⼀个或者多个称之为 Makefile ⽂件的编写。此⽂件正是 make 正常⼯作的基础。
make 是⼀个命令⼯具,它解释 Makefile 中的指令(应该说是规则)。在 Makefile⽂件中描述了整个⼯程所有⽂件的编译顺序、编译规则。准备知识:编译,链接,静态库,共享库
编译:把⾼级语⾔所书写的代码转换成机器可识别的指令,此时还不能够被执⾏,编译器通过检查⾼级语⾔的语法,函数和变量的声明是否正确!如果正确则产⽣中间⽬标⽂件(⽬标⽂件在Liunx中默认后缀为“.o”)
链接:将多.o ⽂件,或者.o ⽂件和库⽂件链接成为可被操作系统执⾏的可执⾏程序
静态库:⼜称为⽂档⽂件(Archive File)。它是多个.o⽂件的集合。Linux中静态库⽂件的后缀为“.a”
共享库:也是多个.o ⽂件的集合,但是这些.o ⽂件时有编译器按照⼀种特殊的⽅式⽣成(共享库已经具备了可执⾏条件)
在执⾏ make  之前,需要⼀个命名为 Makefile  的特殊⽂件(本⽂的后续将使⽤Makefile 作为这个特殊⽂件的⽂件名)来告诉 make 需要做什么(完成什么任务),该怎么做。
当使⽤make ⼯具进⾏编译时,⼯程中以下⼏种⽂件在执⾏make 时将会被编译(重新编译):
1.所有的源⽂件没有被编译过,则对各个 C 源⽂件进⾏编译并进⾏链接,⽣成最后的可执⾏程序;
2.每⼀个在上次执⾏ make 之后修改过的 C 源代码⽂件在本次执⾏make 时将会被重新编译;
3.头⽂件在上⼀次执⾏make 之后被修改。则所有包含此头⽂件的 C 源⽂件在本次执make 时将会被重新编译。
Makefile规则介绍
⼀个简单的 Makefile 描述规则组成:
< :
COMMAND
...
...
target:规则的⽬标。通常是最后需要⽣成的⽂件名或者为了实现这个⽬的⽽必需的中间过程⽂件名。可以是.o⽂件、也可以是最后的可执⾏程序的⽂件名等。另外,⽬标也可以是⼀个make执⾏的动作的名称,如⽬标“clean”(⽬标“clean”不是⼀个⽂件,它仅仅代表执⾏⼀个动作的标识。),我们称这样的⽬标是“伪⽬标”。
prerequisites:规则的依赖。⽣成规则⽬标所需要的⽂件名列表。通常⼀个⽬标依赖于⼀个或者多个⽂件。
command:规则的命令⾏。是规则所要执⾏的动作(任意的shell 命令或者是可在shell 下执⾏的程序)。它限定了make 执⾏这条规则时所需要的动作。
⼀个规则可以有多个命令⾏,每⼀条命令占⼀⾏。注意:每⼀个命令⾏必须以[Tab] 字符开始,[Tab]字符告诉 make 此⾏是⼀个命令⾏。make 按照命令完成相应的动作。
这也是书写 Makefile 中容易产⽣,⽽且⽐较隐蔽的错误。
命令就是在任何⼀个⽬标的依赖⽂件发⽣变化后重建⽬标的动作描述。⼀个⽬标可以没有依赖⽽只有动作(指定的命令)。⽐如Makefile 中的⽬标“clean”,此⽬标没有依赖,只有命令。它所定义的命令⽤来
删除 make 过程产⽣的中间⽂件(进⾏清理⼯作)。
在 Makefile  中“规则”就是描述在什么情况下、如何重建规则的⽬标⽂件,通常规则中包括了⽬标的依赖关系(⽬标的依赖⽂件)和重建⽬标的命令。make 执⾏重建⽬标的命令,来创建或者重建规则的⽬标(此⽬标⽂件也可以是触发这个规则的上⼀个规则中的依赖⽂件)。规则包含了⽂件之间的依赖关系和更新此规则⽬标所需要的命令。
⼀个 Makefile ⽂件中通常还包含了除规则以外的很多东西(后续我们会⼀步⼀步的展开)。⼀个最简单的Makefile 可能只包含规则。规则在有些 Makefile 中可能看起来⾮常复杂,但是⽆论规则的书写是多么的复杂,它都符合规则的基本格式。
make 程序根据规则的依赖关系,决定是否执⾏规则所定义的命令的过程我们称之为执⾏规则。
简单的⽰例
⼀个简单的Makefile,来描述如何创建最终的可执⾏⽂件“edit”,此可执⾏⽂件依赖于8个C源⽂件和3个头⽂件。Makefile⽂件的内容如下:
#sample Makefile
edit : main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
main.o : main.c defs.h
cc -c main.c
linux怎么读取文件
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
⾸先书写时,可以将⼀个较长⾏使⽤反斜线(\ )来分解为多⾏。但需要注意:反斜线之后不能有空格(这也是⼤家最容易犯的错误,错误⽐较隐蔽)。
在完成了这个Maekfile以后;需要创建可执⾏程序“edit”,所要做的就是在包含此Makefile的⽬录(当然也在代码所在的⽬录)下输⼊命
令“make”。删除已经此⽬录下之前使⽤“make”⽣成的⽂件(包括那些中间过程的.o⽂件),也只需要输⼊命令“make clean”就可以了。
make如何⼯作
默认的情况下,make执⾏的是Makefile中的第⼀个规则,此规则的第⼀个⽬标称之为“最终⽬的”或者“终极⽬标”(就是⼀个Makefile最终需要更新或者创建的⽬标)。
上例的 Makefile,⽬标“edit”在 Makefile 中是第⼀个⽬标,因此它就是make 的
“终极⽬标”。当修改了任何C 源⽂件或者头⽂件后,执⾏ make  将会重建终极⽬标
“edit”。
当在shell 提⽰符下输⼊“make”命令以后。make 读取当前⽬录下的 Makefile ⽂件,并将 Makefile ⽂件中的第⼀个⽬标作为其执⾏的“终极⽬
标”,开始处理第⼀个规则(终极⽬标所在的规则)。在上例中,第⼀个规则就是⽬标“edit”所在的规则。规则描述了“edit”的依赖关系,并定义了链接.o ⽂件⽣成⽬标“edit”的命令; make在执⾏这个规则所定义的命令之前,⾸先处理⽬标“edit”的所有的依赖⽂件(例⼦中的那些.o ⽂件)的更新规则(以这些.o ⽂件为⽬标的规则)。对这些.o ⽂件为⽬标的规则处理有下列三种情况:
1.  ⽬标.o ⽂件不存在,使⽤其描述规则创建它;
2.  ⽬标.o ⽂件存在,⽬标.o ⽂件所依赖的.c 源⽂件、.h ⽂件中的任何⼀个⽐⽬标.o⽂件“更新”(在上⼀次 make 之后被修改)。则根据规则重新编译⽣成它;
3.  ⽬标.o ⽂件存在,⽬标.o ⽂件⽐它的任何⼀个依赖⽂件(的.c 源⽂件、.h ⽂件) “更新”(它的依赖⽂件在上⼀次make 之后没有被修改),则什么也不做。
这些.o  ⽂件所在的规则之所以会被执⾏,是因为这些.o  ⽂件出现在“终极⽬标”的依赖列表中。在 Makefile  中⼀个规则的⽬标如果不是“终极⽬标”所依赖的(或者“终极⽬标”的依赖⽂件所依赖的),那么这个规则将不会被执⾏,除⾮明确指定执⾏这个规则(可以通过 make 的命令⾏指定重建⽬标,那么
这个⽬标所在的规则就会被执⾏,例如    “make  clean”)。在编译或者重新编译⽣成⼀个.o ⽂件时,make 同样会去寻它的依赖⽂件的重建规则(是这样⼀个规则:这个依赖⽂件在规则中作为⽬标出现),在这⾥就是.c 和.h ⽂件的重建规则。在上例的Makefile 中没有哪个规则的⽬标是.c或者.h ⽂件,所以没有重建.c 和.h ⽂件的规则
完成了对.o ⽂件的创建(第⼀次编译)或者更新之后,make 程序将处理终极⽬标“edit”所在的规则,分为以下三种情况:
1.  ⽬标⽂件“edit”不存在,则执⾏规则以创建⽬标“edit”。
2.  ⽬标⽂件“edit”存在,其依赖⽂件中有⼀个或者多个⽂件⽐它“更新”,则根据规则重新链接⽣成“edit”。
3.  ⽬标⽂件“edit”存在,它⽐它的任何⼀个依赖⽂件都“更新”,则什么也不做。
上例中,如果更改了源⽂件“insert.c”后执⾏make,“insert.o”将被更新,之后终极⽬标“edit”将会被重⽣成;如果我们修改了头⽂
件“command.h”之后运⾏“make”,那么“kbd.o”、“command.o”和“files.o”将会被重新编译,之后同样终极⽬标“edit”也将被重新⽣成。
指定变量
“objects”作为⼀个变量,它代表所有的.o⽂件的列表。在定义了此变量后,我们就可以在需要使⽤这些.o⽂件列表的地⽅使⽤“$(objects)”来表⽰��,⽽不需要罗列所有的.o⽂件列表。
make如何解析makefile⽂件
GUN make 的执⾏过程分为两个阶段。
第⼀阶段:读取所有的 makefile ⽂件(包括“MAKIFILES”变量指定的、指⽰符“include”指定的、以及命令⾏选项“-f(--file)”指定的 makefile ⽂件),内建所有的变量、明确规则和隐含规则,并建⽴所有⽬标和依赖之间的依赖关系结构链表。
第⼆阶段:根据第⼀阶段已经建⽴的依赖关系结构链表决定哪些⽬标需要更新,并使⽤对应的规则来重建这些⽬标。
总结
make 的执⾏过程如下:
1.依次读取变量“MAKEFILES”定义的 makefile ⽂件列表
2.读取⼯作⽬录下的 makefile⽂件(根据命名的查顺序“GNUmakefile”, “makefile”,“Makefile”,⾸先到那个就读取那个)
3.依次读取⼯作⽬录 makefile ⽂件中使⽤指⽰符“include”包含的⽂件
4.查重建所有已读取的 makefile ⽂件的规则(如果存在⼀个⽬标是当前读取的某⼀个makefile ⽂件,则执⾏此规则重建此 makefile ⽂件,完成以后从第⼀步开始重新执⾏)
5.初始化变量值并展开那些需要⽴即展开的变量和函数并根据预设条件确定执⾏分⽀
6.根据“终极⽬标”以及其他⽬标的依赖关系建⽴依赖关系链表
7.执⾏除“终极⽬标”以外的所有的⽬标的规则(规则中如果依赖⽂件中任⼀个⽂件的时间戳⽐⽬标⽂件新,则使⽤规则所定义的命令重建⽬标⽂件)
8.执⾏“终极⽬标”所在的规则
说明:
执⾏⼀个规则的过程是这样的:
对于⼀个存在的规则(明确规则和隐含规则)⾸先,make程序将⽐较⽬标⽂件和所有的依赖⽂件的时间戳。如果⽬标的时间戳⽐所有依赖⽂件的时间戳更新(依赖⽂件在上⼀次执⾏make之后没有被修改),那么什么也不做。否则(依赖⽂件中的某⼀个或者全部在上⼀次执⾏make后已经被修改过),规则所定义的重建⽬标的命令将会被执⾏。这就是make⼯作的基础,也是其执⾏规制所定义命令的依据。