在類Unix系統中,一個動態庫在其數據段提供了一個 SONAME 字段,用於指定該動態庫的實際連接名稱。該字段在編譯動態庫時經過-Wl,--soname,xxx 選項指定,其中xxx就是實際連接名稱,該實際連接名稱每每同動態庫文件名不一樣。默認狀況下(沒有指定 --soname選項),動態庫的連接名稱就是動態庫的文件名。ios
示例代碼以下:c++
test.cc:spa
#include <iostream>orm
void dumpTest() {
std::cout << "This is dumpTest" << std::endl;
}
main.cc:開發
#include <iostream>io
extern void dumpTest();
int main() {
std::cout << "This is Linux platform" << std::endl;
dumpTest();編譯
return 0;
}
說明:test.cc編譯成動態庫 libtest.so,main.cc編譯連接libtest.so並最終生成可執行文件 main。form
問題:考慮以下應用場景,開發者經過so提供服務,按期更新so版本,並在更新過程當中有可能出現問題須要回退版本。還有可能提供其餘不在主線分支的特定功能版本。這種狀況下,經過傳統的搜索文件名加載動態庫的方式比較麻煩,須要頻繁修改so文件名,或者修改編譯可執行文件的連接選項,極有可能出錯。test
解決辦法:經過 -Wl,--soname,xxx 選項指定實際的連接名稱,-o 選項指定so名稱來解決。這種狀況下,不一樣功能/版本的so文件名不一樣,可是實際的連接名稱都相同,只要建立一個連接名稱的軟鏈接,指向不一樣功能/版本的so,便可方便的切換so。stream
(1)生成多版本的so,文件名不一樣,連接名稱相同(libtest.so):
$ g++ -fPIC -shared -Wl,--soname,libtest.so -o libtest.1.so test.cc
$ g++ -fPIC -shared -Wl,--soname,libtest.so -o libtest.2.so test.cc
$ g++ -fPIC -shared -Wl,--soname,libtest.so -o libtest.3.so test.cc
查看SONAME:
$ readelf -d libtest.3.so
Dynamic section at offset 0xde0 contains 26 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000e (SONAME) Library soname: [libtest.so]
0x000000000000000c (INIT) 0x7d0
0x000000000000000d (FINI) 0x9d0
0x0000000000000019 (INIT_ARRAY) 0x200dc0
0x000000000000001b (INIT_ARRAYSZ) 16 (bytes)
0x000000000000001a (FINI_ARRAY) 0x200dd0
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x1f0
0x0000000000000005 (STRTAB) 0x410
0x0000000000000006 (SYMTAB) 0x230
0x000000000000000a (STRSZ) 417 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000003 (PLTGOT) 0x201000
0x0000000000000002 (PLTRELSZ) 144 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x740
0x0000000000000007 (RELA) 0x620
0x0000000000000008 (RELASZ) 288 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffffe (VERNEED) 0x5e0
0x000000006fffffff (VERNEEDNUM) 2
0x000000006ffffff0 (VERSYM) 0x5b2
0x000000006ffffff9 (RELACOUNT) 4
0x0000000000000000 (NULL) 0x0
(2)生成so的連接文件libtest.so
$ ldconfig -nv .
.:
libtest.so -> libtest.3.so (changed)
該命令搜索當前目錄下的全部so,建立連接庫,並更新連接庫cache。
$ ls -al
-rwxrwxr-x 1 colin colin 8612 Oct 8 11:38 libtest.1.so
-rwxrwxr-x 1 colin colin 8612 Oct 8 11:38 libtest.2.so
-rwxrwxr-x 1 colin colin 8612 Oct 8 11:38 libtest.3.so
lrwxrwxrwx 1 colin colin 12 Oct 8 11:41 libtest.so -> libtest.3.so
-rwxrwxr-x 1 colin colin 9179 Oct 8 11:44 main
(3)編譯生成可執行文件main
$ g++ -L. -o main main.cc -ltest
(4)若是須要更改so,main不須要變更,只須要從新鏈接libtest.so便可:
$ ls -al total 64 -rwxrwxr-x 1 colin colin 8612 Oct 8 11:38 libtest.1.so -rwxrwxr-x 1 colin colin 8612 Oct 8 11:38 libtest.2.so -rwxrwxr-x 1 colin colin 8612 Oct 8 11:38 libtest.3.so lrwxrwxrwx 1 colin colin 12 Oct 8 12:29 libtest.so -> libtest.1.so -rwxrwxr-x 1 colin colin 9179 Oct 8 11:44 main