Makefile总述

一、makefile文件的命名

默认的情况下,make 会在工作目录(执行 make 的目录)下按照文件名顺序寻找makefile 文件读取并执行,查找的文件名顺序为:“GNUmakefile”、“makefile”、
“Makefile”。

通常应该使用“makefile”或者“Makefile”作为一个 makefile 的文件名(我们推荐使用“Makefile”,首字母大写而比较显著,一般在一个目录中和当前目录的一些重
要 文 件 ( README,Chagelist 等 ) 靠 近 , 在 寻 找 时 会 比 较 容 易 的 发 现 它 )。 而“GNUmakefile”是我们不推荐使用的文件名,因为以此命名的文件只有“GNU make”才可以识别,而其他版本的 make 程序只会在工作目录下“makefile”和“Makefile”这两个文件。

当 makefile 文件的命名不是这三个任何一个时,需要通过 make 的“-f”或者“--file”选项来指定 make 读取的 makefile 文件。给 make 指定 makefile 文件的格式为:“-f
NAME”或者“—file=NAME”,它指定文件“NAME”作为执行 make 时读取的 makefile文件。也可以通过多个“-f”或者“--file”选项来指定多个需要读取的 makefile 文件,
多个 makefile 文件将会被按照指定的顺序进行链接并被 make 解析执行。当通过“-f”或者“--file”指定 make 读取 makefile 的文件时,make 就不再自动查找这三个标准命名的 makefile 文件。


二、包含其他makefile文件

如何在一个 Makefile 中包含其它的 makefile 文件。Makefile 中包含其它文件所需要使用的关键字是“include”,和 c 语言对头文件的包含方式一致。

“include”指示符告诉 make 暂停读取当前的 Makefile,而转去读取“include”指定的一个或者多个文件,完成以后再继续当前 Makefile 的读取。Makefile 中指示符
“include”书写在独立的一行,其形式如下:

include FILENAMES...

来看一个例子,存在三个.mk 文件 a.mk、b.mk、c.mk,“$(bar)”被扩展为“bish bash”。则

include foo *.mk $(bar)
等价于
include foo a.mk b.mk c.mk bish bas

通常指示符“include”用在以下场合:

1. 有多个不同的程序,由不同目录下的几个独立的Makefile来描述其重建规则。它们需要使用一组通用的变量定义或者模式规则,通用的做法是将这些共同使用的变量或者模式规则定义在一个文件中,在需要使用的Makefile中使用指示符“include”来包含此文件。

2. 当根据源文件自动产生依赖文件时;我们可以将自动产生的依赖关系保存在另外一个文件中,主Makefile使用指示符“include”包含这些文件。这样的做法
比直接在主Makefile中追加依赖文件的方法要明智的多。其它版本的make已经使用这种方式来处理。

如 果 指 示 符 “ include ” 指 定 的 文 件 不 是 以 斜 线 开 始 ( 绝 对 路 径 , 如/usr/src/Makefile...),而且当前目录下也不存在此文件;make将根据文件名试图在以下几个目录下查找:首先,查找使用命令行选项“-I”或者“--include-dir”,如果找到指定的文件,则使用这个文件;否则继续依此搜索以下几个目录(如果其存在):“/usr/gnu/include”、“/usr/local/include”和“/usr/include”。

当在这些目录下都没有找到“include”指定的文件时,make将会提示一个包含文件未找到的告警提示,但是不会立刻退出。而是继续处理Makefile的后续内容。当完成读取整个Makefile后,make将试图使用规则来创建通过指示符“include”指定的但未找到的文件,当不能创建它时(没有创建这个文件的规则),make将提示致命错误并退出。

通常我们在 Makefile 中可使用“-include”来代替“include”,来忽略由于包含文件不存在或者无法创建时的错误提示(“-”的意思是告诉 make,忽略此操作的错误make 继续执行)。像下边那样:

-include FILENAMES...



三、makefile文件的重建

Makefile 可由其它文件生成,例如 RCS 或 SCCS 文件。如果 Makefile 由其它文件重建,那么在 make 在开始解析这个 Makefile 时需要重新读取更新后的 Makefile、而不是之前的 Makefile。make 的处理过程是这样的:

