版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、 cxMake使用问题、Gcc编译选项问题、GNU 连接问题GNU Make使用make工作自动确定工程的哪部分需要重新编译,执行命令去编译它们。虽然make多用于C程序,然而只要提供命令行的编译器,你可以将其用于任何语言。如果要使用make,你必须写一个叫做“makefile”的文件,这个文件描述工程中文件之间的关系,提供更新每个文件的命令。典型的工程是这样的:可执行文件靠目标文件来更新,目标文件靠编译源文件来更新。Makefile写好之后,每次更改了源文件后,只要执行make就足够了,所有必要的重新编译将执行。Make程序利用makefile中的数据库和文件的最后修改时间来确定那个文件需要
2、更新;对于需要更新的文件,make执行数据库中记录的命令。可以提供命令行参数给make来控制那个文件需要重新编译。Makefile介绍Makefile文件告诉make做什么,多数情况是怎样编译和链接一个程序。这里有一个简单的makefile,描述如何编译链接由8个C文件和3个头文件组成的一个编辑器:edit : main.o kbd.o command.o display.o insert.o serach.o files.o utils.occ o edit main.o kbd.o command.o display.o insert.o search.o files.o utils.om
3、ain.o : main.c defs.hcc c main.ckdb.o : kbd.c defs.h command.hcc c kbd.ccommand.o : command.c defs.h command.hcc -c command.cdisplay.o : display.c defs.h buffer.hcc -c display.cinsert.o : insert.c defs.h buffer.hcc -c insert.csearch.o : search.c defs.h buffer.hcc -c search.cfiles.o : files.c defs.h
4、buffer.h command.hcc -c files.cutils.o : utils.c defs.hcc -c utils.cclean :rm edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o将长行用分开便于阅读,这和使用一个长行的作用是一样的。使用这个makefile创建可执行文件“edit”时运行make就可以了;如果要将可执行文件和目标文件删除,执行make cleanmake重新编译这个编辑器时,每个更改的C文件必须重新编译;如果头文件更改了,每个包含头文件的C文件必须重新编译;每
5、次编译产生一个对应于原文件的目标文件。最终,目标文件链接在一起产生新的可执行文件。规则简介makefile中的规则是这样的:TARGET : DEPENDENCIES COMMAND目标(TARGET)程序产生的文件,如可执行文件和目标文件;目标也可以是要执行的动作,如“clean”。依赖(DEPENDENCIES)是用来产生目标的输入文件,一个目标通常依赖于多个文件。命令(COMMAND)是make执行的动作,一个可以有多个命令,每个占一行。注意:每个命令行的起始字符必须为TAB字符!有依赖关系规则中的命令通常在依赖文件变化时负责产生target文件,make执行这些命令更新或产生targe
6、t。规则可以没有依赖关系,如包含target “clean”的规则。规则解释如何和何时重做该规则中的文件,make根据依赖关系执行产生或更新目标;规则也说明如何和何时执行动作。有的规则看起来很复杂,但都符合上述模式。make工作原理缺省make从第一个target开始(第一个非 . 开始的target),这称作缺省目标。在上述的makefile中,缺省目标是更新执行程序edit,将这个目标置于最前面。当执行make的时候,make程序从当前目录读入makefile开始处理第一个规则;在例子中,这个规则是重新链接edit;在make处理这个规则之前,必须处理edit所依赖的那些文件的规则,例子中
7、是目标文件。这些文件按照他们自己的规则处理:通过编译源文件来更新每个.o文件;当依赖关系中的源文件或头文件比目标文件新,或目标文件不存在时,必须重新编译。其它的规则被处理是因为他们的target是目标的依赖,和目标没有依赖关系的规则不会被处理,除非指定make处理(如make clean)。在重新编译目标文件之前,make会试图更新它的依赖:源文件和头文件。例子中的makefile对源文件和头文件未指定任何操作:.c和.h文件不是任何规则的目标。确认所有的目标文件都是最新的之后,make决定是否重新链接edit:如果edit不存在,或者任何一个目标文件都比它新,则链接工作将进行。这样,如果我们
8、改变insert.c运行make,make会编译这个文件来更新insert.o,然后链接edit;如果修改了command.h运行make,kbd.o,command.o,files.o会重新生成,链接edit。使用变量在例子中,在规则edit中,目标文件被列出来两次:edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.occ -o edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o这样的重复容易出错:假设工程中
9、加入了一个新的目标文件,可能只将其加入了一个列表中;通过使用变量可以消除这种风险:变量允许一个预定义的字符串在多个地方被替换。在makefile中,可以写这样一行来定义object变量:objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o于是在需要目标文件名列表的地方,使用$(object) 来代替变量的值。以下是使用了变量以后的makefile:objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.
10、oedit : $(objects)cc -o edit $(objects)main.o : main.c defs.hcc -c main.ckbd.o : kbd.c defs.h command.hcc -c kbd.ccommand.o : command.c defs.h command.hcc -c command.cdisplay.o : display.c defs.h buffer.hcc -c display.cinsert.o : insert.c defs.h buffer.hcc -c insert.csearch.o : search.c defs.h buffe
11、r.hcc -c search.cfiles.o : files.c defs.h buffer.h command.hcc -c files.cutils.o : utils.c defs.hcc -c utils.cclean :rm edit $(objects)简化命令为每个文件写出编译命令不是必要的,因为make可以自己来做;以.c文件更新.o文件有一个隐含的规则,使用cc -c命令。Make将利用cc c main.c o main.o来将main.c编译为main.o,因此在生成目标文件的规则中,可以省略命令。当.c文件以这样的方式使用时,将自动加入到依赖关系中;由是在省略命令的
12、前提下,可以将.c文件从依赖关系中省略。以下是简化过的makefile:objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.oedit : $(objects) cc -o edit $(objects)main.o : defs.hkbd.o : defs.h command.hcommand.o : defs.h command.hdisplay.o : defs.h buffer.hinsert.o : defs.h buffer.hsearch.o : defs.h buffer.hfil
13、es.o : defs.h buffer.h command.hutils.o : defs.h.PHONY : cleanclean : -rm edit $(objects)另一种风格如果makefile中的目标都是以隐含规则生成,可以将规则按照依赖关系分组:objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.oedit : $(objects) cc -o edit $(objects)$(objects) : defs.hkbd.o command.o files.o : command.
14、hdisplay.o insert.o search.o files.o : buffer.h这里defs.h作为所有目标文件的依赖。这种风格是好是坏取决于个人喜好,它非常紧凑,但是将每个目标的依赖信息放在一起看起来更清楚一些。清理编写规则不至于编译程序。Makefile通常描述如何做其它事情:比如删除目录中的目标文件和可执行文件来清理目录。例子中是这样写的:clean: rm edit $(objects)实际情况是,我们需要处理一些意外事件:存在一个叫做clean的文件;如果rm出错,并不希望make过程停止下来,修改过的版本如下:.PHONY : cleanclean : -rm edi
15、t $(objects)这样的规则当然不能放在makefile的开始,因为这并不是我们缺省要做的工作。由于clean并不是edit的依赖,在运行make时没有参数时,这条规则不会执行;要执行这个规则,必须运行make clean。MakefileMakefile中包含五种内容:显式规则,隐式规则,变量定义,指令(directive)和注释。显式规则描述如何生成规则的目标,它列出了目标依赖的文件,指定了产生或更新目标的命令隐式规则描述如何生成基于文件名的一类文件,说明目标可能依赖于和其文件名类似的文件,指定了相应的命令。指令类似与编译器的伪指令,包含:指示make读入另一个makefile决定是
16、否忽略makefile中的一部分定义一个变量一行中#开始是注释,直到行末,除非遇到续行符号。在define和命令中不能有注释,其它情况下注释可出现在任何地方。makefile名字缺省情况下,make以下列名字查找makefile:GNUmakefile,makefile和Makefile(注意大小写)。通常你的makefile应叫做makefile或Makefile。GNUmakefile不推荐,除非你的makefile是为GNU的make定制的,其它的make不认为该名字是一个makefile的名字。如果你使用非标准命名的makefile,必须用命令开关-f 或 file。参数 f NAME
17、或file NAME告诉make读入NAME作为makefile。如果使用多个该开关,所有的文件将按顺序连接起来。如果使用该选项,标准的makefile名字不会自动检测。包含include指令告诉make暂停处理余下的内容,读入其它makefile。语法如下:include FILENAMES 这一行起始可以有空格,但TAB字符不允许。如果文件名包含变量或函数,这些将被扩展。MAKEFILE变量如果环境变量MAKEFILE已定义,make认为它的值是一系列空格隔开的文件名,这些文件在处理其它makefile前被make程序读入。这类似于include指令;这些文件中的目标不会影响缺省目标,而且
18、如果文件未找到的话,make并不认为是错误。这个变量的主要用途是递归引用make程序时通讯如何重新生成makefile有时候makefile是从其它文件生成的,比如RCS或SCCS文件。如果makefile是由其它文件生成的,需要make读入最新版本的makefile。在读入所有makefile之后,make认为每个makefile是一个目标,试图去更新它;如果makefile中有一条如何更新它的规则,或者有适用的隐式规则,需要的更新会进行。所有的makefile检查完之后,如果有的改变了,make重新开始再读入(make会试图再做更新,但通常不会再改变了,因为已经是最新的了)。如果一个文件使
19、用双冒号规则,提供了命令但没有依赖关系,文件始终会被更新。在makefile的情况下,如果makefile双冒号规则,提供了命令但没有依赖关系,这样makefile始终会重新生成,这会导致循环:make只是在不断更新makefile,却不干活。为避免这种情况,make不会重新生成那些只有命令没有依赖关系的双冒号规则的makefile。如果没有使用-f或-file选项,make会尝试缺省的makefile文件名。和指明-f或-file选项不同,make不能确定这些文件是否应当存在。然而,如果缺省makefile不存在但可以通过运行make规则生成,你可能希望这些规则被运行使得makefile可以
20、使用。因此,如果没有缺省makefile,make试图按照makefile名查找的顺序生成它,直到成功或名字用完。注意如果make 不能找到或生成makefile,这并不是错误;makefile不总是必需的。当使用-t或-touch选项时,不希望使用过时的makefile来决定那个目标来touch。所以-t选项对makefile更新不起作用;类似-q(or question)和-n(or just-print)不阻止makefile的更新,因为过时的makefile会产生错误的输出。这样make f mfile n foo会更新mfile,读入它,打印出更新foo需要执行的命令但不运行这些命令
21、。与foo有关的命令是更新过的mfile中的内容。但是有时不希望更新makefile,可以将makefile作为命令行的目标,当makefile被显式指定为目标时,-t选项也适用于它们。这样make f mfile n mfile foo会读入mfile,打印出更新执行的命令,foo的命令是当前的mfile中的内容。重载makefile可以使用include指令来包含其它makefile,增加目标的变量定义。然而,make不允许同一个目标有不同的命令,有其它的途径可以达到目的。假设有makefile 和mfile,makfile要包含mfile,但都有对于目标foo的规则。这是可以在makef
22、ile中写一条匹配任意模式的规则,指明当make在makefile中未找到目标时,搜索mfile:foo: frobnicate foo%: force $(MAKE) -f mfile $ force: ;当执行make foo时,make找到makefile,执行命令 frobnicate foo;执行make bar时,在makefile中未找到相应的规则,这时模式规则适用,执行命令make f mfile bar,makefile中未提及的其它目标也是类似的。这种方法之所有工作是因为模式规则的模式是%,可以匹配任何的目标;这条规则的依赖是force,保证即使目标存在命令也会执行;for
23、ce规则的命令为空防止make为其搜索隐式规则这样会导致依赖循环。规则makefile中的规则描述如何生成特定的文件,即规则的目标。规则列出了目标的依赖文件,指定生成或更新目标的命令。规则的次序是不重要的,除非是确定缺省目标:缺省目标是第一个makefile中的第一个规则;如果第一个规则有多个目标,第一个目标是缺省的。有两个例外:以.开头的目标不是缺省目标;模式规则对缺省目标没有影响。通常我们所写的地一个规则是编译整个或makefile中指定的所有程序。例子foo.o : foo.c defs.h # module for twiddling the frobscc -c -g foo.c它的
24、目标是foo.o,依赖于foo.c和defs.h,有一个命令cc c g foo.c。命令行以TAB字符开始标识它是一个命令。这条规则说明两件事:如何决定foo.o是旧的:如果它不存在,或者foo.c或者defs.h比它新。如何更新foo.o文件:通过运行cc程序。命令未提及defs.h,担可以猜想foo.c包含了它,这是defs.h被置于依赖关系中的理由。规则的语法语法如下:TARGETS : DEPENDENCIESCOMMAND.或者TARGETS : DEPENDENCIES ; COMMANDCOMMAND.TARGETS是以空格隔开的文件名,统配符可以使用。通常一个规则只有一个目标
25、,偶尔也有多个。命令行以TAB键开始。第一条命令可在依赖关系的下一行;或者在同一行,在分号后面;两种方式效果相同。因为$符号被用做变量引用,如果要在规则中使用$符号,必须写两个:$。可以用符号来分割一个长行,这不是必须的,因为make对行的长度没有限制。通配符规则中的文件名可以包含统配符,如*,?。文件名前的字符有特殊的含义。单独使用,或跟随一个/,代表用户的home目录,比如/bin扩展为/home/you/bin;如果跟随一个单词,表示单词指示的那个用户的home目录,如john/bin扩展为/home/john/bin。通配符在目标,依赖关系,命令中自动扩展,其它情况下,统配符的扩展除非
26、显式使用wildcard函数。通配符的特殊意义可以使用符号关闭。例子:clean: rm -f *.o和print: *.c lpr -p $? touch print通配符在定义变量时并不扩展,例如:objects = *.o则objects的值是字符串*.o;但是如果你将objects用于目标,依赖或命令中,扩展会进行。要将objects设置成扩展过的内容,使用:objects := $(wildcard *.o)通配符的缺陷这是一个使用通配符的例子,但结果不是你所期望的。假设可执行文件foo是从当前目录中的所有.o文件生成的:objects = *.ofoo : $(objects) c
27、c -o foo $(CFLAGS) $(objects)objects变量的值是字符串*.o。通配符扩展在规则foo中进行,于是所有存在的.o文件成为foo的依赖而且在需要时重新编译。但如果删除了所有的.o文件呢?当通配符不匹配任何文件时,一切都保持原样:则foo依赖于一个叫做*.o的文件;由于这个文件不大可能存在,make程序会报告一个无法生成*.o文件的错误,这不是期待的结果。实际上可以用通配符获得期望结果,但是需要复杂的技术,包括wildcard函数和字符串替换函数。wildcard函数通配符自动在规则中进行。但是在变量赋值的和函数的参数中通配符不会扩展,如果在这些情况下需要通配符扩展
28、,必须使用wildcard函数。语法如下:$(wildcard PATTERN.)这个在makefile任何地方出现的字符串,会被匹配任何一个文件名格式的以空格隔开的现有文件列表替换。如果没有任何文件匹配一个模式,这个模式从wildcard的输出中忽略,注意,这和上述的通配符的处理是不一样的。wildcard函数的一个功能是找出目录中所有的.c文件:$(wildcard *.c)可以通过替换后缀.c为.o从C文件列表得到目标文件的列表:$(patsubst %.c,%.o,$(wildcard *.c)这样,上节中的makefile改写为:objects := $(patsubst %.c,%
29、.o,$(wildcard *.c)foo : $(objects) cc -o foo $(objects)这个makefile利用了编译C程序的隐含规则,所以不需要对编译写出显式的规则。(:=是=的一个变体)注意:PATTERN是大小写敏感的。目录搜索对于大的系统,通常将源文件和目标文件放在不同的目录中。目录搜索功能可以让make自动在多个目录中搜寻依赖文件,当你将文件重新分布是,不需要改变规则,更改搜索路径即可。VPATHmake变量VPATH列出make应当搜索的目录列表。很多情况下,当前目录不包含依赖文件,VPATH描述一个对所有文件的搜索列表,包含那些是规则的目标的文件。如果一个目
30、标或者依赖文件在当前目录没找到的话,make在VPATH中列出的目录中查找同名的文件。如果找到的话,那个文件成为依赖文件;规则可以象这些文件在当前目录中一样来使用他们。在VPATH变量中,目录名以冒号或空格隔开;目录列出的顺序决定make查找的顺序。(注:在pSOSystem 2.5移植到Win32的GNU make目录名必须使用分号隔开,以下均简称Win32 GNU make)。举例说明:VPATH = src:./headers 则规则foo.o : foo.c 被解释为foo.o : src/foo.c假设foo.c在当前目录不存在,在src目录中可以找到。选择性搜索与VPATH变量相似
31、但更具选择性的是vpath指令(注意是小写),可以指定对于符合特定模式文件的查找路径。这样可以为不同类型的文件指定不同的搜索路径。vpath指令共有三中形式:vpath PATTERN DIRECTORIES为匹配PATTERN的文件名指定搜索路径DIRECTORIES,目录的分隔和VPATH的相同vpath PATTERN清除为匹配PATTERN的文件名指定的搜索路径vpath清除所有以前用vpath指定的搜索路径vpath的模式是包含%的字符串:这个字符串必须匹配需要搜索的依赖文件名,%字符匹配0个或多个任意字符。例如:%.h匹配任何以.h结尾的文件(如果没有%,则PATTERN必须和依赖
32、文件完全一致,这种用法不太多)。当当前目录中不存在依赖文件时,如果vpath中的PATTERN匹配依赖文件名,则指令中DIRECTORIES列出的目录和VPATH中同样处理。举例:vpath %.h ./headers告诉make在当前目录中未找到的.h文件在./headers目录中查找。如果多个vapth的模式匹配依赖文件名,make将逐一处理,在所有指定的目录中搜索。Make按照vapth在makefile中的次序;来处理它们,多个相同模式的vapth是相互独立的。vpath %.c foovpath % blishvpath %.c bar将按照foo,blish,bar的次序查找.c文
33、件。而vpath %.c foo:barvpath % blish按照foo,bar,blish的顺序搜索。使用自动变量目录搜索的结果并不改变规则中的命令:命令按原样被执行。因此,必须写出与目录搜索功相适应的命令。这可以通过使用$这样的自动变量来完成。$表示规则中的所有依赖文件,包含它们所在的目录名(参见目录搜索);$表示目标。例如:foo.o : foo.ccc -c $(CFLAGS) $ -o $通常情况下,依赖文件也包含头文件,但命令中并不提及这些文件:变量$表示第一个依赖文件:VPATH = src:./headersfoo.o : foo.c defs.h hack.hcc c $
34、(CFLAGS) $ $和bigoutput : text.g generate text.g -big bigoutputlittleoutput : text.g generate text.g -little littleoutput等同。这里假设程序generate产生两种输出:一种使用-big选项,一种使用-little选项。如果想象使用$变化命令那样来变化依赖关系,不能通过多目标的普通规则实现,但是可以通过模式规则来实现。一个目标多条规则一个文件可以是多条规则的目标,所有规则的依赖关系被合并。如果目标比任一个依赖文件旧,命令被执行。一个文件只能有一组命令执行。如果多个规则对于同一个
35、文件都给出了命令,make使用最后一组并打印错误信息(特殊情况:如果文件名以.开始,并不打印错误信息,这一点是为了和其它make兼容)。没有任何理由需要将makefile写成这样,这是make给出错误信息的理由。一条只有依赖关系的附加规则可以一次给出许多文件的附加依赖文件。例如objects变量表示系统中编译器的所有输出.,说明当config.h更改时所有文件必须重做的简单方法如下: objects = foo.o bar.o foo.o : defs.h bar.o : defs.h test.h $(objects) : config.h不用改变实际目标文件生成的规则,这条规则可以在需要增
36、删附加的依赖关系时插入或提出。另一个诀窍是附加的依赖关系可以用变量表示,在make执行时,可以给变量赋值:extradeps=$(objects) : $(extradeps)当命令make extradeps=foo.h执行时会认为foo.h是每个目标文件的依赖文件,但简单的make命令不是这样。静态模式规则静态模式规则(static pattern rules)可以指定多个目标,并且使用目标名字来建议依赖文件的名字;比普通多目标规则更通用因为不需要依赖关系是相同的:依赖关系必须类似但不需要相同。语法TARGETS .: TARGET-PATTERN: DEP-PATTERNS . COMM
37、ANDS .TARGETS列表指出规则应用的目标,可以包含通配符,于普通规则的目标相同。TARGET-PATTERN和DEP-PATTERNS来表明目标的依赖关系如何计算:匹配TARGET-PATTERN的目标从名字中抽出一部分,叫做词干(stem),词干被替换到DEP-PATTERNS来形成依赖文件名。每个模式通常包含一个%字符。当TARGET-PATTERN匹配一个目标时,%字符可以匹配目标名中的任何部分;这部分即是词干,模式的其余部分必须完全匹配。例如foo.o匹配%.o,foo是词干;目标foo.c和foo.out并不匹配这个模式。目标的依赖文件名通过将DEP-PATTERNS中的%替
38、换为词干形成:如果依赖模式为%.c,在替换词干foo可以得到foo.c。依赖模式中不包含%也是合法的,此依赖文件对所有的目标均有效。如果需要在模式规则中使用%字符,必须在其前面加字符,如果%前的字符是有实际意义的,必须在其前面加,其它的不必如此处理。如the%weird%pattern在有效的%前是the%weird,其后是pattern。最后的保持原样是因为其并不影响%字符。以下例子从相应的.c文件编译foo.o和bar.o:objects = foo.o bar.o$(objects): %.o: %.c $(CC) -c $(CFLAGS) $ -o $每个目标必须匹配目标模式,对于不匹
39、配的目标会给出警告。如果列表中只有部分文件匹配模式,可以使用filter函数移去不匹配的文件名:files = foo.elc bar.o lose.o$(filter %.o,$(files): %.o: %.c $(CC) -c $(CFLAGS) $ -o $(filter %.elc,$(files): %.elc: %.el emacs -f batch-byte-compile $ $命令generate执行时,$*扩展为词干big或little。静态模式规则和隐式规则静态模式规则和隐式规则在作为模式规则是具有很多共同点,都有目标模式和构造依赖文件名的模式,不同之处在于make决定
40、何时应用规则的方法。隐式规则可应用于匹配其模式的任何目标,但只限于没有指定命令的目标,如果有多条可应用的隐式规则,只有一条被使用,取决于规则的顺序。反之,静态模式规则适用于规则中明确目标列表,不适用于其它目标且总是适用于指定的每个目标。如果有两条冲突的规则,且都有命令,这是一个错误。静态模式规则比隐式规则优越之处如下:可为一些不能按句法分类,但可以显式列出的文件重载隐式规则不能判定目录中的精确内容,一些无关的文件可能导致make适用错误的隐式规则;最终结果可能依赖于隐式规则的次序。适用静态模式规则时,这种不确定性是不存在的:规则适用于明确指定的目标。双冒号规则双冒号规则(Double-colo
41、n rules)的目标后是:而不是:,当一个目标出现在多条规则中时,其处理和普通规则的处理不同。当一个目标出现在多条规则中时,所有规则必须是相同类型的:都是普通的或者都是双冒号的。如果是双冒号,规则之间相互独立;如果目标需要更新,则规则的命令被执行;结果可能是没有执行,或者执行了其中一些,或者所有的规则都执行了。同一目标的双冒号规则事实是完全孤立的,每条规则被被单独处理,就象不同目标的规则一样;规则按照在makefile中出现的次序被处理,此类规则真正有意义的是那些于命令执行次序无关的。这种规则有时比较晦涩不是特别有用;它提供了一种机制:通过不同依赖文件的更新来对目标进行不同的处理,这种情形很
42、罕见。每个这种规则应当提供命令,如果没有,适用的隐式规则将使用。自动生成依赖关系在makefile中,许多规则都是一些目标文件依赖于一些头文件。例如:main.c 通过#include使用defs.h,这样规则:main.o: defs.h告诉make在defs.h变化时更新main.o。在程序比较大时,需要写许多这样的规则;而且当每次增删#include时,必须小心的更新makefile。许多现代的编译器可以帮你写这些规则,通常这是通过编译器的-M选项,例如命令:cc M main.c输出以下内容:main.o : main.c defs.h这样就不必写这些规则,有编译器代劳了。注意这样的依
43、赖关系中提及main.o,不会被隐式规则认为是中间文件,这意味这make在使用过它之后不会将其删除。使用老的make程序时,习惯做法是使用make depend命令利用编译器的功能产生依赖关系,该命令会产生一个depend文件包含所有自动产生的依赖关系,然后在makefile中使用include将其读入。使用GNU的make时,重新生成makefile的功能使得这种做法变得过时:从不需要显式请求更新依赖关系,因为它总是重新生成任何过时的makefile。自动依赖关系生成推荐的做法是对每个源文件做一个makefile。对每个源文件NAME.c,有一个makefile NAME.d,其中列出了目标
44、文件NAME.o依赖的所有文件,这样在源文件更新时,需要扫描来产生新的依赖关系。例子是一个从NAME.c产生依赖关系文件NAME.d的模式规则:%.d: %.c $(SHELL) -ec $(CC) -M $(CPPFLAGS) $ $-e选项是当$(CC)命令失败时(exit状态非0),shell立刻退出。通常shell的返回值是管道中最后一条命令(sed)的返回值,这样make不会注意到编译器出错。使用GNU的C编译器时(gcc),可以用-MM选项来代替-M选项,这样省略系统头文件的依赖关系。sed命令的目的是将main.o : main.c defs.h转换为main.o main.d
45、: main.c defs.h这样使得每个.d文件依赖于.o文件相应源文件和头文件,make则可以在原文间或头文件变化时更新依赖关系文件。如果定义了生成.d文件的规则,可以使用include指令来读入所有的文件:sources = foo.c bar.cinclude $(sources:.c=.d)例中使用替换变量来将源文件列表 foo.c bar.c转换为依赖关系文件的列表。因为.d文件和其它文件一样,不需要更多工作,make会在需要时重新生成它们。编写命令规则的命令是由一一执行的shell命令组成。除了以分号隔开写在依赖关系后的命令,每个命令行必须以tab字符开始空行和注释行可以出现在命
46、令行中,处理时被忽略(注意:以tab字符开始的空行不是空行,是一条空命令)。可以在命令中使用任何程序,但这些程序是由$(SHELL)来执行的。回显通常make打印出要执行的命令,称之为回显,这和亲自敲命令的现象是一样的。当行之前有字符时,命令不再回显,字符在传递给shell前丢弃。典型的用法是只对打印命令有效,比如echo命令:echo About to make distribution files当make使用-n或just-print选项时,显示要发生的一切,但不执行命令。只有在这种情况下,即使命令以开始,命令行仍然显示出来。这个选项对查看make实际要执行的动作很有用。-s或silen
47、t选项阻止make所有回显,就象所有命令以开始一样;一条没有依赖关系的.SILENT规则有相同的作用,但是更加灵活。执行在需要执行命令更新目标时,make为每一行创建一个子shell来执行。这意味着诸如为进程设置局部变量的shell命令cd(改变进程的当前目录)不会影响以后的命令。如果需要cd影响下一个命令,将它们放在一行上用分号隔开,这样make认为是一条命令传递给shell程序(注意:这需要shell支持):foo : bar/lose cd bar; gobble lose ./foo另一个形式使用续行符:foo : bar/lose cd bar; gobble lose ./foos
48、hell程序的名字是通过SHELL变量来取得的。(*UNIX)不象大多数变量,SHELL变量不是通过环境来设置的(即需要在makefile中设置),因为SHELL环境是个人选择的,如果不同人的选择会影响makefile的功能的话,这样很糟糕。并行执行GNU make可以一次执行几条命令。通常make一次执行一条命令,等待其返回,再执行下一条。使用-j或jobs可以同时执行多条命令。如果-j后梗一个正数,表示一次可以执行的命令条数;如果-j之后没有参数,则不限制可执行的命令数。缺省的数量是一。一个讨厌的问题是如果同时执行多条命令,它们的输出会混在一起;另一个问题是两个进程不能从同一个设备获得输入
49、。错误每条shell命令返回时,make会检查其返回状态。如果命令执行成功,则下一条命令被执行,最后一条命令执行完后,规则执行结束。如果有错误(返回非0状态),make放弃当前规则,也可能是所有规则。有时候命令执行错误并不是问题,比如使用mkdir命令确保目录存在:如果目录一存在,则mkdir会报告错误,但仍希望make继续。要忽略命令的错误,在命令之前使用-字符,-字符在传递给shell之前被丢弃:clean: -rm -f *.o如果使用-i或ignore-errors选项,make会忽略所有命令产生的错误;一条没有依赖关系的.IGNORE规则有相同的作用,但-更灵活。在忽略错误时,mak
50、e将错误也认为是成功,只是通知你命令的退出状态和和错误被忽略。如果make并未告知忽略错误,在错误发生时,表明该目标不能成功更新,直接或间接依赖于此的目标当然也不能成功;这些目标的命令不会被执行,因为其先决条件不满足。通常make会立即以非0状态退出。然而,如果给定-k或keep-going选项,make在退出前会处理其它的依赖关系,进行必要的更新。例如,在编译一个目标文件遇到错误,make -k会继续编译其它的目标文件。通常认为你的目的是更新指定的目标,当make知道这是不可能时,会立即报告失败;-k选项指示真正目的是测试更新程序的更多可能性:在编译之前找出更多不相关的问题。如果命令失败了,
51、假设它更新的目标文件,这个文件是不完整的不能使用至少不是完全更新的。但文件的最后修改时间表明停已经是最新的,下一次make运行时,不会再更新这个文件。这种情况和命令被kill相同;则通常情况下在命令失败时将目标删除是正确的;当.DELETE_ON_ERROR是目标时make帮你做这件事。虽然你总是希望make这么做,但这不是过去的习惯;所以必须显式要求make这样做(其它的make自动这样做)。中断make如果make执行命令时遇到错误,可能会删除命令更新的目标文件: make检查文件的修改时间是否变化。删除目标的目的是确保make下次执行时重新生成它。为什么这样做?假设在编译器运行时按了Ct
52、rl-c,此时编译器写生成目标文件foo.o。Ctrl-c kill了编译器,留下一个不完整的文件,但它的修改时间比源文件foo.c新;此时make也受到Ctrl-c信号删除这个不完整的文件,如果make不这样做,下次make运行时认为foo.o不需要更新,会在链接时出现奇怪的错误。可以使用.PRECIOUS规则来防止目标文件被删除。在make更新目标时,会检测其是否为.PRECIOUS的依赖,决定在命令出错或中断时是否删除该目标。如果你希望目标的更新是原子操作,或是用来记录修改时间,或必须一直存在防止其它类型的错误,这些理由使得你必须这样做。递归使用递归使用make就是在makefile中使
53、用make命令。这种技术在你将一个大系统分解为几个子系统,为每个自系统提供一个makefile时有用处。比如有一个子目录subdir中有自己的makefile,希望make在自目录中运行,可以这样做:subsystem: cd subdir; $(MAKE)或者subsystem: $(MAKE) -C subdir可以照抄这个;例子来递归使用makeMAKE变量递归的make必须使用MAKE变量,不是显式的make命令:subsystem: cd subdir; $(MAKE)该变量的值是被调用的make的名字。在命令中使用MAKE有特殊的功能:它改变了-t (-touch), -n (-j
54、ust-print)和-q (-question)选项的含义。使用上例来考虑make t命令(-t选项将目标标记为最新但不运行命令),更加-t选项的功能,该命令将创建一个subsystem文件,实际希望的操作是运行cd subdir; make t;但这会执行命令,与-t的原意不符。这个特殊功能做了期望的工作。当命令行包含变量MAKE时,选项-t,-n和-q并不适用。不管这些导致不会执行命令的标志,包含MAKE变量的命令始终会执行。正常的MAKEFLAGS机制将这些标志传递到子make,这样打印命令的请求被传播到子系统中。传递变量到子make上级(top-level)make中的变量可以显式通
55、过环境传递到子make中。在子make中,这些变量被缺省定义,但不会重载子makefile中的定义除非使用-e选项。为向下传递,或输出变量,make在运行命令时将其加入到环境变量中;子make,可以使用环境变量来初始化变量表。除非显式要求,make只输出初始环境中或命令行设置的变量而且变量名只由字母,数字和下划线组成。一些shell不能处理有其它字符的环境变量。特殊变量SHELL,MAKEFLAGS总是输出,如果MAKEFILE变量有值,也会输出。Make自动通过MAKEFLAGS来输出命令行定义的变量。如果想要输出特定变量,使用export指令:export VARIABLE .如果要阻止输
56、出一个变量,使用unexport指令:unexport VARIABLE .为方便起见,可以在定义变量时输出它:export VARIABLE = value和VARIABLE = valueexport VARIABLE作用相同。如果要输出所有的变量,使用export指令本身就可以了。变量MAKELEVEL在一级一级传递时会改变,这个变量的值是表示嵌套层数的字符串,顶级make是,变量的值为0;子make的值为1;子子make的值为2,依此类推。MAKELEVEL的用途是在条件指令中测试它,这样写出在递归运行时和直接运行时表现不同的makefile。以下内容拷贝自GNU Make Manua
57、l命令行参数-b-m These options are ignored for compatibility with other versions ofmake.-C DIR-directory=DIR Change to directory DIR before reading the makefiles. If multiple -C options are specified, each is interpreted relative to the previous one: -C / -C etc is equivalent to -C /etc. This is typically
58、 used with recursive invocations of make (*note Recursive Use of make: Recursion.).-d-debug Print debugging information in addition to normal processing. The debugging information says which files are being considered for remaking, which file-times are being compared and with what results, which fil
59、es actually need to be remade, which implicit rules are considered and which are applied-everything interesting about how make decides what to do.-e-environment-overrides Give variables taken from the environment precedence over variables from makefiles. *Note Variables from the Environment: Environ
60、ment.-f FILE-file=FILE-makefile=FILE Read the file named FILE as a makefile. -h-help Remind you of the options that make understands and then exit.-i-ignore-errors Ignore all errors in commands executed to remake files. -I DIR-include-dir=DIR Specifies a directory DIR to search for included makefile
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年国有控股混合所有制企业员工持股试点意见(133号文)操作指南
- 2026年网络沉迷预防教育
- 2026年网络安全教育课程
- 2026年水电防诈骗培训
- 2026年实验室安全应急预案
- 2026年山区旅游安全攻略
- 机动护士的护理健康教育
- DB36-T 2060-2024 社会消防技术服务评价规范
- 母婴护理中的质量控制
- 急诊常用监护技术及护理
- 福建省莆田市2026届高中毕业班第二次质量调研测试试卷(莆田二检) 英语+答案
- 2026年安徽扬子职业技术学院单招职业技能考试题库附答案详解(预热题)
- 2026年南通师范高等专科学校单招职业适应性考试题库附参考答案详解(考试直接用)
- 2026及未来5年中国钢板桩行业市场行情动态及发展前景研判报告
- 2025年北京市第二次普通高中学业水平合格性考试地理仿真模拟地理试卷01(解析版)
- 住院病历书写规范2026
- 封装热管理模型优化多芯片散热效率
- 行业事业单位内控制度
- 业扩报装合同模板(3篇)
- 人教版八年级生物上册《4.6.3神经系统支配下的运动》同步练习题及答案
- 2026年广西信息职业技术学院单招职业适应性测试题库附答案解析
评论
0/150
提交评论