文件chmod用法

chmod用法  时间:2021-04-05  阅读:()

GNUMake使用手册(中译版)GNUMake使用手册(中译版)翻译:于凤昌译者注:本人在阅读Linux源代码过程中发现如果要全面了解Linux的结构、理解Linux的编程总体设计及思想必须首先全部读通Linux源代码中各级的Makefile文件.
目前,在网上虽然有一些著作,但都不能全面的解释Linux源代码中各级的Makefile文件,因此本人认真阅读了GNUMake使用手册(3.
79)版原文,在此基础上翻译了该手册,以满足对Linux源代码有兴趣或者希望采用GCC编写程序但对缺乏GNUMake全面了解之人士的需要.
本人是业余爱好不是专业翻译人士,如果有问题请通过电子信箱与我联系共同商讨,本人的E-mail为:yfc70@public2.
lyptt.
ha.
cn.
注意在文章中出现的斜体加粗字表示章节.
GNUmakeVersion3.
79April2000RichardM.
StallmanandRolandMcGrath目录1make概述1.
1怎样阅读本手册1.
2问题和BUG2Makefile文件介绍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变量MAKEFILES3.
5Makefile文件重新生成的过程3.
6重载其它Makefile文件3.
7make读取Makefile文件的过程4编写规则4.
1规则的语法http://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第1/79页)2006-8-1818:49:00GNUMake使用手册(中译版)4.
2在文件名中使用通配符4.
2.
1通配符例子4.
2.
2使用通配符的常见错误4.
2.
3函数wildcard4.
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中断或关闭make5.
6递归调用make5.
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特定格式变量的值7Makefile文件的条件语句http://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第2/79页)2006-8-1818:49:01GNUMake使用手册(中译版)7.
1条件语句的例子7.
2条件语句的语法7.
3测试标志的条件语句8文本转换函数8.
1函数调用语法8.
2字符串替换和分析函数8.
3文件名函数8.
4函数foreach8.
5函数if8.
6函数call8.
7函数origin8.
8函数shell8.
9控制Make的函数9运行make9.
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档案文件的后缀规则12GNUmake的特点13不兼容性和失去的特点14Makefile文件惯例14.
1makefile文件的通用惯例14.
2makefile文件的工具14.
3指定命令的变量14.
4安装路径变量14.
5用户标准目标http://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第3/79页)2006-8-1818:49:01GNUMake使用手册(中译版)14.
6安装命令分类15快速参考16make产生的错误17复杂的Makefile文件例子附录名词翻译对照表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章节.
1.
1怎样阅读本手册如果您现在对Make一无所知或者您仅需要了解对make的普通性介绍,请查阅前几章内容,略过后面的章节.
前几章节是普通介绍性内容,后面的章节是具体的专业、技术内容.
如果您对其它Make程序十分熟悉,请参阅GNUMake的特点和不兼容性和失去的特点部分,GNUMake的特点这一章列出了GNUMake对make程序的扩展,不兼容和失去的特点一章解释了其它Make程序有的特征而GNUMake缺乏的原因.
对于快速浏览者,请参阅选项概要、快速参考和内建的特殊目标名部分.
1.
2问题和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个头文件编译和连接成为一个文本编辑器.
http://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第4/79页)2006-8-1818:49:01GNUMake使用手册(中译版)Makefile文件可以同时告诉Make怎样运行所需要的杂乱无章的命令(例如,清除操作时删除特定的文件).
如果要看更详细、复杂的Makefile文件例子,请参阅复杂的Makefile文件例子一章.
当Make重新编译这个编辑器时,所有改动的C语言源文件必须重新编译.
如果一个头文件改变,每一个包含该头文件的C语言源文件必须重新编译,这样才能保证生成的编辑器是所有源文件更新后的编辑器.
每一个C语言源文件编译后产生一个对应的OBJ文件,如果一个源文件重新编译,所有的OBJ文件无论是刚刚编译得到的或原来编译得到的必须从新连接,形成一个新的可执行文件.
2.
1规则的格式一个简单的Makefile文件包含一系列的"规则",其样式如下:目标(target)…:依赖(prerequiries)…命令(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.
okbd.
ocommand.
odisplay.
o\insert.
osearch.
ofiles.
outils.
occ-oeditmain.
okbd.
ocommand.
odisplay.
o\insert.
osearch.
ofiles.
outils.
omain.
o:main.
cdefs.
hcc-cmain.
ckbd.
o:kbd.
cdefs.
hcommand.
hcc-ckbd.
ccommand.
o:command.
cdefs.
hcommand.
hcc-ccommand.
cdisplay.
o:display.
cdefs.
hbuffer.
hcc-cdisplay.
cinsert.
o:insert.
cdefs.
hbuffer.
hcc-cinsert.
csearch.
o:search.
cdefs.
hbuffer.
hcc-csearch.
cfiles.
o:files.
cdefs.
hbuffer.
hcommand.
hcc-cfiles.
cutils.
o:utils.
cdefs.
hcc-cutils.
cclean:rmeditmain.
okbd.
ocommand.
odisplay.
o\http://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第5/79页)2006-8-1818:49:01GNUMake使用手册(中译版)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忽略错误的.
2.
3make处理makefile文件的过程缺省情况下,make开始于第一个目标(假想目标的名称前带'.
').
这个目标称为缺省最终目标(即make最终更新的目标,具体内容请看指定最终目标的参数一节).
在上节的简单例子中,缺省最终目标是更新可执行文件'edit',所以我们将该规则设为第一规则.
这样,一旦您给出命令:makemake就会读当前目录下的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可执行文件.

2.
4使用变量简化makefile文件在我们的例子中,我们在'edit'的生成规则中把所有的OBJ文件列举了两次,这里再重复一遍:edit:main.
okbd.
ocommand.
odisplay.
o\insert.
osearch.
ofiles.
outils.
occ-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.
ohttp://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第6/79页)2006-8-1818:49:01GNUMake使用手册(中译版)edit:$(objects)cc-oedit$(objects)main.
o:main.
cdefs.
hcc-cmain.
ckbd.
o:kbd.
cdefs.
hcommand.
hcc-ckbd.
ccommand.
o:command.
cdefs.
hcommand.
hcc-ccommand.
cdisplay.
o:display.
cdefs.
hbuffer.
hcc-cdisplay.
cinsert.
o:insert.
cdefs.
hbuffer.
hcc-cinsert.
csearch.
o:search.
cdefs.
hbuffer.
hcc-csearch.
cfiles.
o:files.
cdefs.
hbuffer.
hcommand.
hcc-cfiles.
cutils.
o:utils.
cdefs.
hcc-cutils.
cclean:rmedit$(objects)2.
5让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.
oedit:$(objects)cc-oedit$(objects)main.
o:defs.
hkbd.
o:defs.
hcommand.
hcommand.
o:defs.
hcommand.
hdisplay.
o:defs.
hbuffer.
hinsert.
o:defs.
hbuffer.
hsearch.
o:defs.
hbuffer.
hfiles.
o:defs.
hbuffer.
hcommand.
hutils.
o:defs.
h.
PHONY:cleanclean:-rmedit$(objects)这是我们实际编写makefile文件的例子.
(和目标'clean'联系的复杂情况在别处阐述.
具体参见假想目标及命令错误两节内容.
)因为隐含规则十分方便,所以它们非常重要,在makefile文件中经常使用它们.
2.
6另一种风格的makefile文件当时在makefile文件中使用隐含规则创建OBJ文件时,采用另一种风格的makefile文件也是可行的.
在这种风格的makefile文件中,可以依据依赖分组代替依据目标分组.
下面是采用这种风格的makefile文件:objects=main.
okbd.
ocommand.
odisplay.
o\insert.
osearch.
ofiles.
outils.
ohttp://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第7/79页)2006-8-1818:49:01GNUMake使用手册(中译版)edit:$(objects)cc-oedit$(objects)$(objects):defs.
hkbd.
ocommand.
ofiles.
o:command.
hdisplay.
oinsert.
osearch.
ofiles.
o:buffer.
h这里的defs.
h是所有OBJ文件的共同的一个依赖;command.
h和bufffer.
h是具体列出的OBJ文件的共同依赖.
虽然采用这种风格编写makefile文件更具风味:makefile文件更加短小,但一部分人以为把每一个目标的信息放到一起更清晰易懂而不喜欢这种风格.
2.
7在目录中删除文件的规则编译程序并不是编写make规则的唯一事情.
Makefile文件可以告诉make去完成编译程序以外的其它任务,例如,怎样删除OBJ文件和可执行文件以保持目录的'干净'等.
下面是删除利用make规则编辑器的例子:clean:rmedit$(objects)在实际应用中,应该编写较为复杂的规则以防不能预料的情况发生.
更接近实用的规则样式如下:.
PHONY:cleanclean:-rmedit$(objects)这样可以防止make因为存在名为'clean'的文件而发生混乱,并且导致它在执行rm命令时发生错误(具体参见假想目标及命令错误两节内容).
诸如这样的规则不能放在makefile文件的开始,因为我们不希望它变为缺省最终目标.
应该象我们的makefile文件例子一样,把关于edit的规则放在前面,从而把编译更新edit可执行程序定为缺省最终目标.
3编写makefile文件make编译系统依据的信息来源于称为makefile文件的数据库.
3.
1makefile文件的内容makefile文件包含5方面内容:具体规则、隐含规则、定义变量、指令和注释.
规则、变量和指令将在后续章节介绍.
l具体规则用于阐述什么时间或怎样重新生成称为规则目标的一个或多个文件的.
它列举了目标所依靠的文件,这些文件称为该目标的依赖.
具体规则可能同时提供了创建或更新该目标的命令.
详细内容参阅编写规则一章.
l隐含规则用于阐述什么时间或怎样重新生成同一文件名的一系列文件的.
它描述的目标是根据和它名字相同的文件进行创建或更新的,同时提供了创建或更新该目标的命令.
详细内容参阅使用隐含规则一节.
l定义变量是为一个变量赋一个固定的字符串值,从而在以后的文件中能够使用该变量代替这个字符串.
注意在makefile文件中定义变量占一独立行.
在上一章的makefile文件例子中我们定义了代表所有OBJ文件的变量objects(详细内容参阅使用变量简化makefile文件一节).
l指令是make根据makefile文件执行一定任务的命令.
这些包括如下几方面:n读其它makefile文件(详细内容参见包含其它的makefile文件).
n判定(根据变量的值)是否使用或忽略makefile文件的部分内容(详细内容参阅makefile文件的条件语句一节).
n定义多行变量,即定义变量值可以包含多行字符的变量(详细内容参见定义多行变量一节).
l以'#'开始的行是注释行.
注释行在处理时将被make忽略,如果一个注释行在行尾是'\'则表示下一行继续为注释行,这样注释可以持续多行.
除在define指令内部外,注释可以出现在makefile文件的任何地方,甚至在命令内部(这里shell决定什么是注释内容).
3.
2makfile文件的命名http://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第8/79页)2006-8-1818:49:01GNUMake使用手册(中译版)缺省情况下,当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文件.
3.
3包含其它的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文件包含的文件中.
这种方式比其它版本的make把依赖附加在主makefile文件后部的传统方式更显得简洁.
具体内容参阅自动产生依赖.
如果makefile文件名不以'/'开头,并且在当前目录下也不能找到,则需搜寻另外的目录.
首先,搜寻以'-|'或'--include-dir'参数指定的目录,然后依次搜寻下面的目录(如果它们存在的话):'prefix/include'(通常为'/usr/local/include')'/usr/gnu/include','/usr/local/include','/usr/include'.
如果指定包含的makefile文件在上述所有的目录都不能找到,make将产生一个警告信息,注意这不是致命的错误.
处理完include指令包含的makefile文件之后,继续处理当前的makefile文件.
一旦完成makefile文件的读取操作,make将试图创建或更新过时的或不存在的makefile文件.
详细内容参阅makefile文件重新生成的过程.
只有在所有make寻求丢失的makefile文件的努力失败后,make才能断定丢失的makefile文件是一个致命的错误.
如果您希望对不存在且不能重新创建的makefile文件进行忽略,并且不产生错误信息,则使用-include指令代替include指令,格式如下:-includefilenames.
.
.
这种指令的作用就是对于任何不存在的makefile文件都不会产生错误(即使警告信息也不会产生).
如果希望保持和其它版本的make兼容,使用sinclude指令代替-include指令.
3.
4变量MAKEFILES如果定义了环境变量MAKEFILES,make认为该变量的值是一列附加的makefile文件名,文件名之间由空格隔开,并且这些makefile文件应首先读取.
Make完成这个工作和上节完成include指令的方式基本相同,即在特定的目录中搜寻这些文件.
值得注意的是,缺省最终目标不会出现在这些makefile文件中,而且如果一些makefile文件没有找到也不会出现任何错误信息.
环境变量MAKEFILES主要在make递归调用过程中起通讯作用(详细内容参阅递归调用make).
在make顶级调用之前设置环境变量并不是十分好的主意,因为这样容易将makefile文件与外界的关系弄的更加混乱.
然而如果运行make而缺少makefile文件时,环境变量MAKEFILES中makefile文件可以使内置的隐含规则更好的发挥作用,如搜寻定义的路径等(详细内容参阅在目录中搜寻依赖).
http://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第9/79页)2006-8-1818:49:01GNUMake使用手册(中译版)一些用户喜欢在登录时自动设置临时的环境变量MAKEFILES,而makefile文件在该变量指定的文件无效时才使用.
这是非常糟糕的主意,应为许多makefile文件在这种情况下运行失效.
最好的方法是直接在makefile文件中写出具体的include指令(详细内容参看上一节).
3.
5makefile文件重新生成的过程有时makefile文件可以由其它文件重新生成,如从RCS或SCCS文件生成等.
如果一个makefile文件可以从其它文件重新生成,一定注意让make更新makefile文件之后再读取makefile文件.
完成读取所有的makefile文件之后,make检查每一个目标,并试图更新它.
如果对于一个makefile文件有说明它怎样更新的规则(无论在当前的makefile文件中或其它makefile文件中),或者存在一条隐含规则说明它怎样更新(具体内容参见使用隐含规则),则在必要的时候该makefile文件将会自动更新.
在所有的makefile文件检查之后,如果发现任何一个makefile文件发生变化,make就会清空所有记录,并重新读入所有makefile文件.
(然后再次试图更新这些makefile文件,正常情况下,因为这些makefile文件已被更新,make将不会再更改它们.
)如果您知道您的一个或多个makefile文件不能重新创建,也许由于执行效率缘故,您不希望make按照隐含规则搜寻或重建它们,您应使用正常的方法阻止按照隐含规则检查它们.
例如,您可以写一个具体的规则,把这些makefile文件当作目标,但不提供任何命令(详细内容参阅使用空命令).
如果在makefile文件中指定依据双冒号规则使用命令重建一个文件,但没有提供依赖,则一旦make运行就会重建该文件(详细内容参见双冒号规则).
同样,如果在makefile文件中指定依据双冒号规则使用命令重建的一个makefile文件,并且不提供依赖,则一旦make运行就会重建该makefile文件,然后重新读入所有makefile文件,然后再重建该makefile文件,再重新读入所有makefile文件,如此往复陷入无限循环之中,致使make不能再完成别的任务.
如果要避免上述情况的发生,一定注意不要依据双冒号规则使用命令并且不提供依赖重建任何makefile文件.
如果您没有使用'-f'或'--file'指定makefile文件,make将会使用缺省的makefile文件名(详细内容参见3.
2节内容).
不象使用'-f'或'--file'选项指定具体的makefile文件,这时make不能确定makefile文件是否存在.
如果缺省的makefile文件不存在,但可以由运行的make依据规则创建,您需要运行这些规则,创建要使用的makefile文件.
如果缺省的makefile文件不存在,make将会按照搜寻的次序将它们试着创建,一直到将makefile文件成功创建或make将所有的文件名都试过来.
注意make不能找到或创建makefile文件不是错误,makefile文件并不是运行make必须的.
因为即使您使用'-t'特别指定,'-t'或'--touch'选项对更新makefile文件不产生任何影响,makefile文件仍然会更新,所以当您使用'-t'或'--touch'选项时,您不要使用过时的makefile文件来决定'touch'哪个目标(具体含义参阅代替执行命令).
同样,因为'-q'(或'--question')和'-n'(或'--just-print')也能不阻止更新makefile文件,所以过时的makefile文件对其它的目标将产生错误的输出结果.
如,'make-fmfile-nfoo'命令将这样执行:更新'mfile',然后读入,再输出更新'foo'的命令和依赖,但并不执行更新'foo',注意,所有回显的更新'foo'的命令是在更新后的'mfile'中指定的.
在实际使用过程中,您一定会遇见确实希望阻止更新makefile文件的情况.
如果这样,您可以在makefile文件命令行中将需要更新的makefile文件指定为目标,如此则可阻止更新makefile文件.
一旦makefile文件名被明确指定为一个目标,选项'-t'等将会对它发生作用.
如这样设定,'make-fmfile-nfoo'命令将这样执行:读入'mfile',输出更新'foo'的命令和依赖,但并不执行更新'foo'.
回显的更新'foo'的命令包含在现存的'mfile'中.
3.
6重载其它makefile文件有时一个makefile文件和另一个makefile文件相近也是很有用的.
您可以使用'include'指令把更多的makefile文件包含进来,如此可加入更多的目标和定义的变量.
然而如果两个makefile文件对相同的目标给出了不同的命令,make就会产生错误.
在主makefile文件(要包含其它makefile文件的那个)中,您可以使用通配符格式规则说明只有在依靠当前makefile文件中的信息不能重新创建目标时,make才搜寻其它的makefile文件,详细内容参见定义与重新定义格式规则.
例如:如果您有一个说明怎样创建目标'foo'(和其它目标)的makefile文件称为'Makefile',您可以编写另外一个称为'GNUmakefile'的makefile文件包含以下语句:foo:frobnicate>foo%:force@$(MAKE)-fMakefile$@force:;如果键入'makefoo',make就会找到'GNUmakefile',读入,然后运行'frobnicate>foo'.
如果键入'makebar',make发现无法根据'GNUmakefile'创建'bar',它将使用格式规则提供的命令:'make–fMakefilebar'.
如果在'Makefile'中提供了'bar'更新的规则,make就会使用该规则.
对其它'GNUmakefile'不提供怎样更新的目标make也会同样处理.
这种工作的方式是使用了格式规则中的格式匹配符'%',它可以和任何目标匹配.
该规则指定了一个依赖'force',用来保证命令一定要执行,无论目标文件是否存在.
我们给出的目标'force'时使用了空命令,这样可防止make按照隐含规则搜寻和创http://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第10/79页)2006-8-1818:49:01GNUMake使用手册(中译版)建它,否则,make将把同样的匹配规则应用到目标'force'本身,从而陷入创建依赖的循环中.
3.
7make读取makefile文件的过程GNUmake把它的工作明显的分为两个阶段.
在第一阶段,make读取makefile文件,包括makefile文件本身、内置变量及其值、隐含规则和具体规则、构造所有目标的依靠图表和它们的依赖等.
在第二阶段,make使用这些内置的组织决定需要重新构造的目标以及使用必要的规则进行工作.
了解make两阶段的工作方式十分重要,因为它直接影响变量、函数扩展方式;而这也是编写makefile文件时导致一些错误的主要来源之一.
下面我们将对makefile文件中不同结构的扩展方式进行总结.
我们称在make工作第一阶段发生的扩展是立即扩展:在这种情况下,make对makefile文件进行语法分析时把变量和函数直接扩展为结构单元的一部分.
我们把不能立即执行的扩展称为延时扩展.
延时扩展结构直到它已出现在上下文结构中或make已进入到了第二工作阶段时才执行展开.
您可能对这一部分内容不熟悉.
您可以先看完后面几章对这些知识熟悉后再参考本节内容.
变量赋值变量的定义语法形式如下:immediate=deferredimmediate=deferredimmediate:=immediateimmediate+=deferredorimmediatedefineimmediatedeferredendef对于附加操作符'+=',右边变量如果在前面使用(:=)定义为简单扩展变量则是立即变量,其它均为延时变量.
条件语句整体上讲,条件语句都按语法立即分析,常用的有:ifdef、ifeq、ifndef和inneq.
定义规则规则不论其形式如何,都按相同的方式扩展.
immediate:immediate;deferreddeferred目标和依赖部分都立即扩展,用于构造目标的命令通常都是延时扩展.
这个通用的规律对具体规则、格式规则、后缀规则、静态格式规则和简单依赖定义都适用.
4编写规则makefile文件中的规则是用来说明何时以及怎样重建特定文件的,这些特定的文件称为该规则的目标(通常情况下,每个规则只有一个目标).
在规则中列举的其它文件称为目标的依赖,同时规则还给出了目标创建、更新的命令.
一般情况下规则的次序无关紧要,但决定缺省最终目标时却是例外.
缺省最终目标是您没有另外指定最终目标时,make认定的最终目标.
缺省最终目标是makefile文件中的第一条规则的目标.
如果第一条规则有多个目标,只有第一个目标被认为是缺省最终目标.
有两种例外的情况:以句点('.
')开始的目标不是缺省最终目标(如果该目标包含一个或多个斜杠'/',则该目标也可能是缺省最终目标);另一种情况是格式规则定义的目标不是缺省最终目标(参阅定义与重新定义格式规则).
所以,我们编写makefile文件时,通常将第一个规则的目标定为编译全部程序或是由makefile文件表述的所有程序(经常设定一个称为'all'的目标).
参阅指定最终目标的参数.
4.
1规则的语法通常一条规则形式如下:targets:prerequisitescommand.
.
.
或:http://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第11/79页)2006-8-1818:49:01GNUMake使用手册(中译版)targets:prerequisites;commandcommand.
.
.
目标(target)是文件的名称,中间由空格隔开.
通配符可以在文件名中使用(参阅在文件名中使用通配符),'a(m)'形式的文件名表示成员m在文件a中(参阅档案成员目标).
一般情况下,一条规则只有一个目标,但偶尔由于其它原因一条规则有多个目标(参阅具有多个目标的规则).
命令行以Tab字符开始,第一个命令可以和依赖在一行,命令和依赖之间用分号隔开,也可以在依赖下一行,以Tab字符为行的开始.
这两种方法的效果一样,参阅在规则中使用命令.
因为美元符号已经用为变量引用的开始符,如果您真希望在规则中使用美元符号,您必须连写两次,'$$'(参阅使用变量).
您可以把一长行在中间插入'\'使其分为两行,也就是说,一行的尾部是'\'的话,表示下一行是本行的继续行.
但这并不是必须的,make没有对makefile文件中行的长度进行限制.
一条规则可以告诉make两件事情:何时目标已经过时,以及怎样在必要时更新它们.
判断目标过时的准则和依赖关系密切,依赖也由文件名构成,文件名之间由空格隔开,通配符和档案成员也允许在依赖中出现.
一个目标如果不存在或它比其中一个依赖的修改时间早,则该目标已经过时.
该思想来源于目标是根据依赖的信息计算得来的,因此一旦任何一个依赖发生变化,目标文件也就不再有效.
目标的更新方式由命令决定.
命令由shell解释执行,但也有一些另外的特点.
参阅在规则中使用命令.
4.
2在文件名中使用通配符一个简单的文件名可以通过使用通配符代表许多文件.
Make中的通配符和Bourneshell中的通配符一样是'*'、''和'[…]'.
例如:'*.
C'指在当前目录中所有以'.
C'结尾的文件.
字符'~'在文件名的前面也有特殊的含义.
如果字符'~'单独或后面跟一个斜杠'/',则代表您的home目录.
如'~/bin'扩展为'/home/bin'.
如果字符'~'后面跟一个字,它扩展为home目录下以该字为名字的目录,如'~John/bin'表示'home/John/bin'.
在一些操作系统(如ms-dos,ms-windows)中不存在home目录,可以通过设置环境变量home来模拟.

在目标、依赖和命令中的通配符自动扩展.
在其它上下文中,通配符只有在您明确表明调用通配符函数时才扩展.
通配符另一个特点是如果通配符前面是反斜杠'\',则该通配符失去通配能力.
如'foo\*bar'表示一个特定的文件其名字由'foo'、'*'和'bar'构成.
4.
2.
1通配符例子通配符可以用在规则的命令中,此时通配符由shell扩展.
例如,下面的规则删除所有OBJ文件:clean:rm–f*.
o通配符在规则的依赖中也很有用.
在下面的makefile规则中,'makeprint'将打印所有从上次您打印以后又有改动的'.
c'文件:print:*.
clpr-p$touchprint本规则使用'ptint'作为一个空目标文件(参看使用空目标文件记录事件);自动变量'$'用来打印那些已经修改的文件,参看自动变量.
当您定义一个变量时通配符不会扩展,如果您这样写:objects=*.
o变量objects的值实际就是字符串'*.
o'.
然而,如果您在一个目标、依赖和命令中使用变量objects的值,通配符将在那时扩展.
使用下面的语句可使通配符扩展:objects=$(wildcard*.
o)详细内容参阅函数wildcard.
4.
2.
2使用通配符的常见错误下面有一个幼稚使用通配符扩展的例子,但实际上该例子不能完成您所希望完成的任务.
假设可执行文件'foo'由在当前目录的所有OBJ文件创建,其规则如下:objects=*.
ohttp://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第12/79页)2006-8-1818:49:01GNUMake使用手册(中译版)foo:$(objects)cc-ofoo$(CFLAGS)$(objects)由于变量objects的值为字符串'*.
o',通配符在目标'foo'的规则下扩展,所以每一个OBJ文件都会变为目标'foo'的依赖,并在必要时重新编译自己.
但如果您已删除了所有的OBJ文件,情况又会怎样呢因没有和通配符匹配的文件,所以目标'foo'就依靠了一个有着奇怪名字的文件'*.
o'.
因为目录中不存在该文件,make将发出不能创建'*.
o'的错误信息.
这可不是所要执行的任务.
实际上,使用通配符获得正确的结果是可能的,但您必须使用稍微复杂一点的技术,该技术包括使用函数wildcard和替代字符串等.
详细内容将在下一节论述.
微软的操作系统(MS-DOS、MS-WINDOWS)使用反斜杠分离目录路径,如:C:\foo\bar\bar.
c这和Unix风格'c:/foo/bar/bar.
c'等价('c:'是驱动器字母).
当make在这些系统上运行时,不但支持在路径中存在反斜杠也支持Unix风格的前斜杠.
但是这种对反斜杠的支持不包括通配符扩展,因为通配符扩展时,反斜杠用作引用字符.
所以,在这些场合您必须使用Unix风格的前斜杠.
4.
2.
3函数wildcard通配符在规则中可以自动扩展,但设置在变量中或在函数的参数中通配符一般不能正常扩展.
如果您需要在这些场合扩展通配符,您应该使用函数wildcard,格式如下:$(wildcardpattern.
.
.
)可以在makefile文件的任何地方使用该字符串,应用时该字符串被一列在指定目录下存在的并且文件名和给出的文件名的格式相符合的文件所代替,文件名中间由空格隔开.
如果没有和指定格式一致的文件,则函数wildcard的输出将会省略.
注意这和在规则中通配符扩展的方式不同,在规则中使用逐字扩展方式,而不是省略方式(参阅上节).
使用函数wildcard得到指定目录下所有的C语言源程序文件名的命令格式为:$(wildcard*.
c)我们可以把所获得的C语言源程序文件名的字符串通过将'.
c'后缀变为'.
o'转换为OBJ文件名的字符串,其格式为:$(patsubst%.
c,%.
o,$(wildcard*.
c))这里我们使用了另外一个函数:patsubst,详细内容参阅字符串替换和分析函数.
这样,一个编译特定目录下所有C语言源程序并把它们连接在一起的makefile文件可以写成如下格式:objects:=$(patsubst%.
c,%.
o,$(wildcard*.
c))foo:$(objects)cc-ofoo$(objects)这里使用了编译C语言源程序的隐含规则,因此没有必要为每个文件写具体编译规则.
':='是'='的变异,对':='的解释,参阅两种风格的变量.
4.
3在目录中搜寻依赖对于大型系统,把源文件安放在一个单独的目录中,而把二进制文件放在另一个目录中是十分常见的.
Make的目录搜寻特性使自动在几个目录搜寻依赖十分容易.
当您在几个目录中重新安排您的文件,您不必改动单独的规则,仅仅改动一下搜寻路径即可.
4.
3.
1VPATH:所有依赖的搜寻路径make变量VPATH的值指定了make搜寻的目录.
经常用到的是那些包含依赖的目录,并不是当前的目录;但VPATH指定了make对所有文件都适用的目录搜寻序列,包括了规则的目标所需要的文件.
如果一个作为目标或依赖的文件在当前目录中不存在,make就会在VPATH指定的目录中搜寻该文件.
如果在这些目录中找到要寻找的文件,则就象这些文件在当前目录下存在一样,规则把这些文件指定为依赖.
参阅编写搜寻目录的shell命令.
在VPATH变量定义中,目录的名字由冒号或空格分开.
目录列举的次序也是make搜寻的次序.
在MS-DOS、MS-WINDOWS系统中,VPATH变量定义中的目录的名字由分号分开,因为在这些系统中,冒号用为路径名的一部分(通常在驱动器字母后面).
例如:VPATH=src:.
.
/headers指定了两个目录,'src'和'…/headers',make也按照这个次序进行搜寻.
使用该VPATH的值,下面的规则,foo.
o:foo.
chttp://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第13/79页)2006-8-1818:49:01GNUMake使用手册(中译版)在执行时就象如下写法一样会被中断:foo.
o:src/foo.
c然后在src目录下搜寻foo.
c.
4.
3.
2vpath指令vpath指令(注意字母是小写)和VPATH变量类似,但却更具灵活性.
vpath指令允许对符合一定格式类型的文件名指定一个搜寻路径.
这样您就可以对一种格式类型的文件名指定一个搜寻路径,对另外格式类型的文件名指定另外一个搜寻路径.
总共由三种形式的vpath指令:vpathpatterndirectories对一定格式类型的文件名指定一个搜寻路径.
搜寻的路径由一列要搜寻的目录构成,目录由冒号(在MS-DOS、MS-WINDOWS系统中用分号)或空格隔开,和VPATH变量定义要搜寻的路径格式一样.
vpathpattern清除和一定类型格式相联系的搜寻路径.
vpath清除所有前面由vapth指令指定的搜寻路径.
一个vpath的格式pattern是一个包含一个'%'的字符串.
该字符串必须和正搜寻的一个依赖的文件名匹配,字符%可和任何字符串匹配(关于格式规则,参阅定义与重新定义格式规则).
例如,%.
h和任何文件名以.
h结尾的文件匹配.
如果不使用'%',格式必须与依赖精确匹配,这种情况很少使用.
在vpath指令格式中的字符'%'可以通过前面的反斜杠被引用.
引用其它字符'%'的反斜杠也可以被更多的反斜杠引用.
引用字符'%'和其它反斜杠的反斜杠在和文件名比较之前和格式是分开的.
如果反斜杠所引用的字符'%'没有错误,则该反斜杠不会运行带来任何危害.
如果vpath指令格式和一个依赖的文件名匹配,并且在当前目录中该依赖不存在,则vpath指令中指定的目录和VPATH变量中的目录一样可以被搜寻.
例如:vpath%.
h.
.
/headers将告诉make如果在当前目录中以'.
h'结尾文件不存在,则在'.
.
/headers'目录下搜寻任何以'.
h'结尾依赖.
如果有几个vpath指令格式和一个依赖的文件名匹配,则make一个接一个的处理它们,搜寻所有在指令中指定的目录.
Make按它们在makefile文件中出现的次序控制多个vpath指令,多个指令虽然有相同的格式,但它们是相互独立的.
以下代码:vpath%.
cfoovpath%blishvpath%.
cbar表示搜寻`.
c'文件先搜寻目录`foo'、然后`blish',最后`bar';如果是如下代码:vpath%.
cfoo:barvpath%blish表示搜寻`.
c'文件先搜寻目录'foo'、然后'bar',最后'blish'.
4.
3.
3目录搜寻过程当通过目录搜寻找到一个文件,该文件有可能不是您在依赖列表中所列出的依赖;有时通过目录搜寻找到的路径也可能被废弃.
Make决定对通过目录搜寻找到的路径保存或废弃所依据的算法如下:1、如果一个目标文件在makefile文件所在的目录下不存在,则将会执行目录搜寻.
2、如果目录搜寻成功,则路径和所得到的文件暂时作为目标文件储存.
3、所有该目标的依赖用相同的方法考察.
4、把依赖处理完成后,该目标可能需要或不需要重新创建:1、如果该目标不需要重建,目录搜寻时所得到的文件的路径用作该目标所有依赖的路径,同时包含该目标文件.
简而言之,如果make不必重建目标,则您使用通过目录搜寻得到的路径.
2、如果该目标需要重建,目录搜寻时所得到的文件的路径将废弃,目标文件在makefile文件所在的目录下重建.
简而言之,如果make要重建目标,是在makefile文件所在的目录下重建目标,而不是在目录搜寻时所得到的文件的路径下.
该算法似乎比较复杂,但它却可十分精确的解释实际您所要的东西.
其它版本的make使用一种比较简单的算法:如果目标文件在当前目录下不存在,而它通过目录搜寻得到,不论该目标是否需要重建,始终使用通过目录搜寻得到的路径.
实际上,如果在GNUmake中使您的一些或全部目录具备这种行为,您可以使用GPATH变量来指定这些目录.
GPATH变量和VPATH变量具有相同的语法和格式.
如果通过目录搜寻得到一个过时的目标,而目标存在的目录又出现在http://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第14/79页)2006-8-1818:49:01GNUMake使用手册(中译版)GPATH变量,则该路径将不废弃,目标将在该路径下重建.
4.
3.
4编写目录搜寻的shell命令即使通过目录搜寻在其它目录下找到一个依赖,不能改变规则的命令,这些命令同样按照原来编写的方式执行.
因此,您应该小心的编写这些命令,以便它们可以在make能够在发现依赖的目录中处理依赖.
借助诸如'$^'的自动变量可更好的使用shell命令(参阅自动变量).
例如,'$^'的值代表所有的依赖列表,并包含寻找依赖的目录;'$@'的值是目标.
foo.
o:foo.
ccc-c$(CFLAGS)$^-o$@变量CFLAGS存在可以方便您利用隐含规则指定编译C语言源程序的旗标.
我们这里使用它是为了保持编译C语言源程序一致性.
参阅隐含规则使用的变量.
依赖通常情况下也包含头文件,因自动变量'$bigoutputlittleoutput:text.
ggeneratetext.
g-little>littleoutput这里我们假设程序可以产生两种输出文件类型:一种给出'-big',另一种给出'-little'.
参阅字符串代替和分析函数,对函数subst的解释.
如果您喜欢根据目标变换依赖,象使用变量'$@'变换命令一样.
您不必使用具有多个目标的规则,您可以使用静态格式规则.
详细内容见下文.
4.
9具有多条规则的目标一个目标文件可以有多个规则.
在所有规则中提及的依赖都将融合在一个该目标的依赖列表中.
如果该目标比任何一个依赖'旧',所有的命令将执行重建该目标.
但如果一条以上的规则对同一文件给出多条命令,make将使用最后给出的规则,同时打印错误信息.
(作为特例,如果文件名以点'.
'开始,不打印出错信息.
这种古怪的行为仅仅是为了和其它版本的make兼容).
您没有必要这样编写您的makefilehttp://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第18/79页)2006-8-1818:49:01GNUMake使用手册(中译版)文件,这正是make给您发出错误信息的原因.
一条特别的依赖规则可以用来立即给多条目标文件提供一些额外的依赖.
例如,使用名为'objects'的变量,该变量包含系统产生的所有输出文件列表.
如果'congfig.
h'发生变化所有的输出文件必须重新编译,可以采用下列简单的方法编写:objects=foo.
obar.
ofoo.
o:defs.
hbar.
o:defs.
htest.
h$(objects):config.
h这些可以自由插入或取出而不影响实际指定的目标文件生成规则,如果您希望断断续续的为目标添加依赖,这是非常方便的方法.
另外一个添加依赖的方法是定义一个变量,并将该变量作为make命令的参数使用.
详细内容参阅变量重载.
例如:extradeps=$(objects):$(extradeps)命令`makeextradeps=foo.
h'含义是将'foo.
h'作为所有OBJ文件的依赖,如果仅仅输入'make'命令则不是这样.
如果没有具体的规则为目标的生成指定命令,那么make将搜寻合适的隐含规则进而确定一些命令来完成生成或重建目标.
详细内容参阅使用隐含规则.
4.
10静态格式规则静态格式规则是指定多个目标并能够根据每个目标名构造对应的依赖名的规则.
静态格式规则在用于多个目标时比平常的规则更常用,因为目标可以不必有完全相同的依赖;也就是说,这些目标的依赖必须类似,但不必完全相同.
4.
10.
1静态格式规则的语法这里是静态格式规则的语法格式:targets.
.
.
:target-pattern:dep-patterns.
.
.
commands.
.
.
目标列表指明该规则应用的目标.
目标可以含有通配符,具体使用和平常的目标规则基本一样(参阅在文件名中使用通配符).
目标的格式和依赖的格式是说明如何计算每个目标依赖的方法.
从匹配目标格式的目标名中依据格式抽取部分字符串,这部分字符串称为径.
将径分配到每一个依赖格式中产生依赖名.
每一个格式通常包含字符'%'.
目标格式匹配目标时,'%'可以匹配目标名中的任何字符串;这部分匹配的字符串称为径;剩下的部分必须完全相同.
如目标'foo.
o'匹配格式'%.
o',字符串'foo'称为径.
而目标'foo.
c'和'foo.
out'不匹配格式.
每个目标的依赖名是使用径代替各个依赖中的'%'产生.
如,如果一个依赖格式为'%.
c',把径'foo'代替依赖格式中的'%'生成依赖的文件名'foo.
c'.
在依赖格式中不包含'%'也是合法的,此时对所有目标来说,依赖是相同的.
在格式规则中字符'%'可以用前面加反斜杠'\'方法引用.
引用'%'的反斜杠也可以由更多的反斜杠引用.
引用'%'、'\'的反斜杠在和文件名比较或由径代替它之前从格式中移走.
反斜杠不会因为引用'%'而混乱.
如,格式`the\%weird\\%pattern\\'是`the%weird\'加上字符'%',后面再和字符串'pattern\\'连接.
最后的两个反斜杠由于不能影响任何统配符'%'所以保持不变.
这里有一个例子,它将对应的'.
c'文件编译成'foo.
o'和'bar.
o'.
objects=foo.
obar.
oall:$(objects)$(objects):%.
o:%.
c$(CC)-c$(CFLAGS)$$@当命令generate执行时,$*扩展为径,即'big'或'little'二者之一.
4.
10.
2静态格式规则和隐含规则静态格式规则和定义为格式规则的隐含规则有很多相同的地方(详细参阅定义与重新定义格式规则).
双方都有对目标的格式和构造依赖名称的格式,差异是make使用它们的时机不同.
隐含规则可以应用于任何于它匹配的目标,但它仅仅是在目标没有具体规则指定命令以及依赖可以被搜寻到的情况下应用.
如果有多条隐含规则适合,仅有执行其中一条规则,选择依据隐含规则的定义次序.
相反,静态格式规则用于在规则中指明的目标.
它不能应用于其它任何目标,并且它的使用方式对于各个目标是固定不变的.
如果使用两个带有命令的规则发生冲突,则是错误.
静态格式规则因为如下原因可能比隐含规则更好:l对一些文件名不能按句法分类的但可以给出列表的文件,使用静态格式规则可以重载隐含规则链.
l如果不能精确确定使用的路径,您不能确定一些无关紧要的文件是否导致make使用错误的隐含规则(因为隐含规则的选择根据其定义次序).
使用静态格式规则则没有这些不确定因素:每一条规则都精确的用于指定的目标上.
4.
11双冒号规则双冒号规则是在目标名后使用'::'代替':'的规则.
当同一个目标在一条以上的规则中出现时,双冒号规则和平常的规则处理有所差异.
当一目标在多条规则中出现时,所有的规则必须是同一类型:要么都是双冒号规则,要么都是普通规则.
如果他们都是双冒号规则,则它们之间都是相互独立的.
如果目标比一个双冒号规则的依赖'旧',则该双冒号规则的命令将执行.
这可导致具有同一目标双冒号规则全部或部分执行.
双冒号规则实际就是将具有相同目标的多条规则相互分离,每一条双冒号规则都独立的运行,就像这些规则的目标不同一样.
对于一个目标的双冒号规则按照它们在makefile文件中出现的顺序执行.
然而双冒号规则真正有意义的场合是双冒号规则和执行顺序无关的场合.
双冒号规则有点模糊难以理解,它仅仅提供了一种在特定情况下根据引起更新的依赖文件不同,而采用不同方式更新目标的机制.
实际应用双冒号规则的情况非常罕见.
每一个双冒号规则都应该指定命令,如果没有指定命令,则会使用隐含规则.
详细内容参阅使用隐含规则.
4.
12自动生成依赖在为一个程序编写的makefile文件中,常常需要写许多仅仅是说明一些OBJ文件依靠头文件的规则.
例如,如果'main.
c'通过一条#include语句使用'defs.
h',您需要写入下的规则:main.
o:defs.
h您需要这条规则让make知道如果'defs.
h'一旦改变必须重新构造'main.
o'.
由此您可以明白对于一个较大的程序您需要在makefile文件中写很多这样的规则.
而且一旦添加或去掉一条#include语句您必须十分小心地更改makefile文件.
为避免这种烦恼,现代C编译器根据原程序中的#include语句可以为您编写这些规则.
如果需要使用这种功能,通常可在编译源程序时加入'-M'开关,例如,下面的命令:cc-Mmain.
c产生如下输出:main.
o:main.
cdefs.
h这样您就不必再亲自写这些规则,编译器可以为您完成这些工作.
注意,由于在makefile文件中提及构造'main.
o',因此'main.
o'将永远不会被隐含规则认为是中间文件而进行搜寻,这同时意味着make不会在使用它之后自动删除它;参阅隐含规则链.
对于旧版的make程序,通过一个请求命令,如'makedepend',利用编译器的特点生成依赖是传统的习惯.
这些命令将产生一个'depend'文件,该文件包含所有自动生成的依赖;然后makefile文件可以使用include命令将它们读入(参阅包含其它makefile文件).
http://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第20/79页)2006-8-1818:49:01GNUMake使用手册(中译版)在GNUmake中,重新构造makefile文件的特点使这个惯例成为了过时的东西――您永远不必具体告诉make重新生成依赖,因为GNUmake总是重新构造任何过时的makefile文件.
参阅Makefile文件的重新生成的过程.
我们推荐使用自动生成依赖的习惯是把makefile文件和源程序文件一一对应起来.
如,对每一个源程序文件'name.
c'有一名为'name.
d'的makefile文件和它对应,该makefile文件中列出了名为'name.
o'的OBJ文件所依赖的文件.
这种方式的优点是仅在源程序文件改变的情况下才有必要重新扫描生成新的依赖.
这里有一个根据C语言源程序'name.
c'生成名为'name.
d'依赖文件的格式规则:%.
d:%.
cset-e;$(CC)-M$(CPPFLAGS)$.
.
/foo如果您喜欢将一个单一的命令分割成多个文本行,您必须用反斜杠作为每一行的结束,最后一行除外.
这样,多个文本行通过删除反斜杠按顺序组成一新行,然后将它传递给shell.
如此,下面的例子和前面的例子是等同的:foo:bar/losecdbar;\gobblelose>.
.
/foo用作shell的程序是由变量SHELL指定,缺省情况下,使用程序'/bin/sh'作为shell.
在MS_DOS上运行,如果变量SHELL没有指定,变量COMSPEC的值用来代替指定shell.
在MS_DOS上运行和在其它系统上运行,对于makefile文件中设置变量SHELL的行的处理也不一样.
因为MS_DOS的shell,'command.
com',功能十分有限,所以许多make用户倾向于安装一个代替的shell.
因此,在MS_DOS上运行,make检测变量SHELL的值,并根据它指定的Unix风格或DOS风格的shell变化它的行为.
即使使用变量SHELL指向'command.
com',make依然检测变量SHELL的值.
如果变量SHELL指定Unix风格的shell,在MS_DOS上运行的make将附加检查指定的shell是否能真正找到;如果不能找到,则忽略指定的shell.
在MS_DOS上,GNUmake按照下述步骤搜寻shell:1、在变量SHELL指定的目录中.
例如,如果makefile指明`SHELL=/bin/sh',make将在当前路径下寻找子目录'/bin'.
2、在当前路径下.
3、按顺序搜寻变量PATH指定的目录.
在所有搜寻的目录中,make首先寻找指定的文件(如例子中的'sh').
如果该文件没有存在,make将在上述目录中搜寻带有确定的可执行文件扩展的文件.
例如:'.
exe','.
com','.
bat','.
btm','.
sh'文件和其它文件等.
如果上述过程中能够成功搜寻一个shell,则变量SHELL的值将设置为所发现shell的全路径文件名.
然而如果上述努力全部失败,变量SHELL的值将不改变,设置shell的行的有效性将被忽略.
这是在make运行的系统中如果确实安装了Unix风格的shell,make仅支持指明的Unix风格shell特点的原因.
注意这种对shell的扩展搜寻仅仅限制在makefile文件中设置变量SHELL的情况.
如果在环境或命令行中设置,希望您指定shell的全路径文件名,而且全路径文件名需象在Unix系统中运行的一样准确无误.
经过上述的DOS特色的处理,而且您还把'sh.
exe'安装在变量PATH指定的目录中,或在makefile文件内部设置`SHELL=/bin/sh'(和多数Unix的makefile文件一样),则在MS_DOS上的运行效果和在Unix上运行完全一样.
不像其它大多数变量,变量SHELL从不根据环境设置.
这是因为环境变量SHELL是用来指定您自己选择交互使用的shell程序.
如果变量SHELL在环境中设置,它将影响makefile文件的功能,这是非常不划算的,参阅环境变量.
然而在MS-DOS和MS-WINDOWS中在环境中设置变量SHELL的值是要使用的,因为在这些系统中,绝大多数用户并不设置该变量的值,所以make很可能特意为该变量指定要使用的值.
在MS-DOS上,如果变量SHELL的设置对于make不合适,您可以设置变量MAKESHELL用来指定make使用的shell;这种设置将使变量SHELL的值失效.
5.
3并行执行GNUmake可以同时执行几条命令.
正常情况下,make一次执行一个命令,待它完成后在执行下一条命令.
然而,使用'-j'和'--jobs'选项将告诉make同时执行多条命令.
在MS-DOS上,'-j'选项没有作用,因为该系统不支持多进程处理.
如果'-j'选项后面跟一个整数,该整数表示一次执行的命令的条数;这称为jobslots数.
如果'-j'选项后面没有整数,也就是没有对jobslots的数目限制.
缺省的jobslots数是一,这意味着按顺序执行(一次执行一条命令).
同时执行多条命令的一个不太理想的结果是每条命令产生的输出与每条命令发送的时间对应,即命令产生的消息回显可能较为混乱.
另一个问题是两个进程不能使用同一设备输入,所以必须确定一次只能有一条命令从终端输入,make只能保证正在运行的命令的标准输入流有效,其它的标准输入流将失效.
这意味着如果有几个同时从标准输入设备输入的话,对于绝大多数子进程将产生致命的错误(即产生一个'Brokenpipe'信号).
命令对一个有效的标准输入流(它从终端输入或您为make改造的标准输入设备输入)的需求是不可预测的.
第一条运行的命令总是第一个得到标准输入流,在完成一条命令后第一条启动的另一条命令将得到下一个标准输入流,等等.
如果我们找到一个更好替换方案,我们将改变make的这种工作方式.
在此期间,如果您使用并行处理的特点,您不应该使用任何需要标准输入的命令.
如果您不使用该特点,任何需要标准输入的命令将都能正常工作.
http://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第22/79页)2006-8-1818:49:01GNUMake使用手册(中译版)最后,make的递归调用也导致出现问题.
更详细的内容参阅与子make通讯的选项.
如果一个命令失败(被一个信号中止,或非零退出),且该条命令产生的错误不能忽略(参阅命令错误),剩余的构建同一目标的命令行将会停止工作.
如果一条命令失败,而且'-k'或'--keep-going'选项也没有给出(参阅选项概要),make将放弃继续执行.
如果make由于某种原因(包括信号)要中止,此时又子进程正在运行,它将等到这些子进程结束之后再实际退出.
当系统正满负荷运行时,您或许希望在负荷轻的时再添加任务.
这时,您可以使用'-|'选项告诉make根据平均负荷限制同一时刻运行的任务数量.
'-|'或'--max-load'选项一般后跟一个浮点数.
例如:-|2.
5将不允许make在平均负荷高于2.
5时启动一项任务.
'-|'选项如果没有跟数据,则取消前面'-|'给定的负荷限制.
更精确地讲,当make启动一项任务时,而它此时已经有至少一项任务正在运行,则它将检查当前的平均负荷;如果不低于'-|'选项给定的负荷限制时,make将等待直到平均负荷低于限制或所有其它任务完成后再启动其它任务.
缺省情况下没有负荷限制.
5.
4命令错误在每一个shell命令返回后,make检查该命令退出的状态.
如果该命令成功地完成,下一个命令行就会在新的子shell环境中执行,当最后一个命令行完成后,这条规则也宣告完成.
如果出现错误(非零退出状态),make将放弃当前的规则,也许是所有的规则.
有时一个特定的命令失败并不是出现了问题.
例如:您可能使用mkdir命令创建一个目录存在,如果该目录已经存在,mkdir将报告错误,但您此时也许要make继续执行.
要忽略一个命令执行产生的错误,请使用字符'-'(在初始化TAB的后面)作为该命令行的开始.
字符'-'在命令传递给shell执行时丢弃.
例如:clean:-rm-f*.
o这条命令即使在不能删除一个文件时也强制rm继续执行.
在运行make时使用'-i'或'--ignore-errors'选项,将会忽略所有规则的命令运行产生的错误.
在makefile文件中使用如果没有依赖的特殊目标.
IGNORE规则,也具有同样的效果.
但因为使用字符'-'更灵活,所以该条规则已经很少使用.
一旦使用'-'或'-i'选项,运行命令时产生的错误被忽略,此时make象处理成功运行的命令一样处理具有返回错误的命令,唯一不同的地方是打印一条消息,告诉您命令退出时的编码状态,并说明该错误已经被忽略.
如果发生错误而make并不说明其被忽略,则暗示当前的目标不能成功重新构造,并且和它直接相关或间接相关的目标同样不能重建.
因为前一个过程没有完成,所以不会进一步执行别的命令.
在上述情况下,make一般立即放弃任务,返回一个非零的状态.
然而,如果指定'-k'或'--keep-goning'选项,make则继续考虑这个目标的其它依赖,如果有必要在make放弃返回非零状态之前重建它们.
例如,在编译一个OBJ文件发生错误后,即使make已经知道将所有OBJ文件连接在一起是不可能的,'make-k'选项也继续编译其它OBJ文件.
详细内容参阅选项概要.
通常情况下,make的行为基于假设您的目的是更新指定的目标,一旦make得知这是不可能的,它将立即报告失败.
'-k'选项是告诉make真正的目的是测试程序中所有变化的可行性,或许是寻找几个独立的问题以便您可以在下次编译之前纠正它们.
这是Emacs编译命令缺省情况下传递'-k'选项的原因.
通常情况下,当一个命令运行失败时,如果它已经改变了目标文件,则该文件很可能发生混乱而不能使用或该文件至少没有完全得到更新.
但是,文件的时间戳却表明该文件已经更新到最新,因此在make下次运行时,它将不再更新该文件.
这种状况和命令被发出的信号强行关闭一样,参阅中断或关闭make.
因此,如果在开始改变目标文件后命令出错,一般应该删除目标文件.
如果.
DELETE_ON_ERROR作为目标在makefile文件中出现,make将自动做这些事情.
这是您应该明确要求make执行的动作,不是以前的惯例;特别考虑到兼容性问题时,您更应明确提出这样的要求.
5.
5中断或关闭make如果make在一条命令运行时得到一个致命的信号,则make将根据第一次检查的时间戳和最后更改的时间戳是否发生变化决定它是否删除该命令要更新的目标文件.
删除目标文件的目的是当make下次运行时确保目标文件从原文件得到更新.
为什么假设正在编译文件时您键入Ctrl-c,而且这时已经开始写OBJ文件'foo.
o',Ctrl-c关闭了该编译器,结果得到不完整的OBJ文件'foo.
o'的时间戳比源程序'foo.
c'的时间戳新,如果make收到Ctrl-c的信号而没有删除OBJ文件'foo.
o',下次请求make更新OBJ文件'foo.
o'时,make将认为该文件已更新到最新而没有必要更新,结果在linker将OBJ文件连接为可执行文件时产生奇怪的错误信息.
您可以将目标文件作为特殊目标.
PRECIOUS的依赖从而阻止make这样删除该目标文件.
在重建一个目标之前,make首先检查该目标文件是否出现在特殊目标.
PRECIOUS的依赖列表中,从而决定在信号发生时是否删除该目标文件.
您不删除这种目标文件的原因可能是:目标更新是一种原子风格,或目标文件存在仅仅为了记录更改时间(其内容无关紧要),或目标文件必http://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第23/79页)2006-8-1818:49:01GNUMake使用手册(中译版)须一直存在,用来防止其它类型的错误等.
5.
6递归调用make递归调用意味着可以在makefile文件中将make作为一个命令使用.
这种技术在包含大的系统中把makefile分离为各种各样的子系统时非常有用.
例如,假设您有一个子目录'subdir',该目录中有它自己的makefile文件,您希望在该子目录中运行make时使用该makefile文件,则您可以按下述方式编写:subsystem:cdsubdir&&$(MAKE)或,等同于这样写(参阅选项概要):subsystem:$(MAKE)-Csubdir您可以仅仅拷贝上述例子实现make的递归调用,但您应该了解它们是如何工作的,它们为什么这样工作,以及子make和上层make的相互关系.
为了使用方便,GNUmake把变量CURDIR的值设置为当前工作的路径.
如果'-C'选项有效,它将包含的是新路径,而不是原来的路径.
该值和它在makefile中设置的值有相同的优先权(缺省情况下,环境变量CURDIR不能重载).
注意,操作make时设置该值无效.
5.
6.
1变量MAKE的工作方式递归调用make的命令总是使用变量MAKE,而不是明确的命令名'make',如下所示:subsystem:cdsubdir&&$(MAKE)该变量的值是调用make的文件名.
如果这个文件名是'/bin/make',则执行的命令是`cdsubdir&&/bin/make'.
如果您在上层makefile文件时用特定版本的make,则执行递归调用时也使用相同的版本.
在命令行中使用变量MAKE可以改变'-t'('--touch'),'-n'('--just-print'),或'-q'('--question')选项的效果.
如果在使用变量MAKE的命令行首使用字符'+'也会起到相同的作用.
参阅代替执行命令.
设想一下在上述例子中命令'make-t'的执行过程.
('-t'选项标志目标已经更新,但却不执行任何命令,参阅代替执行命令.
)按照通常的定义,命令'make–t'在上例中仅仅创建名为'subsystem'的文件而不进行别的工作.
您实际要求运行'cdsubdir&&make–t'干什么是执行命令或是按照'-t'的要求不执行命令Make的这个特点是这样的:只要命令行中包含变量MAKE,标志`-t',`-n'和`-q'将不对本行起作用.
虽然存在标志不让命令执行,但包含变量MAKE的命令行却正常运行,make实际上是通过变量MAKEFLAGS将标志值传递给了子make(参阅与子make通讯的选项).
所以您的验证文件、打印命令的请求等都能传递给子系统.
5.
6.
2与子make通讯的变量通过明确要求,上层make变量的值可以借助环境传递给子make,这些变量能在子make中缺省定义,在您不使用'-e'开关的情况下,传递的变量的值不能代替子make使用的makefile文件中指定的值(参阅命令概要).
向下传递、或输出一个变量时,make将该变量以及它的值添加到运行每一条命令的环境中.
子make,作为响应,使用该环境初始化它的变量值表.
参阅环境变量.
除了明确指定外,make仅向下输出在环境中定义并初始化的或在命令行中设置的变量,而且这些变量的变量名必须仅由字母、数字和下划线组成.
一些shell不能处理名字中含有字母、数字和下划线以外字符的环境变量.
特殊变量如SHELL和MAKEFLAGS一般总要向下输出(除非您不输出它们).
即使您把变量MAKEFILE设为其它的值,它也向下输出.

Make自动传递在命令行中定义的变量的值,其方法是将它们放入MAKEFLAGS变量中.
详细内容参阅下节.
Make缺省创造的变量的值不能向下传递,子make可以自己定义它们.
如果您要将指定变量输出给子make,请用export指令,格式如下:exportvariable.
.
.
您要将阻止一些变量输出给子make,请用unexport指令,格式如下:unexportvariable.
.
.
为方便起见,您可以同时定义并输出一个变量:exportvariable=valuehttp://lsec.
cc.
ac.
cn/~peace/articles/gnumaketranslated.
html(第24/79页)2006-8-1818:49:01GNUMake使用手册(中译版)下面的格式具有相同的效果:variable=valueexportvariable以及exportvariable:=value具有相同的效果:variable:=valueexportvariable同样,exportvariable+=value亦同样:variable+=valueexportvariable参阅为变量值追加文本.
您可能注意到export和unexport指令在make与shell中的工作方式相同,如sh.
如果您要将所有的变量都输出,您可以单独使用export:export这告诉make把export和unexport没有提及的变量统统输出,但任何在unexport提及的变量仍然不能输出.
如果您单独使用export作为缺省的输出变量方式,名字中含有字母、数字和下划线以外字符的变量将不能输出,这些变量除非您明确使用export指令提及才能输出.
单独使用export的行为是老板本GNUmake缺省定义的行为.
如果您的makefile依靠这些行为,而且您希望和老板本GNUmake兼容,您可以为特殊目标.
EXPORT_ALL_VARIABLES编写一条规则代替export指令,它将被老板本GNUmake忽略,但如果同时使用export指令则报错.
同样,您可以单独使用unexport告诉make缺省不要输出变量,因为这是缺省的行为,只有前面单独使用了export(也许在一个包括的makefile中)您才有必要这样做.
您不能同时单独使用export和unexport指令实现对某些命令输出对其它的命令不输出.
最后面的一条指令(export或unexport)将决定make的全部运行结果.
作为一个特点,变量MAKELEVEL的值在从一个层次向下层传递时发生变化.
该变量的值是字符型,它用十进制数表示层的深度.
'0'代表顶层make,'1'代表子make,'2'代表子-子-make,以此类推.
Make为一个命令建立一次环境,该值增加1.
该变量的主要作用是在一个条件指令中测试(参阅makefile文件的条件语句);采用这种方法,您可以编写一个makefile,如果递归调用采用一种运行方式,由您控制直接执行采用另一种运行方式.
您可以使用变量MAKEFILES使所有的子make使用附加的makefile文件.
变量MAKEFILES的值是makefile文件名的列表,文件名之间用空格隔开.
在外层makefile中定义该变量,该变量的值将通过环境向下传递;因此它可以作为子make的额外的makefile文件,在子make读正常的或指定的makefile文件前,将它们读入.
参阅变量MAKEFILES.

RackNerd美国大硬盘服务器促销:120G SSD+192TB HDD,1Gbps大带宽,月付$599,促销美国月付$服务器促销带宽

racknerd怎么样?racknerd最近发布了一些便宜美国服务器促销,包括大硬盘服务器,提供120G SSD+192TB HDD,有AMD和Intel两个选择,默认32G内存,1Gbps带宽,每个月100TB流量,5个IP地址,月付$599。价格非常便宜,需要存储服务器的朋友可以关注一下。RackNerd主要经营美国圣何塞、洛杉矶、达拉斯、芝加哥、亚特兰大、新泽西机房基于KVM虚拟化的VPS、...

ZJI(月付450元),香港华为云线路服务器、E3服务器起

ZJI发布了9月份促销信息,针对香港华为云线路物理服务器华为一型提供立减300元优惠码,优惠后香港华为一型月付仅450元起。ZJI是原来Wordpress圈知名主机商家:维翔主机,成立于2011年,2018年9月更名为ZJI,提供中国香港、台湾、日本、美国独立服务器(自营/数据中心直营)租用及VDS、虚拟主机空间、域名注册等业务,商家所选数据中心均为国内访问质量高的机房和线路,比如香港阿里云、华为...

NameCheap新注册.COM域名$5.98

随着自媒体和短视频的发展,确实对于传统的PC独立网站影响比较大的。我们可以看到云服务器商家的各种促销折扣活动,我们也看到传统域名商的轮番新注册和转入的促销,到现在这个状态已经不能说这些商家的为用户考虑,而是在不断的抢夺同行的客户。我们看到Namecheap商家新注册域名和转入活动一个接一个。如果我们有需要新注册.COM域名的,只需要5.98美元。优惠码:NEWCOM598。同时有赠送2个月免费域名...

chmod用法为你推荐
brandoff香港购物在哪里access数据库Access数据库对象的操作包括哪五种?lunwenjiancepaperfree论文检测怎样算合格8090lu.com8090看看电影网怎么打不开了www.119mm.comwww.993mm+com精品集!www.kanav001.com翻译为日文: 主人,请你收养我一天吧. 带上罗马音标会更好www杨丽晓博客杨丽晓今年高考了吗?www.175qq.com求带名字的情侣网名!dpscycle国服魔兽WLK,有什么适合死亡骑士的插件?本冈一郎本冈一郎有副作用吗?主要有什么呢?
虚拟主机评测 免费申请域名和空间 新加坡主机 cloudstack la域名 wordpress技巧 gitcafe 太原联通测速平台 百兆独享 工作站服务器 91vps 爱奇艺vip免费试用7天 上海联通宽带测速 空间租赁 789 摩尔庄园注册 工信部icp备案查询 阿里云邮箱登陆 测试网速命令 江苏徐州移动 更多