帶你玩轉Visual Studio——帶你發布自己的工程庫

來源:互聯網
上載者:User

標籤:vs2010   c++   靜態庫   動態庫   

上一篇文章帶你玩轉Visual Studio——帶你高效管理代碼通過對VisualSVN優秀外掛程式的講解,讓我們掌握了在整合式開發環境VS中快捷高效地管理代碼的技能。然而我們開發的程式並不總是直接地產生可執行檔軟體,我們可能只是開發某個大型系統的一個組件,也可能是開發某個軟體的核心SDK提供給上層的應用程式調用,在開發的過程中我們也可能會用到第三方的開源庫。那如果將自己的程式編譯成程式庫給調用方用呢?又如何在自己的程式中引用第三方庫呢?這將是這篇文章要講的內容——發布自己的工程庫。

什麼是程式庫?

庫是寫好的現有的,成熟的,可以複用的代碼。現實中每個程式都要依賴很多基礎的底層庫,不可能每個人的代碼都從零開始,因此庫的存在意義非同尋常。比如你經常使用的STL(Standard Template Library)也是庫,有了STL你才能方便地使用std::string、std::cout這些類。

本質上來說庫是一種可執行代碼的二進位形式,可以被作業系統載入記憶體,被別的程式調用執行。C++的庫有兩種:靜態庫和動態庫。將一個程式編譯成可執行檔一般經過 先行編譯–>編譯–>連結 這幾個過程,而靜態庫與動態庫的區別主要體現在連結這個過程。

靜態庫:

在連結階段,會將編譯的目標檔案.obj 與引用到的庫.lib 一起連結打包到可執行檔exe(也稱為目標代碼)中,程式運行時將不再需要該靜態庫。

因此最終連結成的可執行檔(.exe)體積較大。在Windows中一般以.lib為尾碼名,在Linux中一般以.a為尾碼名。

動態庫:

在連結階段,動態庫.dll並沒有真正被串連到目標代碼中,只是將這個動態庫的聲明連結到目標代碼中(這樣程式運行時才知道怎樣使用這個動態庫),動態庫.dll依然是獨立存在的,只有在程式運行是才會將.dll載入到記憶體中被程式調用。因此程式運行時必須要有這個動態庫且放在正確的路徑中。

因此最終連結成的可執行檔(.exe)體積較小。在Windows中一般以.dll為尾碼名,在Linux中一般以.so為尾碼名。

靜態庫與動態庫的區別:
特點 靜態庫 動態庫
對函數庫的連結時機 在編譯的連結階段完成的 延遲到程式啟動並執行時期
運行過程與庫的關係 程式在運行時與靜態庫再無瓜葛 程式在運行時與動態庫庫需要一直存在且路徑正確
是否連結到可執行檔 靜態庫被連結合成一個可執行檔 動態庫不會被連結到可執行檔中
目標檔案大小 體積較大 體積較小
記憶體佔用度 佔用記憶體。如果多個程式使用了同一個靜態庫,每一個程式者會包含這個靜態庫 節約記憶體。如果多個程式使用了同一個動態庫,可以實現進程之間的資源共用(因此動態庫也稱為共用庫)
程式移植 移植方便 移植不太方便,需要所有動態庫的標頭檔
程式升級 程式升級麻煩,需要下載整個程式進行升級 程式升級更簡單,只需要升級某個DLL或某個程式,下載一個升級包即可
編譯自己的工程庫

假設我們有這樣一個工程,這個工程的作用就是提供一些常用的工具類和方法,然後我們要將這個工程編譯成庫提供給別人使用。

編譯靜態庫

假設我們已經建好工程並寫好了相應的代碼:

工程目錄

Utils.h:

