-------------------------------------------------------------copy right------------------------------------------
哥哥原创!
转载请附上哥哥的链接!!!
blog写作缘由:
项目突然需要使用到NMAKE来编译一个工程文件,于是开始找NMAKE相关资料,寻觅良久,仍末见中文版本(GNU的makefile有比较多的中文资料)。所以呢,只好自己开始死磕MSDN相关英文资料。此时刚好找到一英文版的NMAKE Guide,就拿来瞅瞅了。貌似用点心看,磕起来不太累。看到一半,突然想起一个问题,哥哥以后要是再想查相关资料,岂不是还得死嗑英文呢。所以就有了将该英文版本翻译一下的冲动。于是乎,就有了它了。
PS:哥哥英文不太好哦,大学很幸运地将六级“睡”过去了呢。之后就一直没瞅英文了,外加哥哥的语文好像不太好呢,所以大伙看到一些晦涩的地方,笑笑就可以了,因为哥哥实在不知道怎么翻了或是不晓得用啥中文来表述原意。
Guide写完后附上英文版,我这没看懂的可以查英文原版哦!!!
希望写出来可以帮助到一些人哦!!反正哥哥以后是可以看中文版的喽!!
(英文版本大概有59页,大概预计得二周内翻译完。)
-------------------------------------------------------------end-------------------------------------------------
特殊宏定义
NMAKE提供了一些特殊的宏定义来代表不同的文件名和命令。这些宏的一个用途就是在预定义推导规则中。
(更多的信息,请参阅567页的“预处理推导规则"一节。)和用户自定义宏名一样,特殊宏的名字也是区分大小写的。
举例来说,NMAKE认为CC和cc是两个不同的宏名。
接下来的章节我们将描述四种特别的宏。文件名宏提供了一种便捷的从依赖行中获取文件名的描述方法。
递归宏允许您在makefile文件中调用NMAKE程序。命令宏和选项宏可以让您方便地调用微软语言编译器。
文件名宏
NMAKE提供了预定义宏来描述文件名。该文件名正如您在依赖行中所指定的,而不是他们存在于磁盘上的完整的说明。
如同所有的单字符的宏一样,这些文件宏并不需要被括在括号内。(
NMAKE提供了一些特殊的宏定义来代表不同的文件名和命令。这些宏的一个用途就是在预定义推导规则中。
(更多的信息,请参阅567页的“预处理推导规则"一节。)和用户自定义宏名一样,特殊宏的名字也是区分大小写的。
举例来说,NMAKE认为CC和cc是两个不同的宏名。
接下来的章节我们将描述四种特别的宏。文件名宏提供了一种便捷的从依赖行中获取文件名的描述方法。
递归宏允许您在makefile文件中调用NMAKE程序。命令宏和选项宏可以让您方便地调用微软语言编译器。
文件名宏
NMAKE提供了预定义宏来描述文件名。该文件名正如您在依赖行中所指定的,而不是他们存在于磁盘上的完整的说明。
如同所有的单字符的宏一样,这些文件宏并不需要被括在括号内。(
当前目标的完整名字(路径、基本名字和后缀)按当前在描述块中指定的。
此宏只适用于在依赖行中指定特定的依赖项。
$*
当前目标的路径和基本文件名,不包括文件后缀。
$**
当前目标的所有的依赖项。
$?
当前目标的所有的依赖项中比目标具有一个更新的时间戳的依赖项集合。
$<
当前目标依赖项中比目标具有一个更新的时间戳的依赖项文件。
您只能在推导规则的命令块中使用该宏。
例子1
下面的例子使用了$?宏,代表了所有比目标具有更新的修改的依赖项。
!命令修饰符让NMAKE为列表中每个依赖项执行一次命令。
因此LIB命令将会执行三次,每次更新一个模块。
trig.lib : sin.obj cos.obj arctan.obj
!LIB trig.lib -+$?;
例子2
在现面的例子中,NMAKE更新另一个目录的一个文件通过使用当前目录中的一个同名文件来替换。
$@宏用来替代当前目标的完整名字。
# File in objects directory depends on version in current directory
DIR = c:/objects
$(DIR)/a.obj : a.obj
COPY a.obj $@
修饰文件名宏
您可以附加下表的一个修饰符于任一的文件名宏,用来提取的一个文件名的一部分。
如果您附加这些修饰符于文件宏,那么您必须用括号将宏名和修饰符括起来。
Modifier Resulting Filename Part
-------------------------------------------------------------------------
D Drive plus directory
B Base name
F Base name plus extension
R Drive plus directory plus base name
例子1
假设$@宏代表了目标C:/SOURCE/PROG/SORT.OBJ。下表列出了每个修饰符与$@结合的结果:
Macro Reference Value
--------------------------------------------------------------------------
$(@D) C:/SOURCE/PROG
$(@F) SORT.OBJ
$(@B) SORT
$(@R) C:/SOURCE/PROG/SORT
如果$@的值为SORT.OBJ并没有指定目录,那么$(@R)的值为SORT,$(@D)的值为(.)代表了当前目录。
例子2
下面的例子使用了F修饰符来指定当前目录中一个同名的文件:
# Files in objects directory depend on versions in current directory
DIR = c:/objects
$(DIR)/a.obj $(DIR)/b.obj $(DIR)/c.obj : $$(@F)
COPY $(@F) $@
-------------------------------------------------------------------
注意:另一种引用文件名部分的方法请参阅546页的“文件名部分语法”一节。
-------------------------------------------------------------------
递归宏
当您想在makefile文件中递归调用NMAKE程序时,NMAKE提供了三种您可以使用的宏。
这些宏可以使得递归更高效。
MAKE
定义成您指定给操作系统的名字在您可调用NMAKE程序的地方,默认名字为NMAKE除非您重命名了NMAKE.EXE实体文件。
使用该宏去递归调用NMAKE程序。/N命令行选项,以防止执行命令并不妨碍执行此命令(怪怪的)。
建议不要重定义MAKE宏
MAKEDIR
在NMAKE程序调用时定义成当前目录。
MAKEFLAGS
定义成当前起作用的NMAKE选项。该宏被自动传递给NMAKE程序当您递归NMAKE程序时。
然而递归调用时该宏的规范是没有恶意的;因此,您可以使用以前指定了该宏的makefile文件。
您不能重定义MAKEFLAGS宏。想在makefile里改变/D,/I,/N和/S选项,使用预处理指令!CMDSWITCHES。
(请看572页的“预处理指令”一节。)在递归时想要添加其他的选项给NMAKE到那些已经在起作用的MAKEFLAGS宏,
请在递归命令中指定他们。
NMAKE的递归调用
在一个命令块中,您可以指定一个NMAKE的自我调用,不管是MAKE宏或是直接指定NMAKE。
下面的NMAKE信息在递归时对于被调用的NMAKE是有效的:
环境变量宏(请看563页的“继承宏”)。如果想让所有的宏都是被继承的,那么请指定/V选项。
MAKEFLAGS宏。如果设置了.IGNORE或是!CMDSWITCHES+I指令,那么在该宏传递给递归调用时,MAKEFLAGS宏将包含/I选项。
同样的,如果设置了.SILENT或是!CMDSWITCHES+S指令,那么在该宏传递给递归调用时,MAKEFLAGS宏将包含/S选项。
在递归调用的命令行上定义的宏。
所有在TOOLS.INI中定义的信息。
在makefile中定义的推导规则并不传递给被调用的NMAKE程序。.SUFFIXES和.PRECIOUS指令的设置同样是不会被继承的。
当然您可以让.SUFFIXES、.PRECIOUS和所有的推导规则对于递归调用是有效的,通过在TOOLS.INI文件中定义他们或是将其定义在一个文件中然后在每个NMAKE会话中用!INCLUDE指令包含该命令。
例子
MAKE宏在生成一个程序的不同版本时是有用的。下面的makefile递归调用NMAKE来在目录/vers1和/vers2中生成目标。
all : vers1 vers2
vers1 :
cd /vers1
$(MAKE)
cd ..
vers2 :
cd /vers2
$(MAKE) /F vers2.mak
cd ..
如果依赖含有vers1作为目标执行,NMAKE执行命令改变当前目录为/VERS1目录,然后调用NMAKE程序使用那个目录下的MAKEFILE文件。
如果依赖含有vers2作为目标执行,NMAKE执行命令改变当前目录为/VERS2目录,然后调用NMAKE程序使用那个目录下的VERS2.MAK文件。
命令宏
NMAKE预先定义了一些宏来代表针对微软产品的命令。您可以在描述块或是推导规则中将这些宏当做命令来使用。
他们被自动应用于NMAKE的预定义推导规则中。(请看563页的“推导规则”。)您可重定义这些宏来代表命令行的一部分或是全部,包含选项。
AS
定义为ml,调用微软宏汇编译器的命令。
BC
定义为bc,调用微软的basic编译器的命令。
CC
定义为cl,调用微软的C编译器的命令。
COBOL
定义为cobol,调用微软的cobol编译器的命令。
CPP
定义为cl,调用微软的c++编译器的命令。
CXX
定义为cl,调用微软的C++编译器的命令。
FOR
定义为fl,调用 微软的FORTRAN编译器的命令。
PASCAL
定义为pl,调用微软的pascal编译器的命令。
RC
定义为rc,调用微软的资源编译器的命令。
选项宏
下面的宏代表了传递给命令的选项在调用微软的语言编译器时。这些宏在预定义推导规则中自动被使用。(请看567页的”预定义推导规则“。)
默认情形下,这些宏都是没有定义的。您可以定义他们来代表您想传递给编译器的选项,然后您可以在描述块和推导规则的命令段中使用他们。
和其他所有的宏一样,您还是可以使用这些宏即使他们是没有定义的。一个末定义的宏或是一个定义成空的宏在其被使用的地方将会由一个空串来替换。
AFLAGS
传递选项给微软的宏汇编译器
BFLAGS
传递选项给微软的basic编译器
CFLAGS
传递选项给微软的C编译器
COBFLAGS
传递选项给微软的cobol编译器
CPPFLAGS
传递选项给微软的C++编译器
CXXFLAGS
传递选项给微软的C++编译器
FFLAGS
传递选项给微软的FORTRAN编译器
PFLAGS
传递选项给微软的pascal编译器
RFLAGS
传递选项给微软的资源编译器
宏替换
就像宏允许您在makefile中替换文本一样,您也可以在宏本身中替换文本。
这种替换只应用于当前该宏的使用且并不会改变原先的宏定义。
想要在宏中实现文本替换,请使用下面的语法:
$(macroname:string1=string2)
在宏中出现的每个string1都会被替换成string2。
不要在分号前加任何的空格或是制表符。在分号后出现的空格都会认为是string1的一部分。
如果string2是空串,那么所有宏中出现的string1字串都会从宏中删除。
宏中的替换是文本的且大小敏感的。这意味着在string1中出现的字串必须和宏中的目标字串的一模一样且大小写一致,否则替换将不会被执行。
这同样意味着string2就像其指定的一样精确地的被替换。因为替换是文本的,所以替换字串不能包含宏展开。
例子1
下面的makefile示例了一个宏替换:
SOURCES = project.c one.c two.c
project.exe : $(SOURCE:.c=.obj)
LINK $**;
预定义宏$**代表了所有的依赖文件(请看555页的"文件名宏”一节。)当执行这个makefile时,NMAKE执行下面的命令:
LINK project.obj one.obj two.obj;
这个宏替换并不改变宏SOURCE的定义,如果宏SOURCE在makefile文件的其他地方再次使用,宏SOURCE还是其原来定义的值。
例子2
如果宏OBJS定义如下:
OBJS = ONE.OBJ TWO.OBJ THREE.OBJ
您可以将宏OBJS值中的每个空格替换为一个空格加上一个加号再加上一个换行符通过使用如下的宏替换:
$(OBJS: = +^
)
加字符号(^)告诉NMAKE将行尾的换行当作文本换行符来处理。替换后的宏展开如下:
ONE.OBJ +
TWO.OBJ +
THREE.OBJ
这个例子可以用来创建响应文件。
预定义宏中的替换
您也可以使用同样的语法来替换预定义宏中的文本($$@除外)。
下面描述块中的命令为预定义宏$@(代表了当前目标的完整文件名)做了一个文本替换。
值得注意的是尽管$@是一个单字符宏,当对其使用文本替换时,该宏须用括号括起来。
target.abc : depend.xyz
echo $(@:targ=blank)
NMAKE替换目标中targ字串为blank,生成字串blanket.abc。如果依赖项depend.xyz时间戳比目标文件target.abc的新,
那么NMAKE将执行如下命令:
echo blanket.abc
环境变量宏
当NMAKE运行时,在开始NMAKE会话之前,它将继承和宏的名字一样的环境变量的宏定义。
如果一个环境变量比如LIB或是INCLUDE已经定义在操作系统的环境中了,您可以使用他们的值就好像您已经定义了一个同名的具有相同值的NMAKE宏。
继承宏的名字都会转成大写的。宏继承动作发生在预处理之前。
/E选项将导致NMAKE覆盖makefile文件中定义的与从环境中继承来的宏有同样名字的宏。
您可以像定义或重定义其他宏一样重定义环境变量宏。
修改一个宏并不修改对应的环境变量,想要改变对应的变量,请使用SET命令。
同样,在NMAKE会话中使用SET命令修改某个环境变量的值并不改变对应的的宏定义。
想要改变宏定义,请定义宏。
如果一个环境变量并没在操作系统中有被设置,通过一个宏定义,它的值并不能被设置。
但是您可以在NMAKE会话中使用SET命令来设置该变量。然后这个变量的值对于NMAKE剩下的会话都是有效的,
除非它被重定义或是被重新设置。出现在makefile中的SET定义并不创建一个变量名字的对应宏。
如果您想要一个NMAKE会话中创建的环境变量的宏,那么您必须在设置环境变量之外显示地的定义该宏。
如果一个环境变量定义成一段不符合makefile语法的字串,NMAKE将不会从该环境变量创建一个宏。不会产生任何警告。
-----------------------------------------------------------------------------------------------
警告: 如果一个环境变量包含一个美元符号,NMAKE认为这是一个宏调用的开始。由此导致的宏展开将引发
无法预料的行为且有可能产生一个错误。
-----------------------------------------------------------------------------------------------
例子
下面的makefile重定义了名为LIB的环境变量:
LIB = C:/TOOLS/LIB
sample.exe : sample.obj
LINK sampel;
不论环境变量LIB之前的值为多少,当NMAKE执行这个描述块中的LINK命令时,它的值为c:/tools/lib。
重定义继承宏并不影响原始的环境变量,当NMAKE执行结束,LIB仍然是其原来的值。
如果在NMAKE会话之前LIB并没有定义,之前例子中定义的LIB宏并不为LINK命令设置了LIB环境变量的值。
想要做到这个,请使用下面的makefile:
sample.exe : sample.obj
SET LIB=c:/tools.lib
LINK sample;
继承的宏
当NMAKE被递归调用时,被调用的NMAKE程序继承的宏只有在命令行参数中定义的宏或是环境变量。
makefile文件中定义的宏并不被调用的NMAKE程序继承。有好几种方法将宏传递给递归调用的NMAKE程序:
使用/V选项运行NMAKE程序。这个选项强制所有的宏都被继承到调用的NMAKE程序中。
您可以在NMAKE的命令行中使用该选项以将宏继承应用于整个NMAKE会话周期。
或者您可以在一个调用NMAKE的命令中指定该选项来只影响指定的递归会话周期。
使用SET命令设置一个环境变量在递归NMAKE会话之前。
在递归调用命NMAKE的令参数行中定义宏
在TOOLS.INI文件中定义宏。每次递归NMAKE程序时,它都会读取TOOLS.INI文件中的内容。
宏定义的优先级
如果您在多处定义同名的宏,NMAKE将使用具有最高优先级的宏定义。
宏定义的优先级从高到低如下排列:
1.在命令行参数中定义的宏
2.在makefile文件或是包含文件中定义的宏
3.继承环境变量的宏
4.在TOOLS.INI中定义的宏
4.预定义宏,比如AS或是CC
/E选项使用继承环境变量宏来覆盖makefile文件中所有同名的宏。
!UNDEF指令可以覆盖在命令行中定义的宏。
如果依赖含有vers2作为目标执行,NMAKE执行命令改变当前目录为/VERS2目录,然后调用NMAKE程序使用那个目录下的VERS2.MAK文件。
命令宏
NMAKE预先定义了一些宏来代表针对微软产品的命令。您可以在描述块或是推导规则中将这些宏当做命令来使用。
他们被自动应用于NMAKE的预定义推导规则中。(请看563页的“推导规则”。)您可重定义这些宏来代表命令行的一部分或是全部,包含选项。
AS
定义为ml,调用微软宏汇编译器的命令。
BC
定义为bc,调用微软的basic编译器的命令。
CC
定义为cl,调用微软的C编译器的命令。
COBOL
定义为cobol,调用微软的cobol编译器的命令。
CPP
定义为cl,调用微软的c++编译器的命令。
CXX
定义为cl,调用微软的C++编译器的命令。
FOR
定义为fl,调用 微软的FORTRAN编译器的命令。
PASCAL
定义为pl,调用微软的pascal编译器的命令。
RC
定义为rc,调用微软的资源编译器的命令。
选项宏
下面的宏代表了传递给命令的选项在调用微软的语言编译器时。这些宏在预定义推导规则中自动被使用。(请看567页的”预定义推导规则“。)
默认情形下,这些宏都是没有定义的。您可以定义他们来代表您想传递给编译器的选项,然后您可以在描述块和推导规则的命令段中使用他们。
和其他所有的宏一样,您还是可以使用这些宏即使他们是没有定义的。一个末定义的宏或是一个定义成空的宏在其被使用的地方将会由一个空串来替换。
AFLAGS
传递选项给微软的宏汇编译器
BFLAGS
传递选项给微软的basic编译器
CFLAGS
传递选项给微软的C编译器
COBFLAGS
传递选项给微软的cobol编译器
CPPFLAGS
传递选项给微软的C++编译器
CXXFLAGS
传递选项给微软的C++编译器
FFLAGS
传递选项给微软的FORTRAN编译器
PFLAGS
传递选项给微软的pascal编译器
RFLAGS
传递选项给微软的资源编译器
宏替换
就像宏允许您在makefile中替换文本一样,您也可以在宏本身中替换文本。
这种替换只应用于当前该宏的使用且并不会改变原先的宏定义。
想要在宏中实现文本替换,请使用下面的语法:
$(macroname:string1=string2)
在宏中出现的每个string1都会被替换成string2。
不要在分号前加任何的空格或是制表符。在分号后出现的空格都会认为是string1的一部分。
如果string2是空串,那么所有宏中出现的string1字串都会从宏中删除。
宏中的替换是文本的且大小敏感的。这意味着在string1中出现的字串必须和宏中的目标字串的一模一样且大小写一致,否则替换将不会被执行。
这同样意味着string2就像其指定的一样精确地的被替换。因为替换是文本的,所以替换字串不能包含宏展开。
例子1
下面的makefile示例了一个宏替换:
SOURCES = project.c one.c two.c
project.exe : $(SOURCE:.c=.obj)
LINK $**;
预定义宏$**代表了所有的依赖文件(请看555页的"文件名宏”一节。)当执行这个makefile时,NMAKE执行下面的命令:
LINK project.obj one.obj two.obj;
这个宏替换并不改变宏SOURCE的定义,如果宏SOURCE在makefile文件的其他地方再次使用,宏SOURCE还是其原来定义的值。
例子2
如果宏OBJS定义如下:
OBJS = ONE.OBJ TWO.OBJ THREE.OBJ
您可以将宏OBJS值中的每个空格替换为一个空格加上一个加号再加上一个换行符通过使用如下的宏替换:
$(OBJS: = +^
)
加字符号(^)告诉NMAKE将行尾的换行当作文本换行符来处理。替换后的宏展开如下:
ONE.OBJ +
TWO.OBJ +
THREE.OBJ
这个例子可以用来创建响应文件。
预定义宏中的替换
您也可以使用同样的语法来替换预定义宏中的文本($$@除外)。
下面描述块中的命令为预定义宏$@(代表了当前目标的完整文件名)做了一个文本替换。
值得注意的是尽管$@是一个单字符宏,当对其使用文本替换时,该宏须用括号括起来。
target.abc : depend.xyz
echo $(@:targ=blank)
NMAKE替换目标中targ字串为blank,生成字串blanket.abc。如果依赖项depend.xyz时间戳比目标文件target.abc的新,
那么NMAKE将执行如下命令:
echo blanket.abc
环境变量宏
当NMAKE运行时,在开始NMAKE会话之前,它将继承和宏的名字一样的环境变量的宏定义。
如果一个环境变量比如LIB或是INCLUDE已经定义在操作系统的环境中了,您可以使用他们的值就好像您已经定义了一个同名的具有相同值的NMAKE宏。
继承宏的名字都会转成大写的。宏继承动作发生在预处理之前。
/E选项将导致NMAKE覆盖makefile文件中定义的与从环境中继承来的宏有同样名字的宏。
您可以像定义或重定义其他宏一样重定义环境变量宏。
修改一个宏并不修改对应的环境变量,想要改变对应的变量,请使用SET命令。
同样,在NMAKE会话中使用SET命令修改某个环境变量的值并不改变对应的的宏定义。
想要改变宏定义,请定义宏。
如果一个环境变量并没在操作系统中有被设置,通过一个宏定义,它的值并不能被设置。
但是您可以在NMAKE会话中使用SET命令来设置该变量。然后这个变量的值对于NMAKE剩下的会话都是有效的,
除非它被重定义或是被重新设置。出现在makefile中的SET定义并不创建一个变量名字的对应宏。
如果您想要一个NMAKE会话中创建的环境变量的宏,那么您必须在设置环境变量之外显示地的定义该宏。
如果一个环境变量定义成一段不符合makefile语法的字串,NMAKE将不会从该环境变量创建一个宏。不会产生任何警告。
-----------------------------------------------------------------------------------------------
警告: 如果一个环境变量包含一个美元符号,NMAKE认为这是一个宏调用的开始。由此导致的宏展开将引发
无法预料的行为且有可能产生一个错误。
-----------------------------------------------------------------------------------------------
例子
下面的makefile重定义了名为LIB的环境变量:
LIB = C:/TOOLS/LIB
sample.exe : sample.obj
LINK sampel;
不论环境变量LIB之前的值为多少,当NMAKE执行这个描述块中的LINK命令时,它的值为c:/tools/lib。
重定义继承宏并不影响原始的环境变量,当NMAKE执行结束,LIB仍然是其原来的值。
如果在NMAKE会话之前LIB并没有定义,之前例子中定义的LIB宏并不为LINK命令设置了LIB环境变量的值。
想要做到这个,请使用下面的makefile:
sample.exe : sample.obj
SET LIB=c:/tools.lib
LINK sample;
继承的宏
当NMAKE被递归调用时,被调用的NMAKE程序继承的宏只有在命令行参数中定义的宏或是环境变量。
makefile文件中定义的宏并不被调用的NMAKE程序继承。有好几种方法将宏传递给递归调用的NMAKE程序:
使用/V选项运行NMAKE程序。这个选项强制所有的宏都被继承到调用的NMAKE程序中。
您可以在NMAKE的命令行中使用该选项以将宏继承应用于整个NMAKE会话周期。
或者您可以在一个调用NMAKE的命令中指定该选项来只影响指定的递归会话周期。
使用SET命令设置一个环境变量在递归NMAKE会话之前。
在递归调用命NMAKE的令参数行中定义宏
在TOOLS.INI文件中定义宏。每次递归NMAKE程序时,它都会读取TOOLS.INI文件中的内容。
宏定义的优先级
如果您在多处定义同名的宏,NMAKE将使用具有最高优先级的宏定义。
宏定义的优先级从高到低如下排列:
1.在命令行参数中定义的宏
2.在makefile文件或是包含文件中定义的宏
3.继承环境变量的宏
4.在TOOLS.INI中定义的宏
4.预定义宏,比如AS或是CC
/E选项使用继承环境变量宏来覆盖makefile文件中所有同名的宏。
!UNDEF指令可以覆盖在命令行中定义的宏。
No comments:
Post a Comment