庫是寫好的現有的,成熟的,可以復用的**。現實中每個程式都要依賴很多基礎的底層庫,不可能每個人的**都從零開始,因此庫的存在意義非同尋常。
本質上來說庫是一種可執行**的二進位制形式,可以被作業系統載入記憶體執行。庫有兩種:靜態庫(.a、.lib)和動態庫(.so、.dll)。
所謂靜態、動態是指鏈結。回顧一下,將乙個程式編譯成可執行程式的步驟:
之所以成為【靜態庫】,是因為在鏈結階段,會將彙編生成的目標檔案.o與引用到的庫一起鏈結打包到可執行檔案中。因此對應的鏈結方式稱為靜態鏈結。
試想一下,靜態庫與彙編生成的目標檔案一起鏈結為可執行檔案,那麼靜態庫必定跟.o檔案格式相似。其實乙個靜態庫可以簡單看成是一組目標檔案(.o/.obj檔案)的集合,即很多目標檔案經過壓縮打包後形成的乙個檔案。靜態庫特點總結:
下面編寫一些簡單的四則運算c++類,將其編譯成靜態庫給他人用,標頭檔案如下所示:
標頭檔案
#pragma once
class staticmath
;
linux下使用ar工具、windows下vs使用lib.exe,將目標檔案壓縮到一起,並且對其進行編號和索引,以便於查詢和檢索。一般建立靜態庫的步驟如圖所示:
1. linux靜態庫命名規則
linux靜態庫命名規範,必須是」lib[your_library_name].a」:lib為字首,中間是靜態庫名,擴充套件名為.a。
2. 建立靜態庫(.a)
通過上面的流程可以知道,linux建立靜態庫過程如下:
g++ -c staticmath.cpp注意帶引數-c,否則直接編譯為可執行檔案
ar -crv libstaticmath.a staticmath.o生成靜態庫libstaticmath.a。
大一點的專案會編寫makefile檔案(cmake等等工程管理工具)來生成靜態庫,輸入多個命令太麻煩了。
3. 使用靜態庫
編寫使用上面建立的靜態庫的測試**:
#include "staticmath.h"
#include
using
namespace
std;
int main(int argc, char* argv)
linux下使用靜態庫,只需要在編譯的時候,指定靜態庫的搜尋路徑(-l選項)、指定靜態庫名(不需要lib字首和.a字尾,-l選項)。
通過上面的介紹發現靜態庫,容易使用和理解,也達到了**復用的目的,那為什麼還需要動態庫呢?
為什麼還需要動態庫?
為什麼需要動態庫,其實也是靜態庫的特點導致。
動態庫在程式編譯時並不會被連線到目標**中,而是在程式執行是才被載入。不同的應用程式如果呼叫相同的庫,那麼在記憶體裡只需要有乙份該共享庫的例項,規避了空間浪費問題。動態庫在程式執行是才被載入,也解決了靜態庫對程式的更新、部署和發布頁會帶來麻煩。使用者只需要更新動態庫即可,增量更新。
動態庫特點總結:
window與linux執行檔案格式不同,在建立動態庫的時候有一些差異。
與建立靜態庫不同的是,不需要打包工具(ar、lib.exe),直接使用編譯器即可建立動態庫。
1. linux動態庫的命名規則
動態鏈結庫的名字形式為 lib***.so,字首是lib,字尾名為「.so」。
2. 建立動態庫(.so)
編寫四則運算動態庫**:
標頭檔案
#pragma once
class dynamicmath
;
g++ -fpic -c dynamicmath.cpp-fpic 建立與位址無關的編譯程式(pic,position independent code),是為了能夠在多個應用程式間共享。
g++ -shared -o libdynmath.so dynamicmath.o-shared指定生成動態鏈結庫。
其實上面兩個步驟可以合併為乙個命令:
g++ -fpic -shared -o libdynmath.so dynamicmath.cpp3. 使用動態庫編寫使用動態庫的測試**:
#include "../dynamiclibrary/dynamicmath.h"
#include
using
namespace
std;
int main(int argc, char* argv)
引用動態庫編譯成可執行檔案(跟靜態庫方式一樣):
g++ testdynamiclibrary.cpp -l ../dynamiclibrary -ldynmath然後執行:./a.out,發現竟然報錯了
發現還是報錯!那麼,在執行的時候是如何定位共享庫檔案的呢?
1) 當系統載入可執行**時候,能夠知道其所依賴的庫的名字,但是還需要知道絕對路徑。此時就需要系統動態載入器(dynamic linker/loader)。
2) 對於elf格式的可執行程式,是由ld-linux.so*來完成的,它先後搜尋elf檔案的 dt_rpath段—環境變數ld_library_path—/etc/ld.so.cache檔案列表—/lib/,/usr/lib 目錄找到庫檔案後將其載入記憶體。
如何讓系統能夠找到它:
我們將建立的動態庫複製到/usr/lib下面,然後執行測試程式。
二者的不同點在於**被載入的時刻不同。
動態庫的好處是,不同的應用程式如果呼叫相同的庫,那麼在記憶體裡只需要有乙份該共享庫的例項。帶來好處的同時,也會有問題!如經典的dll hell問題,關於如何規避動態庫管理問題,可以自行查詢相關資料。
C 靜態庫與動態庫
感覺比較形象,就摘過來了.這次分享的 宗旨是 讓大家學會建立與使用靜態庫 動態庫,知道靜態庫與動態庫的區別,知道使用的時候如何選擇。這裡不深入介紹靜態庫 動態庫的底層格式,記憶體布局等,有興趣的同學,推薦一本書 程式設計師的自我修養 鏈結 裝載與庫 庫是寫好的現有的,成熟的,可以復用的 現實中每個程...
c 靜態庫與動態庫
庫分為靜態庫,動態庫,在不同系統下字尾不同。2.1.1 在鏈結和執行階段都涉及庫的呼叫 訪問 h檔案 標頭檔案 是庫的介面。h檔案提供給庫的使用者,使用者通過.h來呼叫庫中的api。2.1.2 庫中包含的是函式的實現 一堆函式的實現 這些函式在編寫的時候同樣要包含1中的標頭檔案,然後生成庫。2.1....
C 靜態庫與動態庫
1.靜態庫 1.靜態庫實際上就是一些目標檔案 一般以.o結尾 的集合,靜態庫一般以.a結尾,只用於生成可執行檔案階段。2.在鏈結步驟中,鏈結器將從庫檔案取得所需 複製到生成的可執行檔案中。這種庫稱為靜態庫。其特點是 可執行檔案中包含了庫 的乙份完整拷貝,在編譯過程中被引導程式中。缺點就是多次使用就會...