window下makefile的使用.docx
- 文档编号:16619582
- 上传时间:2023-07-15
- 格式:DOCX
- 页数:18
- 大小:26.31KB
window下makefile的使用.docx
《window下makefile的使用.docx》由会员分享,可在线阅读,更多相关《window下makefile的使用.docx(18页珍藏版)》请在冰点文库上搜索。
window下makefile的使用
Windows下的makefile
1.windows下nmake的使用
为nmake、cl、link运行设置环境变量:
把VS安装目录下的VC/bin设置到环境变量path中。
2.windows下使用makefile的问题解决
2.1FatalerrorU1052:
‘win32.mak’notfoundstop
在执行构建(nmake)命令时有时会出现如下错误:
FatalerrorU1052:
‘win32.mak’notfoundstop
解决方法:
运行visualstudio中的VC\bin\vcvars32.bat
不要关闭命令窗口,然后在同一窗口中执行命令就不会出错。
3.nmake的命令行语法
NMAKE的命令行语法
语法:
NMAKE[options][macros][targets]
其中,options是NMAKE的选项,macros是在命令行中的宏定义,targets是NMAKE的目标文件列表。
选项(忽略大小写):
1) /A强制重新构件所有与NMAKE的target相关的dependents,即使这些dependents并没有过期;
2) /B即使dependent与target有相同的timestamp,也重建该target。
大部分的OS中的timestamp是以2秒为单位的,如果一个2秒之内被修改,那么它的timestamp将不会有任何变化。
在这种情况下,你就需要使用该选项让NMAKE重建之。
为了预防万一,总是应该使用该选项,尽管可能会导致不必要的重建操作。
3) /C屏蔽掉大部分的NMAKE输出信息,包括:
非致命错误信息,警告信息,timestamp和版权信息。
如果/C和/K选项同时存在,则/K发出的警告信息也会被干掉。
4) /D在NMAKE执行期间显示相关的信息。
包括每个文件的timestamp,依赖关系,以及类似于“文件不存在”之类的提示信息。
用于对makefile除错;
5) /E使环境变量可以覆盖预定义宏;
6) /Ffilename指定makefile的名字。
如果用“-”代替filename,则NMAKE从STDIN获取makefile的输入(对于键盘终端,用F6或CTRL+Z来结束输入)。
可以指定多个makefile,每个makefile前都要有一个/F。
如果没有/F选项,则NMAKE会在当前目录查找一个名为MAKEFILE(没后缀)的文件作为makefile,如果找不到,则对命令行目标文件使用推导规则。
7) /HELP显示帮助;
8) /I忽略makefile中所有指令的返回值;
9) /K当某条指令出现错误时并不退出而是继续执行其他指令。
在默认的情况下,如果任何一条指令返回非0值,NMAEK就回终止执行。
当打开/K选项后,NMAKE会继续执行其他指令,但不会构建与出错指令相关的文件,而是发出一条警告信息。
如果/K选项打开,同时构建无法完成,则NMAKE返回1;
10) /M在MS-DOS下,将NMAKE程序交换到磁盘中,以腾出更多的内存。
11) /N显示但不执行makefile中的命令(预处理命令除外),用于DEBUG;
12) /NOLOGO禁止NMAKE版权信息;
13) /P在执行NMAKE之前,将所有NMAKE信息输出到STDOUT,包括所有的宏定义,IR,目标文件描述和.SUFFIXESlist。
如果打开/P选项,而且不指定任何目标文件,则NMAKE仅显示相关信息。
14) /Q检查target和dependent的timestamp,但不执行commandsblock。
如果目标文件为有效的,则返回0,否则返回255。
只有makefile中的预处理命令会被执行。
当在批处理文件中调用NMAKE时,该选项会十分有用。
15) /R清除.SUFFIXESlist,忽略所有的IR和TOOLS.INI中定义的或预定义的宏。
16) /S禁止makefile中所有的被执行指令的显示信息;
17) /T将命令行中输入文件的timestamp改为当前时间,只执行预处理命令而不执行commandsblock,目标文件的内容不会被改变;
18) /V当NMAKE被递归调用时,所有定义的宏都会被继承。
在默认的情况下,只有在命令行中定义的宏和环境变量(实际上也是一个宏)是可以被继承的。
19) /Xfilename将NMAKE的所有错误信息输出到filename指定的文件或设备中。
如果用“-”代替filename,则错误信息会被输出到STDOUT。
在默认情况下,错误信息输出到STDERR。
该选项不会影响由makefile中的指令产生的到STDERR的输出。
20) /?
显示NMAKE的语法和可用选项;
NMAKE的返回值
NMAKE的返回值及其含义见下表:
值含义
0没有错误
1没有完全执行commandsblock中的指令(只在/K选项打开时有效)
2程序错误,可能的原因包括:
● makefile的语法错误
● commandsblock中的某条指令出现错误
● 用户中断
4系统错误,例如内存不足
255在/Q选项打开时,如果目标文件已过期,则返回该值
4.makefile的编写
关于NMAKE
MicrosoftProgramMaintenanceUtility,外号NMAKE,顾名思义,是用来管理程序的工具。
其实说白了,就是一个解释程序。
它处理一种叫做makefile的文件(以mak为后缀),解释里面的语句并执行相应的指令。
我们编写makefile文件,按照规定的语法描述文件之间的依赖关系,以及与该依赖关系相关联的一系列操作。
然后在调用NMAKE时,它会检查所有相关的文件,如果目标文件(targetfile,下文简称target,即依赖于其它文件的文件)的timestamp(就是文件最后一次被修改的时间,一个32位数,表示距离1980年以来经过的时间,以2秒为单位)小于依赖文件(dependentfile,下文简称dependent,即被依赖的文件)的timestamp,NMAKE就执行与该依赖关系相关联的操作。
请看下面这个例子:
foo.exe:
first.objsecond.obj
linkfirst.obj,second.obj
第一行定义了依赖关系,称为dependencyline;第二行给出了与该依赖关系相关联的操作,称为commandline。
因为foo.exe由first.obj和second.obj连接而成,所以说foo.exe依赖于first.ogj和second.obj,即foo.exe为target,first.obj和second.obj为dependent。
如果first.obj和second.obj中的任何一个被修改了(其timestamp更大),则调用link.exe,重新连接生成foo.exe。
这就是NMAKE的执行逻辑。
综上,NMAKE的核心就是这3个家伙——依赖关系,操作和判定逻辑(target.timestamp MAKEFILE的语法 现在详细讨论一下makefile的语法。 makefile就像一个玩具型的程序语言,麻雀虽小,但五脏具全。 makefile的组成部分包括: 描述语句(descriptionblock),inferencerules(推导规则),宏和指令(directive)。 描述语句就是dependentlines和commandlines的组合;inferencerules就是预先定义好的或用户自己定义的依赖关系和关联命令;宏就不用说了吧;指令就是内定的一些可以被NMAKE识别的控制命令,提供了很多有用的功能。 另外,makefile中使用以下几个具有特殊意义的符号: ^#\(){}! @-: ;$ ^(caret): 用于关闭某些字符所具有的特殊意义,使其只表示字面上的意义。 例如: ^#abc表示#abc这个字符串,而#abc则用于在makefile中加入注释,#在这里为注释标志,就像C++中的//。 另外,在一行的末尾加上^,可以使行尾的回车换行符成为字串的一部分。 #(numbersign): 为注释标志,NMAKE会忽略所有从#开始到下一个换行符之间的所有文本。 这里要注意的是: 在commandlines中不能存在注释。 因为对于commandlines,NMAKE是将其整行传递给OS的。 通常对于commandlines的注释都是放在行与行之间。 \(backslash): 用于将两行合并为一行。 将其放在行尾,NMAKE就会将行尾的回车换行符解释为空格(space)。 %(percentsymbol): 表示其后的字符串为一文件名。 用法较复杂,在讲dependentlines的时候再详细讨论。 ! (exclamationsymbol): 命令修饰符,在下面会有详细的讨论。 @(atsign): 命令修饰符,在下面会有详细的讨论。 : (colon): 用于dependentlines和inferencerules中,用于分隔target和dependent。 ;(semicolon): 如果对于一个dependentline只有一条命令,则可以将该命令放在dependentline的后面,二者之间用“;”分隔。 $(dolorsign): 用于调用宏,在下面讲宏的时候再详细讨论。 在makefile中还可以使用DOS通配符(wildcard)来描述文件: *和? 。 作用相信大家都很熟悉了,在此就不再浪费口水了。 如果要将中间有空格或制表符的字符串作为整体对待,则应该用双引号将之括起来,例如,在指定一个中间有空格的长文件名的时候: “MyDocument” 或在定义一个宏的时候: MYMACRO=”copya: \foo.exec: \” 描述语句块(DescriptionBlocks) 描述语句块为makefile主体的基本组成单元,其典型结构如下: target: dependents commandsblock DependentLine 每一个描述语句块中只有一个dependentline,其定义了一个依赖关系。 该行的开头不能有任何空白(空格或制表符)。 冒号两边的target和dependent都可以有多个,之间以空格分隔。 NMAKE在分析makefile时首先会从头到尾扫描每一个dependentline,然后根据依赖关系建立起一棵依赖关系树(dependenttree)。 例如对于依赖关系: foo.exe: first.objsecond.obj first.obj: first.cpp second.obj: second.cpp 则在其依赖关系树中,foo.exe为first.obj和second.obj的父亲,而first.obj则是first.cpp的父亲,second.obj是second.cpp的父亲。 如果second.cpp被更新了,则second.obj会被重新构造,从而导致foo.exe被重新构造。 NMAKE就是这样由下而上地对整棵树中的结点进行评估的。 虽然makefile中可以有很多的dependentlines,但NMAKE只会构造出现在它的命令行中的targets,或者,如果命令行中没有给出targets,就构造第一个dependentline中的第一个target。 其他所有无关的targets都不会被构造。 例如: foo1.exefoo2.exe: first.obj first.obj: first.cpp second.obj: second.cpp 假设上面的第一行语句为makefile中出现的第一个dependentline,且命令行中没有给出target。 当first.cpp被更新后,first.obj和foo1.exe都会被重新构造,而foo2.exe和second.obj则不会。 当在一个dependentline中出现多个target时,例如: boy.exegirl.exe: first.obj echoHello 该语句相当于: boy.exe: first.obj echoHello girl.exe: first.obj echoHello (注: echo是一条控制台命令,用于在STDOUT上显示一行信息) 同一个target也可以出现在多个dependentlines中。 在这种情况下,如果只有一个dependentline后跟有commandline,则它们会被合并为一个描述语句块,例如: foo.exe: first.obj echoBuildingfoo.exe… … foo.exe: second.obj NMAKE会将其处理为: foo.exe: first.objsecond.obj echoBuildingfoo.exe… 如果每一个dependentline后都有commandline,则它们会被作为两个描述语句块处理。 如果在dependentline中使用双冒号(: : )来分隔target和dependent,并且同一个target出现在多个描述语句块中,此时,NMAKE将会匹配最合适的语句块,以构造该target。 例如: target.lib: : one.asmtwo.asmthree.asm MLone.asmtwo.asmthree.asm LIBtarget-+one.obj-+two.obj-+three.obj; target.lib: : four.cfive.c CL/cfour.cfive.c LIBtarget-+four.obj-+five.obj; Target.lib同时出现在两个描述语句块中,此时,NMAKE在处理该makefile时,将会选择其中一个描述语句块中的命令来执行。 如果任何asm文件被更新了,NMAKE就调用ML重新编译之,然后再调用LIB(但CL以及之后的命令都不会被调用);类似地,如果任何C文件被更新了,NMAKE就会调用CL。 在通常情况下,target和dependent都是文件名。 NMAKE会首先在当前目录下搜索dependent,如果没有找到,就到用户指定的目录下搜索。 指定搜索路径的语法如下: {directory1;directory2;…}dependent 搜索路径放在{}之中,如果有多个,就用“;”分开。 注意,在各个语法成分之间是不能有空白的。 Target和dependent也可以不是一个文件,而是一个标号(label)。 这时,就称之为pseudotarget(伪文件)。 Pseudotarget的名字不能与当前目录下的任何文件名相同。 一个pseudotarget如果要作为dependent,那么它必须要作为target出现在某个dependentline中。 当使用pseudotarget作为target时,与之关联的commandsblock一定会被执行,同时NMAKE会赋予它一个假想的timestamp。 该timestamp等于它的dependents中最大的timestamp,或者,如果它没有dependent,就等于当前时间。 该假想的timestamp在pseudotarget作为dependent时会被用来进行有效性评估。 这个特性最大的好处就是,你可以让NMAKE构造多个target,而不用将每个target都在NMAKE的命令行中列出来,例如: all: setenvproject1.exeproject2.exe project1.exe: project1.obj LINKproject1; project2.exe: project2.obj LINKproject2; setenv: setLIB=\project\lib 上例中有两个pseudotarget,一个是all,另一个是setenv。 首先是setenv被评估,其作用是设置环境变量LIB,然后project1.exe和project2.exe依次被更新. CommandsBlock 第二行开始到下一个dependentline之间为commandsblock,其给出了当dependents中的任何一个的timestamp大于target时,需要执行的指令序列(commadnsblock也可以为空,此时,NMAKE什么也不干)。 commandline必须以空白开头(刚好与dependentline相反,NMAKE就是通过该特征来分辨二者的),并且在dependentline和commandsblock中的第一条语句之间不能有空白行(就是除了一个换行符,什么也没有的行。 所以只有一个空格或制表符的行是合法的,此时NMAKE将其解释为一个nullcommand),但在commandlines之间可以有空白行。 Commandsblock中的每一条命令可以是在控制台中合法的任何命令。 事实上大可将commandsblock当成一个由控制台命令序列组成的批处理文件。 此外,对commandsblock中的命令,还可以在其前面添加一个或多个所谓的命令修饰符(commandmodifier),以实现对命令的一些额外的控制。 命令修饰符有以下3种: 1) @command 消除该命令的所有到STDOUT的输出。 2) –[number]command 关掉对该命令返回值的检测。 在默认的情况下,如果一条命令返回非0值,则NMAKE将会停止执行。 但如果在命令前加上一“-”,则NMAKE将会忽略该命令的返回值。 如果“-”紧接着一个整数,则NMAKE会忽略掉任何大于该整数的返回值。 3) ! command 如果该命令的执行对象为$**或$? (这两个都是预定义的宏,前者表示相应的dependentline中所有的dependent,后者表示所有比target具有更大的timestamp的dependent),则该“! ”修饰符将会使该命令施行于这两个宏所描述的每一个独立的文件上。 NMAKE还提供了一些语法可以在commandsblock中表示相应的dependentline中第一个dependent的文件名组成。 例如: foo.exe: c: \sample\first.objc: \sample\second.obj link%s NMAKE将“link%s”解释为: linkc: \sample\first.obj 如果将命令改为“link%|pfF.exe”,则NMAKE将之解释为: linkc: \sample\first.exe %s表示全文件名,%|[part]F表示文件名中的某个部分,part可以是下列字符中的一个或多个,如果part为空,%|F与%s的意思相同: 1) d: 盘符; 2) p: 路径; 3) f: 文件基本名; 4) e: 文件扩展名; InferenceRules(推导规则) Inferencerules(下文简称IR)是一个模板,它用于决定如何从一个具有某种扩展名的文件构造出一个具有另一种扩展名的文件。 NMAKE通过IR来确定用来更新target的命令以及推导target的dependents。 IR的好处在于它满足了像我这样的懒人的需要。 只要提供了正确的IR,则描述语句块就可以极大地化简。 请看下面的例子: foo.obj: 上面的语句将会运作得很好。 是不是觉得很吃惊呢? 事实上,NMAKE在处理该语句的时候,它首先在当前目录下搜索基本名为foo的文件(假设当前目录下有一个foo.c文件)。 然后它查找一个后缀列表(suffixlist),里面的每一项包含了从一种类型的文件构造另一种类型的文件需要调用的命令和参数的相关信息。 在NMAKE预定义的列表中,foo.c到foo.obj的构造命令为CL。 最后NMAKE调用CL,编译foo.c。 呵呵,这么一长串的操作一条简单的语句就搞定了,是不是很方便呢! 当出现下列情况之一时,NMAKE就会尝试使用IR: ● NMAKE遇到一个没有任何命令的描述语句块。 此时NMAKE就会搜索后缀列表,试图找到一个匹配的命令来构造target。 ● 无法找到某个dependent,并且该dependent没有作为target出现在其它dependentline中(即它不是一个pseudotarget)。 此时NMAKE就会搜索给定的目录以及后缀列表,试图找到一个IR来构造出该dependent。 ● 一个target没有dependent,并且描述语句块中没有给出指令。 此时NMAKE就会试图找出一个IR来构造出该target。 ● 一个target在NMAKE的命令行中给出,但在makefile里没有该target的相关信息(或根本就没有makefile)。 此时NMAKE就会试图找出一个IR来构造出该target。 定义一个IR的语法如下: [{frompath}].fromext[{topath}].toext; commands 注意,各语法元素之间不能有任何空格。 Dependent的后缀名在fromext中给出,target的后缀名在toext中给出。 Frompath和topath是可选的,分别给出了搜索的路径。 在每个IR的定义中只能分别为每一个后缀名给出一个搜索路径。 如果想要指定多个搜索路径,就必须定义多个IR。 并且,如果你为一个后缀指定了搜索路径,那么你也必须为另一个后缀指定搜索路径。 即是说,fromext和topath只要有一个存在,则另一个也必须存在。 你可以使用{.}或{}来表示当前目录。 另外,要注意的是,如果你在IR中指定了搜索路径,则在dependentlien中也必须指定同样的路径,否则IR将不会应用于dependentline上,例如: {..\proj}.exe{..\proj}.obj: 该IR不会用于下列语句上: project1.exe: project1.obj 但会用于下列语句上: {..\proj}project1.exe: {..\proj}project1.obj NMAKE本身提供了一个预定义的后缀列表,内容如下: RuleCommandDefaultAction .asm.exe $(AS)$(AFLAGS)$*.asmML$*.ASM .asm.obj $(AS)$(AFLAGS)/c$*.asmML/c$*.ASM
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- window makefile 使用