QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 2735|回复: 0

GNU Make 使用手册(中译版)

[复制链接]
发表于 2005-10-2 11:54:01 | 显示全部楼层 |阅读模式
GNU Make 使用手册(中译版)
翻译:于凤昌
译者注:本人在阅读Linux源代码过程中发现如果要全面了解Linux的结构、理解Linux的编程总体设计及思想必须首先全部读通Linux源代码中各级的Makefile文件。目前,在网上虽然有一些著作,但都不能全面的解释Linux源代码中各级的Makefile文件,因此本人认真阅读了GNU Make 使用手册(3.79)版原文,在此基础上翻译了该手册,以满足对Linux源代码有兴趣或者希望采用GCC编写程序但对缺乏GNU Make全面了解之人士的需要。本人是业余爱好不是专业翻译人士,如果有问题请通过电子信箱与我联系共同商讨,本人的E-mail为:[email protected] 。注意在文章中出现的斜体加粗字表示章节。
GNU make Version 3.79
April 2000
Richard M. Stallman and Roland McGrath

目录
1 make概述
1.1 怎样阅读本手册
1.2 问题和BUG
2 Makefile文件介绍
2.1 规则的格式
2.2一个简单的Makefile文件
2.3make处理Makefile文件的过程
2.4使用变量简化Makefile文件
2.5让make推断命令
2.6另一种风格的Makefile文件
2.7在目录中删除文件的规则
3         编写Makefile文件
3.1Makefile文件的内容
3.2Makefile文件的命名
3.3包含其它的Makefile文件
3.4变量MAKEFILES
3.5Makefile文件重新生成的过程
3.6重载其它Makefile文件
3.7make读取Makefile文件的过程
4 编写规则
4.1规则的语法
4.2在文件名中使用通配符
4.2.1通配符例子
4.2.2使用通配符的常见错误
4.2.3函数wildcard
4.3在目录中搜寻依赖
4.3.1VPATH:所有依赖的搜寻路径
4.3.2vpath指令
4.3.3目录搜寻过程
4.3.4编写搜寻目录的shell命令
4.3.5目录搜寻和隐含规则
4.3.6连接库的搜寻目录
4.4假想目标
4.5没有命令或依赖的规则
4.6使用空目录文件记录事件
4.7内建的特殊目标名
4.8具有多个目标的规则
4.9具有多条规则的目标
4.10静态格式规则
4.10.1静态格式规则的语法
4.10.2静态格式规则和隐含规则
4.11双冒号规则
4.12自动生成依赖
5 在规则中使用命令
5.1命令回显
5.2执行命令
5.3并行执行
5.4命令错误
5.5中断或关闭make
5.6递归调用make
5.6.1变量MAKE的工作方式
5.6.2与子make通讯的变量
5.6.3与子make通讯的选项
5.6.4`--print-directory'选项
5.7定义固定次序命令
5.8使用空命令
6         使用变量
6.1变量引用基础
6.2变量的两个特色
6.3变量高级引用技术
6.3.1替换引用
6.3.2嵌套变量引用
6.4变量取值
6.5设置变量
6.6为变量值追加文本
6.7override指令
6.8定义多行变量
6.9环境变量
6.10特定目标变量的值
6.11特定格式变量的值
7 Makefile文件的条件语句
7.1条件语句的例子
7.2条件语句的语法
7.3测试标志的条件语句
8 文本转换函数
8.1函数调用语法
8.2字符串替换和分析函数
8.3文件名函数
8.4函数foreach
8.5函数if
8.6函数call
8.7函数origin
8.8函数shell
8.9控制Make的函数
9         运行make
9.1指定Makefile文件的参数
9.2指定最终目标的参数
9.3代替执行命令
9.4避免重新编译文件
9.5变量重载
9.6测试编译程序
9.7选项概要
10 使用隐含规则
10.1使用隐含规则
10.2隐含规则目录
10.3隐含规则使用的变量
10.4隐含规则链
10.5定义与重新定义格式规则
10.5.1格式规则简介
10.5.2格式规则的例子
10.5.3自动变量
10.5.4格式匹配
10.5.5万用规则
10.5.6删除隐含规则
10.6定义最新类型的缺省规则
10.7过时的后缀规则
10.8隐含规则搜寻算法
11 使用make更新档案文件
11.1档案成员目标
11.2档案成员目标的隐含规则
11.2.1更新档案成员的符号索引表
11.3使用档案的危险
11.4档案文件的后缀规则
12 GNU make的特点
13 不兼容性和失去的特点
14 Makefile文件惯例
14.1makefile文件的通用惯例
14.2makefile文件的工具
14.3指定命令的变量
14.4安装路径变量
14.5用户标准目标
14.6安装命令分类
15快速参考
16make产生的错误
17复杂的Makefile文件例子
   附录  名词翻译对照表
1 Make 概述
Make 可自动决定一个大程序中哪些文件需要重新编译,并发布重新编译它们的命令。本版本GNU Make使用手册由Richard M. Stallman and Roland McGrath编著,是从Paul D. Smith撰写的V3.76版本发展过来的。
GNU Make符合IEEE Standard 1003.2-1992 (POSIX.2) 6.2章节的规定。
因为C语言程序更具有代表性,所以我们的例子基于C语言程序,但Make并不是仅仅能够处理C语言程序,它可以处理那些编译器能够在Shell命令下运行的的各种语言的程序。事实上,GNU Make不仅仅限于程序,它可以适用于任何如果一些文件变化导致另外一些文件必须更新的任务。
如果要使用Make,必须先写一个称为Makefile的文件,该文件描述程序中各个文件之间的相互关系,并且提供每一个文件的更新命令。在一个程序中,可执行程序文件的更新依靠OBJ文件,而OBJ文件是由源文件编译得来的。
一旦合适的Makefile文件存在,每次更改一些源文件,在shell命令下简单的键入:
make
就能执行所有的必要的重新编译任务。Make程序根据Makefile文件中的数据和每个文件更改的时间戳决定哪些文件需要更新。对于这些需要更新的文件, Make基于Makefile文件发布命令进行更新,进行更新的方式由提供的命令行参数控制。具体操作请看运行Make章节。
1.1怎样阅读本手册
如果您现在对Make一无所知或者您仅需要了解对make 的普通性介绍,请查阅前几章内容,略过后面的章节。前几章节是普通介绍性内容,后面的章节是具体的专业、技术内容。
如果您对其它Make程序十分熟悉,请参阅GNU Make的特点和不兼容性和失去的特点部分,GNU Make的特点这一章列出了GNU Make对make程序的扩展,不兼容和失去的特点一章解释了其它Make程序有的特征而GNU Make缺乏的原因。
对于快速浏览者,请参阅选项概要、快速参考和内建的特殊目标名部分。
1.2问题和BUG
如果您有关于GNU Make的问题或者您认为您发现了一个BUG,请向开发者报告;我们不能许诺我们能干什么,但我们会尽力修正它。在报告BUG之前,请确定您是否真正发现了BUG,仔细研究文档后确认它是否真的按您的指令运行。如果文档不能清楚的告诉您怎么做,也要报告它,这是文档的一个BUG。
在您报告或者自己亲自修正BUG之前,请把它分离出来,即在使问题暴露的前提下尽可能的缩小Makefile文件。然后把这个Makefile文件和Make给出的精确结果发给我们。同时请说明您希望得到什么,这可以帮助我们确定问题是否出在文档上。
一旦您找到一个精确的问题,请给我们发E-mail,我们的E-mail地址是:
[email protected]
在邮件中请包含您使用的GNU Make的版本号。您可以利用命令‘make--version’得到版本号。同时希望您提供您的机器型号和操作系统类型,如有可能的话,希望同时提供config.h文件(该文件有配置过程产生)。
2 Makefile文件介绍
Make程序需要一个所谓的Makefile文件来告诉它干什么。在大多数情况下,Makefile文件告诉Make怎样编译和连接成一个程序。
本章我们将讨论一个简单的Makefile文件,该文件描述怎样将8个C源程序文件和3个头文件编译和连接成为一个文本编辑器。Makefile文件可以同时告诉Make怎样运行所需要的杂乱无章的命令(例如,清除操作时删除特定的文件)。如果要看更详细、复杂的Makefile文件例子,请参阅复杂的 Makefile文件例子一章。
当Make重新编译这个编辑器时,所有改动的C语言源文件必须重新编译。如果一个头文件改变,每一个包含该头文件的C语言源文件必须重新编译,这样才能保证生成的编辑器是所有源文件更新后的编辑器。每一个C语言源文件编译后产生一个对应的OBJ文件,如果一个源文件重新编译,所有的OBJ文件无论是刚刚编译得到的或原来编译得到的必须从新连接,形成一个新的可执行文件。
2.1 规则的格式
一个简单的Makefile文件包含一系列的“规则”,其样式如下:
目标(target)…: 依赖(prerequiries)…
<tab>命令(command)
  …
  …
目标(target)通常是要产生的文件的名称,目标的例子是可执行文件或OBJ文件。目标也可是一个执行的动作名称,诸如‘clean’(详细内容请参阅假想目标一节)。
依赖是用来输入从而产生目标的文件,一个目标经常有几个依赖。
命令是Make执行的动作,一个规则可以含有几个命令,每个命令占一行。注意:每个命令行前面必须是一个Tab字符,即命令行第一个字符是Tab。这是不小心容易出错的地方。
通常,如果一个依赖发生变化,则需要规则调用命令对相应依赖和服务进行处理从而更新或创建目标。但是,指定命令更新目标的规则并不都需要依赖,例如,包含和目标‘clern’相联系的删除命令的规则就没有依赖。
规则一般是用于解释怎样和何时重建特定文件的,这些特定文件是这个详尽规则的目标。Make需首先调用命令对依赖进行处理,进而才能创建或更新目标。当然,一个规则也可以是用于解释怎样和何时执行一个动作,详见编写规则一章。
一个Makefile文件可以包含规则以外的其它文本,但一个简单的Makefile文件仅仅需要包含规则。虽然真正的规则比这里展示的例子复杂,但格式却是完全一样。
2.2一个简单的Makefile文件
一个简单的Makefile文件,该文件描述了一个称为文本编辑器(edit)的可执行文件生成方法,该文件依靠8个OBJ文件(.o文件),它们又依靠8个C源程序文件和3个头文件。
在这个例子中,所有的C语言源文件都包含‘defs.h’ 头文件,但仅仅定义编辑命令的源文件包含‘command.h’头文件,仅仅改变编辑器缓冲区的低层文件包含‘buffer.h’头文件。
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文件创建可执行的称为‘edit’的文件,键入:make
使用Makefile文件从目录中删除可执行文件和目标,键入:make clean
在这个Makefile文件例子中,目标包括可执行文件‘edit’和OBJ文件‘main.o’及‘kdb.o’。依赖是C语言源文件和C语言头文件如 ‘main.c’和‘def.h’等。事实上,每一个OBJ文件即是目标也是依赖。所以命令行包括‘cc -c main.c’和‘cc -c kbd.c’。
当目标是一个文件时,如果它的任一个依赖发生变化,目标必须重新编译和连接。任何命令行的第一个字符必须是‘Tab’字符,这样可以把Makefile文件中的命令行与其它行分别开来。(一定要牢记:Make并不知道命令是如何工作的,它仅仅能向您提供保证目标的合适更新的命令。 Make的全部工作是当目标需要更新时,按照您制定的具体规则执行命令。)
目标‘clean’不是一个文件,仅仅是一个动作的名称。正常情况下,在规则中‘clean’这个动作并不执行,目标‘clean’也不需要任何依赖。一般情况下,除非特意告诉make执行‘clean’命令,否则 ‘clean’命令永远不会执行。注意这样的规则不需要任何依赖,它们存在的目的仅仅是执行一些特殊的命令。象这些不需要依赖仅仅表达动作的目标称为假想目标。详细内容参见假想目标;参阅命令错误可以了解rm或其它命令是怎样导致make忽略错误的。
2.3 make处理makefile文件的过程
缺省情况下,make开始于第一个目标(假想目标的名称前带‘.’)。这个目标称为缺省最终目标(即make最终更新的目标,具体内容请看指定最终目标的参数一节)。
在上节的简单例子中,缺省最终目标是更新可执行文件‘edit’,所以我们将该规则设为第一规则。这样,一旦您给出命令:
make
make 就会读当前目录下的makefile文件,并开始处理第一条规则。在本例中,第一条规则是连接生成‘edit’,但在make全部完成本规则工作之前,必须先处理‘edit’所依靠的OBJ文件。这些OBJ文件按照各自的规则被处理更新,每个OBJ文件的更新规则是编译其源文件。重新编译根据其依靠的源文件或头文件是否比现存的OBJ文件更‘新’,或者OBJ文件是否存在来判断。
其它规则的处理根据它们的目标是否和缺省最终目标的依赖相关联来判断。如果一些规则和缺省最终目标无任何关联则这些规则不会被执行,除非告诉Make强制执行(如输入执行make clean命令)。
  在OBJ文件重新编译之前,Make首先检查它的依赖C语言源文件和C语言头文件是否需要更新。如果这些C语言源文件和C语言头文件不是任何规则的目标, make将不会对它们做任何事情。Make也可以自动产生C语言源程序,这需要特定的规则,如可以根据Bison或Yacc产生C语言源程序。
在OBJ文件重新编译(如果需要的话)之后,make决定是否重新连接生成edit可执行文件。如果edit可执行文件不存在或任何一个OBJ文件比存在的edit可执行文件‘新’,则make重新连接生成edit可执行文件。
  这样,如果我们修改了‘insert.c’文件,然后运行make,make将会编译‘insert.c’文件更新‘insert.o’文件,然后重新连接生成edit可执行文件。如果我们修改了‘command.h’文件,然后运行make,make将会重新编译‘kbd.o’和‘command.o’ 文件,然后重新连接生成edit可执行文件。
2.4使用变量简化makefile文件
在我们的例子中,我们在‘edit’的生成规则中把所有的OBJ文件列举了两次,这里再重复一遍:
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
这样的两次列举有出错的可能,例如在系统中加入一个新的OBJ文件,我们很有可能在一个需要列举的地方加入了,而在另外一个地方却忘记了。我们使用变量可以简化makefile文件并且排除这种出错的可能。变量是定义一个字符串一次,而能在多处替代该字符串使用(具体内容请阅读使用变量一节)。
在makefile文件中使用名为objects, OBJECTS, objs, OBJS, obj, 或 OBJ的变量代表所有OBJ文件已是约定成俗。在这个makefile文件我们定义了名为objects的变量,其定义格式如下:
objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o
然后,在每一个需要列举OBJ文件的地方,我们使用写为`$(objects)'形式的变量代替(具体内容请阅读使用变量一节)。下面是使用变量后的完整的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 : 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 $(objects)
2.5 让make推断命令
编译单独的C语言源程序并不需要写出命令,因为make可以把它推断出来:make有一个使用‘CC –c’命令的把C语言源程序编译更新为相同文件名的OBJ文件的隐含规则。例如make可以自动使用‘cc -c main.c -o main.o’命令把‘main.c’编译 ‘main.o’。因此,我们可以省略OBJ文件的更新规则。详细内容请看使用隐含规则一节。
如果C语言源程序能够这样自动编译,则它同样能够自动加入到依赖中。所以我们可在依赖中省略C语言源程序,进而可以省略命令。下面是使用隐含规则和变量objects的完整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’联系的复杂情况在别处阐述。具体参见假想目标及命令错误两节内容。)因为隐含规则十分方便,所以它们非常重要,在makefile文件中经常使用它们。
2.6 另一种风格的makefile文件
当时在makefile文件中使用隐含规则创建OBJ文件时,采用另一种风格的makefile文件也是可行的。在这种风格的makefile文件中,可以依据依赖分组代替依据目标分组。下面是采用这种风格的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是所有OBJ文件的共同的一个依赖;command.h和bufffer.h是具体列出的OBJ文件的共同依赖。
虽然采用这种风格编写makefile文件更具风味:makefile文件更加短小,但一部分人以为把每一个目标的信息放到一起更清晰易懂而不喜欢这种风格。
2.7 在目录中删除文件的规则
编译程序并不是编写make规则的唯一事情。Makefile文件可以告诉make去完成编译程序以外的其它任务,例如,怎样删除OBJ文件和可执行文件以保持目录的‘干净’等。下面是删除利用make规则编辑器的例子:
clean:
        rm edit $(objects)
在实际应用中,应该编写较为复杂的规则以防不能预料的情况发生。更接近实用的规则样式如下:
.PHONY : clean
clean :
        -rm edit $(objects)
这样可以防止make因为存在名为’clean’的文件而发生混乱,并且导致它在执行rm命令时发生错误(具体参见假想目标及命令错误两节内容)。
诸如这样的规则不能放在makefile文件的开始,因为我们不希望它变为缺省最终目标。应该象我们的makefile文件例子一样,把关于edit的规则放在前面,从而把编译更新edit可执行程序定为缺省最终目标。
3 编写makefile文件
make编译系统依据的信息来源于称为makefile文件的数据库。
3.1 makefile文件的内容
makefile文件包含5方面内容:具体规则、隐含规则、定义变量、指令和注释。规则、变量和指令将在后续章节介绍。
l         具体规则用于阐述什么时间或怎样重新生成称为规则目标的一个或多个文件的。它列举了目标所依靠的文件,这些文件称为该目标的依赖。具体规则可能同时提供了创建或更新该目标的命令。详细内容参阅编写规则一章。
l         隐含规则用于阐述什么时间或怎样重新生成同一文件名的一系列文件的。它描述的目标是根据和它名字相同的文件进行创建或更新的,同时提供了创建或更新该目标的命令。详细内容参阅使用隐含规则一节。
l         定义变量是为一个变量赋一个固定的字符串值,从而在以后的文件中能够使用该变量代替这个字符串。注意在makefile文件中定义变量占一独立行。在上一章的makefile文件例子中我们定义了代表所有OBJ文件的变量objects(详细内容参阅使用变量简化makefile文件一节)。
l         指令是make根据makefile文件执行一定任务的命令。这些包括如下几方面:
n n         读其它makefile文件(详细内容参见包含其它的makefile文件)。
n n         判定(根据变量的值)是否使用或忽略makefile文件的部分内容(详细内容参阅makefile文件的条件语句一节)。
n n         定义多行变量,n 即定义变量值可以包含多行字符的变量(详细内容参见定义多行变量一节)。
l         以‘#’开始的行是注释行。注释行在处理时将被make忽略,如果一个注释行在行尾是‘\’则表示下一行继续为注释行,这样注释可以持续多行。除在 define指令内部外,注释可以出现在makefile文件的任何地方,甚至在命令内部(这里shell决定什么是注释内容)。
3.2 makfile文件的命名
缺省情况下,当make寻找makefile文件时,它试图搜寻具有如下的名字的文件,按顺序:‘GNUmakefile’、‘makefile’和‘Makefile’。
通常情况下您应该把您的makefile文件命名为‘makefile’或‘Makefile’。(我们推荐使用‘Makefile’,因为它基本出现在目录列表的前面,后面挨着其它重要的文件如‘README’等。)。虽然首先搜寻‘GNUmakefile’,但我们并不推荐使用。除非您的 makefile文件是特为GNU make编写的,在其它make版本上不能执行,您才应该使用‘GNUmakefile’作为您的makefile的文件名。
如果make不能发现具有上面所述名字的文件,它将不使用任何makefile文件。这样您必须使用命令参数给定目标,make试图利用内建的隐含规则确定如何重建目标。详细内容参见使用隐含规则一节。
如果您使用非标准名字makefile文件,您可以使用‘-f’或‘--file’参数指定您的makefile文件。参数‘-f name’或‘--file=name’能够告诉make读名字为‘name’的文件作为makefile文件。如果您使用 ‘-f’或‘--file’参数多于一个,意味着您指定了多个makefile文件,所有的makefile文件按具体的顺序发生作用。一旦您使用了‘- f’或‘--file’参数,将不再自动检查是否存在名为‘GNUmakefile’、‘makefile’或‘Makefile’的makefile文件。
3.3 包含其它的makefile文件
include指令告诉make暂停读取当前的makefile文件,先读完include指令指定的makefile文件后再继续。指令在makefile文件占单独一行,其格式如下:
include filenames...
filenames可以包含shell文件名的格式。
在include 指令行,行开始处的多余的空格是允许的,但make处理时忽略这些空格,注意该行不能以Tab字符开始(因为,以Tab字符开始的行,make认为是命令行)。include和文件名之间以空格隔开,两个文件名之间也以空格隔开,多余的空格make处理时忽略,在该行的尾部可以加上以‘#’为起始的注释。文件名可以包含变量及函数调用,它们在处理时由make进行扩展(具体内容参阅使用变量一节)。
例如,有三个‘.mk’文件:‘a.mk’、‘b.mk’和‘c.mk’,变量$(bar)扩展为bish bash,则下面的表达是:
include foo *.mk $(bar)
和‘include foo a.mk b.mk c.mk bish bash’等价。
    当make遇见include指令时, make就暂停读取当前的makefile文件,依次读取列举的makefile文件,读完之后,make再继续读取当前makefile�
您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-5-7 14:41 , Processed in 0.089864 second(s), 15 queries .

© 2021 Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表