一個程序的前世今生(三)——動態鏈接庫和靜態鏈接庫


簡介:

  在程序編寫的時候我們會依賴很多底層的實現(除非單純操作簡單的硬件如單片機點燈),所以不可能永遠從零開始書寫,因此不可避免的會使用到很多庫文件,那么什么是庫文件。

一:什么是庫

  庫是寫好的現有的,成熟的,可以復用的代碼。現實中每個程序都要依賴很多基礎的底層庫,不可能每個人的代碼都從零開始,因此庫的存在意義非同尋常

  本質上來說庫是一種可執行代碼的二進制形式,可以被操作系統載入內存執行。庫有兩種:靜態庫(.a.lib)和動態庫(.so.dll)。

二:什么是靜態庫

  在計算機科學中,靜態庫(英語:Static library, Statically-linked library),或稱靜態庫,是一個外部函數與變量的集合體。靜態庫的文件內容,通常包含一堆程序員自定的變量與函數,其內容不像動態鏈接庫那么復雜,在編譯期間由編譯器與鏈接器將它集成至應用程序內,並制作成目標文件以及可以獨立運作的可執行文件。而這個可執行文件與編譯可執行文件的程序,都是一種程序的靜態創建(static build)。以過去的觀點來說,庫只能算是靜態(static)類型。

  使用靜態方式編譯hello文件,執行如下命令: gcc -static -o hello hello.c, 標准庫將被靜態的鏈接到可執行文件中,多個可執行文件使用同一個靜態庫將會使靜態庫拷貝多份,對比靜態方式和動態方式編譯出的可執行文件

  

  2.1 生成靜態庫的方法如下:

  • 編譯object文件。例如:cc -Wall -c test1.c test2.c,該命令會生成test1.o和、test2.o(其中-Wall表示編譯時輸出警告)。
  • 創建庫文件。ar -cvq libctest.a test1.o test2.o。該命令會得到一個libctest.a文件
  • 可以通過ar -t查看.a文件中包含哪些.o。所以,實際上ar就是一個打包命令,類似tar
  • 構建符號表。ranlib libctest.a用於為.a創建符號表。有些ar命令實際上已經集成了ranlib的功能

 

三: 什么時動態庫

  動態庫即動態鏈接庫。與靜態庫相反,動態庫在鏈接時不復制(目標程序中只會存儲指向動態庫的引用),程序運行時由系統動態加載到內存,系統只加載一次,多個程序共用,節省內存。

  編譯可執行文件使用動態庫時不添加static參數,參考上圖。

  3.1 生成動態庫的方法如下:

  • 編譯object文件時使用-fPIC(位置無關碼)選項:
  • gcc -Wall -fPIC -c *.c

  這個選項的目的是讓編譯器生成地址無關(position independent)的代碼,這是因為,動態庫是在運行期間鏈接的,變量和函數的偏移量是事先不知道的,需要鏈接以后根據offset進行地址重定向。

  • 使用-shared鏈接
    gcc -shared -Wl,-soname,libtest.so.1 -o libtest.so.1.0 *.o

  -shared選項是讓動態庫得以在運行期間被動態鏈接;-Wl,options是設置傳遞給ld(鏈接器)的參數,在上面的例子中,當鏈接器在鏈接.o時會執行ld -soname ibtest.so.1

  • 創建軟鏈

  上面的命令將最終輸出一個動態庫libtest.so.1.0,而出於習慣,會創建兩個軟鏈:

  mv libtest.so.1.0 /opt/lib
  ln -sf /opt/lib/libtest.so.1.0 /opt/lib/libtest.so.1
  ln -sf /opt/lib/libtest.so.1.0 /opt/lib/libtest.so

  libtest.so用於在編譯期間使用-ltest編譯器找到動態庫,而libtest.so.1用於在運行期間鏈接。

 

  3.2 運行期間查找動態庫

 

    運行期間,系統需要知道到哪里去查找動態庫,這是通過/etc/ld.so.conf配置的。ldconfig用於配置運行時動態庫查找路徑,實際是更新/etc/ld.so.cache。另外一些環境變量也可以影響查找:(Linux/Solaris: LD_LIBRARY_PATH, SGI: LD_LIBRARYN32_PATH, AIX: LIBPATH, Mac OS X: DYLD_LIBRARY_PATH, HP-UX: SHLIB_PATH)

  3.3 動態加載和卸載的庫

  需要應用程序希望設計成插件化的架構,這就需要可以動態加載和卸載庫的機制。與動態鏈接不同的是,動態加載的意思是,編譯期間可以對動態庫的存在一無所知,而是在運行期間通過用戶程序嘗試加載進來的。

  通過dlfcn.h中的dlopendlsymdlclose等函數實現此種功能。

  另外,使用到dlfcn機制的可執行文件需要使用-rdynamic選項,它將指示連接器把所有符號(而不僅僅只是程序已使用到的外部符號,但不包括靜態符號,比如被static修飾的函數)都添加到動態符號表(即.dynsym表)里。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM