nmake的用法

nmake的用法

在命令行键入nmake /? 可以显示帮助信息,nmake的语法如下:

nmake [选项] [/f 描述文件名] [/x 输出信息文件名] [宏定义] [目标]

说明如下:

●   /f参数——如果描述文件名不使用默认的makefile,可以用/f参数指定。

●   /x参数——如果想把屏幕输出的信息存到一个文件中,可以用/x参数指定(用DOS下的管道操作符nmake > 文件名的方法无效)。

●   宏定义——可以用新的定义覆盖描述文件中的宏定义。

●   目标——指定建立描述文件中描述的某个文件,如上面的例子中默认是生成最后的test.exe文件,也可以用nmake x.res指定更新x.res文件。

nmake常用的选项如表2.8所示。

表2.8 nmake的常用选项

选    项

简    介

/A

不检测文件时间,强制更新所有文件

/B

文件时间相等时也要更新文件

/D

make时显示文件新旧信息

/N

显示make时要执行的命令,但并不真正执行

/P

一个比较有用的选择,make时显示详细的信息

由 于nmake的应用是基于文件时间的,当计算机的时钟不准确或文件拷贝到另一台计算机后文件时间有些偏差,那么文件的更新可能会不正确,这时最好用/A选 项强制把所有文件更新一遍。在平时使用的时候,以makefile当做建立的描述文件名,那么仅键入不加参数的nmake命令就可以完成所有工作了。

描述文件的语法

make工具最主要也是最基本的功能就是通过 描述文件来描述源程序之间的相互关系并自动维护编译工作,而描述文件需要按照某种语法进行编写,文件中需要说明如何编译各个源文件并链接生成可执行文件, 并要求定义源文件之间的依赖关系,为了更方便使用,文件中同时可以用一些宏定义。描述文件一般需要包含以下内容:

●   注释

●   宏定义

●   显式规则

●   隐含规则

在这里,首先为2.4.1节中有关test.exe的例子写出一个描述文件,再逐步介绍各部分的书写语法。为了方便使用,一般都把描述文件的文件名取为默认文件名:makefile。这个例子的makefile文件如下(注意前面括号里的是行号,不是文件的真正内容):

(001)   # nmake工具的描述文件例子

(002)   EXE = Test.exe                         #指定输出文件

(003)   OBJS = x.obj /

(004)       y.obj                               #需要的目标文件

(005)   RES = x.res                              #需要的资源文件

(006)  

(007)   LINK_FLAG = /subsystem:windows      #链接选项

(008)   ML_FLAG = /c /coff                    #编译选项

(009)  

(010)   #定义依赖关系和执行命令

(011)   $(EXE): $(OBJS) $(RES)

(012)       Link $(LINK_FLAG) /out:$(EXE) $(OBJS) $(RES)

(013)   $(OBJS): Common.inc

(014)   y.obj: y.inc

(015)

(016)   #定义汇编编译和资源编译的默认规则

(017)   .asm.obj:

(018)       ml $(ML_FLAG) $<

(019)   .rc.res:

(020)       rc $<

(021)  

(022)   #清除临时文件

(023)   clean:

(024)       del *.obj

(025)       del *.res

1. 注释和换行

makefile中的注释是以#号开头一直到行尾的字符,当nmake工具处理到这些字符的时候,它会完全忽略#号及其后面的全部字符。

当一行的内容过长的时候,可以用换行符来继续,makefile的换行符是/,如例子中的第三行和第四行可以合并为:

OBJS = x.obj y.obj     #需要的目标文件

在使用换行符的时候要注意在“/”后面不能再加上其他字符,包括注释和空格,否则nmake检测到“/”不在一行的最后,就不会把它当成换行符解释,从而出现错误。

2. 宏定义

makefile中允许使用简单的宏定义指代源文件及其相关编译信息,可以把宏称为变量,在整个描述文件中,只要符合下面语法的行就是宏定义:

变量名=变量内容

如上面例子文件中的第2到第8行就是宏定义,在引用宏时只需在变量前加$符号,但是要注意的是,如果变量名的长度超过一个字符,在引用时就必须加圆括号(),下面都是有效的宏引用:

$(LINK_FLAG)

$(EXE)

$A

$(A)

其中最后两个引用是完全一致的。

宏定义的使用可以使makefile的使用更 灵活:首先可以使文件便于修改,比如把第8行和第18行中ml的选项部分写成宏定义,以后要改变编译选项的时候,只要直接在makefile文件头部改变 宏定义就可以了,不必阅读修改整个makefile文件;其次,当不止一个地方用到同一个文件的时候,把文件名定义为宏定义可以减少错误,增加可读性,同 时也可以便于修改;最大的好处是可以直接在命令行中用新的宏定义覆盖,比如在命令行中键入:

nmake ML_FLAG="/c /coff /Fl"

那么这时就会以新的/c /coff /Fl定义代替makefile中定义的/c /coff,在这种使用中要注意两个问题:一是宏名称要区分大小写,ML_FLAG和ml_flag是不一样的;二是定义值中有空格的时候要用双引号引起 来(没有空格时可以不用双引号,如ML_FLAG=/c),这使临时使用不同的参数编译文件时可以不必修改makefile。

3. 显式规则

makefile中包含有一些规则,这些规则定义了文件之间的依赖关系和产生命令,一个规则的格式是这样的:

目标文件:依赖文件;命令            (方法1)

目标文件:依赖文件             (方法2)

        命令

在规则定义和命令行中,不能包含注释,例子中的第11和12行把宏定义展开后就是:

test.exe:x.obj y.obj x.res

    Link /subsystem:windows /out:test.exe x.obj y.obj x.res

这里的目标文件就是test.exe,它依赖 于3个文件x.obj,y.obj和x.res,如果有必要,产生目标文件的命令就是下面的Link命令。规则可以用两种方法,用方法2的时候,命令可以 从第二行开始,第一行的“;”省略,但是这时命令前面必须有一个Tab字符,否则nmake无法区分这究竟是命令还是别的定义。

在同一个规则中,目标文件可以有多个,依赖文件也可以有多个,同时命令也可以由多个命令行组成,当然这时候就必须用第二种方法定义了,否则无法在同一行中写入多条命令。

我们也可以用和上例中类似的方法定义其他规 则,如x.obj或x.res的生成方法,但nmake如何知道哪个是最终要make的文件呢?实际上nmake默认将整个描述文件的第一条规则中的目标 文件认为是最终文件,如果我们把11,12行放到第13行后面,那么x.obj和y.obj的建立规则就成了第一条规则,nmake建立了x.obj和 x.obj之后就不理会test.exe的建立了,所以我们必须把最终需要生成的文件放在第一条规则定义。当然,在nmake的命令行参数中可以指定要 make的目标,如我们只需生成x.res文件,那么不必修改makefile将x.res的描述规则移动到最前面,而是直接在命令行键入以下命令即可:

nmake x.res

参数中也可以同时带好几个目标文件名,nmake会一一处理,如果指定的目标文件没有对应的规则,nmake会返回一个出错信息:

fatal error U1073: don't know how to make 'xxx文件'

当用户要求nmake去建造一个目标 时,make会去找到这个目标的依赖规则,这时规则中定义的命令并不会立刻被执行,而是首先要做一些事情:nmake先去检查依赖文件是否是另一条规则的 目标文件,如果是,则先处理这一条规则;如果不是,nmake再检查各个依赖文件的时间,看这些文件有没有比目标文件更新的,如果没有,nmake会决定 不再重新建造目标文件,并给出提示:'xxx文件' is up-to-date,如果依赖文件有比目标文件更新的,才执行命令。

所以一个顺序下来,所有的目标文件,以及它们 的依赖文件,以及依赖文件的依赖文件都会被检查并更新,总而言之,一个目标文件的建立包含了顺序正确的指令链接,这个链接结构是树状的,目标文件是根,一 级级扩展到多个文件,我们要求的是nmake去建立链接中处于根部的那个文件,nmake会根据链接结构从目标开始向初始状态前进,最后慢慢回来,在这个 过程中执行建立每个文件所必需的命令,一直到最终目标建立完成。

目标也可以没有依赖文件,而且目标也可以不是 一个真正存在的文件,如例子第23行到第25行中的clean是一个目标,但我们并不是要生成一个clean文件,而是希望在文件调试完毕后用nmake 来清除临时文件,当我们键入nmake clean的时候,工作目录下并没有clean这个文件,那么nmake就会去执行clean定义中的命令,因为nmake把每一个不存在的目标当做是一 个过时的目标,如此一来,就会删除中间过程中的文件*.obj和*.res。

指出了目标文件全名的规则称为显式规则,但有些类别的文件的编译方法可以是雷同的,如从asm文件产生obj文件的命令总是用ml,从rc文件产生res文件的命令总是用rc,对于每个文件都写一条规则有些多余,这时候就要用到隐含规则。

4. 隐含规则

隐含规则可以为某一类的文件指出建立的命令,它具体定义了如何将带一个特定扩展名的文件转换成具有另一种扩展名的文件,定义的格式是:

.源扩展名.目标扩展名:;命令        (方法1)

.源扩展名.目标扩展名:         (方法2)

    命令

隐含规则的语法和显式规则相似,也是用“:”隔开,在“;”下面书写命令,也可以不用“;”而将命令写在第二行,同理,这时命令之前要加一个Tab字符。

隐含规则不能有依赖文件,所以“:”下面没有 内容,例子中的第17、18行定义了从asm文件建立obj文件的隐含规则,第19和20行定义了从rc文件建立res文件的隐含规则,隐含规则中无法指 定确定的输入文件名,因为输入文件名是泛指的有相同扩展名的一整类文 件,这时候就要用到几个特殊的内定宏来指定文件名,这些宏是$@,$*,$?和$<,它们的含义如下:

●   $@ —— 全路径的目标文件。

●   $* —— 除去扩展名的全路径的目标文件。

●   $? —— 所有源文件名。

●   $< —— 源文件名(只能用在隐含规则中)。

所以第19、20行中的rc $< 用于x.rc的时候就是rc x.rc,而用于y.rc时就是rc y.rc了。

读者可以注意到一些显式规则没有命令行,如第 13行的“$(OBJS): Common.inc”指出了所有的obj文件都依赖于Common.inc文件,第14行的“y.obj: y.inc”则指出了y.obj除了依赖第13行的规则外,还依赖于y.inc。但是第13行和第14行的两条规则都没有指出产生这些obj文件的命令, 所以nmake处理的时候会到隐含规则中去找命令行,最后会用第18行的“ml $(ML_FLAG) $<”命令去产生这些obj文件。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值