linux下製作靜態庫與動態庫

       我們在編寫程序的過程過有可能會調用到不是我們自己寫的函數,這裏我稱其爲外部的函數,比如在寫C語言程序的時候,你會調用到printf函數用於調試輸出等,還有可能是這個情況,你自己寫的一些通用用途的函數,你在軟件項目中有多處地方要調用這些函數,這樣的話做成庫函數會比較合適,其他進程只需包含這個庫和頭文件就可以使用這些函數了。庫函數分兩種,一種是靜態庫,另一種則是動態庫,在程序執行過程中對於靜態庫,它是直接包含到可執行程序中的,通俗的說就是不管要不要調用都先包含編譯進來,而對於動態庫,它是在程序執行的時候動態地包含要使用的庫,同樣通俗的說就是要調用的時候再臨時的去動態庫裏取。

       1. 鏈接方式:

       1.1 靜態鏈接:編譯時以-static選項指明靜態編譯方式

       優點:生成的可執行程序對環境的依賴性小,即編譯後的執行程序不需要外部的函數庫支持,因爲所有使用的函數都已經被編譯進去了。

       缺點:因爲所有函數都被編譯進可執行程序,所以目標文件比較偏大,佔用空間,還有一點就是當靜態函數庫改變了,那麼你的程序必須重新編譯。

       例:以世界上最經典的例子hello.c來說明靜態鏈接方式:gcc hello.c -static -o hello_static,這個編譯例子的意思是將hello.c程序以靜態鏈接方式編譯生成hello_static可執行程序。

       1.2 動態鏈接:當不特別指明是-static靜態編譯時,系統默認是以動態鏈接方式編譯目標

       優點:因爲是動態編譯,所以函數並沒有實際編進可執行文件中,程序執行到相關函數時才調用該函數庫裏的相應函數,所以動態鏈接方式生成的可執行程序體積比較小,而且動態函數庫的改變並不影響你的程序,所以動態函數庫的升級比較方便。

       缺點:對環境的依賴比較大,由於函數庫沒有被整合進你的程序,而是程序運行時動態的申請並調用,所以程序的運行環境中必須提供相應的庫。

       例:gcc hello.c  -o hello_share,這個編譯例子的意思是將hello.c程序默認以動態鏈接方式編譯生成hello_share可執行程序。

       2. 製作靜態鏈接庫

       在linux中,靜態庫的命名規則是:lib[庫名].a。假設對於一個現有寫好的程序mylib.c,現在把這個源文件編譯成testlib庫文件,即libtestlib.a。只需如下兩個步驟OK。

       gcc -c mylib.c -o mylib.o (-c編譯但不鏈接)

       ar rc libtestlib.a mylib.o (ar rc 創建一個歸檔文件,通常用於創建靜態庫)

       3. 動態庫的使用

       假設現在hello.c文件要用到上面這個庫libtestlib.a的函數,詳見在以下三種情況中的使用:

       3.1 庫與頭文件(假設該庫有對應的"*.h"文件,下同)均在當前源文件的同一目錄下

       gcc -o hello_exe hello.c libtestlib.a (./hello_exe 可直接運行)

       3.2 庫與頭文件在指定目錄/opt下

       gcc -o hello_exe hello.c -L/opt -ltestlib -I/opt (前一個"-l"是小寫的"-L",後一個"-l"是大寫的"-i",具體含義可見我 的另一篇博文"Linux之gcc的使用")

       3.3 庫與頭文件分別在系統默認搜索路徑下

       在linux中,系統有一些庫和頭文件的默認搜索目錄,比如標準輸入輸出頭文件"stdio.h",當然你也完全可以把自己編譯的靜態和動態庫及相應的頭文件加入到那些目錄中,這樣就可以直接像如下方式使用庫了。

       linux下系統默認搜索的庫文件*.a、*.so搜索路徑:/lib /usr/lib /usr/local/lib

       linux下系統默認搜索的頭文件*.h搜索路徑:/usr/include

       mv libtestlib.a /lib (把庫加入到系統默認搜索目錄)

       gcc -o hello_exe hello.c -ltestlib

       4. 製作動態鏈接庫

       在linux中,動態庫的命名規則是:lib[庫名].so。假設對於一個現有寫好的程序mylib.c,現在把這個源文件編譯成testlib庫文件,即libtestlib.so。只需如下一步OK。

       gcc -shared mylib.c -o libtestlib.so

       5. 靜態庫的使用(分以下三種情況)

       假設現在hello.c文件要用到上面這個庫libtestlib.so的函數,詳見在以下三種情況中的使用:

       5.1 庫與頭文件均在當前源文件的同一目錄下

       gcc -o hello_exe hello.c libtestlib.so (./hello_exe 可直接運行)

       5.2 庫與頭文件在指定目錄/opt下

       gcc -o hello_exe hello.c -L/opt -ltestlib -I/opt

       注:5.1和5.2能編譯通過生成可執行文件hello_exe,但是運行時會出錯:編譯時找到了庫函數,但鏈接時找不到庫。解決方法可通過環境變量LD_LIBRARY_PATH指定動態庫搜索路徑(當通過該環境變量指定多個動態庫搜索路徑時,路徑之間用冒號":"分隔),比如這裏需要執行操作:#export LD_LIBRARY_PATH=./:/opt:$LD_LIBRARY_PATH,把當前目錄加入搜索路徑。

       5.3 庫與頭文件分別在系統默認搜索路徑下(同3.3)

       gcc -o hello_exe hello.c -ltestlib (編譯運行都不會報錯)

      問題:有個問題出現了?我們前面的靜態庫也是放在/lib下,那麼連接的到底是動態庫還是靜態庫呢?
      答:當靜態庫與動態庫重名時,系統會優先連接動態庫,或者我們可以加入-static指定使用靜態庫。

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