GNU Make 使用手册中译版.docx
《GNU Make 使用手册中译版.docx》由会员分享,可在线阅读,更多相关《GNU Make 使用手册中译版.docx(130页珍藏版)》请在冰豆网上搜索。
GNUMake使用手册中译版
GNUMakeversion3.79
April2000
RichardM.StallmanandRolandMcGrath
1Make概述
Make可自动决定一个大程序中哪些文件需要重新编译,并发布重新编译它们的命令。
本版本GNUMake使用手册由RichardM.StallmanandRolandMcGrath编著,是从PaulD.Smith撰写的V3.76版本发展过来的。
GNUMake符合IEEEStandard1003.2-1992(POSIX.2)6.2章节的规定。
因为C语言程序更具有代表性,所以我们的例子基于C语言程序,但Make并不是仅仅能够处理C语言程序,它可以处理那些编译器能够在Shell命令下运行的的各种语言的程序。
事实上,GNUMake不仅仅限于程序,它可以适用于任何如果一些文件变化导致另外一些文件必须更新的任务。
如果要使用Make,必须先写一个称为Makefile的文件,该文件描述程序中各个文件之间的相互关系,并且提供每一个文件的更新命令。
在一个程序中,可执行程序文件的更新依靠OBJ文件,而OBJ文件是由源文件编译得来的。
一旦合适的Makefile文件存在,每次更改一些源文件,在shell命令下简单的键入:
make
就能执行所有的必要的重新编译任务。
Make程序根据Makefile文件中的数据和每个文件更改的时间戳决定哪些文件需要更新。
对于这些需要更新的文件,Make基于Makefile文件发布命令进行更新,进行更新的方式由提供的命令行参数控制。
具体操作请看运行Make章节。
怎样阅读本手册
如果你现在对Make一无所知或者你仅需要了解对make的普通性介绍,请查阅前几章内容,略过后面的章节。
前几章节是普通介绍性内容,后面的章节是具体的专业、技术内容。
如果你对其它Make程序十分熟悉,请参阅GNUMake的特点和不兼容性和失去的特点部分,GNUMake的特点这一章列出了GNUMake对make程序的扩展,不兼容和失去的特点一章解释了其它Make程序有的特征而GNUMake缺乏的原因。
对于快速浏览者,请参阅选项概要、快速参考和内建的特殊目标名部分。
问题和BUG
如果你有关于GNUMake的问题或者你认为你发现了一个BUG,请向开发者报告;我们不能许诺我们能干什么,但我们会尽力修正它。
在报告BUG之前,请确定你是否真正发现了BUG,仔细研究文档后确认它是否真的按你的指令运行。
如果文档不能清楚的告诉你怎么做,也要报告它,这是文档的一个BUG。
在你报告或者自己亲自修正BUG之前,请把它分离出来,即在使问题暴露的前提下尽可能的缩小Makefile文件。
然后把这个Makefile文件和Make给出的精确结果发给我们。
同时请说明你希望得到什么,这可以帮助我们确定问题是否出在文档上。
一旦你找到一个精确的问题,请给我们发E-mail,我们的E-mail地址是:
bug-make@gnu.org
在邮件中请包含你使用的GNUMake的版本号。
你可以利用命令‘make--version’得到版本号。
同时希望你提供你的机器型号和操作系统类型,如有可能的话,希望同时提供config.h文件(该文件有配置过程产生)。
2Makefile文件介绍
Make程序需要一个所谓的Makefile文件来告诉它干什么。
在大多数情况下,Makefile文件告诉Make怎样编译和连接成一个程序。
本章我们将讨论一个简单的Makefile文件,该文件描述怎样将8个C源程序文件和3个头文件编译和连接成为一个文本编辑器。
Makefile文件可以同时告诉Make怎样运行所需要的杂乱无章的命令(例如,清除操作时删除特定的文件)。
如果要看更详细、复杂的Makefile文件例子,请参阅复杂的Makefile文件例子一章。
当Make重新编译这个编辑器时,所有改动的C语言源文件必须重新编译。
如果一个头文件改变,每一个包含该头文件的C语言源文件必须重新编译,这样才能保证生成的编辑器是所有源文件更新后的编辑器。
每一个C语言源文件编译后产生一个对应的OBJ文件,如果一个源文件重新编译,所有的OBJ文件无论是刚刚编译得到的或原来编译得到的必须从新连接,形成一个新的可执行文件。
规则的格式
一个简单的Makefile文件包含一系列的“规则”,其样式如下:
目标(target)…:
依赖(prerequiries)…
命令(command)
…
…
目标(target)通常是要产生的文件的名称,目标的例子是可执行文件或OBJ文件。
目标也可是一个执行的动作名称,诸如‘clean’(详细内容请参阅假想目标一节)。
依赖是用来输入从而产生目标的文件,一个目标经常有几个依赖。
命令是Make执行的动作,一个规则可以含有几个命令,每个命令占一行。
注意:
每个命令行前面必须是一个Tab字符,即命令行第一个字符是Tab。
这是不小心容易出错的地方。
通常,如果一个依赖发生变化,则需要规则调用命令对相应依赖和服务进行处理从而更新或创建目标。
但是,指定命令更新目标的规则并不都需要依赖,例如,包含和目标‘clean’相联系的删除命令的规则就没有依赖。
规则一般是用于解释怎样和何时重建特定的文件,这些特定文件是这个详尽规则的目标。
Make需首先调用命令对依赖进行处理,进而才能创建或更新目标。
当然,一个规则也可以是用于解释怎样和何时执行一个动作,详见编写规则一章。
一个Makefile文件可以包含规则以外的其它文本,但一个简单的Makefile文件仅仅需要包含规则。
虽然真正的规则比这里展示的例子复杂,但格式却是完全一样。
一个简单的Makefile文件
一个简单的Makefile文件,该文件描述了一个称为文本编辑器(edit)的可执行文件生成方法,该文件依靠8个OBJ文件(.o文件),它们又依靠8个C源程序文件和3个头文件。
在这个例子中,所有的C语言源文件都包含‘defs.h’头文件,但仅仅定义编辑命令的源文件包含‘command.h’头文件,仅仅改变编辑器缓冲区的低层文件包含‘buffer.h’头文件。
edit:
main.okbd.ocommand.odisplay.o\
insert.osearch.ofiles.outils.o
cc-oeditmain.okbd.ocommand.odisplay.o\
insert.osearch.ofiles.outils.o
main.o:
main.cdefs.h
cc-cmain.c
kbd.o:
kbd.cdefs.hcommand.h
cc-ckbd.c
command.o:
command.cdefs.hcommand.h
cc-ccommand.c
display.o:
display.cdefs.hbuffer.h
cc-cdisplay.c
insert.o:
insert.cdefs.hbuffer.h
cc-cinsert.c
search.o:
search.cdefs.hbuffer.h
cc-csearch.c
files.o:
files.cdefs.hbuffer.hcommand.h
cc-cfiles.c
utils.o:
utils.cdefs.h
cc-cutils.c
clean:
rmeditmain.okbd.ocommand.odisplay.o\
insert.osearch.ofiles.outils.o
我们把每一个长行使用反斜杠-新行法分裂为两行或多行,实际上它们相当于一行,这样做的意图仅仅是为了阅读方便。
使用Makefile文件创建可执行的称为‘edit’的文件,键入:
make
使用Makefile文件从目录中删除可执行文件和目标,键入:
makeclean
在这个Makefile文件例子中,目标包括可执行文件‘edit’和OBJ文件‘main.o’及‘kdb.o’。
依赖是C语言源文件和C语言头文件如‘main.c’和‘def.h’等。
事实上,每一个OBJ文件即是目标也是依赖。
所以命令行包括‘cc-cmain.c’和‘cc-ckbd.c’。
当目标是一个文件时,如果它的任意一个依赖发生变化,目标必须重新编译和连接。
任何命令行的第一个字符必须是‘Tab’字符,这样可以把Makefile文件中的命令行与其它行分别开来。
(一定要牢记:
Make并不知道命令是如何工作的,它仅仅能向你提供保证目标的合适更新的命令。
Make的全部工作是当目标需要更新时,按照你制定的具体规则执行命令。
)
目标‘clean’不是一个文件,仅仅是一个动作的名称。
正常情况下,在规则中‘clean’这个动作并不执行,目标‘clean’也不需要任何依赖。
一般情况下,除非特意告诉make执行‘clean’命令,否则‘clean’命令永远不会执行。
注意这样的规则不需要任何依赖,它们存在的目的仅仅是执行一些特殊的命令。
像这些不需要依赖仅仅表达动作的目标称为假想目标。
详细内容参见假想目标;参阅命令错误可以了解rm或其它命令是怎样导致make忽略错误的。
make处理makefile文件的过程
缺省情况下,make开始于第一个目标(假想目标的名称前带‘.’)。
这个目标称为缺省最终目标(即make最终更新的目标,具体内容请看指定最终目标的参数一节)。
在上节的简单例子中,缺省最终目标是更新可执行文件‘edit’,所以我们将该规则设为第一规则。
这样,一旦你给出命令:
make
make就会读当前目录下的makefile文件,并开始处理第一条规则。
在本例中,第一条规则是连接生成‘edit’,但在make全部完成本规则工作之前,必须先处理‘edit’所依靠的OBJ文件。
这些OBJ文件按照各自的规则被处理更新,每个OBJ文件的更新规则是编译其源文件。
重新编译根据其依靠的源文件或头文件是否比现存的OBJ文件更‘新’,或者OBJ文件是否存在来判断。
其它规则的处理根据它们的目标是否和缺省最终目标的依赖相关联来判断。
如果一些规则和缺省最终目标无任何关联则这些规则不会被执行,除非告诉Make强制执行(如输入执行makeclean命令)。
在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可执行文件。
使用变量简化makefile文件
在我们的例子中,我们在‘edit’的生成规则中把所有的OBJ文件列举了两次,这里再重复一遍:
edit:
main.okbd.ocommand.odisplay.o\
insert.osearch.ofiles.outils.o
cc-oeditmain.okbd.ocommand.odisplay.o\
insert.osearch.ofiles.outils.o
这样的两次列举有出错的可能,例如在系统中加入一个新的OBJ文件,我们很有可能在一个需要列举的地方加入了,而在另外一个地方却忘记了。
我们使用变量可以简化makefile文件并且排除这种出错的可能。
变量是定义一个字符串一次,而能在多处替代该字符串使用(具体内容请阅读使用变量一节)。
在makefile文件中使用名为objects,OBJECTS,objs,OBJS,obj,或OBJ的变量代表所有OBJ文件已是约定成俗。
在这个makefile文件我们定义了名为objects的变量,其定义格式如下:
objects=main.okbd.ocommand.odisplay.o\
insert.osearch.ofiles.outils.o
然后,在每一个需要列举OBJ文件的地方,我们使用写为’$(objects)'形式的变量代替(具体内容请阅读使用变量一节)。
下面是使用变量后的完整的makefile文件:
objects=main.okbd.ocommand.odisplay.o\
insert.osearch.ofiles.outils.o
edit:
$(objects)
cc-oedit$(objects)
main.o:
main.cdefs.h
cc-cmain.c
kbd.o:
kbd.cdefs.hcommand.h
cc-ckbd.c
command.o:
command.cdefs.hcommand.h
cc-ccommand.c
display.o:
display.cdefs.hbuffer.h
cc-cdisplay.c
insert.o:
insert.cdefs.hbuffer.h
cc-cinsert.c
search.o:
search.cdefs.hbuffer.h
cc-csearch.c
files.o:
files.cdefs.hbuffer.hcommand.h
cc-cfiles.c
utils.o:
utils.cdefs.h
cc-cutils.c
clean:
rmedit$(objects)
让make推断命令
编译单独的C语言源程序并不需要写出命令,因为make可以把它推断出来:
make有一个使用‘CC–c’命令的把C语言源程序编译更新为相同文件名的OBJ文件的隐含规则。
例如make可以自动使用‘cc-cmain.c-omain.o’命令把‘main.c’编译‘main.o’。
因此,我们可以省略OBJ文件的更新规则。
详细内容请看使用隐含规则一节。
如果C语言源程序能够这样自动编译,则它同样能够自动加入到依赖中。
所以我们可在依赖中省略C语言源程序,进而可以省略命令。
下面是使用隐含规则和变量objects的完整makefile文件的例子:
objects=main.okbd.ocommand.odisplay.o\
insert.osearch.ofiles.outils.o
edit:
$(objects)
cc-oedit$(objects)
main.o:
defs.h
kbd.o:
defs.hcommand.h
command.o:
defs.hcommand.h
display.o:
defs.hbuffer.h
insert.o:
defs.hbuffer.h
search.o:
defs.hbuffer.h
files.o:
defs.hbuffer.hcommand.h
utils.o:
defs.h
.PHONY:
clean
clean:
-rmedit$(objects)
这是我们实际编写makefile文件的例子。
(和目标‘clean’联系的复杂情况在别处阐述。
具体参见假想目标及命令错误两节内容。
)因为隐含规则十分方便,所以它们非常重要,在makefile文件中经常使用它们。
另一种风格的makefile文件
当时在makefile文件中使用隐含规则创建OBJ文件时,采用另一种风格的makefile文件也是可行的。
在这种风格的makefile文件中,可以依据依赖分组代替依据目标分组。
下面是采用这种风格的makefile文件:
objects=main.okbd.ocommand.odisplay.o\
insert.osearch.ofiles.outils.o
edit:
$(objects)
cc-oedit$(objects)
$(objects):
defs.h
kbd.ocommand.ofiles.o:
command.h
display.oinsert.osearch.ofiles.o:
buffer.h
这里的defs.h是所有OBJ文件的共同的一个依赖;command.h和bufffer.h是具体列出的OBJ文件的共同依赖。
虽然采用这种风格编写makefile文件更具风味:
makefile文件更加短小,但一部分人以为把每一个目标的信息放到一起更清晰易懂而不喜欢这种风格。
在目录中删除文件的规则
编译程序并不是编写make规则的唯一事情。
Makefile文件可以告诉make去完成编译程序以外的其它任务,例如,怎样删除OBJ文件和可执行文件以保持目录的‘干净’等。
下面是删除利用make规则编辑器的例子:
clean:
rmedit$(objects)
在实际应用中,应该编写较为复杂的规则以防不能预料的情况发生。
更接近实用的规则样式如下:
.PHONY:
clean
clean:
-rmedit$(objects)
这样可以防止make因为存在名为’clean’的文件而发生混乱,并且导致它在执行rm命令时发生错误(具体参见假想目标及命令错误两节内容)。
诸如这样的规则不能放在makefile文件的开始,因为我们不希望它变为缺省最终目标。
应该像我们的makefile文件例子一样,把关于edit的规则放在前面,从而把编译更新edit可执行程序定为缺省最终目标。
3编写makefile文件
make编译系统依据的信息来源于称为makefile文件的数据库。
makefile文件的内容
makefile文件包含5方面内容:
具体规则、隐含规则、定义变量、指令和注释。
规则、变量和指令将在后续章节介绍。
1.具体规则用于阐述什么时间或怎样重新生成称为规则目标的一个或多个文件的。
它列举了目标所依靠的文件,这些文件称为该目标的依赖。
具体规则可能同时提供了创建或更新该目标的命令。
详细内容参阅编写规则一章。
2.隐含规则用于阐述什么时间或怎样重新生成同一文件名的一系列文件的。
它描述的目标是根据和它名字相同的文件进行创建或更新的,同时提供了创建或更新该目标的命令。
详细内容参阅使用隐含规则一节。
3.定义变量是为一个变量赋一个固定的字符串值,从而在以后的文件中能够使用该变量代替这个字符串。
注意在makefile文件中定义变量占一独立行。
在上一章的makefile文件例子中我们定义了代表所有OBJ文件的变量objects(详细内容参阅使用变量简化makefile文件一节)。
4.指令是make根据makefile文件执行一定任务的命令。
这些包括如下几方面:
a)读其它makefile文件(详细内容参见包含其它的makefile文件)。
b)判定(根据变量的值)是否使用或忽略makefile文件的部分内容(详细内容参阅makefile文件的条件语句一节)。
c)定义多行变量,即定义变量值可以包含多行字符的变量(详细内容参见定义多行变量一节)。
5.以‘#’开始的行是注释行。
注释行在处理时将被make忽略,如果一个注释行在行尾是‘\’则表示下一行继续为注释行,这样注释可以持续多行。
除在define指令内部外,注释可以出现在makefile文件的任何地方,甚至在命令内部(这里shell决定什么是注释内容)。
makfile文件的命名
缺省情况下,当make寻找makefile文件时,它试图搜寻具有如下的名字的文件,按顺序:
‘GNUmakefile’、‘makefile’和‘Makefile’。
通常情况下你应该把你的makefile文件命名为‘makefile’或‘Makefile’。
(我们推荐使用‘Makefile’,因为它基本出现在目录列表的前面,后面挨着其它重要的文件如‘README’等。
)。
虽然首先搜寻‘GNUmakefile’,但我们并不推荐使用。
除非你的makefile文件是特为GNUmake编写的,在其它make版本上不能执行,你才应该使用‘GNUmakefile’作为你的makefile的文件名。
如果make不能发现具有上面所述名字的文件,它将不使用任何makefile文件。
这样你必须使用命令参数给定目标,make试图利用内建的隐含规则确定如何重建目标。
详细内容参见使用隐含规则一节。
如果你使用非标准名字makefile文件,你可以使用‘-f’或‘--file’参数指定你的makefile文件。
参数‘-fname’或‘--file=name’能够告诉make读名字为‘name’的文件作为makefile文件。
如果你使用‘-f’或‘--file’参数多于一个,意味着你指定了多个makefile文件,所有的makefile文件按具体的顺序发生作用。
一旦你使用了‘-f’或‘--file’参数,将不再自动检查是否存在名为‘GNUmakefile’、‘makefile’或‘Makefile’的makefile文件。
包含其它的makefile文件
include指令告诉make暂停读取当前的makefile文件,先读完include指令指定的makefile文件后再继续。
指令在makefile文件占单独一行,其格式如下:
includefilenames...
filenames可以包含shell文件名的格式。
在include指令行,行开始处的多余的空格是允许的,但make处理时忽略这些空格,注意该行不能以Tab字符开始(因为,以Tab字符开始的行,make认为是命令行)。
include和文件名之间以空格隔开,两个文件名之间也以空格隔开,多余的空格make处理时忽略,在该行的尾部可以加上以‘#’为起始的注释。
文件名可以包含变量及函数调用,它们在处理时由make进行扩展(具体内容参阅使用变量一节)。
例如,有三个‘.mk’文件:
‘a.mk’、‘b.mk’和‘c.mk’,变量$(bar)扩展为bishbash,则下面的表达是:
includefoo*.mk$(bar)
和‘includefooa.mkb.mkc.mkbishbash’等价。
当make遇见include指令时,make就暂停读取当前的makefile文件,依次读取列举的makefile文件,读完之后,make再继续读取当前makefile文件中include指令以后的内容。
使用include指令的一种情况是几个程序分别有单独的makefile文件,但它们需要一系列共同的变量定义(详细内容参阅设置变量),或者一系列共同的格式规则(详细内容参阅定义与重新定义格式规则)。
另一种使用include指令情况是需要自动从源文件为目标产生依赖的情况,此时,依赖在主makefile文件包含的文件中。
这种方式比其它版本的mak