makefile

Microsoft Program Maintenance Utility ,外号 NMAKE ,顾名思义,是用来管理程序的工具。其实说白了,就是一个解释程序。它处理一种叫做 makefile 的文件(以 mak 为后缀),解释里面的语句并执行相应的指令。我们编写 makefile 文件,按照规定的语法描述文件之间的依赖关系,以及与该依赖关系相关联的一系列操作。然后在调用 NMAKE 时,它会检查所有相关的文件,如果目标文件( target file ,下文简称 target ,即依赖于其它文件的文件)的 time stamp (就是文件最后一次被修改的时间,一个 32 位数,表示距离 1980 年以来经过的时间,以 2 秒为单位)小于依赖文件( dependent file ,下文简称 dependent ,即被依赖的文件)的 time stamp NMAKE 就执行与该依赖关系相关联的操作。请看下面这个例子:

foo.exe : first.obj second.obj

link first.obj,second.obj

第一行定义了依赖关系,称为 dependency line ;第二行给出了与该依赖关系相关联的操作,称为 command line 。因为 foo.exe first.obj second.obj 连接而成,所以说 foo.exe 依赖于 first.ogj second.obj ,即 foo.exe target first.obj second.obj dependent 。如果 first.obj second.obj 中的任何一个被修改了(其 time stamp 更大),则调用 link.exe ,重新连接生成 foo.exe 。这就是 NMAKE 的执行逻辑。

综上, NMAKE 的核心就是依赖关系,操作和判定逻辑( target.timestamp < dependent.timestamp ,如果为 true ,就执行相应操作)。

 

MAKEFILE 的语法

 

现在详细讨论一下 makefile 的语法。 makefile 就像一个玩具型的程序语言,麻雀虽小,但五脏具全。 makefile 的组成部分包括:描述语句( description block ), inference rules (推导规则),宏和指令( directive )。描述语句就是 dependent lines command lines 的组合; inference rules 就是预先定义好的或用户自己定义的依赖关系和关联命令;宏就不用说了吧;指令就是内定的一些可以被 NMAKE 识别的控制命令,提供了很多有用的功能。

另外, makefile 中使用以下几个具有特殊意义的符号:

^ # / ( ) { } ! @ - : ; $

^ caret ):用于关闭某些字符所具有的特殊意义,使其只表示字面上的意义。例如: ^#abc 表示 #abc 这个字符串,而 #abc 则用于在 makefile 中加入注释, # 在这里为注释标志,就像 C++ 中的 // 。另外,在一行的末尾加上 ^ ,可以使行尾的回车换行符成为字串的一部分。

# number sign ):为注释标志, NMAKE 会忽略所有从 # 开始到下一个换行符之间的所有文本。这里要注意的是:在 command lines 中不能存在注释。因为对于 command lines NMAKE 是将其整行传递给 OS 的。通常对于 command lines 的注释都是放在行与行之间。

/ backslash ):用于将两行合并为一行。将其放在行尾, NMAKE 就会将行尾的回车换行符解释为空格( space )。

% percent symbol ):表示其后的字符串为一文件名。用法较复杂,在讲 dependent lines 的时候再详细讨论。

!( exclamation symbol ):命令修饰符,在下面会有详细的讨论。

@ at sign ):命令修饰符,在下面会有详细的讨论。

: colon ):用于 dependent lines inference rules 中,用于分隔 target dependent

; semicolon ):如果对于一个 dependent line 只有一条命令,则可以将该命令放在 dependent line 的后面,二者之间用“;”分隔。

$ dolor sign ):用于调用宏,在下面讲宏的时候再详细讨论。

makefile 中还可以使用 DOS 通配符( wildcard )来描述文件: * 和?。

如果要将中间有空格或制表符的字符串作为整体对待,则应该用双引号将其括起来,例如,在指定一个中间有空格的长文件名的时候:

My Document”

或在定义一个宏的时候:

        MYMACRO=”copy a:/foo.exe c:/”

 

