跳轉到內容

C++ 程式設計/編譯器/連結器/庫

來自華夏公益教科書,開放書籍,開放世界

庫允許在程式中重用現有程式碼。庫類似於程式,但它們不依賴於main()來完成工作,而是呼叫庫提供的特定函式來完成工作。函式提供了被編寫程式和被使用的庫之間的介面。這個介面被稱為應用程式程式設計介面或 API。

庫應該並且傾向於特定於領域,以便允許在應用程式之間具有更高的可移植性,並提供擴充套件的專業化。不是特定於領域的庫通常是僅包含標頭檔案的釋出,旨在進行靜態連結,以便允許編譯器和應用程式僅使用所需的程式碼片段。

什麼是 API?

對於程式設計師來說,作業系統由其API定義。API代表應用程式程式設計介面API包含應用程式程式可以與硬體或作業系統通訊的所有函式呼叫,或任何提供給程式設計師一組介面的其他應用程式(即:庫),以及相關資料型別和結構的定義。大多數API都在應用程式軟體開發工具包(SDK)中定義,用於程式開發。

簡單來說,API可以被認為是使用者(或使用者程式)將透過其與作業系統、硬體或其他程式進行互動的介面,使它們執行一項任務,這也可能導致獲得結果訊息。

API 可以稱為框架嗎?

不,框架可以提供 API,但框架不僅僅是一個簡單的 API。預設情況下,框架還定義了程式碼的編寫方式,它是一組解決方案,甚至是類,這些解決方案作為一個整體解決了有限的一組相關問題的處理,不僅提供 API,還提供預設功能,設計良好的框架使其可互換用於類似的框架,努力提供相同的 API。

檔案組織部分所示,編譯後的庫包含預處理器包含的 C++ 標頭檔案和連結器用於生成最終編譯結果的二進位制庫檔案。對於動態連結庫,只有載入程式碼被新增到使用它們的編譯中,庫的實際載入是在執行時在記憶體中完成的。

程式可以使用兩種形式的庫,靜態或動態,具體取決於程式設計師如何決定分發其程式碼,甚至由於第三方庫使用的許可證,本書的靜態和動態庫部分將深入探討這個主題。

注意
正如我們將在介紹多執行緒時看到的那樣,在選擇庫時,請記住驗證它們是否符合您在該領域的特定需求。

第三方庫

[編輯 | 編輯原始碼]

超越標準庫(如垃圾回收)的附加功能可以透過第三方庫獲得(通常是免費的),但請記住,第三方庫不一定提供與標準庫相同的普遍跨平臺功能或符合 API 樣式。它們存在的主要動機是避免重複造輪子,並使努力集中;幾代程式設計師已經花費了大量的精力來編寫安全且“可移植”的程式碼。

程式設計師預計會了解或至少對一些庫有所瞭解。時間、一致性和擴充套件引用將使一些庫從其他庫中脫穎而出。一個值得注意的例子是備受尊敬的Boost 庫集合,我們將在後面進行研究。

第三方庫的許可證

程式設計師也可能受到外部庫許可證要求的限制,他無法直接控制這些要求,例如在封閉源應用程式中使用GNU 通用公共許可證(GNU GPL)程式碼是不允許的,為了解決這個問題,FSF 提供了 GNU LGPL 許可證的形式,允許這種使用,但只允許以動態連結的形式,這反映了程式設計師必須注意和遵守的許多其他法律要求。

庫有兩種形式,原始碼形式編譯/二進位制形式。原始碼形式的庫必須先編譯才能包含到另一個專案中。這將把庫的 cpp 檔案轉換為 lib 檔案。如果必須重新編譯程式才能使用新版本的庫,但不需要進行任何其他更改,則該庫被稱為原始碼相容。如果程式不需要修改和重新編譯即可使用庫的新版本,則該庫被歸類為二進位制相容

靜態庫和動態庫

[編輯 | 編輯原始碼]
Clipboard

待辦事項
在這裡定義“靜態庫”和“動態庫”以及“靜態二進位制檔案”。


使用靜態二進位制檔案的優點

  • 簡化程式分發(更少的檔案)。
  • 程式碼簡化(不需要動態庫中所需的版本檢查)。
  • 只編譯使用的程式碼。

使用靜態二進位制檔案的缺點

  • 浪費資源:生成更大的二進位制檔案,因為庫被編譯到可執行檔案中。浪費記憶體,因為庫不能在程序之間(取決於作業系統)共享(在記憶體中)。
  • 程式將不會從庫中的錯誤修復或擴充套件中獲益,除非重新編譯。
庫的二進位制/原始碼相容性

如果動態連結到該庫的早期版本的程式繼續使用該庫的其他版本工作,則該庫被稱為二進位制相容。如果程式需要重新編譯才能使用每個新版本的庫,則該庫被稱為原始碼相容

生成二進位制相容庫有利於分發,但程式設計師更難維護。如果庫僅是原始碼相容的,靜態連結通常被認為是更好的解決方案,因為它不會給終端使用者造成問題。

二進位制相容性省去了很多麻煩,並且表明該庫已達到穩定狀態。這使得為特定平臺分發軟體變得更容易。如果不確保發行版之間的二進位制相容性,人們將被迫提供靜態連結的二進位制檔案。

僅包含標頭檔案的庫

關於庫的另一個常見的區別是關於它們是如何分發的(關於結構和使用)。僅包含標頭檔案的庫被稱為僅包含標頭檔案的庫。這通常意味著它們更簡單,更易於使用,但是對於複雜的程式碼,這並不是理想的解決方案,它不僅會影響可讀性,還會導致更長的編譯時間。此外,由於內聯而導致的最終結果,取決於編譯器及其最佳化能力(或選項),可能會生成更大的二進位制檔案。這對於主要使用模板實現的庫來說可能並不那麼重要。僅包含標頭檔案的庫將始終包含實現的原始碼,商業庫很少見。

示例:配置 MS Visual C++ 以使用外部庫

[編輯 | 編輯原始碼]

Boost 庫用作示例庫。

注意
Boost.org有一個名為在 Windows 上入門(Getting Started on Windows)的安裝指南,它指向由BoostPro Computing提供的自動安裝(通常支援以前和舊的版本),同時還注意到,如果使用“原始碼和文件”(Source and Documentation)未選中(預設情況下選中)的選項,它將不會顯示 libs/ 子目錄。這將阻止使用者重新構建不是僅包含標頭檔案的庫的一部分。這使得本節中顯示的自己安裝它成為最佳選擇。

假設您已經解壓縮並已構建 Boost 庫的二進位制部分,那麼您必須執行以下步驟:

包含目錄

[編輯 | 編輯原始碼]

設定包含目錄。這是包含標頭檔案(.h/hpp)的目錄,這些標頭檔案描述了庫介面

include directories

庫目錄

[編輯 | 編輯原始碼]

設定庫目錄。這是包含預編譯庫檔案(.lib)的目錄。

library directories

庫檔案

[編輯 | 編輯原始碼]

附加依賴項中輸入庫檔名,以便使用庫。

library filenames (the Boost "REGEXP"-library in this example)



某些庫(例如 Boost)使用自動連結來自動選擇要連結的庫檔案,具體取決於包含的標頭檔案。如果您的編譯器支援自動連結,則無需為這些庫手動選擇庫檔名。

動態庫

[編輯 | 編輯原始碼]

對於動態載入(.dll)庫,還需要將 DLL 檔案放置在與可執行檔案相同的資料夾中,或放置在系統 PATH 中。

執行時庫

[編輯 | 編輯原始碼]

庫還必須使用與專案中使用的相同的執行時庫進行編譯。因此,許多庫都以不同的版本提供,具體取決於它們是針對單執行緒還是多執行緒執行時以及除錯還是釋出執行時編譯的,以及它們是否包含除錯符號

selection of run-time library

華夏公益教科書