强制GCC在共享库中通知未定义引用的情况

68

我有一个被链接到另一个(第三方)共享库的共享库。然后在我的应用程序中使用 dlopen 加载我的共享库,一切都正常工作(假设文件在正确的路径下等)。

现在的问题是,当我链接我的库时,我甚至不需要指定链接第三方共享库。GCC接受它而不报告有关未定义引用的错误。所以,问题来了: 我如何强制 GCC 通知我有关未定义引用的问题

如果我将我的库更改为(暂时)可执行文件,则会出现未定义的引用(当没有向链接器提供该库时)。 (如果我指定链接器可以使用该库,则正常工作。)

也就是说,进行了以下操作:

g++ -fPIC -shared -o libb.so b.o 
g++ -fPIC -shared -o liba.so a.o
g++ -o a.exe a.cpp 

第二行代码不会报错,而第三行代码会抱怨未定义的引用。

示例代码:

a.h:

class a
{
public:
    void foobar();
};

a.cpp:

#include "a.h"
#include "b.h"

void a::foobar()
{
    b myB;
    myB.foobar();
}

int main()
{
    a myA; myA.foobar();
}

b.h:

class b
{
public:
    void foobar();
};

b.cpp:

#include "b.h"

void b::foobar()
{
}
2个回答

70

在构建共享库时,-Wl,--no-undefined 链接器选项可以使用,未定义的符号将显示为链接器错误。

g++ -shared -Wl,-soname,libmylib.so.5 -Wl,--no-undefined \
    -o libmylib.so.1.1 mylib.o -lthirdpartylib

你能提供链接器输出吗? - Dmitry Yudakov
嗯,我记得之前做过这个,但没有得到任何输出。再次尝试后似乎可以正常工作了(也就是说,我收到了一个错误!) - Fredrik Ullner
2
我将-Wl,-no-undefined编辑为-Wl,--no-undefined(正如ld手册所说),尽管这两种情况对我来说都有效。 - Dmitry Yudakov

24
经过更多的研究,我意识到了处理这种情况的方式。有两个链接器选项可以操作共享库中未定义的符号:
第一个是--no-undefined。它会在链接阶段立即报告未解析的未定义符号。除非该符号在链接的共享库中被手动(使用-l开关)或自动(libgcc_s、C++运行时;libc、C运行时;ld-linux-**.so、动态连接器实用程序)找到,否则--no-undefined将其报告为错误。这就是提问者所需要的关键。
还有另外一个重要的选项,--no-allow-shlib-undefined(描述也建议使用--no-undefined)。它检查您链接共享库时是否满足共享库中的定义。这个选项在本主题中显示的情况下用处不大,但它可能很有用。然而,它也有自己的障碍。
手册提供了一些关于为什么它不是默认值的基本原理:
   --allow-shlib-undefined
   --no-allow-shlib-undefined
       Allows  (the  default)  or  disallows  undefined  symbols  in  shared
       libraries (It is meant, in shared libraries _linked_against_, not the
       one we're creating!--Pavel Shved). This switch is similar to --no-un-
       defined except  that it determines  the  behaviour when the undefined
       symbols are in a shared library rather than a regular object file. It
       does not  affect  how  undefined  symbols in regular object files are
       handled.

       The  reason  that  --allow-shlib-undefined is the default is that the
       shared library being specified at link time may not be  the  same  as
       the one that is available at load time, so the symbols might actually
       be resolvable at load time.  Plus there are some systems,  (eg  BeOS)
       where  undefined  symbols in shared libraries is normal.  (The kernel
       patches them at load time to select which function is most  appropri-
       ate for the current architecture.  This is used for example to dynam-
       ically select an appropriate memset function).  Apparently it is also
       normal for HPPA shared libraries to have undefined symbols.

问题在于上面所说的也适用于Linux系统,其中一些共享库的内部例程是在ld-linux.so中实现的,即动态加载器(它既是可执行文件又是共享库)。除非您以某种方式将其链接,否则您将会得到类似以下的输出:

/lib64/libc.so.6: undefined reference to `_dl_argv@GLIBC_PRIVATE'
/lib64/libc.so.6: undefined reference to `_rtld_global_ro@GLIBC_PRIVATE'
/usr/lib64/gcc/x86_64-suse-linux/4.3/libstdc++.so: undefined reference to `__tls_get_addr@GLIBC_2.3'
/lib64/libc.so.6: undefined reference to `_rtld_global@GLIBC_PRIVATE'
/lib64/libc.so.6: undefined reference to `__libc_enable_secure@GLIBC_PRIVATE'

这些是来自于加载器 ld-linux.so 的未定义引用。它是特定于平台的(例如,在我的系统上,正确的加载器是 /lib64/ld-linux-x86-64.so)。您可以将加载器链接到您的库并检查上面显示的复杂引用:

g++ -fPIC -shared -o liba.so a.o -Wl,--no-allow-shlib-undefined  /lib64/ld-linux-x86-64.so.2

没有错误,无论我使用--no-allow-shlib-undefined还是--no-undefined。 - Fredrik Ullner
@Fredrik,我猜你忘记添加-Wl,的东西了。虽然它确实显示错误,但不是你想要的那个。但这已经是你能得到的最多了。 - P Shved
看起来 --no-undefined 的效果符合预期,但是 --no-allow-shlib-undefined 却不行。(像你说的那样工作。) - Fredrik Ullner
1
@Fredrik,谢谢。我已经修复了我的完全错误的帖子,希望对你有所帮助。 - P Shved
1
引用的 manpage 文本已经 更改,因为默认值已更改为 --no-allow-shlib-undefined - Ben C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接