Linux靜態、共用和動態庫之編程

來源:互聯網
上載者:User
一.庫的分類
    有兩種說法, 如果熟悉WIN平台下的DLL, 相信不難理解:

    庫可以有三種使用的形式:靜態、共用和動態.靜態庫的代碼在編譯時間就已串連到開發人員開發的應用程式中, 而共用庫只是在程式開始運行時才載入, 在編譯時間, 只是簡單地指定需要使用的庫函數.動態庫則是共用庫的另一種變化形式.動態庫也是在程式運行時載入, 但與共用庫不同的是, 使用的庫函數不是在程式運行開始, 而是在程式中的語句需要使用該函數時才載入.動態庫可以在程式運行期間釋放動態庫所佔用的記憶體, 騰出空間供其它程式使用.由於共用庫和動態庫並沒有在程式中包括庫函數的內容, 只是包含了對庫函數的引用, 因此代碼的規模比較小.

    Linux下的庫檔案分為共用庫和靜態庫兩大類, 它們兩者的差別僅在程式執行時所需的代碼是在運行時動態載入的, 還是在編譯時間靜態載入的.區分庫類型最好的方法是看它們的檔案尾碼, 通常共用庫以.so(Shared Object的縮寫)結尾, 靜態連結庫通常以.a結尾(Archive的縮寫).在終端預設情況下, 共用庫通常為綠色, 而靜態庫為黑色.

     已經開發的大多數庫都採取共用庫的方式.ELF格式的可執行檔使得共用庫能夠比較容易地實現, 當然使用舊的a.out模式也可以實現庫的共用.Linux系統中目前可執行檔的標準格式為ELF格式.

  .a的是為了支援較老的a.out格式的可執行檔的
  .so的是支援elf格式的可執行檔的庫.

   .a是靜態庫檔案, 可以用ar 命令產生.
  .so是動態庫檔案, 編譯時間加上指定的選項即可產生, 具體選項看相應的系統文檔了.

二.庫的命名規則
    GNU庫的使用必須遵守Library GNU Public License(LGPL許可協議).該協議與GNU許可協議略有不同, 開發人員可以免費使用GNU庫進行軟體開發, 但必須保證向使用者提供所用的庫函數的原始碼.

  系統中可用的庫都存放在/usr/lib和/lib目錄中.庫檔案名稱由首碼lib和庫名以及尾碼組成.根據庫的類型不同, 尾碼名也不一樣.共用庫的尾碼名由.so和版本號碼組成, 靜態庫的尾碼名為.a.採用舊的a.out格式的共用庫的尾碼名為.sa.
  libname.so.major.minor
  libname.a

  這裡的name可以是任何字串, 用來唯一標識某個庫.該字串可以是一個單字、幾個字元、甚至一個字母.數學共用庫的庫名為libm.so.5, 這裡的標識字元為m, 版本號碼為5.libm.a則是靜態數學庫.X-Windows庫名為libX11.so.6, 這裡使用X11作為庫的標識, 版本號碼為6.

三.庫操作命令

   Linux庫操作可以使用命令完成, 目前常用的命令是ldd和ldconfig.

   1.ldd
 ldd是Library Dependency Display縮寫, 它的作用是顯示一個可執行程式必須使用的共用庫.

 $ ldd /usr/bin/mesg
 libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7eaf000)
 /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0xb7feb000)

   2.ldconfig
 庫安裝到系統以後, 為了讓動態連結程式庫為系統所認識及共用, 就需要運行ldconfig.ldconfig命令的用途, 主要是在預設搜尋目錄(/lib和/usr/lib)以及動態庫設定檔/etc/ld.so.conf內所列的目錄下, 搜尋出可共用的動態連結程式庫(格式如lib*.so*), 進而建立出動態裝入程式(ld.so)所需的串連和快取檔案.快取檔案預設為/etc/ld.so.cache, 此檔案儲存已排好序的動態連結程式庫名字列表, ldconfig通常在系統啟動時運行, 而當使用者安裝了一個新的動態連結程式庫時,就需要手工運行這個命令.

     (1)命令格式
 ldconfig [選項] [libs]

     (2)主要選項
 -v或--verbose ldconfig將顯示正在掃描的目錄、搜尋到的動態連結程式庫, 以及它所建立的串連的名字.

 -f CONF 指定動態連結程式庫的設定檔為CONF, 系統預設為/etc/ld.so.conf.

 -C CACHE 指定產生的快取檔案為CACHE, 系統預設的是/etc/ld.so.cache,檔案存放已排好序的可共用的動態連結程式庫的列表.

 -p或--print-cache 讓ldconfig列印出當前快取檔案所儲存的所有共用庫的名字.

 -r ROOT 改變應用程式的根目錄為ROOT.

 -n ldconfig僅掃描命令列指定的目錄, 不掃描預設目錄(/lib、/usr/lib),也不掃描設定檔/etc/ld.so.conf所列的目錄.

 運行沒有選項的ldconfig命令時, 用於更新高速緩衝檔案.這個命令主要用於高速緩衝DNS伺服器(Caching DNS Server).高速緩衝DNS伺服器的原理是提供查詢的記錄, 並且利用這些記錄來提高查詢的效率.

 當某個查詢是第一次被發送到高速緩衝DNS伺服器時, 高速緩衝DNS伺服器就將此查詢的整個過程記錄下來, 在一定的時期內用它來回答所有相同的查詢, 從而減少整個DNS系統的負擔並且提高查詢速度.

