1. 如果已经有vc6的dsp工程,可直接导出nmake脚本文件(.mak) “Project - Export Makefile...”
注:如果未指定/F选项,则使用当前目录下的名为makefile的文件 【nmake /?】 获取更多帮助! vc6:【D:\program files\Microsoft Visual Studio\VC98\Bin】 vs2008:【D:\program files\Microsoft Visual Studio 9.0\VC\bin】 为了能正确地使用命令行工具及vc6或vs2008下的函数库,需要对一些环境变量进行设置,最快捷地方式是通过如下方式打开命令行窗口(以vs2008为例): 2. vs的c++工程没有提供导出nmake脚本文件的功能,我们只有借助工具或手动编写nmake脚本文件了 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3. rc.exe 【将.rc资源文本转变成.res二进制文件】 所在路径:C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\rc.exe /l 0x804 // 默认语言ID(十六进制数表示) 0x804:简体中文 0x409:美国 更多... /fo"nMakeTest.res" // 指定rc文件输出的res名称 例:rc.exe /l 0x804 /fo"nMakeTest.res" /d "_DEBUG" /d "_AFXDLL" “nMakeTest.rc” 4. cl.exe 常见选项 【将.c,.cpp,.cxx编译成obj文件】 更多... vs2008版本所在路径:D:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\cl.exe 命令行长度说明: windows上整个命令行的长度不能超过260个字符,然而编译命令行往往会超过这个限制,微软提供的解决方案是:将命令行参数写入一个response文件,然后将其传入编译器。 不过要注意的是:response文件仍然有32KB的限制。 如:"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\cl.exe" @"C:\UE4_15_0_Release\Build\Win64\PhysXVehicles.generated.cpp.obj.response" /nologo // 不打印版权申明信息 /I "../include" // 添加头文件查找路径(如果路径中带有空格,一定要用引号括起来) /DWIN32 // 预编译宏定义(win32程序) /D_CONSOLE // 预编译宏定义(控制台程序) /D "_DEBUG" // 预编译宏定义(Debug版本) /D_CRT_SECURE_NO_DEPRECATE // 预编译宏定义(关闭C4996警告。使用strcpy、strcat等不安全函数时会报C4996警告) /D_CRT_NONSTDC_NO_DEPRECATE // 预编译宏定义(关闭C4996警告。使用strcpy、strcat等不安全函数时会报C4996警告) /DLIB_VER=0x2000 // 预编译自定义宏LIB_VER为0x2000 等价于#define LIB_VER 0x2000 /Od // 优化选项:带入Debug信息 /O2 // 优化选项:最快速度 /O1 // 优化选项:最小尺寸 /Oy // 启用帧指针省略【Frame pointer omission (FPO)】优化 // FPO是一种二进制程序代码优化方法,它压缩或者省略了在栈上为该函数创建框架指针的过程。这个选项加速了函数调用,因为不需要建立和移除框架指针(ESP,EBP)了。 // 同时,它还解放出了EBP寄存器,用来存储使用频率较高的变量。只在Intel CPU的架构上才有这种优化。 // 在Vista之前的os中,开启编译优化就会默认进行FPO优化,在Vista以后默认就没有FPO优化了,它所带来的优化效果比起它所带来的函数调用堆栈回溯的问题可以忽略。 /W3 // 设置3级警告级别 /WX // 将Warining视为error /wd4326 // 隐藏编译器警告C4326 /we4457 // 将编译器警告C4457视为错误 /Fp"nMakeTest.pch" // 指定预编译文件名 /Yu"stdafx.h" // 在生成期间使用预编译头文件 预编译头文件技术,就是把一个工程(Project)中常用的一些头文件(如标准头文件Windows.h、Afxwin.h等, 有2点需要注意: /FI "myheader.h" // 在每个源文件的第一行上的#include该文件 /Fd"vcpdb/testpdb" // 会将vc辅助编译的idb及pdb文件(见下面的/Gm选项)输入到vcpdb目录中, 并重命名为testpdb.idb与testpdb.pdb(这里的pdb为project database文件,用于存工程的数据库信息) /Fo"objFiles" // 将obj文件输出到objFiles目录中 /c // 编译但不链接 /feMyTest // 编译后,输出MyTest.exe可执行文件
/EHsc // 启用"C++异常(Exceptions)"的stack unwind,编译器会插入一些代码保证发生异常后所有try块中的对象都能调用析构函数来做清理工作 /EHa // 该参数能让C++ try catch,不但能捕捉标准的C++的异常,还能用catch(...)捕获SEH的异常 如:整数除0,access violation (AV)等
注:将"Enable C++ Exceptions"设置为No,并不是在代码中不能使用c++异常。 c++异常抛出能够正确地被catch捕获,只是没有了stack unwind,try块中对象不会调用析构函数,可能会引发泄漏
/LD // 创建动态链接库 /ML // 使用 libc.lib 创建单线程可执行文件 /Z7 //生成与 C7.0兼容的调试信息 /Za // 禁用语言扩展(不支持ANSI C89 及 C++11) --使用该参数时,编译器会自动定义__STDC__宏 /Ze // 启用语言扩展(默认) /Zl // ZL 非ZI; 告诉编译器从.obj文件中移除默认C库链接指令(注:该链接指令会被传给连接器 形如:/DEFAULTLIB:'LIBCMT') /Gm // 启用最小重新生成 编译器在.idb文件中存储源文件和类定义之间的依赖关系。 /GR // 启用运行时类型识别信息(RTTI,Run-Time Type Information) 编译器会在exe或dll文件中增加一个.rdata的段来存放变量的类型信息 例:int a; bool b = (typeid(a)==typeid(int)); // b为true /GR- // 关闭运行时类型识别信息,exe或dll会更小 /Zp8 // 结构体、类等复合类型的数据成员以8字节进行内存对齐 /bigobj // 提高obj文件中Section数的上限 65,536 (2 ^16) --> 4294967296(2 ^32) 注:vs2005及以上的编译器才支持 /RTCs // 启用栈帧运行时错误检查。主要体现在:1. 当使用的变量尚未初始化时进行报告 2.检测局部变量(如数组)的溢出和不足 3. 检测ESP损坏,如检测调用约定不匹配可能导致ESP损坏 /Ob2 // 启用函数内联
/link // 将/link后指定的选项传递给link.exe // 默认情况下,cl.exe编译完后,会自动调用link.exe进行连接, 例:cl /c test1.cpp test2.cpp // 编译test1.cpp,test2.cpp 例:cl *.cpp /MD /c /I"G:\Visual C++\VC98\PlatformSDK\Include" 5. link.exe常见选项 【将obj、lib、res链接成dll或exe等可执行文件】 vs2008版本所在路径:D:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\link.exe /dll // 输出dll文件 -lib // 生成lib静态库文件 例:link -lib *.obj /out:test.lib /libpath:"..\PublicSDK\lib" // 指定外部lib查找路径(路径中不能带有空格,否则链接时会报LNK1181的错误) /subsystem:windows[console] // 指定子系统 /machine 指定目标平台{AM33|ARM|EBC|IA64|M32R|MIPS|SH3|SH3DSP|SH4|SH5|THUMB|X86|X64},等 /NODEFAULTLIB:libcd.lib // 链接时,忽略libcd.lib库 /debug // 生成调试信息 /export:myAdd=_Add,@1 // 导出extern "C" Add函数,并将符号名修改为myAdd,同时将导出序号设为1(一种dll动态库导出符号的方法) /export:_g_isTest,@2 // 导出extern "C" g_isTest变量,并将导出序号设为2(一种dll动态库导出符号的方法) /def:"nMakeTest.def" // 模块导出文件(另外一种dll动态库导出符号的方法) 注1:def文件名不要求与dll文件名或工程名一致 ;nMakeTest.lib 导出DLL函数 注:还可以在代码中使用__declspec(dllexport)进行符号的导出 #ifdef WIN32DLL_EXPORTS /************** export.c ***************/ WIN32DLL_API int g_isTest = 0; /pdb:"nMakeTest.pdb" // 重命名生成的pdb文件(Program Debug Database),保存调试符号等信息 /map:"nMakeTest.map" // 重命名生成的map文件 /out:"nMakeTest.exe" // 重命名生成的exe文件 /implib:"test.lib" // 生成名为test.lib的导出库 /stack:0x300000 // 设置线程栈Reserve内存大小为3MB windows缺省是1MB -- 格式:/STACK:reserve[,commit] /stack:0x500000,0x200000 // 设置线程栈Reserve内存大小为5MB,Commit内存大小为2MB windows缺省是1MB -- 格式:/STACK:reserve[,commit] /entry:_DllMainCRTStartup@12 // 指定_DllMainCRTStartup函数dll的起始地址 /release // 生成checksum /incremental:yes // 开启增量链接 incremental开关默认是开启的。 例:link gdiplus.lib /subsystem:windows /out:test.exe file1.obj file2.lib file3.res // 生成名为test.exe的windows可执行程序 例:link *.obj rc.res /LIBPATH:"G:\Visual C++\lib" /SUBSYSTEM:WINDOWS /MACHINE:X86 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib OpenGL32.Lib 例:"D:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin/link.exe" /MANIFEST:NO /NOLOGO /DEBUG /errorReport:prompt /MACHINE:x86 /SUBSYSTEM:WINDOWS /FIXED:No /LARGEADDRESSAWARE /NXCOMPAT /STACK:5000000,5000000 /SAFESEH /DEF:UnrealEngine3.def /DELAY:UNLOAD /RELEASE /OPT:REF /OPT:ICF /INCREMENTAL:NO /DELAYLOAD:"dxgi.dll" /DELAYLOAD:"d3d10.dll" /LIBPATH:"../External/zlib/Lib" /LIBPATH:"D:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\/Lib/x86" /NODEFAULTLIB:"MSVCRTD" /NODEFAULTLIB:"MSVCPRTD" /NODEFAULTLIB:"LIBC" /NODEFAULTLIB:"LIBCMT" /NODEFAULTLIB:"LIBCPMT" /NODEFAULTLIB:"LIBCP" /NODEFAULTLIB:"LIBCD" /NODEFAULTLIB:"LIBCMTD" /NODEFAULTLIB:"LIBCPMTD" /NODEFAULTLIB:"LIBCPD" @"g:\svn\MyGame\Binaries\Win32\MyGameRelease.exe.response" /OUT:"g:\svn\MyGame\Binaries\Win32\MyGameRelease.exe" /IMPLIB:"g:\svn\MyGame\Binaries\Win32\MyGameRelease.lib" /PDB:"g:\svn\MyGame\Binaries\Win32\MyGameRelease.pdb" /CLRTHREADATTRIBUTE:STA /FILEALIGN:0x1000 6. nmake指令说明 (1) 符号说明 # // 注释符(命令所在行不能使用注释符,命令应该与注释都独立使用一行进行书写;如:erase nMakeTest.obj # 删除nMakeTest.obj文件【非法】) ^#abc // 表示#abc这个字符串 \ // 连接符,用于将两行合并为一行;在宏中,分多行写时,一定要用"\"进行连接 % // 文件说明符,表示其后的字符串为一文件名 --------------------- 若文件名为 c:\prog.exe --------------------- @ // 命令修饰符;防止修饰的命令的结果,被打印出来 ! // 命令修饰符 $ // 宏引用符 : // 依赖符号 ?【*】 // 通配符支持 ++++++++++++++++++++++++++++++++++++ $@ // 表示所有目标全名(路径+文件名称+扩展名)的挨个值 $$@ // 与$@用法含义一致,但仅在作为依赖项中的依赖项时有效 $< // 表示所有依赖目标的挨个值,仅在推理规则的命令中有效 $^ // 表示所有依赖目标的集合,以空格分隔,若有重复,会被去重; $+ // 与$^含义一致,只是不进行去重处理。 $* // 当前目标的路径和文件名称,没有文件扩展名 ---------------------------- 修饰符 说明 ---------------------------- (2) 长文件名用双引号引起来 例:ALL : nMakeTest.dll // 文件名较短时,可不需要引号 (3) 预定义规则 .c.obj // 默认操作:cl /c $*.c 也可对默认操作显示地重写:
.c.obj:
(4) 包含文件
(5) 条件判断 - 01
(6) 条件判断 - 02 【!IFNDEF !IFDEF】
(7) 输出消息日志
(8) 描述块 - makefile的核心 【注:在依赖项(或规则)和命令块之间不能出现空行,commands之前为一个tab字符,多条command之间用;分割】 只要dependences中任意一个文件比targets新,就执行commands命令
(9) ALL / CLEAN
(10) 编译
(11) 链接
(12) 文件依赖
(13) 预编译文件
# 参考 1. http://msdn.microsoft.com/zh-cn/library/dd9y37ha(v=vs.80).aspx 5. http://blog./2008/09/replacement_of_ide_1.html |
|