在實際的開發過程中,編寫程式往往都需要依賴很多基礎的底層庫,比方說平時用的較多的標準c庫,數學庫等等;我們會頻繁的使用這些庫里的函式,這些函式大多數都是前人為我們寫好的,所以值得慶幸的是我們的工作不必從零開始,我們要做的只是在恰當的位置呼叫合適的庫函式去實現相應的功能,充分利用前人的勞動成果,就是「站在巨人的肩膀上」。本文主要簡述linux下庫的製作以及使用方法。
一、什麼是庫
靜態庫的**在編譯過程中已經被載入可執行程式,因此體積較大。
共享庫的**是在可執行程式執行時才載入記憶體的,在編譯過程中僅簡單的引用,因此**體積較小。
二、初識靜態庫與動態庫
1.靜態函式庫
這類庫的名字一般是lib***.a,***為庫的名字。利用靜態函式庫編譯成的檔案比較大,因為整個函式庫的所有資料都會被整合進目標**中,他的優點就顯而易見了,即編譯後的執行程式不需要外部的函式庫支援,因為所有使用的函式都已經被編譯進去了。當然這也會成為他的缺點,因為如果靜態函式庫改變了,那麼你的程式必須重新編譯。
2.動態函式庫
這類庫的名字一般是lib***.m.n.so,同樣的***為庫的名字,m是庫的主版本號,n是庫的副版本號。當然也可以不要版本號,但名字必須有。相對於靜態函式庫,動態函式庫在編譯的時候並沒有被編譯進目標**中,你的程式執行到相關函式時才呼叫該函式庫裡的相應函式,因此動態函式庫所產生的可執行檔案比較小。由於函式庫沒有被整合進你的程式,而是程式執行時動態的申請並呼叫,所以程式的執行環境中必須提供相應的庫。動態函式庫的改變並不影響你的程式,所以動態函式庫的公升級比較方便。linux系統有幾個重要的目錄存放相應的函式庫,如/lib /usr/lib。
三、靜態庫與動態庫的比較
靜態庫其實從某種意義上來說只不過它操作的物件是目標**而不是原始碼而已。因為靜態庫被鏈結後庫就直接嵌入可執行檔案中了,這樣就帶來了兩個問題。
(1)首先就是系統空間被浪費了。這是顯而易見的,想象一下,如果多個程式鏈結了同乙個庫,則每乙個生成的可執行檔案就都會有乙個庫的副本,必然會浪費系統空間。
(2)再者,一旦發現了庫中有bug,挽救起來就比較麻煩了。必須一一把鏈結該庫的程式找出來,然後重新編譯。
而動態庫的出現正彌補了靜態庫的以上弊端。因為動態庫是在程式執行時被鏈結的,所以磁碟上只須保留乙份副本,因此節約了磁碟空間。如果發現了bug或要公升級也很簡單,只要用新的庫把原來的替換掉就行了。
但是靜態庫也有自己的優點:編譯後的執行程式不需要外部的函式庫支援,因為所有使用的函式都已經被編譯進去了。
四、如何判斷乙個程式有沒有鏈結動態庫
(1)file命令
file程式是用來判斷檔案型別的,啥檔案一看都清楚明了。
(2)ldd命令
看動態庫,如果目標程式沒有鏈結動態庫,則列印「not a dynamic executable」 (不是動態可執行檔案)
五、靜態庫的製作
(1) 為pr1和pr2生成object檔案
gcc -o -c pr1.c pr2.c
(2) ls
(3) 鏈結靜態庫
為了在編譯程式中正確找到庫檔案,靜態庫必須按照 lib[name].a 的規則命名,如下例中[name]=pr.
ar引數意義:
c: create的意思
r:在庫中插入模組(替換)。當插入的模組名已經在庫中存在,則替換同名的模組。
s:寫入乙個目標檔案索引到庫中,或者更新乙個存在的目標檔案索引。
v:該選項用來顯示執行操作選項的附加資訊。
t:顯示庫的模組表清單。一般只顯示模組名。
ar -crsv libpr.a pr1.o pr2.o
ar -t libpr.a //顯示靜態庫所依賴的檔案
(4) 編譯鏈結選項
-l 及-l 引數放在後面.其中,-l 載入庫檔案路徑,-l 指明庫檔案名字.
gcc -o main main.c -l./ -lpr //生成main
-i後面接頭檔案 (大寫的i)
-l後面接庫檔案路徑路徑
-l後面接庫檔名,除了「lib」和「.a」部分,全名為libpr.a
(5)執行目標程式
./main
六、動態庫的製作
(1)生成動態庫 ***.so
gcc -fpic -wall -c pr1.c
pic告訴編譯器產生與位置無關**(position-independent code), 則產生的**中,沒有絕對位址,全部使用相對位址,故而**可以被載入器載入到記憶體的任意位置,都可以正確的執行。這正是共享庫所要求的,共享庫被載入時,在記憶體的位置不是固定的。
gcc -shared -o libpr.so pr1.o
or use one line:
gcc -o -fpic -shared -o libpr.so pr1.c
(2)編譯時呼叫動態庫
gcc -o test main.c –l. -lpr
採用該方法執行會報告./test: error while loading shared libraries: libpr.so: cannot open shared object file: no such file or directory
原因:因為在動態函式庫使用時,會查詢/usr/lib、/lib目錄下的動態函式庫,而此時我們生成的庫不在裡邊。
這個時候有好幾種方法可以讓他成功執行:
(1)最直接最簡單的方法就是把so拉到/usr/lib或/lib中去,但這好像有點汙染環境吧。需要root許可權,在別人的電腦上會很麻煩;會把系統目錄弄得混亂。
(3)export ld_library_path=/tmp
不過這樣export 只對當前shell有效,當另開乙個shell時候,又要重新設定。可以把export ld_library_path=/tmp 語句寫到 ~/.bashrc中,這樣就對當前使用者有效了,寫到/etc/bashrc中就對所有使用者有效了。
echo $ld_library_path
不過ld_library_path的設定作用是全域性的,過多的使用可能會影響到其他應用程式的執行,所以多用在除錯。
小結:
總而言之,靜態庫是以空間換時間,動態庫是以時間換空間。無論你是在linux平台還是windows平台下做開發,庫的使用都大同小異。熟練的使各種庫,會給我們帶來許多便利,減少工作的負擔加快工程的進度,從此公升職,加薪不是夢,希望對你有所幫助。
Linux下的動態庫和靜態庫
靜態庫 程式編譯時載入,可執行程式體積大。一般命名為lib x.a。動態庫 程式執行時載入,可執行程式體積小。一般命名為lib x.so.1.3。x一般指庫名,如libxml2 tinyxml等 動態庫一般預設安裝在 lib 或者 usr lib 或者 usr local lib下。如果安裝的庫不在...
linux下的動態庫和靜態庫
1 使用gcc建立和使用靜態庫 1 gcc o mylib.o c mylib.c 生成o檔案 2 ar rcs libmylib.a mylib.o 生成a檔案 c create的意思 r replace的意思,表示當插入的模組名已經在庫中存在,則替換同名的模組。3 cp libmylib.a u...
Linux下的動態庫和靜態庫
1 使用gcc建立和使用靜態庫 1 gcc o mylib.o c mylib.c 生成o檔案 2 ar rcs libmylib.a mylib.o 生成a檔案 c create的意思 r replace的意思,表示當插入的模組名已經在庫中存在,則替換同名的模組。3 cp libmylib.a u...