靜態(tài)庫和共享(動態(tài))庫(某馬)

1.庫的介紹

  • 什么是庫
    庫是二進制文件, 是源代碼文件的另一種表現(xiàn)形式, 是加了密的源代碼; 是一些功能相近或者是相似的函數(shù)的集合體.

  • 使用庫有什么好處

    • 提高代碼的可重用性, 而且還可以提高程序的健壯性;
    • 可以減少開發(fā)者的代碼開發(fā)量, 縮短開發(fā)周期.
  • 庫制作完成后, 如何給用戶使用

    • 頭文件---包含了庫函數(shù)的聲明
    • 庫文件---包含了庫函數(shù)的代碼實現(xiàn)
      注意: 庫不能單獨使用, 只能作為其他執(zhí)行程序的一部分完成某些功能, 也就是說只能被其他程序調(diào)用才能使用.

庫可分靜態(tài)庫(static library)和共享庫(shared library)

2.靜態(tài)庫(static library)

??靜態(tài)庫可以認為是一些目標代碼的集合, 是在可執(zhí)行程序運行前就已經(jīng)加入到執(zhí)行碼中, 成為執(zhí)行程序的一部分. 按照習慣, 一般以.a做為文件后綴名.

  • 靜態(tài)庫的命名一般分為三個部分:
    • 前綴:lib
    • 庫名稱:自定義即可, 如test
    • 后綴:.a
      所以最終的靜態(tài)庫的名字應(yīng)該為:libtest.a
  • 靜態(tài)庫的制作
    下面以fun1.c , fun2.c和head.h三個文件為例講述靜態(tài)庫的制作和使用, 其中head.h文件中有函數(shù)的聲明, fun1.c和fun2.c中有函數(shù)的實現(xiàn).

  • 步驟1:將c源文件生成對應(yīng)的.o文件
    gcc -c fun1.c fun2.c
    或者分別生成.o文件:
    gcc -c fun1.c -o fun1.o
    gcc -c fun2.c -o fun2.o

  • 步驟2:使用打包工具ar將準備好的.o文件打包為.a文件

    • 在使用ar工具是時候需要添加參數(shù)rcs
    • r更新、c創(chuàng)建、s建立索引
  • 命令:ar rcs 靜態(tài)庫名 .o文件

    • ar rcs libtest1.a fun1.o fun2.o
      
  • 靜態(tài)庫的使用
    靜態(tài)庫制作完成之后, 需要將.a文件和頭文件一定發(fā)布給用戶.
    假設(shè)測試文件為main.c, 靜態(tài)庫文件為libtest1.a, 頭文件為head.h
    用到的參數(shù):
    • -L:指定要連接的庫的所在目錄
    • -l:指定鏈接時需要的靜態(tài)庫, 去掉前綴和后綴
    • -I: 指定main.c文件用到的頭文件head.h所在的路徑
      gcc -o main1 main.c -L./ -ltest1 -I./
  • 靜態(tài)庫的優(yōu)缺點
    • 優(yōu)點:
      • 函數(shù)庫最終被打包到應(yīng)用程序中,實現(xiàn)是函數(shù)本地化,尋址方便、速度快。
        (庫函數(shù)調(diào)用效率==自定義函數(shù)使用效率)
      • 程序在運行時與函數(shù)庫再無瓜葛,移植方便。
    • 缺點:
      • 消耗系統(tǒng)資源較大, 每個進程使用靜態(tài)庫都要復(fù)制一份, 無端浪費內(nèi)存。
  • 靜態(tài)庫會給程序的更新、部署和發(fā)布帶來麻煩。如果靜態(tài)庫libxxx.a更新了,所有使用它的應(yīng)用程序都需要重新編譯、發(fā)布給用戶(對于玩家來說,可能是一個很小的改動,卻導(dǎo)致整個程序重新下載)。

3.共享庫(shared library)/動態(tài)庫

??共享庫在程序編譯時并不會被連接到目標代碼中, 而是在程序運行是才被載入. 不同的應(yīng)用程序如果調(diào)用相同的庫, 那么在內(nèi)存里只需要有一份該共享庫的拷貝, 規(guī)避了空間浪費問題.動態(tài)庫在程序運行時才被載入, 也解決了靜態(tài)庫對程序的更新、部署和發(fā)布會帶來麻煩. 用戶只需要更新動態(tài)庫即可, 增量更新. 為什么需要動態(tài)庫, 其實也是靜態(tài)庫的特點導(dǎo)致.

  • 按照習慣, 一般以”.so”做為文件后綴名.
  • 共享庫的命名一般分為三個部分:
    • 前綴:lib
    • 庫名稱:自己定義即可, 如test
    • 后綴:.so

