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

    在類Unix系統中,一個動態庫在其數據段提供了一個 SONAME 字段,用於指定該動態庫的實際鏈接名稱。該字段在編譯動態庫時通過-Wl,--soname,xxx 選項指定,其中xxx就是實際鏈接名稱,該實際鏈接名稱往往同動態庫文件名不同。默認情況下(沒有指定 --soname選項),動態庫的鏈接名稱就是動態庫的文件名。

    示例代碼如下:

    test.cc:

#include <iostream>

void dumpTest() {
    std::cout << "This is dumpTest" << std::endl;
}
    main.cc:

#include <iostream>

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。

    問題:考慮如下應用場景,開發者通過so提供服務,定期更新so版本,並在更新過程中有可能出現問題需要回退版本。還有可能提供其他不在主線分支的特定功能版本。這種情況下,通過傳統的搜索文件名加載動態庫的方式比較麻煩,需要頻繁修改so文件名,或者修改編譯可執行文件的鏈接選項,極有可能出錯。

    解決辦法:通過 -Wl,--soname,xxx 選項指定實際的鏈接名稱,-o 選項指定so名稱來解決。這種情況下,不同功能/版本的so文件名不同,但是實際的鏈接名稱都相同,只要創建一個鏈接名稱的軟連接,指向不同功能/版本的so,即可方便的切換so。

    (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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章