链接错误:"对符号`xmlFree'的重定位R_X86_64_PC32...重新编译时请加上-fPIC",但是有问题的库已经使用了-fPIC进行编译。

3

我正在尝试构建一个共享库。我的目的是将所有依赖项作为静态库引入到单个共享库中。我的理解是可以使用-Wl,--whole-archive标志来完成此操作。以下是负责配置共享库的CMake脚本片段。

    # shared library
    add_library(semsim SHARED "${SEMSIM_HEADERS}" "${SEMSIM_SOURCES}") # created the shared library
    #fPIC for linux shared library strs
    set_property(TARGET semsim PROPERTY POSITION_INDEPENDENT_CODE ON) #turn fPIC on 
    target_compile_options(semsim PRIVATE -Wl,--whole-archive) # enable pulling static libraries into shared library

我在编译时遇到了错误(打开了详细模式),错误信息如下:
/usr/bin/c++ -fPIC -std=c++14 -g  -shared -Wl,-soname,libsemsim.so -o libsemsim.so CMakeFiles/semsim.dir/CurlGet.cpp.o CMakeFiles/semsim.dir/RDFNode.cpp.o CMakeFiles/semsim.dir/Subject.cpp.o CMakeFiles/semsim.dir/Predicate.cpp.o CMakeFiles/semsim.dir/Resource.cpp.o CMakeFiles/semsim.dir/Triple.cpp.o CMakeFiles/semsim.dir/SemsimUtils.cpp.o CMakeFiles/semsim.dir/MetaID.cpp.o CMakeFiles/semsim.dir/XmlAssistant.cpp.o CMakeFiles/semsim.dir/Reader.cpp.o CMakeFiles/semsim.dir/Editor.cpp.o CMakeFiles/semsim.dir/Writer.cpp.o CMakeFiles/semsim.dir/RDF.cpp.o CMakeFiles/semsim.dir/Participant.cpp.o CMakeFiles/semsim.dir/PhysicalEntity.cpp.o CMakeFiles/semsim.dir/PhysicalPhenomenon.cpp.o CMakeFiles/semsim.dir/PhysicalProcess.cpp.o CMakeFiles/semsim.dir/PhysicalPropertyResource.cpp.o CMakeFiles/semsim.dir/PhysicalForce.cpp.o CMakeFiles/semsim.dir/Query.cpp.o CMakeFiles/semsim.dir/SemsimCombineArchive.cpp.o CMakeFiles/semsim.dir/Triples.cpp.o ../../third_party/libCombine-0.2.3/INSTALL/lib/libcombine-static.a ../../third_party/zipper/INSTALL/lib/libZipper-static.a ../../third_party/zlib-1.2.11/INSTALL/lib/libz.a /usr/local/lib/libbz2.a /usr/local/lib/libxml2.a -ldl -lbz2 -lz -lcurl -lxslt 
/usr/bin/ld: /usr/local/lib/libxml2.a(uri.o): relocation R_X86_64_PC32 against symbol `xmlFree' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status

然而,根据这个问题,/usr/local/lib/lxml2.a 已经使用 fPIC 编译完成:

(base) ciaran@DESKTOP:/usr/local/lib$ ls
cmake            libcharset.so.1.0.0  libraptor2.a         librasqal.la        librdf.so        libxml2.so.2
libbz2.a         libcurlcpp.a         libraptor2.la        librasqal.so        librdf.so.0      libxml2.so.2.9.10
libcharset.a     libiconv.la          libraptor2.so        librasqal.so.3      librdf.so.0.0.0  pkgconfig
libcharset.la    libiconv.so          libraptor2.so.0      librasqal.so.3.0.0  libxml2.a        python2.7
libcharset.so    libiconv.so.2        libraptor2.so.0.0.0  librdf.a            libxml2.la       python3.6
libcharset.so.1  libiconv.so.2.6.1    librasqal.a          librdf.la           libxml2.so       xml2Conf.sh
(base) ciaran@DESKTOP:/usr/local/lib$ readelf -d libxml2.a | grep TEXT
(base) ciaran@DESKTOP:/usr/local/lib$

这让我觉得可能我误解了错误信息 - 有人可以解释一下这里到底发生了什么吗?

1
顺便提一下,--whole-archive 是一个链接器选项,通过 target_compile_options 将其传递给编译器是没有意义的。 - Tsyvarev
1个回答

3

您没有误解错误消息,或者至少不是显著的误解。

然而,根据这个问题,/usr/local/lib/lxml2.a已经被编译为fPIC。

您得出这个结论的原因是以下命令:

/usr/local/lib$ readelf -d libxml2.a | grep TEXT

输出为空,这表明您选择了第二个最受欢迎的答案来回答那个问题,虽然在撰写本文时它的赞数不如最受欢迎的答案

我猜你这样做是因为最受欢迎的答案告诉你如何测试一个目标文件是否为PIC,而你想要测试一个库,就像第二个最受欢迎的答案一样。或者因为你先尝试了最受欢迎的答案,它指出你的libxml2.aPIC。

但是第二个最受欢迎的答案测试的是共享库,而你使用它来测试静态库中的目标文件。共享库与目标文件或这样的静态库非常不同,提出这个答案的问题是关于如何测试一个目标文件是否为PIC。因此,这个答案并没有回答这个问题:实际上它建议如何测试一个名字类似于共享库的文件是否真的是共享库。

最受欢迎的答案回答了这个问题,如果它是正确的答案,那么它也将是适合你的正确答案,因为链接器已经诊断出:

/usr/local/lib/libxml2.a(uri.o): relocation R_X86_64_PC32 against symbol `xmlFree' \
can not be used when making a shared object; recompile with -fPIC

