简介

大家已经习惯于微软提供的功能强大的IDE,已经很少考虑手动编连项目了,所谓技多不压身,有空的时候还是随我一块了解一下命令行编译。

C/C++/VC++程序员或有Unix/Linux编程经验应该很熟悉,以前我曾写过一篇文章描述用csc/vbc来进行命令行编译,今天再介绍一下MS提供的更加快捷有效的编译工具NMake。

MSDN的描述: Microsoft 程序维护实用工具 (NMAKE.EXE) 是一个 32 位,基于说明文件中包含的命令生成项目的工具。

NMake具有丰富的选项,可以完成复杂编译操作。它可以辨别源代码的改动,并选择性的编译,为你节省大量不必要的编译时间。

使用NMAKE

语法:NMAKE [options] [macros] [targets] [@commandfile]

说明:其中,options是NMAKE的选项,macros是在命令行中的宏定义,targets是NMAKE的目标文件列表,commandfile是包含命令行输入的文本文件(或响应文件)。

NMAKE 使用指定 /F 选项的Makefile(生成文件,通常名字是makefile);如果未指定 /F 选项,则使用当前目录下的Makefile。如果未指定Makefile,则 NMAKE 使用推理规则生成命令行 targets。

NMake本身很简单,与NMAKE配合的是Makefile。Makefile的语法比较复杂,通常需要开发者自己手动编写Makefile,下一节我们详细讲解Makefile。

上面的options和macros做了MSDN的链接,内容较多,请自己查询相关页,可以从这里进入NMake的MSDN帮助页面,在线帮助点这里

编写MAKEFILE

注:本节内容来自MSDN,熟悉此节的朋友可以直接跳过

Makefile的组成部分包括:成文件包含:

a.描述块

描述块是后面可跟有命令块的依赖项行:

    targets... : dependents...
commands...

依赖项行指定一或多个目标以及零或多个依赖项。目标必须位于行首。用冒号 (:) 将目标和依赖项分开;允许使用空格或制表符。若要拆分行,请在目标或依赖项后面使用反斜杠 (\ )。如果目标不存在、目标的时间戳比依赖项早或者目标是伪目标,则 NMAKE 执行命令。如果某依赖项是其他地方的目标,并且不存在或对于自己的依赖项已过期,则 NMAKE 在更新当前依赖项之前更新该依赖项。

b.命令

如果依赖项已过期,则描述块或推理规则指定要运行的命令块。NMAKE 在运行命令之前显示每个命令,除非使用了 /S 选项、.SILENT!CMDSWITCHES 或 @。如果描述块后面没有紧跟命令块,NMAKE 将查找匹配的推理规则。

命令块包含一个或多个命令,每个命令位于各自的命令行上。在依赖项(或规则)和命令块之间不能出现空行。但是可以出现只包含空格或制表符的行;该行被解释为空命令,并且不出现错误。命令行之间允许有空行。

命令行以一个或多个空格或制表符开始。后面紧跟着换行符的反斜杠 ( \ ) 在命令中被解释为空格;在行尾使用反斜杠继续下一行命令。如果反斜杠后紧跟有其他任何字符(包括空格或制表符),则 NMAKE 按原义解释反斜杠。

无论后面是否紧跟有命令块,前面带分号 (;) 的命令可以出现在依赖项行上或推理规则中:

project.obj : project.c project.h ; cl /c project.c

c.宏

宏用另一个字符串替换生成文件中的特定字符串。使用宏可以:

  • 创建可生成不同项目的生成文件。
  • 指定命令选项。
  • 设置环境变量。

可以定义您自己的宏或使用 NMAKE 的预定义宏

d.推理规则

推理规则提供命令来更新目标并推理目标的依赖项。推理规则中的扩展名与具有相同基名称的单个目标和依赖项匹配。推理规则是用户定义的,或预定义的;预定义的规则可以重新定义。

如果过期的依赖项没有命令,并且如果 .SUFFIXES 包含依赖项的扩展名,则 NMAKE 使用其扩展名与当前或指定目录中的目标和现有文件匹配的规则。如果有多个规则与现有文件匹配,.SUFFIXES 列表将确定使用哪一个规则;列表优先级从左向右按降序排列。如果依赖文件不存在,并且未在另一个描述块中作为目标列出,则推理规则可以从具有相同基名称的另一个文件创建缺少的依赖项。如果描述块的目标没有依赖项或命令,推理规则可以更新目标。即使不存在描述块,推理规则也可以生成命令行目标。即使指定了显式依赖项,NMAKE 也可以调用推理依赖项的规则。

e.点指令

在描述块之外的行首指定点指令。点指令以句点 ( . ) 开始,后面跟一个冒号 (:)。允许使用空格或制表符。点指令名区分大小写并且应为大写。

