命令行下玩VC

說明:(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、關於nmakeMakefile

 

與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 

相關文章
相關標籤/搜索