描述语句块( Description Blocks

 

描述语句块为 makefile 主体的基本组成单元,其典型结构如下:

       target : dependents

        commands block

 

Dependent Line

 

    每一个描述语句块中只有一个 dependent line ,其定义了一个依赖关系。该行的开头不能有任何空白(空格或制表符)。冒号两边的 target dependent 都可以有多个,之间以空格分隔。 NMAKE 在分析 makefile 时首先会从头到尾扫描每一个 dependent line ,然后根据依赖关系建立起一棵依赖关系树( dependent tree )。例如对于依赖关系:

        foo.exe : first.obj second.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 中可以有很多的 dependent lines ,但 NMAKE 只会构造出现在它的命令行中的 targets ,或者,如果命令行中没有给出 targets ,就构造第一个 dependent line 中的第一个 target 。其他所有无关的 targets 都不会被构造。例如:

        foo1.exe foo2.exe : first.obj

       first.obj : first.cpp

       second.obj : second.cpp

假设上面的第一行语句为 makefile 中出现的第一个 dependent line ,且命令行中没有给出 target 。当 first.cpp 被更新后, first.obj foo1.exe 都会被重新构造,而 foo2.exe second.obj 则不会。

    当在一个 dependent line 中出现多个 target 时,例如:

        boy.exe girl.exe : first.obj

              echo Hello

    该语句相当于:

       boy.exe : first.obj

              echo Hello

 

       girl.exe : first.obj

              echo Hello

(注: echo 是一条控制台命令,用于在 STDOUT 上显示一行信息)

    同一个 target 也可以出现在多个 dependent lines 中。在这种情况下,如果只有一个 dependent line 后跟有 command line ,则它们会被合并为一个描述语句块,例如:

       foo.exe : first.obj

              echo Building foo.exe…

      

        foo.exe : second.obj

NMAKE 会将其处理为:

        foo.exe : first.obj second.obj

              echo Building foo.exe…

    如果每一个 dependent line 后都有 command line ,则它们会被作为两个描述语句块处理。

如果在 dependent line 中使用双冒号( :: )来分隔 target dependent ,并且同一个 target 出现在多个描述语句块中,此时, NMAKE 将会匹配最合适的语句块,以构造该 target

例如:

       target.lib :: one.asm two.asm three.asm

ML one.asm two.asm three.asm

LIB target -+one.obj -+two.obj -+three.obj;

target.lib :: four.c five.c

CL /c four.c five.c

LIB target -+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 出现在某个 dependent line 中。当使用 pseudotarget 作为 target 时,与之关联的 commands block 一定会被执行,同时 NMAKE 会赋予它一个假想的 time stamp 。该 time stamp 等于它的 dependents 中最大的 time stamp ,或者,如果它没有 dependent ,就等于当前时间。该假想的 time stamp pseudotarget 作为 dependent 时会被用来进行有效性评估。这个特性最大的好处就是,你可以让 NMAKE 构造多个 target ,而不用将每个 target 都在 NMAKE 的命令行中列出来,例如:

       all : setenv project1.exe project2.exe

project1.exe : project1.obj

LINK project1;

project2.exe : project2.obj

LINK project2;

setenv :

set LIB=/project/lib

 

上例中有两个 pseudotarget ,一个是 all ,另一个是 setenv 。首先是 setenv 被评估,其作用是设置环境变量 LIB ,然后 project1.exe project2.exe 依次被更新 .

Commands Block

    第二行开始到下一个 dependent line 之间为 commands block ,其给出了当 dependents 中的任何一个的 time stamp 大于 target 时,需要执行的指令序列( commands block 也可以为空,此时, NMAKE 什么也不干)。 command line 必须以空白开头(刚好与 dependent line 相反, NMAKE 就是通过该特征来分辨二者的),并且在 dependent line commands block 中的第一条语句之间不能有空白行(就是除了一个换行符,什么也没有的行。所以只有一个空格或制表符的行是合法的,此时 NMAKE 将其解释为一个 null command ),但在 command lines 之间可以有空白行。 Commands block 中的每一条命令可以是在控制台中合法的任何命令。事实上大可将 commands block 当成一个由控制台命令序列组成的批处理文件。

    此外,对 commands block 中的命令,还可以在其前面添加一个或多个所谓的命令修饰符( command modifier ),以实现对命令的一些额外的控制。命令修饰符有以下 3 种:

1) @command  消除该命令的所有到 STDOUT 的输出。

2) –[number]command

关掉对该命令返回值的检测。在默认的情况下,如果一条命令返回非 0 值,则 NMAKE 将会停止执行。但如果在命令前加上一“ - ”,则 NMAKE 将会忽略该命令的返回值。如果“ - ”紧接着一个整数,则 NMAKE 会忽略掉任何大于该整数的返回值。

3) !command

如果该命令的执行对象为 $** $? (这两个都是预定义的宏,前者表示相应的 dependent line 中所有的 dependent ,后者表示所有比 target 具有更大的 time stamp dependent ),则该“!”修饰符将会使该命令施行于这两个宏所描述的每一个独立的文件上。

      NMAKE 还提供了一些语法可以在 commands block 中表示相应的 dependent line 中第一个 dependent 的文件名组成。例如:

       foo.exe : c:/sample/first.obj c:/sample/second.obj

              link %s

NMAKE 将“ link %s ”解释为:

       link c:/sample/first.obj

如果将命令改为“ link %|pfF.exe ”,则 NMAKE 将之解释为:

       link c:/sample/first.exe

%s 表示全文件名, %|[part]F 表示文件名中的某个部分, part 可以是下列字符中的一个或多个,如果 part 为空, %|F %s 的意思相同:

1) d :盘符;

2) p :路径;

3) f :文件基本名;

4) e :文件扩展名

 


Inference Rules (推导规则)

 

    Inference rules (下文简称 IR )是一个模板,它用于决定如何从一个具有某种扩展名的文件构造出一个具有另一种扩展名的文件。 NMAKE 通过 IR 来确定用来更新 target 的命令以及推导 target dependents IR 的好处在于它满足了像我这样的懒人的需要。只要提供了正确的 IR ,则描述语句块就可以极大地化简。请看下面的例子:

       foo.obj :

上面的语句将会运作得很好。是不是觉得很吃惊呢?事实上, NMAKE 在处理该语句的时候,它首先在当前目录下搜索基本名为 foo 的文件(假设当前目录下有一个 foo.c 文件)。然后它查找一个后缀列表( suffix list ),里面的每一项包含了从一种类型的文件构造另一种类型的文件需要调用的命令和参数的相关信息。在 NMAKE 预定义的列表中, foo.c foo.obj 的构造命令为 CL 。最后 NMAKE 调用 CL ,编译 foo.c 。呵呵,这么一长串的操作一条简单的语句就搞定了,是不是很方便呢!

    当出现下列情况之一时, NMAKE 就会尝试使用 IR

1 NMAKE 遇到一个没有任何命令的描述语句块。此时 NMAKE 就会搜索后缀列表,试图找到一个匹配的命令来构造 target

2 )无法找到某个 dependent ,并且该 dependent 没有作为 target 出现在其它 dependent line 中(即它不是一个 pseudotarget )。此时 NMAKE 就会搜索给定的目录以及后缀列表,试图找到一个 IR 来构造出该 dependent

3 )一个 target 没有 dependent ,并且描述语句块中没有给出指令。此时 NMAKE 就会试图找出一个 IR 来构造出该 target

4 一个 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 中指定了搜索路径,则在 dependent lien 中也必须指定同样的路径,否则 IR 将不会应用于 dependent line 上,例如:

        {../proj}.exe{../proj}.obj:

IR 不会用于下列语句上:

project1.exe : project1.obj

但会用于下列语句上:

{../proj}project1.exe : {../proj}project1.obj

NMAKE 本身提供了一个预定义的后缀列表,内容如下:

       Rule                  Command                       Default Action

      .asm.exe           $(AS)$(AFLAGS) $*.asm                ML $*.ASM

.asm.obj         $(AS)$(AFLAGS) /c $*.asm                   ML /c $*.ASM

.c.exe            $(CC)$(CFLAGS) $*.c                  CL $*.C

.c.obj              $(CC)$(CFLAGS) /c $*.c                  CL /c $*.C

.cpp.exe              $(CPP)$(CPPFLAGS) $*.cpp              CL $*.CPP

     .cpp.obj              $(CPP)$(CPPFLAGS) /c $*.cpp             CL /c $*.CPP

.cxx.exe             $(CXX) $(CXXFLAGS) $*.cxx            CL $*.CXX

.cxx.obj             $(CXX) $(CXXFLAGS) /c $*.cxx          CL /c $*.CXX

.bas.obj           $(BC) $(BFLAGS) $*.bas;                    BC $*.BAS;

.cbl.exe       $(COBOL) $(COBFLAGS) $*.cbl, $*.exe;    COBOL $*.CBL, $*.EXE;

.cbl.obj           $(COBOL) $(COBFLAGS) $*.cbl;             COBOL $*.CBL;

.for.exe             $(FOR) $(FFLAGS) $*.for                    FL $*.FOR

.for.obj            $(FOR) /c $(FFLAGS) $*.for                   FL /c $*.FOR

.pas.exe           $(PASCAL) $(PFLAGS) $*.pas                 PL $*.PAS

.pas.obj           $(PASCAL) /c $(PFLAGS) $*.pas               PL /c $*.PAS

.rc.res              $(RC) $(RFLAGS) /r $*                       RC /r $*

   

  在上表中,类似 AFLAG CFLAG 这种被包含在括号里面的是未定义的宏,通过在 makefile 中对这些宏给出定义,可以为这些命令指定编译器和参数。例如:

       $(AS)$(AFLAGS) $*.asm

AS 宏用于指定编译器, NMAKE 中默认为 ML AFLAGS 宏用于给出编译器参数, NMAKE 将之留给用户定义,默认为空。所以默认的操作为:

ML $*.asm

这里可以看到将宏展开的语法,就是将宏的名字用圆括号括起来,然后在前面加上一个美元符号。另外需要说明的是,“ $* ”是 NMAKE 预定义的一个特殊的宏,其等于 target 的路径加上 target 的基本名。

 

宏( MARCRO

 

    makefile 中通过使用宏将可以获得很大的灵活性。下面就是在 makefile 中定义宏的语法:

       macroname=string

makefile 中, macroname 是宏的名字,其可以是任何字母,数字和下划线的组合,最多可以有 1024 个字符。另外要注意的是, macroname 是大小写敏感的。 string 是宏的定义体,可以有高达 65510 个字符。任何包含 0 个字符或只包含空白的字符串都被视为空字串( null string ),此时,该宏也被视为 NULL ,任何其出现的地方,都会被替换为空白。

在使用宏时,还应知道以下几个具有特殊意义的符号:

1 # 用于注释,例如:

command=ML       # compile asm file

2 / 将宏定义分作多行来写,例如:

LINKCMD = link myapp/

another, , NUL, mylib, myapp

/ ”后面的回车换行符会被空格替换,上面两行相当于:

LINKCMD = link myapp another, , NUL, mylib, myapp

3 $ 将宏展开,用法在后面介绍。

4 ^ 如果要在宏中包含以上符号,但又不使用它们的特殊语义,则可以这样:

 

dir=c:/windows^/

此时, dir 相当于字符串“ c:/windows/ ”。

以下是一些语法上的细节:

1) 在定义宏时,宏名字的第一个字符必须是该行的第一个字符;

2) 每行只能定义一个宏;

3) 在“ = ”两边可以有空格,但它们都会被忽略;

4) 在宏定义体中可以有空格,它们都会被视为宏的一部分;