make 在读入所有 makefile 文件之后,首先将所读取的每个 makefile 作为一个目标,寻找更新它们的规则。如果存在一个更新某一个 makefile 文件明确规则或者隐含规则,就去更新对应的 makefile 文件。完成对所有的 makefile 文件的更新之后,如果之前所读取任何一个 makefile 文件被更新,那么 make 就清除本次执行的状态重新读取一遍所有的 makefile 文件(此过程中,同样在读取完成以后也会去试图更新所有的已经读取的 makefile 文件,但是一般这些文件不会再次被重建,因为它们在时间戳上已经是最新的)。读取完成以后再开始解析已经读取的 makefile 文件并开始执行必要的动作。

实际应用中,我们会明确给出makefile文件,而并不需要来由make自动重建它们。但是make在每一次执行时总会自动地试图重建那些已经存在的makefile文件,如果需要处于效率考虑,可以采用一些办法来避免make在执行过程时查找重建makefile的隐含规则。例如我们可以书写一个明确的规则,以makefile文件作为目标,规则的命令定义为空。


四、make如何解析makefile文件

GUN make 的执行过程分为两个阶段。

第一阶段:读取所有的 makefile 文件(包括“MAKIFILES”变量指定的、指示符“include”指定的、以及命令行选项“-f(--file)”指定的 makefile 文件),内建所有的
变量、明确规则和隐含规则,并建立所有目标和依赖之间的依赖关系结构链表。

第二阶段:根据第一阶段已经建立的依赖关系结构链表决定哪些目标需要更新,并使用对应的规则来重建这些目标。

理解 make 执行过程的两个阶段是很重要的。它能帮助我们更深入的了解执行过程中变量以及函数是如何被展开的。变量和函数的展开问题是书写 Makefile 时容易犯错和引起大家迷惑的地方之一。

首先,明确以下基本的概念;在 make 执行的第一阶段中如果变量和函数被展开,那么称此展开是“立即”的,此时所有的变量和函数被展开在需要构建的结构链表的对应规则中。其他的展开称之为“延后”的。这些变量和函数不会被“立即”展开,而是直到后续某些规则须要使用时或者在 make 处理的第二阶段它们才会被展开。

变量取值

变量定义解析的规则如下:
IMMEDIATE = DEFERRED
IMMEDIATE ?= DEFERRED
IMMEDIATE := IMMEDIATE
IMMEDIATE += DEFERRED or IMMEDIATE
define IMMEDIATE
DEFERRED
Endef
当变量使用追加符(+=)时,如果此前这个变量是一个简单变量(使用 :=定义的)
则认为它是立即展开的,其它情况时都被认为是“延后”展开的变量。

条件语句:

所有使用到条件语句在产生分支的地方,make 程序会根据预设条件将正确地分支展开。就是说条件分支的展开是“立即”的。其中包括:“ifdef”、“ifeq”、“ifndef”和“ifneq”所确定的所有分支命令。

规则的定义

所有的规则在 make 执行时,都按照如下的模式展开:
IMMEDIATE : IMMEDIATE ; DEFERRED
DEFERRED
其中,规则中目标和依赖如果引用其他的变量,则被立即展开。而规则的命令行中的变量引用会被延后展开。此模板适合所有的规则,包括明确规则、模式规则、后缀规则、静态模式规则。



五、总结

make 的执行过程如下:
1. 依次读取变量“MAKEFILES”定义的 makefile 文件列表
2. 读取工作目录下的 makefile 文件(根据命名的查找顺序“GNUmakefile”,
“makefile”,“Makefile”,首先找到那个就读取那个)
3. 依次读取工作目录 makefile 文件中使用指示符“include”包含的文件
4. 查找重建所有已读取的 makefile 文件的规则(如果存在一个目标是当前读取的
某一个 makefile 文件,则执行此规则重建此 makefile 文件,完成以后从第一步
开始重新执行)
5. 初始化变量值并展开那些需要立即展开的变量和函数并根据预设条件确定执行
分支
6. 根据“终极目标”以及其他目标的依赖关系建立依赖关系链表
7. 执行除“终极目标”以外的所有的目标的规则(规则中如果依赖文件中任一个
文件的时间戳比目标文件新,则使用规则所定义的命令重建目标文件)
8. 执行“终极目标”所在的规则

posted on 2017-01-02 23:22  sichenzhao  阅读(173)  评论(0编辑  收藏  举报

导航