链接一个.so与其他符号时的未定义符号

时间:2014-12-11 11:56:16

标签: c linux gcc shared-libraries

a.so定义函数A()b.so定义函数B()并调用A()中定义的a.sob.soa.so相关联,如下所示

gcc -fPIC -shared B.c -o libb.so -la

现在我创建了一个调用B()

中定义的b.so的二进制文件
gcc mybin.c -o mybin -lb

gcc正在检查b.so中的每个符号,并抛出错误,指出A()未定义。

gcc mybin.c -o mybin -lb -la

上述工作但我必须将mybin与a.so相关联,即使它与a.so没有直接关系。我的要求是,如果b.soa.so正确关联,那么将 mybin b.so相关联就可以了。

这可能吗?

3 个答案:

答案 0 :(得分:3)

链接可执行文件时,链接器想要知道libb.so所需的库是否存在,以便它可以检查它们是否解析了libb.so中的任何未定义引用

链接器在通常的位置查找所需的库,因此如果找不到liba.so,那么您可以使用LD_LIBRARY_PATH告诉链接器在哪里查看,如另一个答案所示,或者通过使用专门为此目的而存在的链接器选项-rpath-link

gcc mybin.c -o mybin -lb -Wl,-rpath-link=.

-Wl,前缀是告诉GCC将选项传递给链接器的方式,这是GCC不直接了解的链接器选项所必需的。)

或者,您可以告诉链接器在libb.so中允许未定义的符号,在这种情况下,它不会尝试查找liba.so来解析对A()的引用,并相信您将正确链接并确保库在运行时可用。这是通过--allow-shlib-undefined选项完成的:

gcc mybin.c -o mybin -lb -Wl,--allow-shlib-undefined

但是,通常最好让链接器检查所有符号是否已定义,并告诉它如何找到所需的库,因为它会更快地发现实际问题。

-rpath-link选项 only 告诉链接器在哪里寻找其他共享库,它对链接的可执行文件没有可见的影响(即它不记录库的路径在可执行的任何地方)。另一种方法是创建libb.so,以便它包含如何查找嵌入其中的liba.so的知识。这是通过-rpath链接器选项完成的,例如如果liba.so位于/some/path,您可以执行以下操作:

gcc -fPIC -shared B.c -o libb.so -la -Wl,-rpath=/some/path

这会在DT_RPATH中放置libb.so标记,链接器将使用它来查找其依赖项:

readelf -d libb.so  | fgrep RPATH
 0x000000000000000f (RPATH)              Library rpath: [/some/path]

现在您可以链接可执行文件而无需任何liba.so知识,链接器将看到libb.so需要liba.so并将使用RPATH来查找它:

gcc mybin.c -o mybin -lb

如果路径/some/path/liba.so已修复,则此方法可以正常工作,但在开发期间和部署可执行文件后,可能无法在同一位置找到该库。在这种情况下,您仍然可以使用-rpath-link将可执行文件告诉链接器在链接期间在哪里查找它,并依赖RPATH在运行时查找它。或者,您可以在RPATH中使用特殊字符串$ORIGIN,动态链接器将其扩展到包含RPATH的对象的位置,例如,如果liba.solibb.so始终位于同一目录中,您可以像这样链接libb.so(注意引号以防止shell展开$ORIGIN):

gcc -fPIC -shared B.c -o libb.so -la '-Wl,-rpath=$ORIGIN'

readelf -d libb.so  | fgrep RPATH
 0x000000000000000f (RPATH)              Library rpath: [$ORIGIN]

答案 1 :(得分:2)

缺失的位是LD_LIBRARY_PATH

export LD_LIBRARY_PATH=.
gcc -fPIC -shared a.c -o liba.so
gcc -fPIC -shared b.c -o libb.so -la
gcc mybin.c -o mybin -lb -L.

-L不起作用的原因似乎是这个标志用于«将目录dir添加到要搜索的目录列表 for -l <​​/ strong>»,请参阅{{3 }}。并且libba.so中未指定-l

答案 2 :(得分:0)

以下是步骤:

gcc -fPIC -shared a.c -o liba.so
gcc -fPIC -shared b.c -o libb.so
gcc mybin.c -o mybin -lb -la -L.    # -L to look for the directory to load .so files

Then make sure you do:
export LD_LIBRARY_PATH=<your_directory>

你需要在gcc mybin.c -o mybin -lb -la -L中提到liba.so和libb.so。因为函数A()需要在运行时加载。 b.so没有链接a.so.链接发生在共享库中的运行时。它们已编译,并且未解析对函数或外部变量的任何引用。

如果要包含b.so但不包含a.so,则将b编译为静态库,从而将a加载到其二进制文件中。然后当你编译mybin时,你只需要b.lib