//===============================================================//Summary://          Utils 類, 工具類//FileName://          Utils.h//Remarks://          ...//Date://          2015/10/4//Author://          Administrator([email protected])//===============================================================#ifndef __UTILS_H__#define __UTILS_H__#include <string>#include <strstream>//#include <cstdlib>class Utils{public:    Utils(void);    ~Utils(void);public:    //---------------------------------------------------------------    //function:     //          WString2String wstring 到 string 的轉換    //Access:    //           public      //Parameter:    //          [in] const std::wstring & ws - wstring字串    //Returns:    //          std::string - string字串    //Remarks:    //          些方法跨平台,可移植版本    //author:   luoweifu    //---------------------------------------------------------------    static std::string WString2String(const std::wstring& ws);    //---------------------------------------------------------------    //function:     //          String2WString string 到 wstring 的轉換    //Access:    //           public      //Parameter:    //          [in] const std::string & s - string 字串    //Returns:    //          std::wstring - wstring字串    //Remarks:    //          些方法跨平台,可移植版本    //author:    luoweifu    //---------------------------------------------------------------    static std::wstring String2WString(const std::string& s);};//---------------------------------------------------------------//function: //          ConvertToString 將int轉換成string//Parameter://          [in] int val - 要轉換的變數//Returns://          std::string - 轉換後的字串//Remarks://          ...//author:   luoweifu//---------------------------------------------------------------std::string ConvertToString(int val);#endif  //__UTILS_H__

上述聲明的實現參考後面的附錄Utils.cpp。 這裡的注釋是通過VAssistX產生的,關於VAssistX的用法可參考前面寫的一篇文章帶你玩轉Visual Studio——帶你高效開發。

要編譯成靜態庫,我們可以這樣設定我們的工程:
右鍵工程->Properties


編譯成靜態庫

然後右鍵Build就可以了,你可以在解決方案下的Debug(實際的情況中一般要編譯成Release版本,設定的方法一樣,這裡的內容後一章中再講)目錄下就能看到Utils.lib,這就是編譯出的庫。要將這個庫給別人使用,只要提供這個Utils.lib和這個工程的標頭檔就可以。將Utils.h拷貝到D:\ReleaseLibs\StaticLib\Includes,將Utils.lib拷貝到D:\ReleaseLibs\StaticLib\Libs,把D:\ReleaseLibs\StaticLib這個檔案提供出去就可以了。靜態庫的使用請看後一小節使用靜態庫

編譯動態庫

與靜態庫相比,編譯動態庫要麻煩一些,一般要在匯出函數的聲明處加上_declspec(dllexport)關鍵字首碼。
1. *Utils.h的聲明如下

//===============================================================//Summary://          Utils 類, 工具類//FileName://          Utils.h//Remarks://          ...//Date://          2015/10/4//Author://          Administrator([email protected])//===============================================================#ifndef __UTILS_H__#define __UTILS_H__#include <string>#include <strstream>//#include <cstdlib>//===============================================================//===============================================================class Utils{public:    Utils(void);    ~Utils(void);public:    //---------------------------------------------------------------    //function:     //          Max 獲得兩個數中的最大值    //Access:    //           public      //Parameter:    //          [in] int nValue1 - 第一個數    //          [in] int nValue2 - 每二個數    //Returns:    //          int - 最大值    //Remarks:    //          ...    //author:   luoweifu    //---------------------------------------------------------------    static int Max(int nValue1, int nValue2);    //---------------------------------------------------------------    //function:     //          Min 獲得兩個數中的最小值    //Access:    //           public      //Parameter:    //          [in] int nValue1 - 第一個值    //          [in] int nValue2 - 第二個值    //Returns:    //          int - 最小值    //Remarks:    //          ...    //author:   luoweifu    //---------------------------------------------------------------    static int Min(int nValue1, int nValue2);    //---------------------------------------------------------------    //function:     //          Range 將一值限定在一個範圍內    //Access:    //           public      //Parameter:    //          [in] int nMin - 最小值    //          [in] int nMax - 最大值    //Returns:    //          int - 返回在限制在該範圍內的一個值    //Remarks:    //          ...    //author:   luoweifu    //---------------------------------------------------------------    static int Range(int nMin, int nMax, int nValue);};//---------------------------------------------------------------//function: //          ConvertToInt 將一個常量字串轉換成int類型資料//Access://           public  //Parameter://          [in] const char * pStr - 常量字串//Returns://          int - 轉換成的int值//Remarks://          ...//author:   luoweifu//---------------------------------------------------------------int ConvertToInt(const char* pStr);#endif  //__UTILS_H__
  1. 要編譯成動態庫,我們可以這樣設定我們的工程:
    右鍵工程->Properties

    設定編譯的目標類型

    設定先行編譯宏

