引用自:
(換句話說,soname不是真實存在的檔案,只是在此庫中和將來呼叫此庫的檔案中儲存的乙個名字,在載入時去找這個名字,使用時建立乙個軟連線來指向真實檔案,這樣真實檔案的版本號就可以公升級了)
linux 系統,也同樣面臨和window一樣的問題,如何控制動態庫的多個版本問題。window之前沒有處理好,為此專門有個名詞來形容這個問題 「dll hell」,其嚴重影響軟體的公升級和維護。 dll hell 是指windows 上動態庫新版本覆蓋舊版本,但是卻不相容老版本。常常發生在程式公升級之後,動態庫更新,原有程式執行不起來;或者裝新軟體,但是已有的軟體執行不起來。 同樣linux作業系統,也有同樣的問題,那麼它是怎麼解決的呢?
linux 為解決這個問題,引入了一套機制,如果遵守這個機制來做,就可以避免這個問題。 但是這只事乙個約定,不是強制的。但是建議遵守這個約定,否則同樣也會出現 linux 版的dll hell 問題。 下面來介紹乙個這個機制。 這個機制是通過檔名,來控制dll (shared library) 的版本。
linux 上的dll ,叫shared library,其有三個名字,分別有不同的目的。
第乙個是共享庫本身的檔名(real name),其通常包含版本號,常常是是這樣: libmath.so.1.1.1234 。 lib是linux 上的庫的約定字首,math 是共享庫名字,so 是共享庫的字尾名,1.1.1234的是共享庫的版本號,其主版本號+小版本號+build號。主版本號,代表當前動態庫的版本,如果動態庫的介面有變化,那麼這個版本號就要加1;後面的兩個版本號(小版本號 和 build 號)是告訴你詳細的資訊,比如為乙個hot-fix 而生成的乙個版本,其小版本號加1,build號也應有變化。 這個檔名包含共享庫的**。
第二個是動態庫的soname( short for shared object name),其是應用程式載入dll 時候,其尋找共享庫用的檔名。其格式為
lib + math+.so + ( major version number)
其只包含major version number,換句話說,也就是只要其介面沒有變,應用程式都可以用,不管你其後minor build version or build version。
問題來了,程式執行時怎麼通過soname 找個real name? soname 存在**?如果與real name 關聯起來?什麼時候存的?
這就是接下來要介紹的第三個共享庫的名字,link name,顧名思義,就是在編譯過程,link 階段用的檔名。 其將sonmae 和real name 關聯起來。
第三個名字,共享庫的連線名(link name),是專門為build 階段連線而用的名字。這個名字就是lib + math +.so ,比如libmath.so。其是不帶任何版本資訊的。在共享庫編譯過程中,連線(link) 階段,編譯器將生成乙個共享庫及real name,同時將共享庫的soname,寫在共享庫檔案裡的檔案頭裡面。可以用命令 readelf -d sharelibrary 去檢視。
在應用程式引用共享庫時,其會用到共享庫的link name。在應用程式的link階段,www.linuxidc.com其通過link名字找到動態庫,並且把共享庫的soname 提取出來,寫在自己的共享庫的標頭檔案裡面。當應用程式載入時就會通過soname 去給定的路徑下尋找該共享庫。
下面通過這個**來說明一下系統是如何做的,並且介紹系統的一些設施和工具:
**:
1. file libhello.c
/* hello.c - demonstrate library use. */
#include
void hello(void)
2. file libhello.h
/* libhello.h - demonstrate library use. */
void hello(void);
3. file main.c
/* main.c -- demonstrate direct use of the "hello" routine */
#include "hello.h"
int main(void)
1.生成共享庫,關聯real name 和soname 。
gcc -g -wall -fpic -c hello.c -o hello.o
gcc -shared -w,soname,-libhello.so.0 -o libhello.so.0.0.0 hello.o
將會生成共享庫libhello.so.0.0.0.
可以用系統提供的工具檢視共享庫的頭:
readelf -d libhello.so.0.0.0 | grep libhello
ox00000000000e(soname) library soname: [libhello.so.0]
2.應用程式,引用共享庫。
先手動生成link 名字,以被後面的程式鏈結時用
ln -s libhello.so.0.0.0 libhello.so.0
gcc -g -wall -c main.c -o main.o -i.
gcc -o main main.o -lhello -l.
檢視編譯出來的程式:
readelf -d main | grep libhello
ox000000000001(needed) shared library: [libhello.so.0]
執行該程式,需要指定共享庫的路徑。 有兩種辦法,第一種使用環境變數「ld_library_path」. 兩外一種辦法就是將共享庫拷貝到系統目錄(path 環境變數指定的其中乙個目錄)。
暫停! 我們還沒有解決乙個問題是,程式只知道soname,怎麼從soname 找到共享庫,即real name 檔案呢? 這需要我們定義乙個link檔案,連線到共享庫本身。
ln -s libhello.so.0.0.0 libhello.so.0
當然這個路徑需要放到ld_library_path環境變數中。
這樣就可以執行該程式。
[note]linux 系統提供乙個命令 ldconifg 專門為生成共享庫的soname 檔案,以便程式在載入時後通過soname 找到共享庫。 同時該命令也為加速載入共享庫,把系統的共享庫放到乙個快取檔案中,這樣可以提高查詢速度。可以用下面命令看一下系統已有的被快取起來的共享庫。
ld -p
CentOS 如何解決gcc版本衝突?
今天碰到乙個比較坑爹的問題,在centos上用yum安裝編譯環境,執行 yum y install make gcc gcc c kernel devel m4 ncurses devel openssl devel 結果導致編譯cocos2d x出現錯誤 cc1plus error unrecog...
Linux誤刪libgcc如何解決
在新學習linux時,由於一些不小心的操作從而導致了比較驗證的問題。這裡就是我在初學linux是所遇到的問題,在安裝如那件是由於軟體衝突,不小心把libgcc軟體給刪除了 比如執行了 rpm e nodeps libgcc xx命令 這裡需要的解決辦法就是在其他的跟你系統相同下面拷貝乙個相同的檔案即...
linux如何解決中文亂碼
檢視系統當前字符集 echo lang locale 檢查xshell crt的字符集 命令修改字符集 vim etc profile.d locale.sh export lc ctype zh cn.utf 8export lc all zh cn.utf 8 vim etc locale.co...