GNU make中文手册
ver - 3.8
译者:徐海兵
2004-09-11
GUN make
中文手册
目 录
GNU make中文手册..................................................................................................................... 1
ver - 3.8 .......................................................................................................................................1
第一章:概述 ...............................................................................................................................7
1.1 Make之前基本知识:....................................................................................................... 7
1.1.1 概述............................................................................................................................7
1.1.2 准备知识 .................................................................................................................... 8
1.2 GNU make 介绍 .............................................................................................................. 8
1.2.1 Makefile简介 .............................................................................................................9
1.2.2 Makefile规则介绍 .................................................................................................... 10
1.2.3 简单的示例............................................................................................................... 11
1.2.4 make如何工作 ......................................................................................................... 12
1.2.5 指定变量 .................................................................................................................. 13
1.2.6 自动推导规则 ........................................................................................................... 14
1.2.7 另类风格的 makefile.................................................................................................15
1.2.8 清除工作目录过程文件 ............................................................................................. 16
第二章: Makefile 总述 .............................................................................................................. 16
2 Makefile概述 ........................................................................................................................ 16
2.1 Makefile的内容.............................................................................................................. 16
2.2 makefile 文件的命名 ....................................................................................................... 18
2.3 包含其它 makefile文件................................................................................................... 18
2.4 变量 MAKEFILES.........................................................................................................20
2.5 变量 MAKEFILE_LIST..................................................................................................21
2.6 其他特殊变量 .................................................................................................................22
2.7 makefile文件的重建 ...................................................................................................... 22
2.8 重载另外一个 makefile................................................................................................... 23
2.9 make如何解析 makefile文件.......................................................................................... 24
2.9.1 变量取值 .................................................................................................................. 25
2.9.2 条件语句 .................................................................................................................. 25
2.9.3 规则的定义............................................................................................................... 25
2.10 总结 ............................................................................................................................... 25
第三章: Makefile的规则 ............................................................................................................ 26
3 Makefile规则 ........................................................................................................................ 26
3.1 一个例子 ........................................................................................................................ 27
3.2 规则语法 ........................................................................................................................ 27
3.3 依赖的类型..................................................................................................................... 28
3.4 文件名使用通配符 .......................................................................................................... 29
3.4.1 统配符使用举例........................................................................................................ 30
3.4.2 通配符存在的缺陷 ....................................................................................................30
3.4.3 函数 wildcard...........................................................................................................31
3.5 目录搜寻 ........................................................................................................................ 32
3.5.1 一般搜索(变量 VPATH) ........................................................................................ 32
3.5.2 选择性搜索(关键字 vpath) ....................................................................................32
3.5.3 目录搜索的机制........................................................................................................ 33
3.5.4 命令行和搜索目录 ....................................................................................................35
3.5.5 隐含规则和搜索目录.................................................................................................36
2004年9月 11日
2
GUN make
中文手册
3.5.6 库文件和搜索目录 ....................................................................................................36
3.6 Makefile伪目标.............................................................................................................. 37
3.7 强制目标(没有命令或依赖的规则) ............................................................................. 40
3.8 空目标文件..................................................................................................................... 41
3.9 Makefile的特殊目标....................................................................................................... 41
3.10 多目标............................................................................................................................ 44
3.11 多规则目标..................................................................................................................... 44
3.12 静态模式 ........................................................................................................................ 45
3.12.1 静态模式规则的语法 ....................................................................................... 45
3.12.2 静态模式和隐含规则 ....................................................................................... 47
3.13 双冒号规则..................................................................................................................... 48
3.14 自动产生依赖 .................................................................................................................49
第四章:规则的命令 .................................................................................................................. 51
4 规则中书写命令 ................................................................................................................... 51
4.1 命令回显 ........................................................................................................................ 51
4.2 命令的执行..................................................................................................................... 52
4.3 并发执行命令 .................................................................................................................53
4.4 命令执行的错误..............................................................................................................54
4.5 中断 make的执行............................................................................................................ 56
4.6 make的递归执行............................................................................................................ 56
4.6.1 变量MAKE ............................................................................................................... 57
4.6.2 变量和递归............................................................................................................... 58
4.6.3 命令行选项和递归 ....................................................................................................61
4.6.4 -w 选项......................................................................................................................63
4.7 定义命令包..................................................................................................................... 63
4.8 空命令............................................................................................................................ 65
第五章: Makefile中的变量 ......................................................................................................... 65
5 使用变量 ..............................................................................................................................65
5.1 变量的引用..................................................................................................................... 66
5.2 两种变量定义(赋值)................................................................................................... 68
5.2.1 递归展开式变量........................................................................................................ 68
5.2.2 直接展开式变量........................................................................................................ 69
5.2.3 如何定义一个空格 ....................................................................................................70
5.2.4 “ ?=”操作符............................................................................................................. 71
5.3 变量的高级用法..............................................................................................................71
5.3.1 变量的替换引用........................................................................................................ 72
5.3.2 变量的套嵌引用........................................................................................................ 72
5.4 变量取值 ........................................................................................................................ 76
5.5 如何设置变量 .................................................................................................................76
5.6 追加变量值..................................................................................................................... 77
5.7 override 指示符 ............................................................................................................. 79
5.8 多行定义 ........................................................................................................................ 80
5.9 系统环境变量 .................................................................................................................81
5.10 目标指定变量 .................................................................................................................83
5.11 模式指定变量 .................................................................................................................84
第六章: Makefile的条件执行 .....................................................................................................85
6 Makefile的条件判断 ............................................................................................................. 85
6.1 一个例子 ........................................................................................................................ 85
6.2 条件判断的基本语法 ...................................................................................................... 86
2004年9月 11日
3
GUN make
中文手册
6.3 标记测试的条件语句 ...................................................................................................... 89
第七章:make 的内嵌函数.......................................................................................................... 89
7 make 的函数......................................................................................................................... 89
7.1 函数的调用语法..............................................................................................................90
7.2 文本处理函数 .................................................................................................................91
7.2.1 $(subst FROM,TO,TEXT)....................................................................................... 91
7.2.2 $(patsubst PATTERN,REPLACEMENT,TEXT) ..................................................... 91
7.2.3 $(strip STRINT)....................................................................................................... 92
7.2.4 $(findstring FIND,IN).............................................................................................. 92
7.2.5 $(filter PATTERN…,TEXT)..................................................................................... 93
7.2.6 $(filter-out PATTERN...,TEXT)............................................................................... 93
7.2.7 $(sort LIST)............................................................................................................. 94
7.2.8 $(word N,TEXT)......................................................................................................94
7.2.9 $(wordlist S,E,TEXT).............................................................................................. 94
7.2.10 $(words TEXT) .............................................................................................. 94
7.2.11 $(firstword NAMES…) ..................................................................................95
7.3 文件名处理函数..............................................................................................................95
7.3.1 $(dir NAMES…) ...................................................................................................... 95
7.3.2 $(notdir NAMES…)................................................................................................. 96
7.3.3 $(suffix NAMES…) ................................................................................................. 96
7.3.4 $(basename NAMES…) ......................................................................................... 96
7.3.5 $(addsuffix SUFFIX,NAMES…) ............................................................................. 97
7.3.6 $(addprefix PREFIX,NAMES…)............................................................................. 97
7.3.7 $(join LIST1,LIST2).................................................................................................98
7.3.8 $(wildcard PATTERN)............................................................................................98
7.4 foreach 函数................................................................................................................. 98
7.5 if 函数 ......................................................................................................................... 100
7.6 call函数 ....................................................................................................................... 100
7.7 value函数 .................................................................................................................... 102
7.8 eval函数 ...................................................................................................................... 103
7.9 origin函数 ................................................................................................................... 104
7.10 shell函数 ..................................................................................................................... 106
7.11 make的控制函数.......................................................................................................... 106
7.11.1 $(error TEXT…)...........................................................................................107
7.11.2 $(warning TEXT…)...................................................................................... 107
第八章:执行 make .................................................................................................................. 108
8 执行 make .......................................................................................................................... 108
8.1 指定 makefile文件........................................................................................................ 108
8.2 指定终极目标 ...............................................................................................................109
8.3 替代命令的执行............................................................................................................ 111
8.4 防止特定文件重建 ........................................................................................................ 112
8.5 替换变量定义 ...............................................................................................................113
8.6 使用 make进行编译测试............................................................................................... 114
8.7 make的命令行选项 ...................................................................................................... 115
第九章: make的隐含规则 ........................................................................................................ 119
9 使用隐含规则 ..................................................................................................................... 119
9.1 隐含规则的使用............................................................................................................ 119
9.2 make的隐含规则一览 .................................................................................................. 121
9.3 隐含变量 ...................................................................................................................... 124
9.3.1 代表命令的变量...................................................................................................... 124
9.3.2 命令参数的变量...................................................................................................... 125
9.4 make隐含规则链.......................................................................................................... 126
2004年9月 11日
4
GUN make
中文手册
9.5 模式规则 ...................................................................................................................... 128
9.5.1 模式规则介绍 ......................................................................................................... 128
9.5.2 模式规则示例 ......................................................................................................... 129
9.5.3 自动化变量............................................................................................................. 130
9.5.4 模式的匹配............................................................................................................. 133
9.5.5 万用规则 ................................................................................................................ 133
9.5.6 重建内嵌隐含规则 ..................................................................................................134
9.6 缺省规则 ...................................................................................................................... 135
9.7 后缀规则 ...................................................................................................................... 135
9.8 隐含规则搜索算法 ........................................................................................................ 137
第十章:使用 make更新静态库文件 ......................................................................................... 138
10 更新静态库文件 ............................................................................................................ 138
10.1 库成员作为目标............................................................................................................ 138
ARCHIVE(MEMBER) .............................................................................................................. 138
10.2 静态库的更新 ...............................................................................................................139
10.2.1 更新静态库的符号索引表 .............................................................................. 140
10.3 make静态库的注意事项............................................................................................... 141
10.4 静态库的后缀规则 ........................................................................................................ 141
第十一章 : GNU make的特点............................................................................................... 142
11 GNU make的一些特点 .................................................................................................142
11.1 源自 System v的特点................................................................................................... 142
11.2 源自其他版本的特点 .................................................................................................... 143
11.3 GNU make 自身的特点 .................................................................................................143
第十二章 和其它版本的兼容 ....................................................................................................144
12 不兼容性 ...................................................................................................................... 144
第十三章 Makefile的约定 ........................................................................................................ 146
13 书写约定 ...................................................................................................................... 146
13.1 基本的约定................................................................................................................... 146
13.2 规则命令行的约定 ........................................................................................................ 147
13.3 代表命令变量 ...............................................................................................................149
13.4 安装目录变量 ...............................................................................................................150
13.5 Makefile的标准目标名 ................................................................................................. 154
13.6 安装命令分类 ...............................................................................................................159
第十四章 make的常见错误信息 ............................................................................................... 161
14 make产生的错误信息.......................................................................................................... 161
附录 1:关键字索引 ................................................................................................................. 163
GNU make可识别的指示符:.............................................................................................. 163
GNU make函数: ............................................................................................................... 164
GNU make的自动化变量..................................................................................................... 165
GNU make环境变量............................................................................................................ 166
后序 .........................................................................................................................................166
2004年9月 11日
5
GUN make
中文手册
关于本书
本文瑾献给所有热爱 Linux 的程序员!本文档版权所有,禁止用于任何商业行为。
本文比较完整的讲述 GNU make 工具,涵盖 GNU make 的用法、语法。同时重点讨论如何
为一个工程编写 Makefile 。作为一个 Linux 程序员,make 工具的使用以及编写 Makefile 是必需
的。系统、详细讲述 make 的中文资料比较少,出于对广大中文 Linuxer 的支持,本人在工作之余,
花了 18 个多月时间完成对“info make ”的翻译整理,完成这个中文版的书册。本书并不是一个
语言的翻译版本,其中对 GNU make 的一些语法和用法根据我个人的工作经验进行了一些详细分
析和说明,也加入了一些个人的观点和实践总结。本书的所有的例子都可以在支持V3.8 版本的GNU
make 的系统中正确执行。
由于个人水平限制,本文在一些地方存在描述不准确之处。恳请大家在阅读过程中,提出您宝
贵的意见,也是对我个人的帮助。我的个人电子邮箱地址:
家交流!共同学习。
xhbdahai@126.com。非常愿意和大
阅读本书之前,应该对 GNU 的工具链和 Linux 中的一些常用工具有所了解。诸如: gcc、 as 、
ar、 ld、 yacc 等。在书写 Makefile 时,需要能够理解一些 shell 脚本程序。这些工具是维护一个
工程的基础工具。如果对这些工具的使用不是很熟悉,可参考相关资料。
阅读本文的几点建议:
1. 如果之前你对 GNU make 没有了解、而当前也不想深入的学习 GNU make 的读者。你只
需要阅读本文各章前半部分的基础知识。
2. 如果你已经对 GNU make 比较熟悉,可能你更需要关心此版本的一些特点、新增的功能
和存在的不兼容。
3. 之前你对 GNU make 没有多少概念、或者刚开始接触,本身又想成为一个 Linux 下的专
业程序员,那么建议:完整学习本文的各个章节,包括了基础知识和高级用法、技巧。它
会为你以后在 Linux 下的工程开发、工程管理提供非常有用的帮助。
谢谢!
徐海兵 2005-12-31
2004年9月 11日
6
GUN make
中文手册
第一章:概述
1.1 Make之前基本知识:
1.1.1 概述
Linux 环境下的程序员如果不会使用 GNU make 来构建和管理自己的工程,应该不能算是一
个合格的专业程序员,至少不能称得上是 Linux 程序员。在 Linux 环境下使用 GNU 的 make 工
具能够比较容易的构建一个属于你自己的工程,整个工程的编译只需要一个命令就可以完成编译、
连接以至于最后的执行。不过这需要我们投入一些时间去完成一个或者多个称之为 Makefile 文件
的编写。此文件正是 make 正常工作的基础。
所要完成的 Makefile 文件描述了整个工程的编译、连接等规则。其中包括:工程中的哪些源
文件需要编译以及如何编译、需要创建那些库文件以及如何创建这些库文件、如何最后产生我们想
要得可执行文件。尽管看起来可能是很复杂的事情,但是为工程编写 Makefile 的好处是能够使用
一行命令来完成“自动化编译”,一旦提供一个(多个)正确的 Makefile 。编译整个工程你所要做
的唯一的一件事就是在 shell 提示符下输入 make 命令。整个工程完全自动编译,极大提高了效率。
make 是一个命令工具,它解释 Makefile 中的指令(应该说是规则),Makefile 中描述了工
程中所有文件的编译顺序、规则。Makefile 有自己的书写格式、关键字、函数。像 C 语言有自己
的格式、关键字和函数一样。而且在 Makefile 中可以使用 shell 所提供的任何命令来完成你想要的
工作。Makefile (在其它的系统上可能是另外的文件名)在绝大多数的 IDE 开发环境中都在使用,
已经成为一种工程的编译方法。
目前,系统完整的介绍 make 工具和如何编写 Makefile 的中文文档比较少。我整理这个文档
就是希望能使众多的 Linux 环境下的程序员能够比较容易的掌握和学会使用它。本文所要介绍的是
GNU 的 make ,采用 Red Hat FC 3 (包括最新发布的 GNU Linux 系统)所集成的 GUN make
工具。make 版本信息如下:
本文后续所用到的所有例子都采用 C 语言书写的源程序,因为它是目前最普遍使用的一种语言。
当然 make 工具不仅仅是用来管理 C 语言工程的,那些编译器只要能够在 shell 下运行的语言所构
建的工程都可以使用 make 工具来管理。而且也可以使用 make
有这样的需求:当我们修改了某个或者某些文件后,需要能够根据修改的文件来自动对相关文件进
工具来做一些其它的事。例如,
行重建或者更新。那么应该考虑使用 GNU make 工具。GNU make 工具为我们实现这个目的提
供了非常有利的支持。工程中根据源文件的修改情况来进行代码的编译正是使用了 make 的这个特
征。make 执行时,根据 Makefile 的规则检查文件的修改情况,决定是否执行定义的动作(那些
修改过的文件将会被重新编译)。这是 GNU make 的执行依据。
2004年9月 11日
7
GUN make
中文手册
1.1.2 准备知识
在开始我们关于 make 的讨论之前,首先需要明确一些基本概念:
编译:把高级语言书写的代码转换为机器可识别的机器指令。编译高级语言后生成的指令虽然
可被机器识别,但是还不能被执行。编译时,编译器检查高级语言的语法、函数与变量的声明是否
正确。只有所有的语法正确、相关变量定义正确编译器就可以编译出中间目标文件。通常,一个高
级语言的源文件都可对应一个目标文件。目标文件在 Linux 中默认后缀为“.o ”(如“foo.c ”的目
标文件为“foo.o ”)。
为了和规则的目标文件相区别。本文将编译高级语言后生成的目标文件成为.o 文件。
链接:将多.o 文件,或者.o 文件和库文件链接成为可被操作系统执行的可执行程序。链接器不
检查函数所在的源文件,只检查所有.o 文件中的定义的符号。将.o 文件中使用的函数和其它.o 或
者库文件中的相关符号进行合并,最后生成一个可执行的程序。“ld ”是 GNU 的链接器。
静态库:又称为文档文件(Archive File )。它 是多 个.o 文件的集合。Linux 中静态库文件的后
缀为“.a ”。静态库中的各个成员(.o 文件)没有特殊的存在格式,仅仅是一个.o 文件的集合。使
用“ar ”工具维护和管理静态库。
共享库:也是多个.o 文件的集合,但是这些.o 文件时有编译器按照一种特殊的方式生成。对象
模块的各个成员的地址(变量引用和函数调用)都是相对地址。因此在程序运行时,可动态加载库
文件和执行共享的模块(多个程序可以共享使用库中的某一个模块)。
参考 info ld 了解更加详细的关于 ld 的说明和用法。
1.2 GNU make 介绍
make 在执行时,需要一个命名为 Makefile 的文件。这个文件告诉 make 以何种方式编译源
代码和链接程序。典型地,可执行文件可由一些.o 文件按照一定的顺序生成或者更新。如果在你的
工程中已经存在一个或者多个正确的 Makefile 。当对工程中的若干源文件修改以后,需要根据修改
来更新可执行文件或者库文件,正如前面提到的你只需要在 shell 下执行“make ”。make 会自动
根据修改情况完成源文件的对应.o 文件的更新、库文件的更新、最终的可执行程序的更新。
make 通过比较对应文件(规则的目标和依赖,)的最后修改时间,来决定哪些文件需要更新、
那些文件不需要更新。对需要更新的文件 make 就执行数据库中所记录的相应命令(在 make 读
取 Makefile 以后会建立一个编译过程的描述数据库。此数据库中记录了所有各个文件之间的相互
关系,以及它们的关系描述)来重建它,对于不需要重建的文件 make 什么也不做。
而且可以通过make 的命令行选项来指定需要重新编译的文件。参考
Problems and Bugs
=================
If you have problems with GNU `make' or think you've found a bug, please report it to the developers;
2004年9月 11日
8.2 指定终极目标 一节
8
GUN make
中文手册
we cannot promise to do anything but we might well want to fix it.
Before reporting a bug, make sure you've actually found a real bug.Carefully reread the documentation
and see if it really says you can do what you're trying to do. If it's not clear whether you should be able to
do something or not, report that too; it's a bug in the documentation!
Before reporting a bug or trying to fix it yourself, try to isolate it to the smallest possible makefile that
reproduces the problem. Then send us the makefile and the exact results `make' gave you, including any
error or warning messages. Please don't paraphrase these messages: it's best to cut and paste them into
your report. When generating this small makefile, be sure to not use any non-free or unusual tools in
your commands: you can almost always emulate what such a tool would do with simple shell commands.
Finally, be sure to explain what you expected to occur; this will help us decide whether the problem was
really in the documentation.
Once you have a precise problem you can report it in one of two ways.Either send electronic mail to:
bug-make@gnu.org
or use our Web-based project management tool, at:
http://savannah.gnu.org/projects/make/
In addition to the information above, please be careful to include the version number of `make' you are
using. You can get this information with the command `make --version'. Be sure also to include the
type of machine and operating system you are using. One way to obtain this information is by looking at
the final lines of output from the command
`make --help' .
以上时 GNU make 的 bug 反馈方式。如果在你使用 GNU make 过程中。发现 bug 或者问
题。可以通过以上的方式和渠道反馈。
好了。开始我们的神奇之旅吧!
1.2.1 Makefile简介
在执行 make 之前,需要一个命名为 Makefile 的特殊文件(本文的后续将使用 Makefile 作
为这个特殊文件的文件名)来告诉 make 需要做什么(完成什么任务),该怎么做。通常,make
工具主要被用来进行工程编译和程序链接。
本节将分析一个简单的 Makefile ,它对一个包含 8 个 C 的源代码和三个头文件的工程进行编
译和链接。这个 Makefile 提供给了 make 必要的信息,make 程序根据 Makefile 中的规则描述
执行相关的命令来完成指定的任务(如:编译、链接和清除编译过程文件等)。复杂的 Makefile 我
们将会在本文后续进行讨论。
当使用 make 工具进行编译时,工程中以下几种文件在执行 make 时将会被编译(重新编译):
1. 所有的源文件没有被编译过,则对各个 C 源文件进行编译并进行链接,生成最后的可执行
程序;
2. 每一个在上次执行 make 之后修改过的 C 源代码文件在本次执行 make 时将会被重新编
译;
2004年9月 11日
9
GUN make
中文手册
3. 头文件在上一次执行 make 之后被修改。则所有包含此头文件的 C 源文件在本次执行
make 时将会被重新编译。
后两种情况是 make 只将修改过的 C 源文件重新编译生成.o 文件,对于没有修改的文件不进
行任何工作。重新编译过程中,任何一个源文件的修改将产生新的对应的.o 文件,新的.o 文件将和
以前的已经存在、此次没有重新编译的.o 文件重新连接生成最后的可执行程序。
首先让我们先来看一些 Makefile 相关的基本知识。
1.2.2 Makefile规则介绍
一个简单的 Makefile 描述规则组成:
TARGET... : PREREQUISITES...
COMMAND
...
...
target :规则的目标。通常是程序中间或者最后需要生成的文件名。可以是.o 文件、也可以是
最后的可执行程序的文件名。另外,目标也可以是一个make 执行的动作的名称,如目标“clean ”,
成这样的目标是“伪目标”。参考
3.6 Makefile伪目标 一节
prerequisites:规则的依赖。生成规则目标所需要的文件名列表。通常一个目标依赖于一个
或者多个文件。
command:规则的命令行。是 make 程序所有执行的动作(任意的 shell 命令或者可在 shell
下执行的程序)。
一个规则可以有多个命令行,每一条命令占一行。注意:每一个命令行必须以[Tab] 字符开始,
[Tab]字符告诉 make 此行是一个命令行。 make 按照命令完成相应的动作。这也是书写
Makefile 中容易产生,而且比较隐蔽的错误。
命令就是在任何一个目标的依赖文件发生变化后重建目标的动作描述。一个目标可以没有依赖
而只有动作(指定的命令)。比如 Makefile 中的目标“clean ”,此目标没有依赖,只有命令。它所
指定的命令用来删除 make 过程产生的中间文件(清理工作)。
在 Makefile 中“规则”就是描述在什么情况下、如何重建规则的目标文件,通常规则中包括
了目标的依赖关系(目标的依赖文件)和重建目标的命令。make 执行重建目标的命令,来创建或
者重建规则的目标(此目标文件也可以是触发这个规则的上一个规则中的依赖文件)。规则包含了
目标和依赖的关系以及更新目标所要求的命令。
Makefile 中可以包含除规则以外的部分。一个最简单的 Makefile 可能只包含规则描述。规则
在有些 Makefile 中可能看起来非常复杂,但是无论规则的书写是多么的复杂,它都符合规则的基
本格式。
2004年9月 11日
10
GUN make
中文手册
1.2.3 简单的示例
本小节开始我们在第一小节中提到的例子。此例子由3 个头文件和8 个C 文件组成。我们讲述写
一个简单的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
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 清晰、容易
阅读。注意:反斜线之后不能有空格(这也是大家最容易犯的错误,而且错误比较隐蔽)。大家在
书写Makefile 时,推荐者中将较长行分解为使用反斜线连接得多个行的方式。当我们完成了这个
Maekfile 以后;创建可执行程序“edit ”,你所要做的就是在包含此Makefile 的目录(当然也在代
码所在的目录)下输入命令“make ”。删除已经本目录下生成的文件和所有的.o 文件,只需要输入
命令“make clean ”就可以了。
在这个Makefile 中,目标(target )包含:可执行文件“edit ”和 .o 文件(main.o,kbd.o…. ),
依赖(prerequisites )就是冒号后面的那些 .c 文件和 .h 文件。所有的.o 文件既是依赖(相对于
可执行程序edit )又是目标(相对于.c 和.h 文件)。命令包括 “cc –c maic.c ”、“cc –c kbd.c ”……
目标是一个文件时,当它的任何一个依赖文件被修改以后,这个目标文件将会被重新编译或者
重新连接。当然,此目标的任何一个依赖文件如果有必要则首先会被重新编译。在这个例子中,“edit ”
的依赖为8 个.o 文件;而“main.o ”的依赖文件为“main.c ”和“defs.h ”。当“main.c ”或者“defs.h ”
被修改以后,再次执行“make ”时“main.o ”就会被更新(其它的.o 文件不会被更新),同时“main.o ”
2004年9月 11日
11
GUN make
中文手册
的更新将会导致“edit ”被更新。
在描述目标和依赖之下的shell 命令行,它描述了如何更新目标文件。命令行必需以[Tab]键开
始,以和Makefile 其他行区别。就是说所有的命令行必需以[Tab] 字符开始,但并不是所有的以
[Tab] 键出现行都是命令行。但make 程序会把出现在第一条规则之后的所有的以 [Tab] 字符开始
的行都作为命令行来处理。(要记住:make程序不关心命令是如何工作的,对目标文件的更新需要
你在规则的描述中提供正确的命令。“make ”程序所做的就是当目标程序需要更新时执行规则所定
义的命令)。
目标“clean ”不是一个文件,它仅仅代表了执行一个动作的标识。通常情况下,不需要执行
这个规则所定义的动作,因此目标“clean ”没有出现在其它规则的依赖列表中。在执行make 时,
它所指定的动作不会被执行。除非执行make 时明确地指定它作为重建目标。而且目标“clean ”没
有任何依赖文件,它只有一个目的,就是通过这个目标名来执行它所定义的命令。Makefile 中把
那些没有任何依赖只有执行动作的目标称为“伪目标”(phony targets )。参考
3.6 Makefile 伪目
标 一节。执行“clean”目标所定义的命令,可在shell下输入:make clean。
1.2.4 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 文件“更
8.2 指定终极目标 一
新”(在上一次 make 之后被修改)。则根据规则重新编译生成它;
3. 目标 .o文件存在,目标 .o 文件比它的任何一个依赖文件(的 .c 源文件、 .h 文件)“更新”
(它的依赖文件在上一次 make 之后没有被修改),则什么也不做。
这些.o 文件所在的规则之所以会被执行,是因为这些.o 文件出现在“终极目标”的依赖列表中。
如果在 Makefile 中一个规则所描述的目标不是“终极目标”所依赖的(或者“终极目标”的依赖
2004年9月 11日
12
GUN make
中文手册
文件所依赖的),那么这个规则将不会被执行。除非明确指定这个规则(可以通过 make 的命令行
指定重建目标,那么这个目标所在的规则就会被执行,例如 “make clean”)。在编译或者重新编
译生成一个.o 文件时,make 同样会去寻找它的依赖文件的重建规则(是这样一个规则:这个依赖
文件在规则中作为目标出现),就是.c 和.h 文件的重建规则。在上例的 Makefile 中没有哪个规则
的目标是.c 或者.h 文件,所以没有重建.c 和.h 文件的规则。不过 C 言语的源程序文件可以使用工
具 Bison 或者 Yacc 来生成(具体用法可参考相应的手册)。
完成了对.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 ”也将被重新生成。
以上我们通过一个简单的例子,介绍了 Makefile 中目标和依赖的关系。对于 Makefile 中的目
标。在执行“make ”时首先执行终极目标所在的规则,接下来一层层地去寻找终极目标的依赖文
件所在的规则并执行。当终极目标的规则被完全的展开以后,make 将从最后一个被展开的规则处
开始执行,之后处理倒数第二个规则,……依次回退。最后一步执行的就是终极目标所在的规则。
整个过程就类似于 C 语言中的递归实现一样。在更新(或者创建)终极目标的过程中,如果出现错
误 make 就立即报错并退出。整个过程 make 只是负责执行规则,而对具体规则所描述的依赖关
系的正确性、规则所定义的命令的正确性不做任何判断。就是说,一个规则的依赖关系是否正确、
描述重建目标的规则命令行是否正确,make 不做任何错误检查。
因此,需要正确的编译一个工程。需要在提供给 make 程序的 Makefile 中来保证其依赖关系
的正确性、和执行命令的正确性。
1.2.5 指定变量
同样是上边的例子,我们来看一下终极目标“edit ”所在的规则:
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
在这个规则中.o 文件列表出现了两次;第一次:作为目标“edit ”的依赖文件列表出现,第二
2004年9月 11日
13
GUN make
中文手册
次:规则命令行中作为“cc ”的参数列表。这样做所带来的问题是:如果我们需要为目标“edit ”
增加一个的依赖文件,我们就需要在两个地方添加(依赖文件列表和规则的命令中)。添加时可能
在“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 文件列表(关
于变量可参考
5 使用变量 一章)。因此上例的规则就可以这样写:
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)
需要增加或者去掉一个.o 文件时。我们只需要改变“objects ”的定义(加入或者去掉若干个.o
文件)。这样做不但减少维护的工作量,而且可以避免由于遗漏而产生错误的可能。
1.2.6 自动推导规则
在使用make 编译.c 源文件时,可以省略编译一个.c 文件所使用的命令。这是因为make 存在一
个默认的规则,能够自动完成对.c 文件的编译并生成对应的.o 文件。它执行命令“cc -c ”来编译.c
源文件。对于上边的例子,此默认规则就使用命令“cc -c main.c -o main.o ”来创建文件
“main.o ”。因此对一个目标文件是“N.o ”,倚赖文件是“N.c ”的规则。可以省略其规则的命令
行,使用make 的默认命令。此默认规则称为make 的隐含规则(关于隐含规则可参考
9 使用隐含
规则 一章)
我们书写 Makefile 时,对于一个.c 文件如果使用 make 的隐含规则,那么它会被自动作为对
应.o 文件的一个依赖文件(对应是指:文件名除后缀外,其余都相同的两个文件)。因此我们也可
以在规则中省略目标的倚赖.c 文件。
我们上边的例子就可以以更加简单的方式书写,使用了变量“objects ”。简化版本的 Makefile
2004年9月 11日
14
GUN make
如下:
# 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)
中文手册
这种格式的Makefile 更接近于我们实际的应用。(关于目标“clean ”的详细说明我们在后边。
参考
3.6 Makefile伪目标 一节 和 4.4 命令的错误 一节)
make 的隐含规则在实际工程的 make 中会经常使用,它使得编译过程变得方便。几乎在所有
的 Makefile 中都用到了 make 的隐含规则,make 的隐含规则是非常重要的一个概念。后续我们
会在第九章会专门讨论 make 的隐含规则。
1.2.7 另类风格的 makefile
Makefile 中,目标使用隐含规则生成,我们就可以也可以书写另外一种风格 Makefile 。在这
个 Makefile 中,根据依赖而不是目标对规则进行分组。上例的 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)
$(objects) : defs.h
kbd.o command.o files.o : command.h
display.o insert.o search.o files.o : buffer.h
例子中头文件“defs.h ”作为所有.o 文件的依赖文件。其它两个头文件作为其对应规则的目标
中所列举的所有.o 文件的依赖文件。
但是这种风格的 Makefile 并不值得我们借鉴。问题在于:同时把多个目标文件的依赖放在同
2004年9月 11日
15
GUN make
一个规则中进行描述(一个规则中含有多个目标文件),这样导致规则定义不明了,比较混乱。建
议大家不要在 Makefile 中采用这种方式了书写。否则后期维护将会是一件非常痛苦的事情。
可有多个依赖文件。尽量避免多目标,单依赖的方式。这样后期维护也会非常方便,而且 Makefile
会更清晰、明了。
中文手册
书写规则建议的方式是:单目标,多依赖。就是说尽量要做到一个规则中只存在一个目标文件,
1.2.8 清除工作目录过程文件
在 Makefile 中的规则也可以完成除编译以外的任务。例如:前边提到的实现清除当前目录中
在编译过程中生成的文件(edit 和哪些.o 文件)的规则:
clean :
rm edit $(objects)
在实际应用时,我们会把这个规则写成如下稍微复杂一些的样子。以防止出现始料未及的情况。
.PHONY : clean
clean :
-rm edit $(objects)
这两个实现有两点不同: 1. 通过“.PHONY ”特殊目标将“clean ”目标声明为伪目标。防
止当磁盘上存在一个名为“clean ”文件时,“clean ”所在规则的命令无法执行(参考
伪目标 一节)。2. 在命令行之前使用“-”,意思是忽略命令“rm”的执行错误(参考 4.4 命令
的错误 一节)。
这样的一个目标在 Makefile 中,不能将其作为终极目标(Makefile 的第一个目标)。因为我
们的初衷并不是当你在命令行上输入 make 以后执行删除动作。而是要创建或者更新程序。在我们
上边的例子中。就是在输入 make 以后要需要对目标“edit ”进行创建或者重建。
上例中因为目标“clean ”没有出现在终极目标“edit ”依赖关系中,所以我们执行“make ”
时,目标“clean ”所在的规则将不会被处理。如果需要执行此规则,需要在make 的命令行选项中
明确指定这个目标(执行“make clean ”)。关于make 的执行可参考
8.2 指定终极目标 一节。
3.6 Makefile
第二章:Makefile 总述
2 Makefile概述
2.1 Makefile的内容
在一个完整的 Makefile 中,包含了 5 个东西:显式规则、隐含规则、变量的定义、指示符和
2004年9月 11日
16
GUN make
中文手册
注释。关于“规则”、“变量”和“Makefile 指示符”将在后续的章节进行详细的讨论。本章讨论的
是一些基本概念。
显式规则:它描述了在何种情况下如何更新一个或者多个被称为目标的文件(Makefile
的目标文件)。在书写 Makefile 是需要明确地给出目标文件、目标的依赖文件列表以及
更新目标文件所需要的命令。
隐含规则:它是make 根据此类目标文件的命名(典型的是文件名的后缀)而自动推导
出来的规则。make 根据目标文件的名字,自动产生目标的依赖文件并使用默认的命令
来对目标进行更新。关于隐含规则可参考
第九章 make 的隐含规则
变量定义:就是使用一个字符串代表一段文本串,当定义了变量以后,Makefile 后续在
需要使用此文本串的地方,通过引用这个变量来实现对文本串的使用。第一章的的例子
中,我们就定义了一个变量“objects ”来表示一个.o 文件列表。关于变量的详细讨论可
第五章 Makefile 中的变量
参考
Makefile 指示符:指示符指明在 make 程序读取 makefile 文件过程中所要执行的一个
动作。其中包括:
读取一个文件,读取给定文件名的文件。参考
2.3 包含其它 makefile文件一节
决定(通常是根据一个变量的得值)处理或者忽略Makefile 中的某一特定部分。参
第六章Makefile 的条件执行
考
定义一个多行变量。参考
5.8 多行定义 一节
注释:Makefile 中“ # ”字符后的内容被作为是注释内容(和 shell 脚本一样)处理。
如果此行的第一个非空字符为“# ”,那么此行为注释行。注释行的结尾如果存在反斜线
(\ ),那么下一行也被作为注释行。一般在书写 Makefile 时推荐将注释作为一个独立的
行,而不要和 Makefile 的有效行放在一行中书写。当在 Makefile 中需要使用字符“# ”
时,可以使用反斜线加“# ”(\# )来实现,其表示将“# ”作为一字符而不是注释的开
始标志。
需要注意的地方:
Makefile 中第一个规则之后的所有以 [Tab]字符开始的的行, make 程序都会将其给系统的
shell 程序去解释执行。因此以 [Tab]字符开始的注释行也会被交给 shell 来处理,此命令行是否需
要被执行(shell 执行或者忽略)是由系统 shell 程序来判决的。
另外,在使用指示符“define ”定义一个多行的变量或者命令包时,其定义体(“define ”和
“endef ”之间的内容)会被完整的展开到 Makefile 中引用此变量的地方(包含定义体中的注释行);
make 在引用此变量的地方对所有的定义体进行处理,决定是注释还是有效内容。Makefile 中的变
量可以和 C 语言中的宏(实质一样)一样来理解。对一个变量引用的地方 make 所做的就是将这个
变量根据定义进行基于文本的展开,展开变量的过程不涉及到任何变量的具体含义和功能分析。
2004年9月 11日
17
GUN make
中文手册
2.2 makefile文件的命名
默认的情况下,make 会在工作目录(执行 make 的目录)下按照文件名顺序寻找 makefile
文件读取并执行,查找的文件名顺序为:“GNUmakefile ”、“makefile ”、“Makefile ”。
通常应该使用“makefile ”或者“Makefile ”作为一个 makefile 的文件名(我们推荐使用
“ Makefile ”,首字母大写而比较显著,一般在一个目录中和当前目录的一些重要文件
(README,Chagelist 等)靠近,在寻找时会比较容易的发现它)。而“GNUmakefile ”是我们
不推荐使用的文件名,因为以此命名的文件只有“GNU make ”才可以识别,而其他版本的 make
程序只会在工作目录下“makefile ”和“Makefile ”这两个文件。
如果make 程序在工作目录下无法找到以上三个文件中的任何一个,它将不读取任何其他文件
作为解析对象。但是根据make 隐含规则的特性,我们可以通过命令行指定一个目标,如果当前目
录下存在符合此目标的依赖文件,那么这个命令行所指定的目标将会被创建或者更新,参见注释。
(详细可参考
当 makefile 文件的命名不是这三个任何一个时,需要通过 make 的“-f ”或者“--file ”选项
第九章 make 的隐含规则)
来指定 make 读取的 makefile 文件。给 make 指定 makefile 文件的格式为:“-f NAME ”或者
“—file=NAME ”,它指定文件“NAME ”作为执行 make 时读取的 makefile 文件。也可以通过
多个“-f ”或者“--file ”选项来指定多个需要读取的 makefile 文件,多个 makefile 文件将会被
按照指定的顺序进行连接并被 make 解析执行。当通过“-f ”或者“--file ”指定 make 读取 makefile
的文件时,make 就不再自动查找这三个标准命名的 makefile 文件。
注释:通过命令指定目标使用make 的隐含规则:
当前目录下不存在以“ GNUmakefile ”、“ makefile ”、“ Makefile ”命名的任何文件,
1. 当前目录下存在一个源文件 foo.c的,我们可以使用“make foo.o”来使用make的隐含规则自动生成foo.o。
当执行“ make foo.o”时。我们可以看到其执行的命令为:
cc –c –o foo.o foo.c
之后, foo.o将会被创建或者更新。
2. 如果当前目录下没有 foo.c文件时,就是 make对 .o文件目标的隐含规则中依赖文件不存在。如果使用命令
“ make foo.o”时,将回到到如下提示:
make: *** No rule to make target ‘foo.o’. Stop.
3. 如果直接使用命令“ make”时,得到的提示信息如下:
make: *** No targets specified and no makefile found. Stop.
2.3 包含其它 makefile文件
本节我们讨论如何在一个 Makefile 中包含其它的 makefile 文件。Makefile 中包含其它文件
的关键字是“include ”,和 C 语言对头文件的包含方式一致。
“include ”指示符告诉 make 暂停读取当前的 Makefile ,而转去读取“include ”指定的一
2004年9月 11日
18
GUN make
中文手册
个或者多个文件,完成以后再继续当前 Makefile 的读取。Makefile 中指示符“include ”书写在
独立的一行,其形式如下:
include FILENAMES...
FILENAMES 是 shell 所支持的文件名(可以使用通配符)。
指示符“include ”所在的行可以一个或者多个空格(make 程序在处理时将忽略这些空格)开
始,切忌不能以[Tab]字符开始(如果一行以[Tab]字符开始make程序将此行作为一个命令行来处
理)。指示符“include ”和文件名之间、多个文件之间使用空格或者[Tab]键隔开。行尾的空白字
符在处理时被忽略。使用指示符包含进来的Makefile 中,如果存在变量或者函数的引用。它们将会
在包含它们的Makefile 中被展开(详细可参考
第五章 Makefile 中的变量)。
来看一个例子,存在三个.mk 文件,“$(bar) ”被扩展为“bish bash ”。则
include foo *.mk $(bar)
等价于
include foo a.mk b.mk c.mk bish bash
make 程序在处理指示符 include 时,将暂停对当前使用指示符“include ”的 makefile 文件
的读取,而转去依此读取由“include ”指示符指定的文件列表。直到完成所有这些文件以后再回
过头继续读取指示符“include ”所在的 makefile 文件。
通常指示符“include ”用在以下场合:
1. 有多个不同的程序,由不同目录下的几个独立的Makefile 来描述其创建或者更新规则。它
们需要使用一组通用的变量定义(可参考
9.5 模式规则 一节)。通用的做法是将这些共同使用的变量或者模式规则定义在一个文
考
5.5 如何设置变量 一节)或者模式规则(可参
件中(没有具体的文件命名限制),在需要使用的Makefile 中使用指示符“include ”来包
含此文件。
2. 当根据源文件自动产生依赖文件时;我们可以将自动产生的依赖关系保存在另外一个文件
中,主Makefile 使用指示符“include ”包含这些文件。这样的做法比直接在主Makefile
中追加依赖文件的方法要明智的多。其它版本的make 已经使用这种方式来处理。(参考
3.14 自动产生依赖 一节)
如果指示符“include ”指定的文件不是以斜线开始(绝对路径,如/usr/src/Makefile... ),
而且当前目录下也不存在此文件;make 将根据文件名试图在以下几个目录下查找:首先,查找使
用命令行选项“-I ”或者“--include-dir ”(参考
8.7make 的命令行选项 一节)指定的目录,如
果找到指定的文件,则使用这个文件;否则依此搜索以下几个目录(如果其存在):
“/usr/gnu/include ”、“/usr/local/include ”和“/usr/include ”。
2004年9月 11日
19
GUN make
中文手册
当在这些目录下都没有找到“include ”指定的文件时,make将会提示一个包含文件未找到的
告警提示,但是不会立刻退出。而是继续处理Makefile 的内容。当完成读取所有的makefile 文件后,
make将试图使用规则来创建通过指示符“ include”指定的但未找到的文件(参考
2.7 makefile
文件的重建 一节),当不能创建它时(没有创建这个文件的规则),make 将提示致命错误并退出。
会输出类似如下错误提示:
Makefile:
Make
错误的行数:未找到文件名:提示信息(
:
*** No rule to make target ‘<filename>’. Stop
No such file or directory)
我们可使用“-include”来代替“include”,忽略由于包含文件不存在或者无法创建时的错误
提示(“-”的意思是告诉 make,忽略此操作的错误。make 继续执行)。像下边那样:
-include FILENAMES...
使用这种方式时,当所要包含的文件不存在时不会有错误提示、make 也不会退出;除此之外,
和第一种方式效果相同。以下是这两种方式的比较:
使用“include FILENAMES... ”,make 程序处理时,如果“FILENAMES ”列表中的任何一
个文件不能正常读取而且不存在一个创建此文件的规则时 make 程序将会提示错误并退出。
使用“-include FILENAMES... ”的情况是,当所包含的文件不存在或者不存在一个规则去创
建它,make 程序会继续执行,只有在因为 makefile 的目标的规则不存在时,才会提示致命错误
并退出。
为了和其它的 make 程序进行兼容。也可以使用“sinclude ”来代替“-include ”(GNU 所支
持的方式)。
2.4 变量 MAKEFILES
如果当前环境定义了一个“MAKEFILES ”的环境变量,make 执行时首先将此变量的值作为
需要读入的Makefile 文件,多个文件之间使用空格分开。类似使用指示符“include ”包含其它
Makefile 文件一样,如果文件名非绝对路径而且当前目录也不存在此文件,make 会在一些默认的
目录去寻找(参考
1. 环境变量指定的 makefile 文件中的“目标”不会被作为 make 执行的“终极目标”。就是
说,这些文件中所定义规则的目标,make 不会将其作为“终极目标”来看待。如果在 make
2.3 包含其它makefile 文件 一节)。此情况和使用“include ”的区别:
的工作目录下没有一个名为“Makefile ”、“makefile ”或者“GNUmakefile ”的文件,
make 同样会提示“make: *** No targets specified and no makefile found. Stop. ”;而
在 make 的工作目录下存在这样一个文件(“ Makefile ”、“ makefile ”或者
“GNUmakefile ”),那么 make 执行时的“终极目标”就是当前目录下这个文件中所定
2004年9月 11日
20
GUN make
中文手册
义的“终极目标”。
2. 环境变量所定义的文件列表,在执行 make 时,如果不能找到其中某一个文件(不存在或
者无法创建)。make 不会提示错误,也不退出。就是说环境变量“MAKEFILES ”定义的
包含文件是否存在不会导致 make 错误(这是比较隐蔽的地方)。
3. make 在执行时,首先读取的是环境变量“MAKEFILES ”所指定的文件列表,之后才是
工作目录下的 makefile 文件,“include ”所指定的文件是在 make 发现此关键字的时、
暂停正在读取的文件而转去读取“include ”所指定的文件。
变量“MAKEFILES ”主要用在“make ”的递归调用过程中的的通信(参考
4.6 make 的递归
执行 一节)。实际应用中很少设置此变量。一旦设置了此变量,在多层make 调用时;由于每一级
make 都会读取“MAKEFILES ”变量所指定的文件,这样可能导致执行的混乱(可能不是你想看到
的执行结果)。不过,我们可以使用此环境变量来指定一个定义通用的“隐含规则”和用的变量的
文件,比如设置默认搜索路径(可参考
3.5 目录搜索 一节);通过这种方式设置的“隐含规则”和
定义的变量可以被任何make 进程使用(有点象C 语言中的全局变量)。
也有人想让 login 程序自动的在自己的工作环境中设置此环境变量,编写的 Makefile 建立在
此环境变量的基础上。此想法可以肯定地说不是一个好主意。规劝大家千万不要这么干,否则你所
编写的 Makefile 在其人的工作环境中肯定不能正常工作。因为别人的工作环境中可能没有设置相
同的环境变量“MAKEFILES ”。
推荐的做法实:在需要包含其它 makefile 文件时使用指示符“include ”来实现。
2.5 变量 MAKEFILE_LIST
make 程序在读取多个 makefile 文件时,包括由环境变量“MAKEFILES ”指定、命令行指、
当前工作下的默认的以及使用指示符“include ”指定包含的,在对这些文件进行解析执行之前 make
读取的文件名将会被自动的追加到变量“MAKEFILE_LIST ”的定义域中。
这样我们就可以通过测试此变量的最后一个字来得知当前 make 程序正在处理的是具体的那
个 makefile 文件。具体地说就是一个 makefile 文件中当使用指示符“include ”包含另外一个文
件之后,变量“MAKEFILE_LIST ”的最后一个只可能是指示符“include ”指定所要包含的那个
文件的名字。如果一个 makefile 的内容如下:
name1 := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
include inc.mk
name2 := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
all:
@echo name1 = $(name1)
@echo name2 = $(name2)
执行 make ,则看到的将是如下的结果:
2004年9月 11日
21
GUN make
中文手册
name1 = Makefile
name2 = inc.mk
此例子中涉及到了 make 的函数的和变量定义的方式,这些将在后续的章节中有详细的讲述。
2.6 其他特殊变量
GNU make 支持一个特殊的变量,此变量不能通过任何途经给它赋值。此变量展开以后是一个
特定的值。第一个重要的特殊的变量是“.VARIABLES ”。它被展开以后是此引用点之前、makefile
文件中所定义的所有全局变量列表。包括:空变量(未赋值的变量)和make 的内嵌变量(参考
9.3
隐含变量 一节),但不包含目标指定的变量,目标指定变量值在特定目标的上下文有效。关于目标
变量可参考
5.10 目标指定变量 一节
2.7 makefile文件的重建
有时,Makefile 可由其它文件生成,比如 RCS 或 SCCS 文件。如果 Makefile 由其它文件重
建,那么在 make 开始解析 Makefile 时需要读取的是更新后的 Makefile 、而不是那个没有更新的
Makefile。 make 的处理过程是这样的:
make 在读入所有 makefile 文件之后,首先将所读取的每个 makefile 作为一个目标,试着
去更新它。如果存在一个更新特定 makefile 文件明确规则或者隐含规则,则去更新这个 makefile
文件。在完成对所有的 makefile 文件的更新检查动作之后,如果之前所读取的 makefile 文件已
经被更新,那么 make 就清除本次执行的状态重新读取一遍所有的 makefile 文件(此过程中,同
样在读取完成以后也会去试图更新所有的已经读取的 makefile 文件,但是一般这些文件不会再次
被重建,因为它们在时间戳上已经是最新的)。
实际应用中,我们会很明确的了解我们的那些makefile 文件不需要重建。出于make 效率的考
虑,我们可以采用一些办法来避免make 在执行过程时查找重建makefile 的隐含规则。例如我们可
以书写一个明确的规则,将makefile 文件作为目标,命令为空。(参考
Makefile 规则中,如果使用一个没有依赖只有命令行的
双冒号规则去更新一个文件,那么每次
4.8 空命令 一节)
执行make 时,此规则的目标文件将会被无条件的更新。而假如此规则的目标文件是一个makefile
文件,那么在执行make 时,将会导致这个makefile 文件被无条件更新,时make 的执行陷入到一
个死循环中(此makefile文件被不断的更新、重新读取、更新再重新读取的过程)。为了防止进入
此循环,make 在遇到一个目标是makefile 文件的双冒号规则时,将忽略对这个规则的执行(其中
包括了使用“MAKEFILES ”指定、命令行选项指定、指示符“include ”指定的需要make 读取的
所有makefile 文件中定义的这一类双冒号规则)。
执行 make 时,如果没有使用“-f (--file )”选项指定一个文件,make 程序将读取缺省的
文件。和使用“-f(--file )”选项不同,make 无法确定工作目录下是否存在缺省名称的 makefile
文件。如果缺省 makefile 文件不存在,但可以通过一个规则来创建它(此规则是隐含规则),则
2004年9月 11日
22
GUN make
中文手册
会自动创建缺省 makefile 文件,之后重新读取它并开始执行。
因此,如果不存在缺省 makefile 文件,make 将按照搜索 makefile 文件的名称顺序去创建
它,直到创建成功或者超越其缺省的命名顺序。需要明确的一点是:执行 make 时,如果不能成功
地创建其缺省的 makefile 文件,并不一定会导致错误。运行 make 时一个 makefile 文件并不是
必需的。(关于这一点大家会在后续的阅读过程中体会到)
当使用“-t(--touch)”选项来对 Makefile 目标文件进行时间戳更新时,对于哪些 makefile
文件的目标是无效的。就是说即使执行 make 时使用了选项“-t”,那些目标是 makefile 文件的
规则同样也会被 make 执行(而其它的规则不会被执行,make 只是简单的更新规则目标文件的时
间戳);类似还有选项“-q(—question)”和“-n(—just-print) ”,这主要是因为一个过
时的 makefile 文件对其它目标的重建规则在当前看来可能是错误的。正因为如此,执行命令“make
–f mfile –n foo”首先会试图重建“mfile 文件”、并重新读取它,之后会打印出更新目标“foo”
规则中所定义的命令但不执行此命令。
在这种情况下,如果我们不希望重建 makefile 文件。那么我们就需要在执行 make 时,在命
令行中将这个 makefile 文件中为一个最终目的,这样“–t ”和其它的选项就对这个 makefile 文
件的目标有效,防止执行这个 makefile 作为目标的规则。同样,命令“make –f mfile –n mfile
foo ”会读取文件“mfile ”,打印出重建文件“mfile ”的命令、重建“ foo ”的命令而实际不去执
行此命令。并且所打印的用于更新“foo ”目标的命令是选项“-f ”指定的、没有被重建的“mfile ”
文件中所定义的命令。
2.8 重载另外一个 makefile
有些情况下存在两个比较类似的 makefile 文件。其中一个(makefile-A )需要使用另外一个
文件(makefile-B )中所定义的变量和规则。我们可以在“makefile-A ”中使用指示符“include ”
来包含“mkaefile-B ”来达到目的,这种情况下,如果两个 makefile 文件中存在相同目标,而其
描述规则中使用不同的命令。相同目标有两个不同的规则命令,这是 makefile 所不允许的。遇到
这种情况,使用指示符“include ”显然是行不通的。GNU make 提供另外一种途径来达到此目的。
具体的做法如下:
在需要包含的makefile 文件(makefile-A )中,我们可以使用一个称之为“所有匹配模式”
(参考
9.5 模式规则 一节)的规则来描述在“makefile-A ”中没有明确定义的目标,make 将会
在给定的makefile 文件中寻找没有在当前Makefile 中给出的目标更新规则。
看一个例子,如果存在一个命名为“Makefile ”的 makefile 文件,其中描述目标“foo ”的 规
则和其他的一些规,我们也可以书写一个内容如下命名为“GNUmakefile ”的文件。
#sample GNUmakefile
foo:
2004年9月 11日
23
GUN make
中文手册
frobnicate > foo
%: force
@$(MAKE) -f Makefile $@
force: ;
执行命令“make foo”,make将使用工作目录下命名为“GNUmakefile”的文件并执行目
标“ foo”所在的规则,创建它的命令是:“frobnicate > foo ”。如果我们执行另外一个命令“make
bar”, “GUNmakefile”中没有此目标的更新规则。那么,make 将会使用“所有匹配模式”
规则,执行命令“$(MAKE) -f Makefile bar ”。如果文件“Makefile”中存在此目标更新规则的定
义,那么这个规则会被执行。此过程同样适用于其它 “GNUmakefile”中没有给出的目标更新规
则。此方式的灵活之处在于:如果在“Makefile”文件中存在同样一一个目标“foo”的重建规则,
由于 make 执行时首先读取文件“GUNmakefile”并在其中能够找到目标“foo”的重建规则,所
以 make 就不会去执行这个“所有模式匹配规则”(上例中的目标是“%”的规则)。这样 就避免
了使用指示符“include”包含一个 makefile 文件时所带来的目标规则的重复定义问题。
此种方式,模式规则的模式只使用了单独的“% ”(我们才称他为“所有模式匹配规则”),
它可以匹配任何一个目标;它的依赖是“force ”,保证了即使目标文件已经存在也会执行这个规
则(文件已存在时,需要根据它的依赖文件的修改情况决定是否需要重建这个目标文件);“force ”
规则中使用空命令是为了防止 make 程序试图寻找一个规则去创建目标“force ”时,又使用了模
式规则“%: force ”而陷入无限循环。
2.9 make如何解析makefile文件
GUN make 的执行过程分为两个阶段。
第一阶段:读取所有的 makefile 文件(包括“MAKIFILES ”变量指定的、指示符“include ”
指定的、以及命令行选项“-f(--file) ”指定的 makefile 文件),内建所有的变量、明确规则和隐含
规则,并建立所有目标和依赖之间的依赖关系结构链表。
在第二阶段:根据第一阶段已经建立的依赖关系结构链表决定哪些目标需要更新,并使用对应
的规则来重建这些目标。
理解 make 执行过程的两个阶段是很重要的。它能帮助我们更深入的了解执行过程中变量以及
函数是如何被展开的。变量和函数的展开问题是书写 Makefile 时容易犯错和引起大家迷惑的地方
之一。本节将对这些不同的结构的展开阶段进行简单的总结(明确变量和函数的展开阶段,对正确
的使用变量非常有帮助)。首先,明确以下基本的概念;在 make 执行的第一阶段中如果变量和函
数被展开,那么称此展开是“立即”的,此时所有的变量和函数被展开在需要构建的结构链表的对
应规则中(此规则在建立链表是需要使用)。其他的展开称之为“延后”的。这些变量和函数不会
被“立即”展开,而是直到后续某些规则须要使用时或者在 make 处理的第二阶段它们才会被展开。
2004年9月 11日
24
GUN make
中文手册
可能现在讲述的这些还不能完全理解。不过没有关系,通过后续章节内容的学习,我们会一步
一步的熟悉 make 的执行过程。学习过程中可以回过头来参考本节的内容。相信在看完本书之后,
会对 make 的整个过程有全面深入的理解。
2.9.1 变量取值
变量定义解析的规则如下:
IMMEDIATE = DEFERRED
IMMEDIATE ?= DEFERRED
IMMEDIATE := IMMEDIATE
IMMEDIATE += DEFERRED or IMMEDIATE
define IMMEDIATE
DEFERRED
Endef
当变量使用追加符(+= )时,如果此前这个变量是一个简单变量(使用 := 定义的)则认为它
是立即展开的,其它情况时都被认为是“延后”展开的变量。
2.9.2 条件语句
所有使用到条件语句在产生分支的地方,make 程序会根据预设条件将正确地分支展开。就是
说条件分支的展开是“立即”的。其中包括:“ifdef ”、“ifeq ”、“ifndef ”和“ifneq ”所确定的所
有分支命令。
2.9.3 规则的定义
所有的规则在 make 执行时,都按照如下的模式展开:
IMMEDIATE : IMMEDIATE ; DEFERRED
DEFERRED
其中,规则中目标和依赖如果引用其他的变量,则被立即展开。而规则的命令行中的变量引用
会被延后展开。此模板适合所有的规则,包括明确规则、模式规则、后缀规则、静态模式规则。
2.10 总结
make 的执行过程如下:
1. 依次读取变量“ MAKEFILES”定义的 makefile 文件列表
2. 读取工作目录下的 makefile 文件(根据命名的查找顺序“GNUmakefile”,“makefile”,
“ Makefile”,首先找到那个就读取那个)
2004年9月 11日
25
GUN make
说明:
执行一个规则的过程是这样的:
件的时间戳。如果目标的时间戳比所有依赖文件的时间戳更新(依赖文件在上一次执行make 之后没
有被修改),那么什么也不做。否则(依赖文件中的某一个或者全部在上一次执行make 后已经被修
中文手册
3. 依次读取工作目录 makefile 文件中使用指示符“ include”包含的文件
4. 查找重建所有已读取的 makefile 文件的规则(如果存在一个目标是当前读取的某一个
makefile 文件,则执行此规则重建此 makefile 文件,完成以后从第一步开始重新执行)
5. 初始化变量值并展开那些需要立即展开的变量和函数并根据预设条件确定执行分支
6. 根据“终极目标”以及其他目标的依赖关系建立依赖关系链表
7. 执行除“终极目标”以外的所有的目标的规则(规则中如果依赖文件中任一个文件的时间
戳比目标文件新,则使用规则所定义的命令重建目标文件)
8. 执行“终极目标”所在的规则
对于一个存在的规则(明确规则和隐含规则)首先,make程序将比较目标文件和所有的依赖文
改过),规则所定义的重建目标的命令将会被执行。这就是make 工作的基础,也是其执行规制所定
义命令的依据。(后续讨论规则时将会对此详细地说明)
第三章:Makefile 的规则
3 Makefile规则
本章我们开始讨论 Makefile 的一个重要内容, Makefile 的规则。
Makefile 中,规则描述了何种情况下使用什么命令来重建一个特定的文件,此文件被称为规则
“目标”(通常规则中的目标只有一个)。规则所罗列的其他文件称为“目标”的依赖,而规则中的
命令是用来更新或者创建此规则的目标。
除了 makefile 的“终极目标”所在的规则以外,其他规则的顺序在 makefile 文件中没有意
义。“终极目标”就是当没有使用 make 命令行指定具体目标时,make 默认的哪一个目标。它是
makefile 文件中第一个规则的目标。如果在 makefile 中第一个规则有多个目标的话,那么多个目
标中的第一个将会被作为 make 的“终极目标”。有两种情况的例外:1. 目标名是以点号“.”开
始的其后不存在斜线“/”(“./”被认为是当前目录;“../”被认为是上一级目录);2. 作为模式
规则的目标。此两种情况的 Makefile 的第一个目标都不会被作为“终极目标”来对待。
2004年9月 11日
26
GUN make
中文手册
“终极目标”是执行 make 的唯一目的,其所在的规则作为第一个规则。而其他的规则是在完
成重建“终极目标”的过程中被连带出来的。所以这些目标所在规则在 Makefile 中的顺序无关紧
要。
因此,我们书写的 makefile 的第一个规则应该就是重建整个程序或者多个程序的依赖关系和
执行命令的描述。
3.1 一个例子
我们来看一个规则的例子:
foo.o : foo.c defs.h # module for twiddling the frobs
cc -c -g foo.c
这是一个典型的规则。看到这个例子,大家也许能够说出这个规则的各个部分之间的关系。不
过我们还是要把这个例子拿出来讨论。目的是让我们更加明确的理解 Makefile 的规则。本例第一
行中,文件“foo.o ”是规则需要重建的文件,而“foo.c ”和“defs.h ”是重建“foo.o ”所要使
用的文件。我们把规则所需要重建的文件称为规则的“目标”(foo.o ),而把重新目标所需要的文
件称为“目标”的“依赖”。规则中的第二行“cc -c -g foo.c ”就是规则的“命令”。它描述了如何
使用规则中的依赖文件重建目标。
而且,上面的规则告诉我们了两件事:
1. 如何确定目标文件是否过期(需要重建目标),过期是指目标文件不存在或者目标文件
“foo.o ”在时间戳上比依赖文件中的任何一个“foo.c ”或者“defs.h ”“老”。
2. 如何重建目标文件“foo.o ”。这个规则中使用 cc 编译器。在命令中没有明确的使用到依赖
文件“defs.h ”。我们假设在源文件“foo.c ”中已经包含了此头文件。这也是为什么它作
为目标依赖出现的原因。
3.2 规则语法
通常规则的语法格式如下:
TARGETS : PREREQUISITES
COMMAND
...
或者是这样:
TARGETS : PREREQUISITES ; COMMAND
COMMAND
...
2004年9月 11日
27
GUN make
中文手册
规则中“TARGETS ”可以是空格分开的多个文件名,也可以是一个标签(执行清空的“clean”)。
“TARGETS”的文件名可以使用通配符,格式“A(M)”表示档案文件(Linux下的静态库.a文件)
的成员“M”(关于静态库的重建可参考
目标文件(建议这么做),偶尔会在一个规则中需要多个目标(可参考
第十章 使用make 更新静态库文件)。通常规则只有一个
3.10 多目标 一节)。
书写规则是我们需要注意的几点:
1. 规则的命令部分有两种书写方式:a. 命令可以和目标:依赖描述放在同一行。命令在依赖
文件列表后并使用分号(;)和依赖文件列表分开。b. 命令在目标:依赖的描述的下一行,
作为独立的命令行。当作为独立的命令行时此行必须以[Tab]字符开始。在 Makefile 中,
在第一个规则之后出现的所有以[Tab]字符开始的行都会被当作命令来处理。
2. Mak efile 中对“$ ”有特殊的含义(表示变量或者函数的引用),如果我们的规则如果需要
“$ ”,需要书写两个连续的(“$$ ”)。
3. 在前边我们也提到过,Makefile 一个较长的行,可以使用反斜线“\ ”将其书写到几个独
立的物理行上。虽然 make 对 Makefile 文本行的最大长度是没有限制的,但是还是建议
这样做。不仅书写方便而且更有利于别人的阅读(这也是一个程序员修养的体现)。
一个规则告诉“make ”两件事:1. 目标在什么情况下已经过期; 2. 在需要重建目标的时候,
怎么样去重建这个目标。目标是否过期是由那些使用空格分开的规则的依赖文件所决定的。当目标
文件不存在或者目标文件的最后修改时间比依赖文件中的任何一个都晚,则目标就会被创建或者重
建。也就是说执行规则命令行的前提条件是:1 。 目标文件不存在; 2. 存在一个依赖的最后修改
时间比目标的最后修改时间晚。规则的中心思想就是:目标文件的内容是由依赖文件文件决定,依
赖文件的任何一处改动,将导致目前已经存在的目标文件的内容过期。规则的命令为重建目标提供
了方法。这些命令运行在系统 shell 之上。
3.3 依赖的类型
GNU make 的规则中可以使用两种不同类型的依赖:1. 在以前章节所提到的规则中使用的是
常规依赖,这是我们书写的 Makefile 规则中最常用的一种。2. 另外一种在我们书写 Makefile 时
不会经常使用,它比较特殊、称之为“order-only ”依赖。一个规则的常规依赖(通常是多个依赖文
件)表明了两件事:首先,它决定了重建规则目标所要执行命令的顺序;表明在更新这个规则的目
标(执行此规则的命令行)之前必需要按照什么样的顺序、执行那些命令来重建这些依赖文件(对
所有依赖文件的重建,使用明确或者隐含规则。就是说对于这样的规则:A:B C ,那么在重建目标
A 之前,首先需要完成对它的依赖文件 B 和 C 的重建。重建 B 和 C 的过程就是执行 Makefile 中文
件 B 和 C 所在的规则)。其次,它确定了一个依存关系;规则中如果依赖文件的任何一个比目标文
件新,则被认为规则的目标已经过期同时需要重建目标。
2004年9月 11日
28
GUN make
中文手册
通常,如果规则中依赖文件中的任何一个被更新,则规则的目标相应地也应该被更新。
有时,我们需要定义一个这样的规则,在更新目标(目标文件已经存在)时只需要根据依赖文
件中的部分来决定目标是否需要被重建,而不是在依赖文件的任何一个被修改后都重建目标。为了
实现这个目的,我们需要对依赖进行分类,一类是这些依赖文件的更新需要对应更新目标文件,另
一类是这些依赖的更新不会导致目标被重建。第二类的依赖我们就称他为:“order-only ”依赖。在
书写规则时,“order-only ”依赖使用管道符号“|”开始,作为目标的一个依赖文件。规则的依赖列
表中管道符号“| ”左边的是常规依赖文件,所有出现在管道符号右边的就是“order-only ”依赖。
这样的规则书写格式如下:
TARGETS : NORMAL-PREREQUISITES | ORDER-ONLY-PREREQUISITES
规则中常规依赖文件可以是空。允许对一个目标声明多行按正确顺序依次追加的依赖。需要注
意:规则依赖文件中如果一个文件被同时声明为常规依赖和“order-only ”依赖,那么此文件被作
为常规依赖处理(因为常规依赖所实现的动作是“order-only ”依赖所实现的动作的一个超集)。
“ order-only”依赖的使用举例:
LIBS = libtest.a
foo : foo.c | $(LIBS)
$(CC) $(CFLAGS) $< -o $@ $(LIBS)
make在执行这个规则时,如果目标文件“ foo”已经存在。当“ foo.c”被修改以后,目标“ foo”将会被重建,
但是当“libtest.a ”被修改以后。将不执行规则的命令来重建目标“foo ”。
就是说,规则中依赖文件$(LIBS) 只有在目标文件不存在的情况下,才会参与规则的执行。当目标文件存在时此
依赖不会参与规则的执行过程。
3.4 文件名使用通配符
Maekfile 中表示一个单一的文件名时可使用通配符。可使用的通配符有:“* ”、“ ? ”和“ […] ”。
在 Makefile 中通配符的用法和含义和 Linux(unix )的 Bourne shell 完全相同。例如,“*.c ”代
表了当前工作目录下所有的以“.c ”结尾的文件等。但是在 Makefile 中这些统配符并不是可以用
在任何地方,Makefile 中统配符可以出现在以下两种场合:
1. 可以用在规则的目标、依赖中,此时 make 会自动将其展开;
2. 可出现在规则的命令中,其展开是在 shell 在执行此命令时完成。
除这两种情况之外的其它上下文中,不能直接使用通配符。二是需要通过函数“wildcard ”(可
参考
7.3 文件名处理函数 一节)来实现。
如果规则中的某一个文件的文件名包含作为统配符的字符(“* ”、“.”字符),在使用文件时需
要对文件名中的统配字符进行转义处理,使用反斜线(\ )来进行通配符的转义。例如“foo\*bar ”,
在 Makefile 中它表示了文件“foo*bar ”。Makefile 中对一些特殊字符的转移和 B-SHELL 以及 C
2004年9月 11日
29
GUN make
中文手册
语言中的基本上相同。
另外需要注意:在 Linux (unix )中,以波浪线“~ ”开始的文件名有特殊含义。
单独使用它或者其后跟一个斜线(~/ ),代表了当前用户的宿主目录。(在 shell 下可以通过命
令“echo ~(~\) ”来查看)。例如“~/bin ”代表“/home/username/bin/ ”(当前用户宿主目
录下的 bin 目录)
波浪线之后跟一个单词(~word ),其代表由这个“word ”所指定的用户的宿主目录。例如
“~john/bin ”就是代表用户 john 的宿主目录下的 bin 目录。
在一些系统中(像 MS-DOS 和 MS-Windows ),用户没有各自的宿主目录,此情况下可通过
设置环境变量“HOME ”来模拟。
3.4.1 统配符使用举例
本节开始已经提到过,通配符可被用在规则的命令中,它是在命令被执行时由 shell 进行处理
的。例如 Makefile 的清空过程文件规则:
clean:
rm -f *.o
通配符也可以用在规则的依赖文件名中。看看下面这个例子。执行“make print ”,执行的结
果是打印当前工作目录下所有的在上一次打印以后被修改过的“.c ”文件。
print: *.c
lpr -p $?
touch print
两点说明:1. 上述的规则中目标“print”时一个空目标文件。(不存在一个这样的文件,此目
标不代表一个文件,它只是记录了一个所要执行的动作或者命令。参考
3.8 空目标文件 一节)。
2. 自动环变量“ $?”用在这里表示依赖文件列表中被改变过的所有文件。
变量定义中使用的通配符不会被展开(因此在定义变量不能按照这这种方式,下一小节将会详
细讨论)。如果 Makefile 有这样一句:“objects = *.o ”。那么变量“objects ”的值就是“*.o ”,而
不是使用空格分开的所有.o 文件列表。如果需要变量“objects ”代表所有的.o 文件,则需要是用
函数“wildcard ”来实现(objects = $(wildcar *.o) )。
3.4.2 通配符存在的缺陷
上一小节已经提到过在变量定义时使用通配符可能会导致意外的结果。本小节将此详细地分析
和讨论。在书写 Makefile 时,可能存在这种不正确使用通配符的方法。这种看似正确的方式产生
的结果可能并非你所期望得到的。假如在你的 makefile 中,期望能够根据所有的.o 文件生成可执
2004年9月 11日
30