四.庫的升級

 Linux系統軟體更新很快, 新的核心幾乎每幾個星期就公布一次, 其它軟體的更新也是非常頻繁.多數情況下, 盲目跟隨潮流的升級並不必要, 如果確實需要新版本的特性時再升級.換句話說, 不要為了升級而升級.Linux系統中多數軟體都是用共用庫來編譯的, 其中包含了在不同程式之間共用的公用子常式.

在運行某個程式時, 如果看到如下資訊:“Incompatible library version.”則表明需要將該庫升級到程式所需要的版本.庫是向下相容的, 也就是說, 用老版本庫編譯的程式可以在新安裝的版本庫上運行, 反之則不行.

Linux庫函數的升級是一項重要的工作, 往往與其它軟體包的升級有一定關聯作用, 所以操作前一定要備份檔案.下面看一下如何把Glibc 2.2.4.13升級至2.3.2版本, 其過程如下:

  1.下載.gz壓縮檔並解壓

在GUN C網站下載的四個.gz壓縮檔, 解壓至一臨時目錄中:
cd /usr/caolinux
tar xzvf glibc-2.3.2.tar.gz
cd glibc-2.3.2
tar xzvf ../glibc-linuxthreads-2.3.2.tar.gz
tar xzvf ../glibc-crypt-2.3.2.tar.gz
tar xzvf ../glibc-localedata-2.3.2.tar.gz

  2.建立庫函數的安裝目錄
mkdir /usr/higlibc
cd /usr/higlibc

   3.建立編譯目錄
mkdir cao
cd cao
./configure --enable-add-ons=linuxthreads,crypt,localedata -prefix=/usr/higlibc

  4.編譯與安裝
make
make check
make install

  5.改變資料庫的連結
ln -s /usr/higlibc/lib/ld-linux.so.2 /lib/ld-linux.so.2

然後, 修改/etc/ld.so.conf, 加入一行/usr/higlibc/lib, 執行下面代碼:
ldconfig -v

更新/etc/ld.so.cache的內容, 列出每個庫的版本號碼, 掃描目錄和所要建立及更新的連結.

 6.更改GCC設定

cd /usr/lib/gcc-lib
cp -r i386-redhat-linux higlibc

 7.更新符號連結
cd /usr/higlibc/include
ln -s /usr/src/linux/include/linux
ln -s /usr/src/linux/include/asm
ln -s /usr/X11R6/include/X11

8.測試並完成

五.進階共用庫特性
 1. soname

共用庫的一個非常重要的, 也是非常難的概念是 soname——簡寫共用目標名(short for shared object name).這是一個為共用庫(.so)檔案而內嵌在控制資料中的名字.如前面提到的, 每一個程式都有一個需要使用的庫的清單.這個清單的內容是一系列庫的 soname, 如同 ldd 顯示的那樣, 共用庫裝載器必須找到這個清單.

soname 的關鍵功能是它提供了相容性的標準.當要升級系統中的一個庫時, 並且新庫的 soname 和老的庫的 soname 一樣, 用舊庫串連產生的程式, 使用新的庫依然能正常運行.這個特性使得在 Linux 下, 升級使用共用庫的程式和定位錯誤變得十分容易.

