VS 环境下使用MAKEFILE的工具为NMAKE
注:通常在VS安装目录/VC/BIN 里面,如果在控制台输入此命令无效,可以此路径添加到环境变量PATH里
NMAKE 使用MAKEFILE的语法为
Nmake /f makefile /x stderrfile [macrodefs][targets]
注:makefile 为makefile文件,/xstderrfile为可选参数,即把namke错误存储到文件stderrfile
MAKEFILE 语法
宏
MAKEFILE 的宏与C语言的宏类似
macro name= macro value
例如 OUTDIR= .\Debug
预处理指令
Makefile的预处理指令和C语言的预处理指令类似
常用指令
!ERRORstring —— 显示错误“string”, 然后停止执行,错误代码为U1050
!MESSAGEstring —— 显示字符串,这个一般用于信息显示C语言的#pragmamessage
!INCLUDE[<]filename[>] —— 包含makefile
!IFconst —— 如果成立(非零),则处理!F和下一个!ELSE或!ENDIF之间的语句
还有诸如!IFDEF macroname
!IFNDEF macroname、!ELSE、!ELSEIF、!ELSEIFDEF、!ELSEIFNDEF、!ENDIF和C
语言的#if之类的指令的意义是一致的,这里就不一一详述了
描述块结构
目标:依赖项
命令
目标就是用户最终希望得到的结果,也就是nmake需要生成的结果。目标可以是一个文件、目录,也可以什么都不是。如果目标不存在或者目标的时间戳(文件的最后修改时间)比依赖项早,或者目标类型不是文件,nmake将运行描述块中的“命令”
依赖项是指在生成目标所需要使用到的对象。一个目标可以有一个或多个依赖项,也可以没有依赖项。多个依赖项以空格分隔。如果指定的依赖项不存在,则在其他描述块的目标中寻找,但首先需要生成这个目标
命令是nmake在生成目标时所调用的命令
在使用namke进行程序构建时,nmake采用了时间戳判断机制。在生成一个目标时,会判断目标文件是否存在或目标的最后修改时间是否晚于所有依赖项的最后修改时间。如果所有依赖项的最后修改时间都比目标的最后修改时间晚,则说明当前的目标文件是使用现有的依赖项生成,是最新的,没有必要再进行生成
MAKEFILE 文件结构:
#宏定义
….
#描述块
makefile的一个基本原则:以终为始,这个似乎和我们平时进行的过程式编程的原则相悖。所谓以终为始,就是你通过makefile文件首先告诉编译器这个工程是想生成一个exe还是一个dll还是一个静态库。然后告诉编译器要生成这个exe之类需要生成哪些obj文件rc.exe, cl.exe, link.exe 的常见选项
rc.exe (将.rc资源文本转变成.res二进制文件)
常见选项
/l 0x804 // 默认语言ID(十六进制数表示) 0x804:简体中文 0x409:美国
/fo"nMakeTest.res" //指定rc文件输出的res名称
例:rc.exe /l 0x804/fo"nMakeTest.res" /d "_DEBUG" /d "_AFXDLL" “nMakeTest.rc
cl.exe 常见选项 将.c,.cpp,.cxx编译成obj文件
/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警告)
/Od // 优化选项:带入Debug信息
/O2 // 优化选项:最快速度
/O1 // 优化选项:最小尺寸
/W3// 设置3级警告级别
/WX // 将Warining视为error
/Fp"nMakeTest.pch" // 指定预
/Fp"nMakeTest.pch" // 指定预编译文件名
/Yu"stdafx.h" // 在生成期间使用预编译头文件
/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)",以免出现编译器警告
/LD // 创建动态链接库
LDd // 创建调试动态链接库
/ML // 使用 libc.lib 创建单线程可执行文件
/MLd // 使用libcd.lib 创建调试单线程可执行文件
/MT // 使用libcmt.lib 创建多线程可执行文件
/MTd // 使用libcmtd.lib 创建调试多线程可执行文件
/MD // 使用msvcrt.lib/msvcrt.dll 创建多线程可执行文件
/MDd // 使用 msvcrtd.lib/msvcrtd.dll创建调试多线程可执行文件
/Z7 //生成与 C7.0兼容的调试信息
/Zd //生成行号
/Zi //生成完整的调试信息
/Gm // 启用最小重新生成
例:cl /ctest1.cpp test2.cpp // 编译test1.cpp,test2.cpp
例:cl*.cpp /MD /c /I"G:\Visual C++\VC98\PlatformSDK\Include"
Link.exe 将obj、lib、res链接成dll或exe等可执行文件 常见选项
/dll// 输出dll文件
-lib // 生成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" // 模块导出文件【如果def文件名称与dll名称一致,则不需要显示地指出】(另外一种dll动态库导出符号的方法)
/pdb:"nMakeTest.pdb" // 重命名生成的pdb文件(ProgramDebug Database),保存调试符号等信息
/map:"nMakeTest.map" // 重命名生成的map文件
/out:"nMakeTest.exe" // 重命名生成的exe文件
/implib:"test.lib"// 生成名为test.lib的导出库
/entry:_DllMainCRTStartup@12 // 指定_DllMainCRTStartup函数dll的起始地址
/incremental:yes // 开启增量链接
例:linkgdiplus.lib /subsystem:windows /out:test.exe file1.obj file2.lib file3.res //生成名为test.exe的windows可执行程序
例:linkgdiplus.lib /subsystem:console /out:test.exe *.obj file2.lib file3.res //生成名为test.exe的控制台可执行程序
例:linkgdiplus.lib /subsytem:windows /dll /out:test.dll/implib:test.lib /def:test.def *.obj file2.lib file3.res // 生成名为test.dll动态库
例:link*.obj rc.res /LIBPATH:"G:\Visual C++\lib" /SUBSYSTEM:WINDOWS/MACHINE:X86 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.libadvapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.libodbccp32.lib OpenGL32.Lib
例子
#设置编译标记, 初始化为FALSE
CFGSET = FALSE
#定义debug版本的预处理器
CCDEBUG = -DWIN32 -D_DEBUG -D_CONSOLE -D_MT -MTd
#定义release版本的预处理器
CCNODBG = -DWIN32 -D_NDEBUG -D_CONSOLE
!IFDEF debug
CC = $(CCDEBUG)
OUTDIR = .\Debug
CFGSET = TRUE
!ELSE IFDEF release
CC = $(CCNODBG)
OUTDIR = .\Release
CFGSET = TRUE
!ENDIF
# 提示用法
#
!IF "$(CFGSET)"== "FALSE"
!MESSAGE Usage: nmake /f Makefile.vc [] []
!MESSAGE
!MESSAGE where is one of:
!MESSAGE - release=1 - build release version
!MESSAGE - debug=1 - build debug version
!MESSAGE
!MESSAGE may be:
!MESSAGE - clean - clear output file
!MESSAGE
!MESSAGE
!ERROR please choose a valid configuration instead"
!ENDIF
#这里增加了一个输出:$(OUTDIR)
all: $(OUTDIR) $(OUTDIR)\main.exe
#假如不存在$(OUTDIR)文件夹,就创建它
$(OUTDIR) :
if not exist "$(OUTDIR)" mkdir $(OUTDIR)
clean:
if exist $(OUTDIR) del $(OUTDIR)\*.ilk
if exist $(OUTDIR) del $(OUTDIR)\*.obj
if exist $(OUTDIR) del $(OUTDIR)\*.exe
# compile
$(OUTDIR)\main.obj: main.cpp
# cl -c $(CC) -DCRTAPI1=_cdecl -DCRTAPI2=_cdecl -nologo -GS -D_X86=1 /Gz /Fo"$(OUTDIR)\\" /Fd"$(OUTDIR)\\" main.cpp
cl -c $(CC) /Fo"$(OUTDIR)\\" /Fd"$(OUTDIR)\\" main.cpp
# link
$(OUTDIR)\main.exe: $(OUTDIR)\main.obj
link /machine:x86 /INCREMENTAL:YES /NOLOGO /subsystem:console /out:$(OUTDIR)\main.exe $(OUTDIR)\main.obj kernel32.lib
引用:
http://blog.csdn.net/xiexievv/article/details/45775005