GCC/G++選項 -Wl,--soname,xxx

    在類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

相關文章
相關標籤/搜索