Gcc 非常奇怪的链接器行为

Gcc 非常奇怪的链接器行为,gcc,linker,ld,Gcc,Linker,Ld,这很奇怪,因为我能够通过删除对libm的引用来消除下面的错误 gcc -o example example.o -Wl -L/home/kensey/cdev/lib -L/usr/lib/x86_64-linux-gnu -lmysqlclient -lpthread -lz -L/usr/lib/x86_64-linux-gnu -lm -lrt -ldl -lcdev -L/home/kensey/www.tools/gplot-lib -lgplot -L/home/kensey/w

这很奇怪,因为我能够通过删除对libm的引用来消除下面的错误

gcc -o example example.o -Wl -L/home/kensey/cdev/lib -L/usr/lib/x86_64-linux-gnu   -lmysqlclient -lpthread -lz -L/usr/lib/x86_64-linux-gnu -lm -lrt -ldl -lcdev -L/home/kensey/www.tools/gplot-lib -lgplot -L/home/kensey/www.tools/gd1_3ret -lgd -lxml2 -lcurl
/usr/bin/ld: /home/kensey/www.tools/gplot-lib/libgplot.a(set.o): undefined reference to symbol 'floor@@GLIBC_2.2.5'
/usr/bin/ld: note: 'floor@@GLIBC_2.2.5' is defined in DSO /usr/lib/x86_64-linux-gnu/libm.so so try adding it to the linker command line
/usr/lib/x86_64-linux-gnu/libm.so: could not read symbols: Invalid operation
collect2: ld returned 1 exit status

因此,如果我删除命令的
-lm
部分,就不会得到错误。然而,我想知道是否有人知道为什么删除对所需库的引用会解决这个问题。链接器如何知道要查找哪个库?还有-有没有一种方法可以查询一个构建的可执行文件并说“您解析了对“floor”的引用的哪个库?”?显然,有些事情我不明白,这让我很困扰

很难说。由于命令行中有自定义库目录,
-lm
可以链接不兼容的替代版本。如果没有
-lm
,链接器可能会引入它的另一个版本,因为您链接的某个库需要它

确保
strace
两个调用,并查看
libm.so
在这两种情况下来自何处


顺便说一句,
-Wl
开关似乎什么也不做,而且
-L/usr/lib/x86_64-linux-gnu
被提到了两次。

也许,您的库搜索路径(/usr/local/lib/或/usr/lib/,…)不包含64位libm,因此如果您使用
L
标志指定,gcc无法找到它。如果只指定目录,它看起来可以找到正确的目录。因此,您可以尝试:

LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu


使用
-lm
一种解释可以是:

可能有一个在libm之外定义的弱链接函数
foo
,被libm内部定义的强链接版本
foo
所取代,而正是这个强链接版本调用了未定义的函数


这将解释添加库如何导致未定义的函数错误。

对发生的情况的解释非常简单:

  • 您的
    libgplot.a
    依赖于
    libm.so
    ,但是链接行上
    -lm
    -lgplot
    的顺序是错误的。 链接行上的库的顺序不会改变。一般来说,系统库(
    -lpthread
    -lm
    -lrt
    -ldl
    )应遵循链接线上的所有其他内容

  • 当您从链接行中删除
    -lm
    时,
    libm.so.6
    仍然被链接行后面出现的其他库拉入链接中(
    libgd
    libxml2
    libcurl
    ),因为该库依赖于
    libm.so.6
    )。但是现在,
    libm.so.6
    在链接行中的位置正确,所以一切正常

  • 如果我将-lm放在link命令的末尾,将其列为最后一个库,则不会出现错误


    这证实了上述解释。

    我已经解决了与导出LDFLAGS=“$LDFLAGS-lm”相同的问题,只需添加到答案列表中,这是一个信息性问题。这与上面提出的问题无关,但是,解释与错误消息有关:注意:“some_reference”是在DSO some中定义的。因此,请尝试将其添加到链接器命令行中

    我刚刚遇到了类似的问题;我记得在过去的gcc中,库的顺序并不重要(至少在我处理的案例中不重要)。有人注意到,行为似乎在4.4和4.5之间发生了变化

    在我的例子中,我通过在以下位置进行链接来消除错误消息:

     g++ -Wl,--copy-dt-needed-entries [options] [libraries] [object files] -o executable-file
    
    使用以下命令:

    administrator@administrator-Veriton-M200-H81:~/ishan$ gcc polyscanline1.cpp -lglut -lGLU -lGL -lm
    

    请注意,符号已进行版本控制。它仍然适用吗?@MaximYegorushkin:不确定,抱歉。我认为未定义符号的版本与我可能的诊断是正交的。好吧,我又玩了一些,如果我把-lm放在link命令的末尾,将其列为最后一个库,我不会得到错误。非64位libm的理论可能仍然如此,因为它可能在命令末尾到达-lm之前“找到正确的一个”,因此-lm基本上被忽略。仅供参考-我通过“ar-t”查询了libm,它列出了库的内容。因此,这意味着它的64位/searchable.open(“/lib/x86_64-linux-gnu/libm.so.6”,O|RDONLY | O|u CLOEXEC)=3读(3,“\177ELF\2\1\1\0\0\0\0\0\0\0\0\0pU\0\0\0\0\0”…,832)=832 fstat 3,{st\u mode S=S\ifu reg}44,st\u size=1022320,{
    kensey@kensey:~/cdev$strace./example 2>&1|grep libm open(/usr/lib/x86|u 64-linux-gnu/libmysqlclient.so.18),O|RDONLY | O|u CLOEXEC)=3 open(/lib/x86|u 64-linux-gnu/libm.so.6”,O|RDONLY | O|CLOEXEC)=3
    因此,我不确定这是一个问题的原因,但幸运的是它消失了。我想教训是:确保图书馆排在其他可能引用它们的图书馆之后。strace可能有一种方法可以做更多的调查,但我不熟悉这个工具。谢谢你的帮助!事实上,在我看来,这是相对于早期版本的GNU工具链的一种行为改变。如果我没记错的话,过去给出的库的顺序对于gcc来说是不相关的,它足够聪明地找到了符号。在AIX上使用xlC时,如果我过去也没有记错的话,顺序很重要,
    -Wl
    选项后面通常跟一个逗号(将逗号后面的文本作为选项传递给链接器),您打算用它做什么?GCC版本与此无关,你说的是一个链接器的改变,而不是编译器的改变;明确添加
    -lm
    是问题所在。非常感谢。你能解释一下这是怎么回事吗?
    -lm
    用于链接标准C数学库我的问题并不完全是原始问题,但在我的LDFLAGS定义末尾的makefile中添加-lm是有效的。谢谢