除了可以在 makefile 中定义宏之外,宏定义也可以出现在 NMAKE 命令行中。此时,如果在宏定义中有任何空白,则必须用双引号将之括起来,例如:

NMAKE "LINKCMD = LINK /MAP"

NMAKE LINKCMD="LINK /MAP"

而像下面这样则是不允许的(等号两边有空格):

           NMAKE LINKCMD = "LINK /MAP"

    使用宏的语法如下(注意,整个语句中不能有任何空格):

            $ macroname

    NMAKE 会将整个语句用宏替换掉。如果宏未定义, NMAKE 会用空白替换之,不会产生任何错误。如果宏的名字只有一个字符,则括号可以省略,例如: $L $ L )是等价的。

    NMAKE 为宏的使用还提供了一个很有用的特性,那就是 substitution (子替换)。即是在展开宏的时候,你还可以指明将展开的宏中的某部分文本用另外的文本替换掉。例如:

           SOURCE=one.c two.c

foo.exe : $ SOURCE:.c=.obj

            LINK $**;

展开来就是这样:

SOURCE=one.c two.c

foo.exe : one.obj two.obj

            LINK one.obj two.obj;

语句 $ SOURCE:.c=.obj )表示将 SOURCE 中出现的所有“ .c ”替换为“ .obj ”。

由以上的例子可以看出, substitution 的语法如下(注意,没有空格):

$ macroname:str1=str2

    此外, NMAKE 还提供了 4 组预定义的宏,它们分别是文件名宏,递归宏,命令宏和参数宏。它们都可以被重新定义,但可能会引起一些不必要的麻烦,因为它们被广泛使用。正所谓“动一发而牵全身”,一个小小的改动,甚至有可能会影响到太阳黑子的运动(蝴蝶效应),这就是使用宏的最大的弊端。

 

文件名宏

 

commands block 中使用,以表示特定的文件名,包括:

1) $@   用来表示相关联的 dependent line 中第一个 target 的全名(包括路径)。

2) $$@  同上,但只能用在 dependent line 中。

3) $*    target 的路径加基本名。

4) $**   相应的 dependent line 中的所有 dependent

5) $?     相应的 dependent line 中的所有 time stamp 大于 target dependent

6) $<     同上,但只能用在 IR 中。

 

下面是一个例子:

DIR = c:/objects

$(DIR)/a.obj : a.obj

COPY a.obj $@

最后一句展开来就相当于: copy a.obj c:/objects/a.obj

    另外,在使用以上这些宏的时候,还可以通过以下的字符来提取文件名中的某一个部分:

            D     路径

            B     基本名

            F     基本名加扩展名

            R     路径加基本名

    例如:如果 $@ 表示 c:/objects/a.object ,则

             $ @D       c:/objects

             $ @B        a

             $ @F        a.obj

            $ @R       c:/objects/a

 

递归宏

 

    3 个,它们都是用来在 makefile 中方便地进行 NMAKE 的递归调用,它们分别是:

1) MAKE    表示运行当前 makefile NMAKE 程序的名字。例如,如果你在控制台用以下语句运行 makefile

NMAKE her.mak

MAKE 就等于 NMAKE

但如果你将 NMAKE.EXE 改名为 FUCK.EXE ,那么你运行 makefile 的命令就应该改为:

FUCK her.mak

此时, MAKE 就等于 FUCK

2) MAKEDIR   表示你调用 NMAKE 时所在的目录。

3) MAKEFLAGS 表示你运行当前 makefile 时使用的 NMAKE 参数。

    这几个宏在 build 程序的不同版本时特别有用,例如:

            all : vers1 vers2

vers1 :

cd /vers1

$(MAKE)

cd ..

vers2 :

cd /vers2

$(MAKE) /F vers2.mak

cd ..

    NMAKE 会分别在 ./vers1 ./vers2 目录下运行 vers1.mak vers2.mak

 

