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

相关文章
相关标签/搜索