所以最終的靜態(tài)庫的名字應(yīng)該為:libtest.so



  • 共享庫的制作
  1. 生成目標文件.o, 此時要加編譯選項:-fPIC(fpic)
    gcc -fpic -c fun1.c fun2.c
    參數(shù):-fpic創(chuàng)建與地址無關(guān)的編譯程序(pic, position independent code), 目的就是為了能夠在多個應(yīng)用程序間共享.
  2. 生成共享庫, 此時要加鏈接器選項: -shared(指定生成動態(tài)鏈接庫)
    gcc -shared fun1.o fun2.o -o libtest2.so
  • 共享庫的使用
    引用動態(tài)庫編譯成可執(zhí)行文件(跟靜態(tài)庫方式一樣):
    用到的參數(shù):
    • -L:指定要連接的庫的所在目錄
    • -l:指定鏈接時需要的動態(tài)庫, 去掉前綴和后綴
    • -I: 指定main.c文件用到的頭文件head.h所在的路徑
      gcc main.c -I./ -L./ -ltest2 -o main2


然后運行:./main2,發(fā)現(xiàn)竟然報錯了.

分析為什么在執(zhí)行的時候找不到libtest2.so庫

  • 當系統(tǒng)加載可執(zhí)行代碼時候, 能夠知道其所依賴的庫的名字, 但是還需要知道所依賴的庫的絕對路徑。此時就需要系統(tǒng)動態(tài)載入器(dynamic linker/loader)。
  • ldd命令可以查看可執(zhí)行文件依賴的庫文件, 執(zhí)行l(wèi)dd main2, 可以發(fā)現(xiàn)libtest2.so找不到.
  • 對于elf格式的可執(zhí)行程序,是由ld-linux.so*來完成的, 它先后搜索elf文件的 DT_RPATH段 — 環(huán)境變量LD_LIBRARY_PATH — /etc/ld.so.cache文件列表 — /lib/, /usr/lib目錄找到庫文件后將其載入內(nèi)存。

    使用file命令可以查看文件的類型: file main2



  • 如何讓系統(tǒng)找到共享庫
    • 拷貝自己制作的共享庫到/lib或者/usr/lib

    • 臨時設(shè)置LD_LIBRARY_PATH:

      • export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:庫路徑
    • 永久設(shè)置, 把export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:庫路徑, 設(shè)置到~/.bashrc文件中, 然后在執(zhí)行下列三種辦法之一:

      • 執(zhí)行. ~/.bashrc使配置文件生效(第一個.后面有一個空格)
      • 執(zhí)行source ~/.bashrc配置文件生效
      • 退出當前終端, 然后再次登陸也可以使配置文件生效
    • 永久設(shè)置,把export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:庫路徑,設(shè)置到/etc/profile文件中

    • 將其添加到 /etc/ld.so.cache文件中

      • 編輯/etc/ld.so.conf文件, 加入庫文件所在目錄的路徑
      • 運行sudo ldconfig -v, 該命令會重建/etc/ld.so.cache文件

解決了庫的路徑問題之后, 再次ldd命令可以查看可執(zhí)行文件依賴的庫文件, ldd main2:


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

4.比較靜態(tài)庫和動態(tài)庫的優(yōu)缺點

靜態(tài)庫的優(yōu)點:
1 執(zhí)行速度快, 是因為靜態(tài)庫已經(jīng)編譯到可執(zhí)行文件內(nèi)部了
2 移植方便, 不依賴域其他的庫文件
缺點:
1 耗費內(nèi)存, 是由于每一個靜態(tài)庫的可執(zhí)行程序都會加載一次
2 部署更新麻煩, 因為靜態(tài)庫修改以后所有的調(diào)用到這個靜態(tài)庫的可執(zhí)行文
件都需要重新編譯

動態(tài)庫的優(yōu)點:
1 節(jié)省內(nèi)存
2 部署升級更新方便, 只需替換動態(tài)庫即可, 然后再重啟服務(wù).
缺點:
1 加載速度比靜態(tài)庫慢
2 移植性差, 需要把所有用到的動態(tài)庫都移植.

由于由靜態(tài)庫生成的可執(zhí)行文件是把靜態(tài)庫加載到了其內(nèi)部, 所以靜態(tài)庫生成的可執(zhí)行文件一般會比動態(tài)庫大.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容