命令宏和参数宏

 

    命令宏表示 Microsoft 的编译程序(真的很会做生意,任何时候都不忘自己的产品),而参数宏则是表示传递给这些编译器的参数,在默认情况下,参数宏都是未定义的。当然,你可以重新定义它们,让它们表示 Boland 的编译程序和参数。

 

      命令宏                                            对应的参数宏

1) AS          ml M 的汇编编译器。                       AFLAGS

2) BC          bc M BASIC 编译器。                    BFLAGS

3) CC          cl M C 编译器。                          CFLAGS

4) COBOL   cobol M COBOL 编译器。                   COBFLAGS

5) CPP          cl M C++ 编译器。                       CPPFLAGS

6) CXX         cl M C++ 编译器。                      CXXFLAGS

7) FOR        fl M FORTRAN 编译器。                     FFLAGS

8) PASCAL     pl M PASCAL 编译器。                       PFLAGS

9) RC          rc M 的资源编译器。                           RFLAGS

 

NMAKE 的命令行语法

语法:

NMAKE [options] [macros] [targets]

其中, options NMAKE 的选项, macros 是在命令行中的宏定义, targets NMAKE 的目标文件列表。

选项(忽略大小写):

1) /A    强制重新构件所有与 NMAKE target 相关的 dependents ,即使这些 dependents 并没有过期;

2) /B    即使 dependent target 有相同的 time stamp ,也重建该 target 。大部分的 OS 中的 time stamp 是以 2 秒为单位的,如果一个 2 秒之内被修改,那么它的 time stamp 将不会有任何变化。在这种情况下,你就需要使用该选项让 NMAKE 重建之。为了预防万一,总是应该使用该选项,尽管可能会导致不必要的重建操作。

3) /C    屏蔽掉大部分的 NMAKE 输出信息,包括:非致命错误信息,警告信息, time stamp 和版权信息。如果 /C /K 选项同时存在,则 /K 发出的警告信息也会被干掉。

4) /D    NMAKE 执行期间显示相关的信息。包括每个文件的 time stamp ,依赖关系,以及类似于“文件不存在”之类的提示信息。用于对 makefile 除错;

5) /E    使环境变量可以覆盖预定义宏;

6) /F filename     指定 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 ,目标文件描述和 .SUFFIXES list 。如果打开 /P 选项,而且不指定任何目标文件,则 NMAKE 仅显示相关信息。

 

14)/Q   检查 target dependent time stamp ,但不执行 commands block 。如果目标文件为有效的,则返回 0 ,否则返回 255 。只有 makefile 中的预处理命令会被执行。当在批处理文件中调用 NMAKE 时,该选项会十分有用。

15) /R    清除 .SUFFIXES list ,忽略所有的 IR TOOLS.INI 中定义的或预定义的宏。

16) /S    禁止 makefile 中所有的被执行指令的显示信息;

17)/T    将命令行中输入文件的 time stamp 改为当前时间,只执行预处理命令而不执行 commands block ,目标文件的内容不会被改变;

18) /V    NMAKE 被递归调用时,所有定义的宏都会被继承。在默认的情况下,只有在命令行中定义的宏和环境变量(实际上也是一个宏)是可以被继承的。

19) /X filename    NMAKE 的所有错误信息输出到 filename 指定的文件或设备中。如果用“ - ”代替 filename ,则错误信息会被输出到 STDOUT 。在默认情况下,错误信息输出到 STDERR 。该选项不会影响由 makefile 中的指令产生的到 STDERR 的输出。

20) /   显示 NMAKE 的语法和可用选项;

 

NMAKE 的返回值

     NMAKE 的返回值及其含义见下表:

                          含义

       0              没有错误

       1              没有完全执行 commands block 中的指令(只在 /K 选项打开时有效)

       2              程序错误,可能的原因包括:

1 makefile 的语法错误

                          2 commands block 中的某条指令出现错误

                           3 )用户中断

4              系统错误,例如内存不足

255             /Q 选项打开时,如果目标文件已过期,则返回该值

 

你可能感兴趣的:(C/C++)