【轉載】C++靜態庫與動態庫創建及使用

原文鏈接:https://www.cnblogs.com/skynet/p/3372855.html

出處吳秦:https://www.cnblogs.com/skynet/p/3372855.html

宗旨

  1. 學會創建與使用靜態庫、動態庫;
  2. 知道靜態庫與動態庫的區別;
  3. 知道使用的時候如何選擇。

這裏不深入介紹靜態庫、動態庫的底層格式,內存佈局等,有興趣的同學,推薦一本書 《程序員的自我修養——鏈接、裝載與庫》

什麼是庫?

是寫好的現有的,成熟的,可以複用的代碼。現實中每個程序都要依賴很多基礎的底層庫,不可能每個人的代碼都從零開始,因此庫的存在意義非同尋常。 本質上來說庫是一種可執行代碼的二進制形式,可以被操作系統載入內存執行。

  庫有兩種:靜態庫(.a、.lib)和動態庫(.so、.dll)。 所謂靜態、動態是指鏈接。回顧一下,將一個程序編譯成可執行程序的步驟:

在這裏插入圖片描述

靜態庫

什麼是靜態庫?

  靜態庫之所以成爲【靜態庫】,是因爲在鏈接階段,會將彙編生成的目標文件.o 與引用到的庫一起鏈接打包到可執行文件中。因此對應的鏈接方式稱爲靜態鏈接。

  試想一下,靜態庫與彙編生成的目標文件一起鏈接爲可執行文件,那麼靜態庫必定跟.o文件格式相似。其實一個靜態庫可以簡單看成是一組目標文件(.o/.obj文件)的集合,即很多目標文件經過壓縮打包後形成的一個文件。

靜態庫特點

  • 靜態庫對函數庫的鏈接是放在編譯時期完成的。
  • 程序在運行時與函數庫再無瓜葛,移植方便。
  • 浪費空間和資源,因爲所有相關的目標文件與牽涉到的函數庫被鏈接合成一個可執行文件。

下面編寫一個簡單的打印類myPrint,將其編譯成靜態庫給他人用,文件爲:

// myPrint.h	
void testPrint(void); 
// myPrint.cpp
#include <iostream>  

void testPrint(void)  
{  
  std::cout<<"Hello World!"<<std::endl;
} 
// test.cpp
#include "myPrint.h"  
  
int main(void)  
{  
  testPrint();  
  return 0;  
} 

Linux下使用ar工具,將目標文件壓縮到一起,並且對其進行編號和索引,以便於查找和檢索。一般創建靜態庫的步驟如圖所示:
在這裏插入圖片描述

Linux下創建與使用靜態庫

Linux靜態庫命名規則

  Linux靜態庫命名規範,必須是"lib[yourLibraryName].a":lib爲前綴,中間是靜態庫名,擴展名爲.a。

創建靜態庫

  創建靜態庫(.a) 通過上面的流程可以知道,Linux創建靜態庫過程如下:

  1. 將代碼文件編譯成目標文件.o(myPrint.o)
g++ -c myPrint.cpp          
注意:帶參數-c,否則直接編譯爲可執行文件。
  1. 通過ar工具將目標文件打包成.a靜態庫文件
ar -crv libmyPrint.a myPrint.o

  生成靜態庫libmyPrint.a。

使用靜態庫

  Linux下使用靜態庫,只需要在編譯的時候,指定靜態庫的搜索路徑(-L)、指定靜態庫名(不需要lib前綴和.a後綴,-l)。

g++ test.cpp -L../testLibrary -lmyPrint

-L:表示要連接的庫所在目錄
-l:指定鏈接時需要的動態庫,編譯器查找動態連接庫時有隱含的命名規則,即在給出的名字前面加上lib,後面加上.a或.so來確定庫的名稱。

動態庫

通過上面的介紹發現靜態庫,容易使用和理解,也達到了代碼複用的目的,那爲什麼還需要動態庫呢?

爲什麼還需要動態庫?

爲什麼需要動態庫,其實也是靜態庫的特點導致。

  • 空間浪費是靜態庫的一個問題。
    在這裏插入圖片描述
  • 另一個問題是靜態庫對程序的更新、部署和發佈頁會帶來麻煩。如果靜態庫liba.lib更新了,所以使用它的應用程序都需要重新編譯、發佈給用戶(對於玩家來說,可能是一個很小的改動,卻導致整個程序重新下載,全量更新)。

  動態庫在程序編譯時並不會被連接到目標代碼中,而是在程序 運行時 才被載入。不同的應用程序如果調用相同的庫,那麼在內存裏只需要有一份該共享庫的實例,規避了空間浪費問題。動態庫在程序運行時才被載入,也解決了靜態庫對程序的更新、部署和發佈頁會帶來麻煩。用戶只需要更新動態庫即可,增量更新。
在這裏插入圖片描述

動態庫特點

  • 動態庫把對一些庫函數的鏈接載入推遲到程序運行的時期。
  • 可以實現進程之間的資源共享。(因此動態庫也稱爲共享庫)。
  • 將一些程序升級變得簡單。
  • 甚至可以真正做到鏈接載入完全由程序員在程序代碼中控制(顯示調用)。

與創建靜態庫不同的是,不需要打包工具(ar、lib.exe),直接使用編譯器即可創建動態庫。

Linux下創建與使用動態庫

Linux動態庫的命名規則

動態鏈接庫的名字形式爲 libxx.so,前綴是lib,後綴名爲“.so”。

  • 針對於實際庫文件,每個共享庫都有個特殊的名字“soname”。在程序啓動後,程序通過這個名字來告訴動態加載器該載入哪個共享庫。
  • 在文件系統中,soname僅是一個鏈接到實際動態庫的鏈接。對於動態庫而言,每個庫實際上都有另一個名字給編譯器來用。它是一個指向實際庫鏡像文件的鏈接文件(lib+soname+.so)。

創建動態庫(.so)

  1. 生成目標文件,此時要加編譯器選項-fpic。
g++ -fPIC -c myPrint.cpp

-fPIC 創建與地址無關的編譯程序(pic,position independent code),是爲了能夠在多個應用程序間共享。

  1. 生成動態庫,此時要加鏈接器選項-shared。
g++ -shared -o libmyPrint.so myPrint.o

-shared 指定生成動態鏈接庫。

其實上面兩個步驟可以合併爲一個命令:

g++ -fPIC -shared -o libmyPrint.so myPrint.cpp

使用動態庫

引用動態庫編譯成可執行文件(跟靜態庫方式一樣):

g++ test.cpp -L../testLibrary -lmyPrint
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章