首页 > 解决方案 > 链接器错误:“针对符号 `xmlFree' 重新定位 R_X86_64_PC32 ... 使用 -fPIC 重新编译”但有问题的库已经使用 -fPIC 进行了编译

问题描述

我正在尝试建立一个共享库。我的目标是将所有依赖项作为静态库拉到一个共享库中。我的理解是,这可以通过-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$

这让我相信,也许我误解了错误信息——有人能解释一下这里发生了什么吗?

标签: c++linuxcmakeshared-librariesfpic

解决方案


您没有误解错误消息,或者至少没有严重误解。

但是,根据this question,/usr/local/lib/lxml2.a 已经编译fPIC

你得出这个结论是因为命令:

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

什么都不输出,这表明您选择了该问题的第二受欢迎的答案,尽管在撰写本文时,它的投票率远不及最受欢迎的答案

我猜您这样做是因为最受欢迎的答案告诉您如何测试目标文件的 PIC 特性,并且您想要测试一个库,就像第二个最受欢迎的答案一样。或者可能是因为您首先尝试了最受欢迎的答案,它表明您libxml2.a PIC。

但是第二个最受欢迎的答案是测试共享库,您可以使用它来测试静态库中的目标文件。共享库与目标文件或此类的静态库非常不同,给出此答案的问题是如何测试目标文件的 PIC-ness 。所以这个答案没有回答这个问题:实际上它建议如何测试一个名称像共享库的文件是否真的是一个共享库。

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

/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-ness 测试 - 没有支持论据 - 可能会将非 PIC 目标文件错误地识别为 PIC(正如您所观察到的那样)。

这个问题的答案对你来说都不是正确的答案,为什么也不重要。系统链接器本身是对象文件是否与位置无关的最终权威。除了尝试将目标文件链接到 DSO 之外,任何单行测试都只是尝试对链接器进行二次猜测:如果其判断与链接器不同,则意味着测试已损坏,而不是链接器。

而且您已经知道链接器的判断。它试图链接libxml2.a(uri.o) 到一个 DSO 并发现它不能,因为它包含一个非位置无关的重定位记录。

您所/usr/local/lib/libxml2.a拥有的是建立在传统的默认假设之上,即归档在其中的目标文件不需要编译为与位置无关的代码(使用-fPIC),因为静态库只会输入到非位置无关的可执行文件的链接中。如果你想链接一些 PI 二进制文件,那么你将把它与共享库链接libxml2.so,根据定义,它是 PI。此外,您libxml2.a还使用默认情况下不发出 PI 目标代码的编译器构建。您当前的编译器可能仍然具有越来越过时的特征,但您不需要找出。

您需要将本地libxml2安装替换为其中的目标文件libxml2已用fPIC. 如果您已经知道如何做到这一点,您可以跳过其余部分并继续进行。

如果您在某个地方获得了libxml2已构建和安装的源包,并且您想坚持使用该修订版,则cd进入其根目录并运行:

make uninstall

否则,通过以 root 身份删除所有匹配 /usr/local/lib/libxml2的文件和符号链接以及目录来删除安装/usr/local/include/libxml2

如果你想坚持使用你已经获得的源包(你运行的地方make uninstall),那么,在它的根目录中,运行:

make distclean

以恢复其原始状态。

如果您没有要坚持使用的源代码包,则克隆或下载并提取最新的 from 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 对象文件,并且您将能够将共享库链接到它。

如果您不确定[any other non-default configuration options]./configure命令,请运行:

./configure -h

事先寻求帮助和/或寻求建议。


推荐阅读