问题在于对象文件 uri.o 被归档在 libxml2.a 中,并且不是 PIC。

但是,尽管最流行的答案非常受欢迎,但它是无效的。它提出的 PIC 测试 - 没有支持的论据 - 可以将非 PIC 对象文件误认为是 PIC(正如您可能观察到的那样)。

对于您而言,没有一个那个问题的答案是正确的,而且真的无关紧要。系统链接器本身是确定对象文件是否是位置独立的最终权威。任何单行测试除尝试将对象文件链接到 DSO 外都只是试图猜测链接器:如果其结论与链接器不同,则意味着测试已损坏,而不是链接器。

而您已经知道链接器的结论。它尝试将 libxml2.a(uri.o) 链接到 DSO 中,并发现它无法这样做,因为其中包含非位置独立的重定位记录。

您拥有的 /usr/local/lib/libxml2.a 是根据传统默认假设构建的,即存档在其中的对象文件不需要编译为位置独立代码(使用 -fPIC),因为静态库仅用于非位置独立可执行文件的链接。如果您想链接一些 PI 二进制文件,那么将使用按定义是 PI 的共享库 libxml2.so 进行链接。此外,您的 libxml2.a 是使用默认情况下不发出 PI 对象代码的编译器构建的。您当前使用的编译器可能仍然具有这种越来越过时的特性,但您不需要找到它。

您需要用编译了 fPIC 的对象文件替换本地的 libxml2 安装。如果您已经知道如何做到这一点,可以跳过其余部分并继续进行。

如果您在某个地方获得了已构建和安装的 libxml2 源包,并且希望坚持该版本,则请进入其根目录并运行:

make uninstall

否则,作为root用户,删除所有与/usr/local/lib/libxml2和目录/usr/local/include/libxml2匹配的文件和符号链接来卸载安装。
如果您想使用已经存在的源代码包(在其中运行了make uninstall),则在其根目录中运行:
make distclean

恢复到原始状态。

如果您没有想要使用的源包,则可以从https://gitlab.gnome.org/GNOME/libxml2/克隆或下载并提取最新版本,然后cd到根目录并运行:

./autogen.sh

生成构建系统。

无论你之前做了什么,在包根目录下运行以下命令:

./configure CFLAGS=-fPIC [any other non-default configuration options]

如果成功完成,那么运行以下命令:
make

如果成功完成,那么请以root身份运行以下命令:
make install

如果成功完成,/usr/local/lib/libxml2.a 将被重新创建,其中包含 PI 对象文件,您将能够将共享库与其链接。
如果您对 ./configure 命令的任何其他非默认配置选项不确定,则运行:
./configure -h

提前寻求帮助和/或寻求建议。


哇,谢谢你详细的回答。我很感激你的努力!实际上,我已经通过获取源代码并使用 CMAKE_POSITION_INDEPENDENT_CODE=ON 重新构建来解决了这个问题,我猜这和你所建议的是一样的。你确实帮助我理解了这里发生了什么。 - CiaranWelsh

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