makefile简介与入门

一、makefile简介

在执行 make 之前,需要一个命名为 Makefile 的特殊文件来告诉 make 需要做什么,通常,make 工具主要被用来进行工程编译和程序链接。

当使用 make 工具进行编译时,工程中以下几种情况在执行 make 时将会被编译(重新编译):

1. 所有的源文件没有被编译过,则对各个 C 源文件进行编译并进行链接,生成最后的可执行程序;
2. 每一个在上次执行 make 之后修改过的 C 源代码文件在本次执行 make 时将会被重新编译;
3. 头文件在上一次执行 make 之后被修改。则所有包含此头文件的 C 源文件在本次执行 make 时将会被重新编译。

后两种情况是 make 只将修改过的 C 源文件重新编译生成.o 文件,对于没有修改的文件不进行任何工作。重新编译过程中,任何一个源文件的修改将产生新的对应的.o文件,新的.o 文件将和以前的已经存在、此次没有重新编译的.o 文件重新连接生成最后的可执行程序。



二、makefile规则介绍:

一个简单的 Makefile 描述规则组成:
TARGET... : PREREQUISITES...
COMMAND
...
...

target:规则的目标。通常是最后需要生成的文件名或者为了实现这个目的而必需的中间过程文件名。可以是.o文件、也可以是最后的可执行程序的文件名等。另外,目标也可以是一个make执行的动作的名称,如目标“clean”,我们称这样的目标是“伪目标”。

prerequisites:规则的依赖。生成规则目标所需要的文件名列表。通常一个目标依赖于一个或者多个文件。

command:规则的命令行。是规则所要执行的动作(任意的 shell 命令或者是可在shell 下执行的程序)。它限定了 make 执行这条规则时所需要的动作。

一个规则可以有多个命令行,每一条命令占一行。注意:每一个命令行必须以[Tab]字符开始,[Tab]字符告诉 make 此行是一个命令行。make 按照命令完成相应的动作。这也是书写 Makefile 中容易产生,而且比较隐蔽的错误。

命令就是在任何一个目标的依赖文件发生变化后重建目标的动作描述。一个目标可以没有依赖而只有动作(指定的命令)。比如 Makefile 中的目标“clean”,此目标没有依赖,只有命令。它所定义的命令用来删除 make 过程产生的中间文件(进行清理工作)。

make 程序根据规则的依赖关系,决定是否执行规则所定义的命令的过程我们称之为执行规则。


三、makefile简单实例:

该例子由三个头文件和8个c文件组成

#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
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


首先书写可以用一个反斜线(\)分解成多行。但需要注意:反斜线之后不能有空格(这也是大家最容易犯的错误,错误比较隐蔽)。

在这个Makefile中,我们的目标(target)就是可执行文件“edit”和那些.o文件(main.o,kbd.o....);

依赖(prerequisites)就是冒号后面的那些 .c 文件和 .h文件。

所有的.o文件既是依赖(相对于可执行程序edit)又是目标(相对于.c和.h文件)。命令包括 “cc –c maic.c”、“cc –c kbd.c”......

在描述依赖关系行之下通常就是规则的命令行,比如cc,命令行必需以[Tab]键开始,以和Makefile其他行区别。

就是说所有的命令行必需以[Tab] 字符开始,但并不是所有的以[Tab]键出现行都是命令行。但make程序会把出现在第一条规则之后的所有以[Tab]字符开始的行都作为命令行来处理。

目标“clean”不是一个文件,它仅仅代表执行一个动作的标识,正常情况下,不需要执行这个规则所定义的动作,因此目标“clean”没有出现在其它任何规则的依赖
列表中。因此在执行make时,它所指定的动作不会被执行。,它只有一个目的,就是通过这个目标名来执行它所定义的命令。Makefile中把那些没有任何依赖只有执行动作的目标称为“伪目标”(phony targets)。