在 Linux 中, 應用程式通過使用 soname, 來指定所希望庫的版本.庫作者也可以通過保留或者改變 soname 來聲明, 哪些版本是相互相容的, 這使得程式員擺脫了共用庫版本衝突問題的困擾.

查看/usr/local/lib 目錄, 分析 MiniGUI 的共用庫檔案之間的關係

2. 共用庫裝載器

當程式被調用的時候, Linux 共用庫裝載器(也被稱為動態連接器)也自動被調用.它的作用是保證程式所需要的所有適當版本的庫都被調入記憶體.共用庫裝載器名字是 ld.so 或者是 ld-linux.so, 這取決於 Linux libc 的版本, 它必須使用一點外部互動, 才能完成自己的工作.然而它接受在環境變數和設定檔中的配置資訊.

檔案 /etc/ld.so.conf 定義了標準系統庫的路徑.共用庫裝載器把它作為搜尋路徑.為了改變這個設定, 必須以 root 身份運行 ldconfig 工具.這將更新 /etc/ls.so.cache 檔案, 這個檔案其實是裝載器內部使用的檔案之一.

3. 使用 dlopen

另外一個強大的庫函數是 dlopen().該函數將開啟一個新庫, 並把它裝入記憶體.該函數主要用來載入庫中的符號, 這些符號在編譯的時候是不知道的.比如 Apache Web 服務器利用這個函數在運行過程中載入模組, 這為它提供了額外的能力.一個設定檔控制了載入模組的過程.這種機制使得在系統中添加或者刪除一個模組時, 都不需要重新編譯了.

可以在自己的程式中使用 dlopen().dlopen() 在 dlfcn.h 中定義, 並在 dl 庫中實現.它需要兩個參數:一個檔案名稱和一個標誌.檔案名稱可以是我們學習過的庫中的 soname.標誌指明是否立刻計算庫的依賴性.如果設定為 RTLD_NOW 的話, 則立刻計算;如果設定的是 RTLD_LAZY, 則在需要的時候才計算.另外, 可以指定 RTLD_GLOBAL, 它使得那些在以後才載入的庫可以獲得其中的符號.

當庫被裝入後, 可以把 dlopen() 返回的控制代碼作為給 dlsym() 的第一個參數, 以獲得符號在庫中的地址.使用這個地址, 就可以獲得庫中特定函數的指標, 並且調用裝載庫中的相應函數.

六、LINUX下動態連結程式庫的使用
重要的dlfcn.h標頭檔
LINUX下使用動態連結程式庫, 來源程式需要包含dlfcn.h標頭檔, 此檔案定義了調用動態連結程式庫的函數的原型.下面詳細說明一下這些函數.
1. dlerror
原型為: const char *dlerror(void);
當動態連結程式庫操作函數執行失敗時, dlerror可以返回出錯資訊, 傳回值為NULL時表示操作函數執行成功.
2. dlopen
原型為: void *dlopen (const char *filename, int flag);
dlopen用於開啟指定名字(filename)的動態連結程式庫, 並返回操作控制代碼.
filename: 如果名字不以/開頭, 則非絕對路徑名, 將按下列先後順序尋找該檔案.
(1) 使用者環境變數中的LD_LIBRARY值;
(2) 動態連結緩衝檔案/etc/ld.so.cache
(3) 目錄/lib, /usr/lib
flag表示在什麼時候解決未定義的符號(調用).取值有兩個:
1) RTLD_LAZY : 表明在動態連結程式庫的函數代碼執行時解決.
2) RTLD_NOW : 表明在dlopen返回前就解決所有未定義的符號, 一旦未解決, dlopen將返回錯誤.
dlopen調用失敗時, 將返回NULL值, 否則返回的是操作控制代碼.
3. dlsym : 取函數執行地址
原型為: void *dlsym(void *handle, char *symbol);
dlsym根據動態連結程式庫操作控制代碼(handle)與符號(symbol), 返回符號對應的函數的執行代碼地址.由此地址, 可以帶參數執行相應的函數.
如程式碼: void (*add)(int x,int y); /* 說明一下要調用的動態函數add */
add=dlsym("xxx.so","add"); /* 開啟xxx.so共用庫,取add函數地址 */
add(89,369); /* 帶兩個參數89和369調用add函數 */
4. dlclose : 關閉動態連結程式庫
原型為: int dlclose (void *handle);
dlclose用於關閉指定控制代碼的動態連結程式庫, 只有當此動態連結程式庫的使用計數為0時,才會真正被系統卸載.

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.