命令
如果依赖项已过期,则描述块或推理规则指定要运行的命令块。你可以在命令块中使用任何在MS-DOS中可以执行的命令。一个命令块可以包含多个命令。每条命令独立出现在一行中。如果一个描述块中不包含任何命令,NMAKE会根据匹配的依赖寻找合适的推导规则。下面的例子中依赖行后有两条命令:
myapp.exe : myapp.obj another.obj myapp.def link myapp another, , NUL, mylib, myapp copy myapp.exe c:\project
NMAKE 在运行命令之前显示每个命令,除非使用了 /S 选项、.SILENT、!CMDSWITCHES 或 @。
命令语法
一条命令必须以一个或多个空格或是制表符开始。NMAKE使用这种缩进来区分依赖行和命令行。
依赖行和命令块之间不能出现空行,但是可以出现只包含空格或是制表符的行;该行被当做空命令行,不会有错误产生。命令行之间允许有空行。
长的命令如果跨越多行可以每行都以反斜杠结尾(\)。命令行尾的反斜杠被当做空格处理。举个例子,之前的例子中的LINK命令可以写成:
link myapp\ another, , NUL, mylib, myapp
NMAKE将会将连续的几行当做一条长命令传递给操作系统处理。因此以反斜杠结尾的连续的长命令的长度不能超过操作系统的命令行的长度的限制。如果在反斜杠后还有其他的字符,比如空格或制表符,NMAKE将会将反斜杠和尾随字符解释为文字字符(转义字符处理)。
你也可以在依赖行后放置一条简单的命令。只要使用分号“;”来分隔依赖项和随后的命令,例如:
project.obj : project.c project.h ; cl /c project.c
命令修饰符
可以在命令前面指定一个或多个命令修饰符,可以选择用空格或制表符将其分隔。与命令一样,修饰符也必须缩进。
下面描述了NMAKE的三个命令修饰符。
@command
禁止NMAKE打印命令。但是不会禁止命令的任何输出显示。默认情况下,NMAKE 回显所有已执行的命令。使用 /S 选项取消显示整个Makefile;使用 .SILENT 取消显示部分Makefile。
-[number]command
关闭 command 的错误检查。默认情况下,当命令返回非零退出代码时,NMAKE 暂停。如果使用 -number,当退出代码超过 number 时,NMAKE 停止。空格或制表符不能出现在短划线和 number 之间。number 和 command 之间必须出现至少一个空格或制表符。使用 /I 选项关闭整个生成文件的错误检查;使用 .IGNORE 关闭部分生成文件的错误检查。
!command
如果在使用“!”修饰的命令中使用了预定义宏“$**”或是“$?",那么为每个依赖执行该命令。在命令之前可以出现一个或多个空格或是制表符。“$**”宏定义代表了依赖行中所有的依赖文件。"$?“宏定义代表了在依赖行所有的依赖项中时间戳比目标更早的依赖文件。
示例1
在下面的例子中,@命令修饰符禁止了命令的回显动作:
sort.exe : sort.obj @ECHO Now Sorting...
但是ECHO命令的输出结果并没有被禁止。
示例2
在下面的描述块中,如果sample程序返回一个非零的退出代码,NMAKE并不停止;如果sort程序返回一个比5大的退出代码,NMAKE将会停止:
light.lst : light.txt -sample light.txt -5 sort light.txt
例子3
下面的描述块:
print : one.txt two.txt three.txt !print $** lpt1:
产生下面的命令:
print one.txt lpt1: print two.txt lpt1: print three.txt lpt1:
命令退出代码
如果任一命令或是程序返回任一非零的错误代码,NMAKE将停止运行。错误代码会打印在NMAKE的错误信息中。
您可以使用“/I”或是“/K”选项、或是“.IGNORE”指令、或“!CMDSWITCHES”指令或“-”命令修饰符等方法来控制NMAKE怎么处理非零的错误返回码。
在预处理中也可以使用命令的返回码。你可运行一个程序或是命令然后使用!IF指令来判断该命令是否执行成功。更多信息请参考”预处理中程序的执行“一节。
部分文件名语法
命令中的部分文件名语法表示一个依赖项文件名的组成部分。此文件通常是依赖行分号右边列出的第一个文件。但是,如果一个依赖项是由一个推导规则派生而来的,那么NMAKE将会认为推导依赖为第一个依赖文件,而不是依赖行中第一个明确声明的依赖项。如果同时使用了多个推导规则,那么“.SUFFIXES”列表决定了依赖的先后次序。文件名的组成部分包括驱动器名、路径、基名称、扩展名。
你可以使用“%s”表示完整的文件名。例如,有一个描述块。
sample.exe : c:\project\sample.obj LINK $s;
NMAKE将上面的命令处理成:
LINK c:\project\sample.obj
你可以使用“%|[parts]F”(百分号后面跟着一个竖线字符)表示部分文件名,其中 parts 可以是零个或多个下列字母(按任意顺序排列)。
字母 | 说明 |
---|---|
无字母 | 完整名称(等同于 %s) |
d | 驱动器名 |
p | 路径名 |
f | 文件基名称 |
e | 文件扩展名 |
使用上面的语法,你可以使用"%|F"或是"%|dpfeF"来代表完整的文件名,与”%S“一样。
例子
下面的描述块使用了部分文件名语法:
samplet.exe : c:\project\sample.obj LINK $S, a:%|pfF.exe;
NMAKE解释第一个文件部分为依赖项的路径名,解释第二个文件部分为依赖项的基本文件名,同时使用指定的磁盘符和文件后缀。上面的命令执行如下:
LINK c:\project\samplet.obj, a:\project\sample.exe;
注意:还有另一种代表文件组成部分的方法,详情参考“修改文件名的宏定义”一节。
内联文件
NMAKE可以在命令块中创建“内联"文件。内联文件由NMAKE将你在makefile中指定的内容保存在磁盘上。NMAKE在命令执行时创建内联文件。
响应文件(response file)是内联文件的一种,其他命令可以将这个响应文件作为参数使用,比如LINK或是LIB。响应文件可以绕开操作系统对命令行的最大长度的限制,并自动将指定的输入送给其他命令。除了作为响应文件使用,内联文件还可以用来传递大量的命令给操作系统。
指定内联文件
知道内联文件的语法命令如下:
<<[filename]
你可以在命令行中任意位置使用双尖括号(<<)来声明内联文件,除了命令行的开始,因为命令行必须以空格或制表符缩进标识。尖括号必须作为文本字符使用(前面不能有转义字符)。它不能由宏定义代替实现。
当NMAKE执行描述块的时候,NMAKE先使用内联文件说明生成内联文件,然后内联文件名来替代内联文件说明。它的效果就像直接在命令块中指定文件名一样。
[filename]是内联文件的文件名。它必须紧跟在双尖括号之后,中间不能有空格。你也可以指定文件名的完整路径,不需要后缀名。如果filename指定的文件名已经存在了,NMAKE将覆盖该文件。如果是临时的内联文件,那么该内联文件将会被删除。(临时内联文件将会在下节中描述。)
内联文件的文件名是可选参数。如果你没有为内联文件指定文件名,那么NMAKE将会自动创建一个独一无二的文件名。 如果同时指定了文件名和目录,那么NMAKE将会在指定的目录生成指定的内联文件;如果目录没有指定,将会生成在当前的目录;如果没有指定文件名,那么NMAKE将会在环境变量TMP指定的路径中创建内联文件,如果TMP环境变量没有指定,那么将会创建在当前目录。你可以重复使用之前的内联文件名,NMAKE将会覆盖之前的文件。
创建内联文件
<<[filename]之后的第一行开始会被存入内联文件中。创建内联文件的语法如下:
<<[filenmae] inlinetext . . . <<[KEEP|NOKEEP]
标志着内联文件结束的尖括号(<<)必须位于makefile文件独立一行的开始位置。两个双尖括号之间inlinetext的内容都会存在内联文件中。文件内容可以使用宏扩展和替换。指令和注释会被NMAKE当做文本来处理。出现在内联文件中的空格、制表符和换行符都被认为是普通字符。
内联文件可以是临时文件也可以是永久文件。诺想在NMAKE会话结束后仍保留内联文件,需要在结束的尖括号之后加上“KEEP”。如果您没有在结束的尖括号后指定后缀或是指定了“NOKEEP”的后缀,那么该内联文件是临时文件。“KEEP”和“NOKEEP”是不区分大小写的。临时的内联文件只在NMAKE会话周期内存在。
可以为一个没有命名的内联文件指定为永久文件,这样的话,由NMAKE创建的内联文件将会在NMAKE会话结束之后被保存下来。
例子
下面的makefile使用一个临时内联文件来清除屏幕显示和显示当前目录的内容:
COMMANDS = cls ^ dir showdir : <<showdir.bat $(COMMANDS) <<
在这个例子中,内联文件名是描述块中唯一的命令。该命令相当于运行一个名为SHOWDIR.BAT的批处理文件,SHOWDIR.BAT文件中包含那些在定义$(COMMANDS)中列出的命令。
内联文件的重用
若要重新使用内联文件,请在定义并首次使用该文件的位置指定 <<filename,稍后再在同一命令或其他命令中重新使用不带(<<) 的 filename。创建内联文件的命令必须在使用该文件的所有命令运行之前运行。
不管你有没有在内联文件结束标志后添加KEPP或是NOKEEP,NMAKE将会在整个会话周期中保存该内联文件。
例子
下面的makefile创建了一个名为LIB.LRF的临时的LIB响应文件:
OBJECTS = add.obj sub.obj mul.obj div.obj math.lib : $(OBJECTS) LIB math.lib @<<lib.lrf -+$(?: = &^ -+) listing; << copy lib.lrf \projinfo\lib.lrf
生成的响应文件告诉LIB去使用哪些库、执行哪些命令以及生成清单中的文件:
-+add.obj & -+sub.obj & -+mul.obj & -+div.obj listing;
描述块中第二条命令让NMAKE将生成的响应文件拷贝到另一个目录。
多个内联文件的使用
你可以在一条命令中指定多个的内联文件。对于每个文件,指定一或多行内联文本,该文本后面要跟包含分隔符的结束行。在第一个文件分隔行后面的行上开始第二个文件的文本。
例子
下面的例子创建了两个内联文件:
target.abc : depend.xyz copy <<file1 + <<file2 both.txt I am the contents of file1. << I am the contents of file2. <<KEEP
这和指定
copy file1+file2 both.txt
来连接两个文件一样,FILE1包含:
I am the contents of file1.
FILE2包含:
I am the contents of file2.
KEEP关键词告诉NMAKE在NMAKE执行结束后不要删除FILE2文件。文件FILE2和BOTH.TXT存在当前目录中。