指令 作用
.IGNORE : 忽略从指定该指令的位置到生成文件末尾之间,由命令返回的非零退出代码。默认情况下,如果命令返回非零退出代码,NMAKE 将暂停。若要还原错误检查,请使用 !CMDSWITCHES。若要忽略单个命令的退出代码,请使用短划线 (-) 修饰符。若要忽略整个文件的退出代码,请使用 /I 选项。
.PRECIOUS : targets 若更新 targets 的命令暂停,则将 targets 保留在磁盘上;若命令通过删除文件处理中断,则该指令无效。用一或多个空格或制表符分隔目标名称。默认情况下,如果通过使用 CTRL+C 或 CTRL+BREAK 组合键中断生成,NMAKE 将删除目标。.PRECIOUS 的每一次使用都应用于整个生成文件;多次指定是累计的。
.SILENT : 取消从指定该指令的位置到生成文件末尾之间的已执行命令的显示。默认情况下,NMAKE 显示它调用的命令。若要还原回显,请使用 !CMDSWITCHES。若要取消单个命令的回显,请使用 @ 修饰符。若要取消整个文件的回显,请使用 /S 选项。
.SUFFIXES : list 列出推理规则匹配的扩展名;预定义为:.exe .obj .asm .c .cpp .cxx .bas .cbl .for .pas .res .rc。

若要更改 .SUFFIXES 列表顺序或指定新列表,请清除此列表并指定新的设置。若要清除此列表,请不要在冒号后指定扩展名:

.SUFFIXES :

若要将其他后缀添加到列表的末尾,请指定

.SUFFIXES : suffixlist

其中 suffixlist 是附加后缀的列表,由一或多个空格或制表符分隔。若要查看 .SUFFIXES 的当前设置,请运行选项为 /P 的 NMAKE。

f.预处理指令

可以通过使用预处理指令和表达式控制 NMAKE 会话。预处理指令可以放置在生成文件或 Tools.ini 文件中。使用指令可以有条件地处理生成文件,显示错误信息,包括其他生成文件,取消定义宏以及打开或关闭某些选项。

Makefile示例

看了一堆理论,很累了吧?下面看一段简单的MakeFile

# 宏定义
SOURCES=AssemblyInfo.cs \
Form1.cs \
Form2.cs \
Form3.cs \
HelloWorld.cs
# 引用规则
# 目标:
CLRProfiler.exe : $(SOURCES) #<--依赖项
# 标志
# 下面是命令
csc /t:winexe /out:HelloWorld.exe /r:System.Windows.Forms.dll $(SOURCES)
clean:
del HelloWorld.exe
 

将上述代码保存为Makefile(没有后缀)放在你的项目文件夹下, 然后打开VS2003.NET命令行窗口,进入项目夹所在路径,打入NMake回车, ok

示例2

下面演示一下多个项目时的编译,每个单独的项目创建单独的makefile,解决方案下放一个总的makefile

all:
# 分别对项目进行编译
cd project1
nmake
cd ..
cd project2
nmake
cd ..
cd project3
nmake
cd ..
# 将编译结果汇总到当前路径
copy project1\project1.dll
copy project2\project2.dll
copy project3\project3.exe
clean:
# 清除编译结果
del project1.dll
del project2.dll
del project3.exe
cd project1
nmake clean
cd ..
cd project2
nmake clean
cd ..
cd project3
nmake clean
cd ..
 

小节

本文简单介绍了NMAKE的用法,并对Makefile的语法做了介绍。篇幅所限,既不能面面俱到,又不能深入剖析,只希望能够让更多人了解此工具。笔者也是刚刚接触,经验不多,还请各位网友多多拍砖!

附表(makefile中常用的几个符号)

符合 作用
^ (caret) 用于关闭某些字符所具有的特殊意义,使其只表示字面上的意义。例如:^#abc表示#abc这个字符串,而#abc则用于在makefile中加入注释,#在这里为注释标志,就像C++中的//。另外,在一行的末尾加上^,可以使行尾的回车换行符成为字串的一部分。
# (number sign) 注释标志,NMAKE会忽略所有从#开始到下一个换行符之间的所有文本。这里要注意的是:在command lines中不能存在注释。因为对于command lines,NMAKE是将其整行传递给OS的。通常对于command lines的注释都是放在行与行之间。
\ (backslash) 用于将两行合并为一行。将其放在行尾,NMAKE就会将行尾的回车换行符解释为空格(space)。
% (percent symbol) 表示其后的字符串为一文件名。
( (left parentheses)  
) (right parentheses)  
{  
}  
! (exclamation symbol) 命令修饰符
@ (at sign) 命令修饰符
- (hyphen)  
: (colon) 用于dependent lines和inference rules中,用于分隔target和dependent。
; (semicolon) 如果对于一个dependent line只有一条命令,则可以将该命令放在dependent line的后面,二者之间用“;”分隔。
$ (dolor sign) 用于调用宏

命令行编译工具NMAKE的更多相关文章

  1. iOS系统提供开发环境下命令行编译工具:xcodebuild

    iOS系统提供开发环境下命令行编译工具:xcodebuild[3] xcodebuild 在介绍xcodebuild之前,需要先弄清楚一些在XCode环境下的一些概念[4]: Workspace:简单 ...

  2. Qt之命令行编译(nmake)

    简述 前两节讲解了如何在Visual Studio和Qt Creator中搭建Qt开发环境,并分享了我们第一个小程序-Hello World. 下面分享如何使用命令行来编译Qt程序.当然,MSVC和M ...

  3. ARM 编译工具keil 和 IAR 命令行编译和下载

    目的 不管是Keil还是IAR对代码补全,高亮等编辑功能支持的不是很好,虽然现在的Keil 5.25对界面的支持好了很多,但是很多人还是青睐于第三方的编辑器,命令行的编译方式可以让我们在使用第三方编辑 ...

  4. 一个使用命令行编译Android项目的工具类

    一个使用命令行编译Android项目的工具类 简单介绍 编译apk项目须要使用的几个工具,基本都在sdk中,它们各自是(Windows系统): 1.aapt.exe 资源打包工具 2.android. ...

  5. namke 命令行编译

    简介 大家已经习惯于微软提供的功能强大的IDE,已经很少考虑手动编连项目了,所谓技多不压身,有空的时候还是随我一块了解一下命令行编译. C/C++/VC++程序员或有Unix/Linux编程经验应该很 ...

  6. msvc交叉编译:使用vcvarsall.bat设置命令行编译环境

    一直以来我只知道vc设置命令行编译环境的批处理命令是%VS140COMNTOOLS%/Common7/Tools下的vsvars32.bat,(%VS140COMNTOOLS%为定义vs2015公共工 ...

  7. Windows下使用命令行编译Qt项目(解决DLL丢失问题)

    一.前言 我之前用Qt做了个hello world,结果各种报错,一大堆DLL找不到,今天用命令行编译就通过了 二.准备工作 1.Visual Studio(有nmake就行) 2.Qt 3.把qma ...

  8. 使用命令行编译Qt程序

    code[class*="language-"], pre[class*="language-"] { color: rgba(51, 51, 51, 1); ...

  9. 基于命令行编译打包phonegap for android应用 分类: Android Phonegap 2015-05-10 10:33 73人阅读 评论(0) 收藏

    也许你习惯了使用Eclipse编译和打包Android应用.不过,对于使用html5+js开发的phonegap应用,本文建议你抛弃Eclipse,改为使用命令行模式,绝对的快速和方便. 一直以来,E ...

随机推荐

  1. C#连接SQL Server数据库小贴士

    在较低版本vs中需要添加using system.data.sqlClient; 在新版本vs中需要写成using System.Data.SqlClient; 作者:耑新新,发布于  博客园 转载请 ...

  2. Spark介绍及安装部署

    一.Spark介绍 1.1 Apache Spark Apache Spark是一个围绕速度.易用性和复杂分析构建的大数据处理框架(没有数据存储).最初在2009年由加州大学伯克利分校的AMPLab开 ...

  3. switch case语句

    五.switch case语句 1.格式 Switch(表达式) { case 表达式:语句块 break: … default break: } 2.例题 输入年份.月份.日期,判断是否是闰年,并且 ...

  4. ZooKeeper实践:(2)配置管理

    一. 前言     配置是每个程序不可或缺的一部分,配置有多重方式:xml.ini.property.database等等,从最初的单机环境到现在的分布式环境. 1. 以文件的格式存储配置,修改任何都 ...

  5. 【LOJ】#2067. 「SDOI2016」硬币游戏

    题解 c一样的就是一个独立的游戏 我们对于2和3的指数 sg[i][j] 表示\(c \cdot 2^i \cdot 3^j\)的棋子,只有这个硬币是反面,翻转的硬币是正面的sg值 枚举sg函数所有可 ...

  6. Android应用程序签名打包(AS)

    使用Android studio对Android应用签名步骤: 第一步: 第二步: 第三步: 第四步: 数字证书创建完成后,点击OK----->点击Next------>Finish. 注 ...

  7. [js]面向对象编程

    一.js面向对象基本概念 对象:内部封装.对外预留接口,一种通用的思想,面向对象分析: 1.特点 (1)抽象 (2)封装 (3)继承:多态继承.多重继承 2.对象组成 (1)属性: 任何对象都可以添加 ...

  8. My blog in AI -- 梯度下降算法

    人工神经网络是对生物神经网络的模仿,神经网络对一个问题的学习,需要经历数据输入.网络参数的训练.超参数的调节等部分. 这次我们来详细讨论一下神经网络的学习过程. 假设我们要训练一个神经网络去识别一张图 ...

  9. CSUOJ 2031 Barareh on Fire

    Description The Barareh village is on fire due to the attack of the virtual enemy. Several places ar ...

  10. python pip 不能用报错: ImportError: No module named _internal

    使用python pip安装包的时候报错: Traceback (most recent call last): File "/usr/local/bin/pip", line 7 ...