四、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 文件的创建(第一次编译)或者更新之后,make 程序将处理终极目标“edit”所在的规则,分为以下三种情况:
1. 目标文件“edit”不存在,则执行规则以创建目标“edit”。
2. 目标文件“edit”存在,其依赖文件中有一个或者多个文件比它“更新”,则根据规则重新链接生成“edit”。
3. 目标文件“edit”存在,它比它的任何一个依赖文件都“更新”,则什么也不做。


更新(或者创建)终极目标的过程中,如果任何一个规则执行出现错误 make 就立即报错并退出。整个过程 make 只是负责执行规则,而对具体规则所描述的依赖关系的正确性、规则所定义的命令的正确性不做任何判断。就是说,一个规则的依赖关系是否正确、描述重建目标的规则命令行是否正确,make 不做任何错误检查。

因此,需要正确的编译一个工程。需要在提供给 make 程序的 Makefile 中来保证其依赖关系的正确性、和执行命令的正确性。



五、指定变量

在edit规则中,.o文件列表出现了两次,第一次:作为目标“edit”的依赖文件列表出现,第二次:规则命令行中作为“cc”的参数列表。样做所带来的问题是:如果我
们需要为目标“edit”增加一个的依赖文件,我们就需要在两个地方添加(依赖文件列表和规则的命令中)。

为了避免这个问题,在实际工作中大家都比较认同的方法是,使用一个变量“objects”、“OBJECTS”、“objs”、“OBJS”、“obj”或者“OBJ”来作为所有的.o 文件的列表的替代。在使用到这些文件列表的地方,使用此变量来代替。在上例的 Makefile中我们可以添加这样一行:

objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

“objects”作为一个变量,它代表所有的.o文件的列表。在定义了此变量后,我们就可以在需要使用这些.o文件列表的地方使用“$(objects)”来表示它,而不需要罗列
所有的.o文件列表。

objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
.......
.......
clean :
rm edit $(objects)



六、自动推导规则

在使用make编译.c源文件时,编译.c源文件规则的命令可以不用明确给出。这是因为make本身存在一个默认的规则,能够自动完成对.c文件的编译并生成对应的.o文件。它执行命令“cc -c”来编译.c源文件。

在Makefile中我们只需要给出需要重建的目标文件名(一个.o文件),make会自动为这个.o文件寻找合适的依赖文件(对应的.c文件。对应是指:文件名除后缀外,其余都相同的两个文件),比如main.o 对应的c文件就是main.c,对于上边的例子,此默认规则就使用命令“cc -c main.c -o main.o”来创建文件“main.o”。

这样,在书写 Makefile 时,我们就可以省略掉描述.c 文件和.o 依赖关系的规则,而只需要给出那些特定的规则描述(.o 目标所需要的.h 文件)。因此上边的例子就可以以更加简单的方式书写,我们同样使用变量“objects”。Makefile 内容如下:

# sample Makefile
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h
.PHONY : clean
clean :
rm edit $(objects)

make 的隐含规则在实际工程的 make 中会经常使用,它使得编译过程变得方便。几乎在所有的 Makefile 中都用到了 make 的隐含规则, make 的隐含规则是非常重要的一个概念。



七、标准风格的makefile

书写规则建议的方式是:单目标,多依赖。就是说尽量要做到一个规则中只存在一个目标文件,可有多个依赖文件。尽量避免使用多目标,单依赖的方式。



八、清除工作目录过程文件

规则除了完成源代码编译之外,也可以完成其它任务。例如:前边提到的为了实现清除当前目录中编译过程中产生的临时文件(edit 和那些.o 文件)的规则:

clean :
rm edit $(objects)

在实际应用时,我们把这个规则写成如下稍微复杂一些的样子。以防止出现始料未及的情况。

.PHONY : clean
clean :
-rm edit $(objects)

这两个实现有两点不同: 1. 通过“.PHONY”特殊目标将“clean”目标声明为伪目标。避免当磁盘上存在一个名为“clean”文件时,目标“clean”所在规则的命令无
法执行,2. 在命令行之前使用“-”,意思是忽略命令“rm”的执行错误。

转载于:https://www.cnblogs.com/sichenzhao/p/9320297.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值