說明:(1)轉載請註明出處:http://www.cnblogs.com/opangle/p/4298155.htmlhtml
(2)如下以VS2013爲例,並假設VC安裝路徑爲%VC_INSTALL_PATH%(本人的安裝目錄爲D:\Program Files (x86)\Microsoft Visual Studio 12.0)。linux
1、環境配置windows
■ 方法一:使用MS提供的Developer Command Prompt快捷方式函數
「開始」 => 「Visual Studio 2013」 => 「Visual Studio Tools」 => 「Developer Command Prompt for VS2013」。工具
■ 方法二:使用MS提供的vcvarsall.bat腳本測試
在命令行窗口中進入%VC_INSTALL_PATH%目錄,執行「vcvarsall.bat」腳本。ui
■ 方法三:手動配置環境變量spa
手動配置環境變量,至少要設置一下三個環境變量:操作系統
※ PATH:默認狀況下cl命令(微軟編譯器)是不可使用的,須要將cl.exe文件所在的路徑(即%VC_INSTALL_PATH%\bin目錄)添加到PATH環境變量中。命令行
※ INCLUDE:默認狀況下cl命令不知道從何處查找系統頭文件的,該環境變量告訴cl命令從何處查找系統頭文件。
※ LIB:與INCLUDE環境變量相似,LIB環境變量用來告訴連接器:從何處查找庫文件、目標文件等。
本人試過的最小配置以下:
環境變量 |
配置說明(多個路徑之間用分號分隔) |
PATH |
將如下路徑加入PATH環境變量中: %VC_INSTALL_PATH%\bin |
INCLUDE |
將如下路徑加入INCLUDE環境變量中: %VC_INSTALL_PATH%\include C:\Program Files (x86)\Windows Kits\8.1\include\shared C:\Program Files (x86)\Windows Kits\8.1\include\um |
LIB |
將如下路徑加入到LIB環境變量中: %VC_INSTALL_PATH%\lib C:\Program Files (x86)\Windows Kits\8.1\lib\winv6.3\um\x86 |
注:最完整的配置方式能夠參考「方法一」、「方法二」中的環境變量配置方式。
■ 測試環境配置
寫一個簡單的「Hello World」程序(假設爲hello.cpp),在命令行下執行:cl hello.cpp,若是能成功生成hello.exe可執行文件,即說明配置成功!
2、經常使用的命令行選項
下表列出了一些經常使用的命令行選項,並同時列出了gcc中相對應的選項,熟悉gcc的朋友能夠不用看「說明」應該也能明白各選項的含義和做用。
MSVC |
gcc |
說明 |
/E |
-E |
輸出預處理結果 |
/Dname /Dname=value |
-Dname -Dname=value |
定義一個宏 |
/Idirecotry |
-Idirecotry |
指定頭文件搜索路徑 |
/c |
-c |
編譯、彙編生成目標文件 |
/libpath:direcotry |
-Ldirecotry |
指定庫文件搜索路徑(MSVC的/libpath屬於連接選項,第一個連接選項以前要指定/link選項,用來告訴編譯器驅動,後續選項傳給連接器使用) |
另外,若是以爲每次編譯都要使用一樣的選項,敲太長的命令實在是一件累人的事,微軟一樣爲你們提供了省事的方式:仍然是設置環境變量。詳細說明以下:
※ CL環境變量:其中能夠指定多個經常使用的選項,cl命令會自動將該環境變量的內容加入編譯命令。
※ LINK環境變量:連接器會自動將該環境變量中的內容加入到連接命令中。
3、靜態庫的建立與使用
■ 建立靜態庫
linux下建立靜態庫(*.a)一般須要藉助ar命令,例如:「ar -r mylib.a foo.o bar.o」。微軟也提供了相似的命令——lib命令,該命令的詳細使用方法可參考其幫助文檔「lib /?」,下面僅給出一個簡單的示例:
cl /c foo.cpp cl /c bar.cpp lib foo.obj bar.obj /out:mylib.lib
注:其中「/out選項」用於指定生成的靜態庫文件名。
■ 使用靜態庫
測試目錄結構以下:
. +-- lib | +-- mylib.lib | +-- mylib.h +-- test +-- test.cpp
測試代碼以下:
// mylib.h extern "C" void foo(); // test.cpp #include <mylib.h> int main() { foo(); return 0; }
在test目錄下編譯test.cpp文件:
cl /I..\lib test.cpp /link /libpath:..\lib mylib.lib
其中/link選項用於告訴cl命令:後續選項爲連接選項,請從..\lib目錄查找mylib.lib庫文件!
除了使用命令行選項告訴連接器應該連接的庫、從何處查找庫,還可使用「#pragma comment」指令。
例1(編譯命令cl /I..\lib test.cpp /link /libpath:..\lib):
#include <mylib.h> #pragma comment(lib, "mylib.lib") // 此處包含庫名信息,所以命令行選項中不需指定庫名 int main() { foo(); return 0; }
例2(編譯命令cl /I..\lib test.cpp):
#include <mylib.h> #pragma comment(lib, "..\\lib\\mylib.lib") // 此處包含庫名及路徑信息,注意轉義符用「\\」 int main() { foo(); return 0; }
4、動態庫的建立與使用
與靜態庫的建立相比,動態庫的建立相對複雜。爲了更容易理解,這裏先介紹一些關於windows動態連接庫(DLL)基本概念,而後再介紹動態庫的建立和使用方法。
■ 基本概念一:動態庫的分類
微軟將動態庫分爲四類:
※ 非MFC動態連接庫(Non-MFC DLL)
※ 靜態連接MFC的正規DLL(Regular DLLs statically linked to MFC)
※ 動態連接MFC的正規DLL(Regular DLLs dynamically linked to MFC)
※ 擴展DLL(Extension DLLs)
其中只有第一種動態庫不須要連接微軟的MFC,後三種都須要連接MFC(無論你是否使用MFC),我的感受微軟這樣作,彷佛有點將本身的產品強加於人的感受,固然,這純屬本人的我的想法,也許有人真的須要MFC吧。這裏須要特別說明的是:下文中所提到的「動態庫」,特指上述第一種動態庫,而再也不贅述成「非MFC動態連接庫(Non-MFC DLL)」了。
■ 基本概念二:符號的導出與導入
符號的導出與導入的分兩個方向:
※ 從動態庫導出符號:生成導出符號表;
※ 嚮應用程序導入符號:告知連接器——我須要的符號來自某個動態庫。
下面首先介紹符號的導出,再介紹符號的導入。
windows下的動態庫文件(.dll)與可執行文件(.exe)在文件的組織結構上最大的區別在於:動態庫文件中包含一個導出符號表。只有存在於該導出符號表中的符號(名字)才能夠被其它程序直接訪問,咱們可使用dumpbin命令來查看一個動態庫的導出符號表,例如:
dumpbin /exports mylib.dll
在動態庫中導出符號有兩種方式:
(1) 建立模塊定義文件(.def)(Exporting a symbol from DLL by ordinal):
優勢:能夠減少導出符號表的大小;
缺點:當導出C++函數時,須要使用名字修飾後的符號名。
(2) 使用__declspec(dllexport)關鍵字(Exporting a symbol from DLL by name)。
優勢:不用考慮名字修飾的問題;
缺點:將符號名存儲在導出符號表中,當導出內容較多時,會致使符號表變得很是龐大。
■ 建立動態庫
示例1:建立模塊定義文件來導出函數
// foo.cpp #include <stdio.h> extern "C" void foo() { printf("foo()\n"); } // bar.cpp #include <stdio.h> extern "C" void bar() { printf("bar()\n"); } // mylib.def LIBRARY mylib EXPORTS foo @1 bar @2
編譯生成動態庫:
cl foo.cpp bar.cpp /link /dll /def:mylib.def /out:mylib.dll
示例2:使用__declspec(dllexport)關鍵字來導出函數
// foo.cpp __declspec(dllexport) void foo() { printf("foo()\n"); } // bar.cpp __declspec(dllexport) void __stdcall bar() { printf("foo()\n"); }
編譯生成動態庫:
cl foo.cpp bar.cpp /link /dll /out:mylib.dll
注:上述兩個示例中,不管使用哪一種方式來導出符號,最終都會生成如下三個文件:
※ mylib.dll:動態連接庫;
※ mylib.lib:導入庫,後面「使用動態庫」一節中「使用加載時動態連接」的示例中會用到。
※ mylib.exp:暫未知。
■ 使用動態庫
示例1:加載時動態連接(Using Load-Time Dynamic Linking)
extern "C" __declspec(dllimport) void foo(); extern "C" void bar(); // __declspec(dllimport)並非必須的 int main() { foo(); bar(); return 0; }
編譯連接上述代碼時須要連接導入庫mylib.lib,例如:
cl test.cpp /link /libpath:..\lib mylib.lib
示例2:運行時動態連接(Using Run-Time Dynamic Linking)
#include <windows.h> typedef void (FunType)(void); int main() { FunType* pfoo, *pbar; HINSTANCE dll = LoadLibrary(TEXT("mylib.dll")); pfoo = (FunType*)GetProcAddress(dll, "foo"); pbar = (FunType*)GetProcAddress(dll, "bar"); pfoo(); pbar(); FreeLibrary(dll); return 0; }
編譯連接上述代碼時須要連接導入庫mylib.lib,例如:
cl test.cpp
注:在運行上述兩個示例中生成的test.exe可執行文件時,都須要拷貝一份mylib.dll到test目錄下,或者將mylib.dll所在的路徑加入PATH環境變量中,不然操做系統不知道從何處查找mylib.dll。
5、關於nmake和Makefile
與GNU make相似,VC安裝目錄下還自帶了nmake工具,Makefile的書寫形式也與linux下相似。下面給出一個簡單的示例(示例文件名爲Makefile):
CXX = cl.exe LD = link.exe default: mylib.dll mylib.dll: foo.obj bar.obj $(LD) foo.obj bar.obj /dll /out:mylib.dll foo.obj: foo.cpp $(CXX) /c foo.cpp bar.obj: bar.cpp $(CXX) /c bar.cpp
執行: nmake,便可編譯生成mylib.dll動態庫文件。關於nmake的更多說明可參考:「nmake /?」。
6、參考文檔
Setting the Path and Environment Variables for Command-Line Builds https://msdn.microsoft.com/en-us/library/f2ccy3wt.aspx CL Environment Variables https://msdn.microsoft.com/en-us/library/kezkeayy.aspx LINK Environment Variables https://msdn.microsoft.com/en-us/library/6y6t9esh.aspx Compiler Options Listed by Category https://msdn.microsoft.com/en-us/library/19z1t1wy.aspx Kinds of DLLs https://msdn.microsoft.com/en-us/library/9se914de.aspxImporting and Exporting https://msdn.microsoft.com/en-us/library/9h658af8.aspxExporting from a DLL https://msdn.microsoft.com/en-us/library/z4zxe9k8.aspx Importing into an Application https://msdn.microsoft.com/en-us/library/kh1zw7z7.aspx Using Load-Time Dynamic Linking https://msdn.microsoft.com/en-us/library/ms686923.aspx Using Run-Time Dynamic Linking https://msdn.microsoft.com/en-us/library/ms686944.aspx NMAKE Reference https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx