windows下makefile命令详解
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
windows下makefile命令详解
1. 如果已经有vc6的dsp⼯程,可直接导出nmake脚本⽂件(.mak)
“Project - Export Makefile...”
nmake -f nMakeTest.mak CFG="nMakeTest - Win32 Debug"
nmake -f nMakeTest.mak CFG="nMakeTest - Win32 Debug" all
nmake -f nMakeTest.mak CFG="nMakeTest - Win32 Release" clean
注:如果未指定/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⼆进制⽂件】
/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⽂件】
/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" // 指定预编译⽂件名
/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 // 启⽤最⼩重新⽣成
编译器在.idb⽂件中存储源⽂件和类定义之间的依赖关系。
使⽤.idb ⽂件的信息来确定是否需要编译某个源⽂件。
⽽不是该源⽂件只要包含了被修改的.h⽂件,就必须重新编译。
/link // 将/link后指定的选项传递给link.exe
// 默认情况下,cl.exe编译完后,会⾃动调⽤link.exe进⾏连接,
// 所以直接⽤cl.exe编译带main函数的.c或.cpp后,会⽣成obj与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等可执⾏⽂件】
/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" // 模块导出⽂件【如果def⽂件名称与dll名称⼀致,则不需要显⽰地指出】(另外⼀种dll动态库导出符号的⽅法)
;nMakeTest.lib 导出DLL函数
;作者:kekec
LIBRARY nMakeTest.def
EXPORTS
Add @ 1
g_isTest @ 2
注:还可以在代码中使⽤__declspec(dllexport)进⾏符号的导出
#ifdef WIN32DLL_EXPORTS
#define WIN32DLL_API __declspec(dllexport)
#else
#define WIN32DLL_API __declspec(dllimport)
#endif
/************** export.c ***************/
#ifdef __cplusplus
extern "C"
{
#endif
WIN32DLL_API int __stdcall Add(int a, int b)
{
return (a + b);
}
WIN32DLL_API int g_isTest = 0;
#ifdef __cplusplus
}
#endif
/pdb:"nMakeTest.pdb" // 重命名⽣成的pdb⽂件(Program Debug Database),保存调试符号等信息
/map:"nMakeTest.map" // 重命名⽣成的map⽂件
/out:"nMakeTest.exe" // 重命名⽣成的exe⽂件
/implib:"test.lib" // ⽣成名为test.lib的导出库
/entry:_DllMainCRTStartup@12 // 指定_DllMainCRTStartup函数dll的起始地址
/incremental:yes // 开启增量链接
incremental开关默认是开启的。
开启增量链接产⽣的exe或dll⽂件的size要⼤⼀些。
因为有代码和数据的填充,增量链接的exe或dll⽂件会包含跳转trunk来处理函数重定位到新地址。
MSDN上明确指出:为确保最终发布版本不包含填充或者trunk,请关闭增量链接。
例:link gdiplus.lib /subsystem:windows /out:test.exe file1.obj file2.lib file3.res // ⽣成名为test.exe的windows可执⾏程序
例:link gdiplus.lib /subsystem:console /out:test.exe *.obj file2.lib file3.res // ⽣成名为test.exe的控制台可执⾏程序
例:link gdiplus.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.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib OpenGL32.Lib
6. nmake指令说明
(1) 符号说明
# // 注释符(命令所在⾏不能使⽤注释符,命令应该与注释都独⽴使⽤⼀⾏进⾏书写;如:erase nMakeTest.obj # 删除nMakeTest.obj ⽂件【⾮法】)
^#abc // 表⽰#abc这个字符串
\ // 连接符,⽤于将两⾏合并为⼀⾏;在宏中,分多⾏写时,⼀定要⽤"\"进⾏连接
% // ⽂件说明符,表⽰其后的字符串为⼀⽂件名
---------------------
若⽂件名为 c:\prog.exe
%s 将为 c:\prog.exe
%:F 将为 c:\prog.exe
%:dF 将为 c
%:pF 将为 c:\
%:fF 将为 prog
%:eF 将为 exe
---------------------
@ // 命令修饰符;防⽌修饰的命令的结果,被打印出来
! // 命令修饰符
$ // 宏引⽤符
: // 依赖符号
?【*】 // 通配符⽀持
++++++++++++++++++++++++++++++++++++
$@ // 表⽰所有⽬标全名(路径+⽂件名称+扩展名)的挨个值
$$@ // 与$@⽤法含义⼀致,但仅在作为依赖项中的依赖项时有效
$< // 表⽰所有依赖⽬标的挨个值,仅在推理规则的命令中有效
$^ // 表⽰所有依赖⽬标的集合,以空格分隔,若有重复,会被去重;
$+ // 与$^含义⼀致,只是不进⾏去重处理。
$? // 表⽰所有⽐⽬标⼼的依赖⽬标的集合,以空格分隔
$* // 当前⽬标的路径和⽂件名称,没有⽂件扩展名
$** // 当前⽬标的所有依赖项
----------------------------
修饰符说明
D 驱动器和⽬录
B ⽂件名称
F ⽂件名称和扩展名
R 驱动器、⽬录和⽂件名称
----------------------------
(2) 长⽂件名⽤双引号引起来
例:ALL : nMakeTest.dll // ⽂件名较短时,可不需要引号
例:ALL : "$(OUTDIR)\nMakeTest.exe" // ⽂件名较长时,特别是路径中有空格的情况,⼀定要⽤引号
(3) 预定义规则
.c.obj // 默认操作:cl /c $*.c
也可对默认操作显⽰地重写:
.c.obj:
cl /c /Ox /DWIN32 $<
(4) 包含⽂件
!INCLUDE nmake.opt
include makefile.mak
(5) 条件判断 - 01
!IF "$(CFG)" == ""
CFG=nMakeTest - Win32 Debug
!MESSAGE No configuration specified. Defaulting to nMakeTest - Win32 Debug.
!ELSE
!MESSAGE Be specified.
!ENDIF
(6) 条件判断 - 02 【!IFNDEF !IFDEF】
!IFNDEF PRIVATE_RUNTIMEMODE_DEBUG
RUNTIMEMODE_DEBUG = /MDd
!ELSE
RUNTIMEMODE_DEBUG = $(PRIVATE_RUNTIMEMODE_DEBUG)
!ENDIF
(7) 输出消息⽇志
!MESSAGE Invalid configuration "$(CFG)" specified.
(8) 描述块 - makefile的核⼼【注:在依赖项(或规则)和命令块之间不能出现空⾏,commands之前为⼀个tab字符,多条command之间⽤;分割】
只要dependences中任意⼀个⽂件⽐targets新,就执⾏commands命令
targets... : dependences...
commands...
(9) ALL / CLEAN
OUTDIR=.\Release
INTDIR=.\Release
ALL : "$(OUTDIR)\nMakeTest.exe"
CLEAN :
-@erase "$(INTDIR)\nMakeTest.obj"
-@erase "$(INTDIR)\nMakeTest.pch"
-@erase "$(INTDIR)\nMakeTest.res"
-@erase "$(INTDIR)\nMakeTestDlg.obj"
-@erase "$(INTDIR)\StdAfx.obj"
-@erase "$(INTDIR)\vc60.idb"
-@erase "$(OUTDIR)\nMakeTest.exe"
-@erase "$(OUTDIR)\nMakeTest.map"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
(10) 编译
CPP=cl.exe
CPP_PROJ=/nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS"
/Fp"$(INTDIR)\nMakeTest.pch" /Yu"stdafx.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
.c{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cpp{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cxx{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
(11) 链接
LINK32=link.exe
LINK32_FLAGS=/nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)\nMakeTest.pdb"
/map:"$(INTDIR)\nMakeTest.map" /machine:I386 /out:"$(OUTDIR)\nMakeTest.exe"
LINK32_OBJS= \
"$(INTDIR)\nMakeTest.obj" \
"$(INTDIR)\nMakeTestDlg.obj" \
"$(INTDIR)\StdAfx.obj" \
"$(INTDIR)\nMakeTest.res"
"$(OUTDIR)\nMakeTest.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
(12) ⽂件依赖
SOURCE=.\nMakeTest.cpp
"$(INTDIR)\nMakeTest.obj" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\nMakeTest.pch"
SOURCE=.\nMakeTest.rc
"$(INTDIR)\nMakeTest.res" : $(SOURCE) "$(INTDIR)"
$(RSC) $(RSC_PROJ) $(SOURCE)
(13) 预编译⽂件
SOURCE=.\StdAfx.cpp
!IF "$(CFG)" == "nMakeTest - Win32 Release"
CPP_SWITCHES=/nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS"
/Fp"$(INTDIR)\nMakeTest.pch" /Yc"stdafx.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
"$(INTDIR)\StdAfx.obj" "$(INTDIR)\nMakeTest.pch" : $(SOURCE) "$(INTDIR)"
$(CPP) @<<
$(CPP_SWITCHES) $(SOURCE)
<<
!ELSEIF "$(CFG)" == "nMakeTest - Win32 Debug"
CPP_SWITCHES=/nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS"
/Fp"$(INTDIR)\nMakeTest.pch" /Yc"stdafx.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c "$(INTDIR)\StdAfx.obj" "$(INTDIR)\nMakeTest.pch" : $(SOURCE) "$(INTDIR)"
$(CPP) @<<
$(CPP_SWITCHES) $(SOURCE)
<<
!ENDIF。