在Linux環境下編寫程式時,經常會調用glibc庫中的API。這些庫是如何?的的呢?很多初學者對此一直很困惑,接下來就與大家一起動手練習一下靜態庫和共用庫的製作方法。
作者:滄海獵人 出處:http://blog.csdn.net/embedded_hunter 轉載請註明出處 嵌入式技術交流QQ群:179012822
首先,我們編寫代碼來實現“輸入半徑求出圓的面積和周長”這個任務。看一下我另幾篇文章的內容:
- Linux環境下C語言編程實踐_01
http://blog.csdn.net/embedded_hunter/article/details/6838338 在這篇文章裡,在主函數直接就實現了。非常簡單。
- Linux環境下C語言編程實踐_02 http://blog.csdn.net/embedded_hunter/article/details/6838352 在這篇文章裡,通過函數的方式實現了任務要求,主函數以及普通函數寫在了同一個c源檔案中。
- Linux環境下C語言編程實踐_03
http://blog.csdn.net/embedded_hunter/article/details/6838372 在這篇文章裡,還是通過函數的方式實現的任務要求,但是主函數以及普通函數分別放在了不同的c源檔案中。
接下來我們希望將求圓的面積函數以及求圓的周長函數製作成庫,主函數來直接調用我們自訂的庫。
下面我們分別介紹製作靜態庫和共用庫的方法。在介紹製作方法之前,先瞭解一下靜態庫與共用庫的概念以及區別。
首先,無論是靜態庫還是共用庫都是二進位代碼。在linux中這些庫與可執行檔類似,都是ELF格式檔案。(關於ELF格式檔案,這裡不做詳細介紹,請讀者自行查閱其他資料,如果有機會,我會單獨寫一篇關於ELF格式檔案的文章)
一個來源程式轉化為可執行檔,要經曆編譯、連結階段。編譯是將源檔案轉換為目標代碼,連結是將目標代碼與其他目標檔案或庫進行“組合”,產生可執行程式。
靜態庫與共用庫的主要區別就在於連結過程,靜態庫在連結時會將代碼靜態插入可執行檔中,因此可執行檔比較大,並且可執行檔在運行時不依賴靜態庫;而共用庫則不會將代碼插入可執行檔中,因此可執行檔運行時會依賴共用庫。
一、靜態庫的製作方法
“Linux環境下C語言編程實踐_03 ”一文中有2個源檔案和1個標頭檔:MyPrograme.c,Mylib.h,Mylib.c。需要將Mylib.c製作為靜態庫。
1、產生目標代碼,後面製作靜態庫時需要用到這個目標代碼。
#gcc -c Mylib.c
將會產生Mylib.o目標檔案。
2、 製作靜態庫
#ar -cr libmylib.a Mylib.o
libmylib.a為靜態庫的檔案名稱,必須以lib開頭。lib***.a 中的***為庫名稱。靜態庫必須按照 lib[name].a 的規則命名
使用ar命令,可以產生靜態庫。
3、程式連結時使用靜態庫
#gcc -o main main.c -L. -lmylib
main.c檔案編譯連結時連結mylib靜態庫。連結時庫名稱用-l指定,如-lmylib;靜態庫位置使用-L指定,如-L.,.代表當前路徑,此選項不能省略。
注意:編譯器預設會尋找共用庫的,如果此目錄下還有一個同名共用庫,則編譯器預設使用共用庫進行連結。如果希望使用靜態庫,可以通過-static選項來指定。
4、運行程式
#./main 即可運行
此時即使刪除libmylib.a,程式也能夠運行。如果是共用庫則不能刪除庫。
二、共用庫的製作方法
1、製作共用庫
#gcc -shared -fpic -o libmylib.so Mylib.c
libmylib.so 為靜態庫的檔案名稱,必須以lib開頭。lib***.so中的***為庫名稱。
-shared 產生共用庫
-fpic 產生位置無關代碼,請思考什麼是與位置無關。
2、使用共用庫
#gcc -o main1 main.c -L. -lmylib
3、運行程式
此時無法直接運行程式,因為程式使用了共用庫,需要指定共用庫的位置。預設搜尋共用庫的路徑為/usr/lib和 /lib目錄。
有多方法可以解決這個問題:
(1)將共用庫拷貝到/usr/lib或/lib目錄中
(2)設定環境變數 LD_LIBRARY_PATH
(3)修改設定檔/etc/ld.so.conf
(4)編譯時間指定共用庫路徑。使用選項 -rpath
在這裡我們使用第二種方法:
#export LD_LIBRARY_PATH=/home/linux/:$LD_LIBRARY_PATH
#./main1
4、查看可執行檔依賴哪些庫。
#ldd main1