Shared Libraries

  1. Shared Libraries

共用函式庫( Shared libraries ),是一個被編譯後的程式碼,用途是拿來在不同的程式之間共享的,通常會在/usr/lib/裡面以.so的形式存在。 一個「 library exports symbols 」是一個被編譯過的函式, 類別(class)和變數的table。一個函式庫裡面有一個名字-「SONAME」這個欄位會包含一組版本號碼。這個SONAME版本不一定要跟實際上的release版本號碼一樣。通常剛被編譯的程式的版本都會跟函式庫的SONAME版本不一樣。如果任何一個symbol被移除或改變了,那這個版本號碼就必須要被改變,因為必須強制任何的套件使用這個新的函式庫來重新編譯。 版本號碼通常是由upstream來設定,而我們就是隨著ABI number來更改就好,但是有時候upstream不一定會使用sensible版本並且套件必些保持在分散的版號。

函式庫通常都是由upstream以獨立發行的方式發布,有時候他們只會發布部分的程式。在這個案例中,函式庫是被包含在binary package(bundling)中,如果你不期望其他的程式會使用這個函式庫,通常應該要獨立分開到其他的binary package中。

這些函式庫本身被放在binary package裡面,名字格式為「libfoo1」,foo是這個函式庫的名字,而1是從SONAME來的版本。套件裡的開發檔,像是標頭檔之類的,編譯時必須要隨著這些函式庫(將其放到一個套件叫做「libfoo-dev」)。

10.1. An Example

我們這邊會使用「libnova」為例子:

$ bzr branch ubuntu:trusty/libnova
$ sudo apt-get install libnova-dev

執行底下的指令來找到SONAME:

$ readelf -a /usr/lib/libnova-0.12.so.2 | grep SONAME

以上的例子,SONAME為 libnova-0.12.so.2,跟我們的檔名符合。這個upstream將版號弄成跟部分的SONAME一樣,並且給了他ABI版本2。函式庫的套件名字必須符合它們自己包含的函式庫的SONAME。這個函式庫 binary package叫做「 libnova-0.12-2 」, libnova-0.12是函式庫名稱,2則是ABI號碼。

如果upstream在它們的函式庫裡有不相容的change,它們將會倒回去它們的SONAME,這時候我們就必須要重新命名我們的函式庫。所有在我們函式庫套件裡面會用到的其他套件都必須要重新編譯,如果有新版本的話,通常這樣都是過渡期,而且會花費一些時間。通常這時候我們都會希望我們的ABI號碼將會繼續符合upstream的SONAME,但是有時候因為upstream沒有更改它們的版號,所以會產生不相容的問題,這時候我們就要改變我們的。

在「 debian/libnova-0.12-2.install 」裡面我們可以看到有兩個檔案:

usr/lib/libnova-0.12.so.2
usr/lib/libnova-0.12.so.2.0.0

最後一個是一個真的函式庫,有著minor和point版號。而第一個則是一個指到第二的檔案的鏈結 (symlink)。這個鏈結檔是所有會使用這個函式庫的的程式會使用的,因為會用函式庫的程式根本不管那些minor版號。

libnova-dev.install包含了一個程式,它會隨著這個函式庫在編譯時所需要的所有檔案:「標頭檔」,「組態」,「.la litbool檔」和「 libnova.so 」。 libnova.so是指到函式庫的另一個鏈結檔,程式隨著這個函式庫在編譯時根本不管major版號。

.la libtool 檔會使用在其他非Linux且沒什麼函式庫支援的的系統上,而且通常也會比在Debian系統上製造更多的麻煩。網頁「 Debian goal to remove .la files 」有更多的訊息。

10.2. Static Libraries

-dev package也會送到 usr/lib/libnova.a,而這就是一個靜態(static)的函式庫,這是共用函式庫的另外一種替代方式。任何會用到這個函式庫的程式,在編譯時期都需要直接將這個靜態函式庫給編譯進去。 然而這樣代表任何的bug或是security的問題,都需要跟著函式庫編譯過以後才可以,無法像共用函式庫一樣,替代掉函式庫就好了。所以其實真的不鼓勵靜態函式庫的使用。

10.3. Symbol Files

當一個套件隨著它的函式庫在被建置時,shlibs機制會在這個函式庫上加一個套件相依性。這就是為什麼大部分程式在debian/control上會有 Depends: ${shlibs:Depends}。這個在建置時都會被函式庫相依性所取代掉。然而shlibs只可以讓它相依於major ABI版號 - 2(在我們舉的libnova例子裡),所以如果有新的符號表(Symbol)被新增在libnova2.1裡,一個有使用的程式依然可以安裝 libnova ABI 2.0並使用這些符號表,但是用了以後將會crash掉。

為了讓這些函式庫相依性更加精準,所以在函式庫裡將「.symbols」檔案持續著列出所有的符號表。

libnova裡面沒有symbols檔,所以我們需要經由編譯這個套件來建一個,

$ bzr builddeb -- -nc

「-nc」將會在沒有移除已經建置好的檔案的情況下去建置檔案,接下來是執行「 dpkg-gensymbols 」:

$ cd ../build-area/libnova-0.12.2/
$ dpkg-gensymbols -plibnova-0.12-2 > symbols.diff

下一步會建立一個diff檔,你可以自己套用:

$ patch -p0 < symbols.diff

上一個步驟會建立一個檔案,名稱會類似於「 dpkg-gensymbolsnY_WWI 」,這個檔案會列出所有的符號,也會列出所有目前的套件版本。我們可以從符號表裡面移除這個版號,因為新的符號是由upstream增新的。

$ sed -i s,-0ubuntu2,, dpkg-gensymbolsnY_WWI

接下來就是移動檔案到相對應的位置上去,commit和測試:

$ mv dpkg-gensymbolsnY_WWI ../../libnova/debian/libnova-0.12-2.symbols
$ cd ../../libnova
$ bzr add debian/libnova-0.12-2.symbols
$ bzr commit -m "add symbols file"
$ bzr builddeb

如果成功的編譯了這個符號表,隨著libnova的下一個upstream版本,你只要再次執行「 dpkg-gensymbols 」它就會產生一個diff來更新符號檔。

10.4. C++ Library Symbols Files

C++裡面有比C更多的二進制相容性的標準。Debian Qt/KDE團隊維護了許多的scripts來處理這個,這部分請參考網頁「 Working with symbols files 」,這邊會教你怎麼使用。

10.5. Further Reading

Junichi Uekawa的網頁 Debian Library Packaging Guide 裡面有更多相關的訊息。


Ref:
http://packaging.ubuntu.com/html/libraries.html

results matching ""

    No results matching ""