然後右鍵Build就可以了,你可以在解決方案下的Debug(實際的情況中一般要編譯成Release版本,設定的方法一樣,這裡的內容後一章中再講)目錄下就能看到Utils.dll和Utils.lib,這就是編譯出的庫。要將這個庫給別人使用,只要提供這個Utils.dll、Utils.lib和這個工程的標頭檔就可以。將Utils.h拷貝到D:\ReleaseLibs\DynamicLib\Includes,將Utils.dll和Utils.lib拷貝到D:\ReleaseLibs\DynamicLib\Libs,把D:\ReleaseLibs\DynamicLib這個檔案提供出去就可以了。靜態庫的使用請看後一小節使用動態庫

也許你要問為什麼編譯出的靜態庫是Utils.lib,編譯出的動態庫也有Utils.lib,這兩個.lib檔案是一樣的嗎?
你比較一下兩個.lib檔案的大小就會發現相差很大(靜態庫的lib有235KB,動態庫的lib只有2.7KB),所以肯定不是一樣的啦!動態庫對應的lib檔案叫“匯入庫”,匯入庫只包含了地址符號表等,確保調用方的程式能找到對應函數的一些基本地址資訊,而實際的執行代碼位於DLL檔案中。靜態庫的lib檔案本身就包含了實際執行代碼、符號表等。

使用匯入(第三方)庫

在實際的開發中經常要用第三方提供的庫,如開源庫,或大型系統中合作方提供的組件。如果使用呢?我們就以上面自己製作的庫為例進行講解。假設我們有一個工程TestProject要使用上面自己製作的Utils庫。

使用靜態庫
  1. 右鍵工程->Properties,進行如下的設定。


    設定標頭檔所在的路徑

    設定lib庫所在的路徑

    設定要匯入哪個lib庫

  2. 測試代碼如下:

#include <iostream>#include <tchar.h>#include "Utils.h"int _tmain(int argc, _TCHAR* argv[]){    int nMax = Utils::Max(25, 37);    std::cout << nMax << std::endl;    int nMin = Utils::Min(10, 44);    std::cout << nMin << std::endl;    int nValue = Utils::Range(0, 100, 115);    std::cout << nValue << std::endl;    char* pStr = "1234";    int nValue2 = ConvertToInt(pStr);    std::cout << nValue2 << std::endl;    return 0;}
使用動態庫
  1. 右鍵TestProject工程->Properties,進行如下的設定。


    設定標頭檔所在的路徑

    設定lib庫所在的路徑

    設定要匯入哪個匯入庫

  2. 將Utils.dll放入與TestProject的輸出檔案TestProject.exe相同的路徑下。這個很最重,不然會編譯成功會是執行失敗,因為找不到對應的.dll檔案。

  3. 測試代碼與靜態庫的一樣。

附錄Utils.cpp
#include "Utils.h"Utils::Utils(void){}Utils::~Utils(void){}int Utils::Max( int nValue1, int nValue2 ){    return nValue1 > nValue2 ? nValue1 : nValue2;}int Utils::Min( int nValue1, int nValue2 ){    return nValue1 < nValue2 ? nValue1 : nValue2;}int Utils::Range( int nMin, int nMax, int nValue ){    if (nMax < nMin)    {        int temp = nMin;        nMin = nMax;        nMax = temp;    }    if (nValue < nMin)    {        return nMin;    } else if (nValue > nMax)    {        return nMax;    } else    {        return nValue;    }}int ConvertToInt( const char* pStr ){    int val;      std::strstream ss;      ss << pStr;      ss >> val;      return val;  }

參考文章:C++靜態庫與動態庫

上一篇回顧:
帶你玩轉Visual Studio——帶你高效管理代碼

下一篇要講述的內容:
帶你玩轉Visual Studio——帶你管理多種釋出版本

著作權聲明:本文為博主原創文章,未經博主允許不得用於任何商業用途,轉載請註明出處。

帶你玩轉Visual Studio——帶你發布自己的工程庫

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.