Linker error: "relocation R_X86_64_PC32 against symbol `xmlFree' ... recompile with -fPIC" but offending library was already compiled with -fPIC

Linker error: "relocation R_X86_64_PC32 against symbol `xmlFree' ... recompile with -fPIC" but offending library was already compiled with -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

然而,根据this的问题,/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$

这让我相信我可能误解了错误消息 - 有人可以阐明这里发生的事情吗?

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

However, according to this question, /usr/local/lib/lxml2.a was already compiled fPIC

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

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

没有任何输出,说明你选择了the second most popular answer 这个问题,尽管在撰写本文时,它的投票率几乎没有 the most popular answer

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

但是第二个最流行的答案测试了一个 shared 库,你用它来测试 static 库中的对象文件。共享库与 目标文件或此类的静态库,给出此答案的问题询问如何测试 目标文件的PIC-ness。所以这个答案没有回答问题:真的 它建议如何测试名称类似于共享库的文件是否真的是 共享库。

最受欢迎的答案确实回答了问题,如果是正确答案 它也适合您,因为 linker 已经诊断出:

/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

libxml2.a中存档的目标文件uri.o不是PIC。

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

None 个 that 问题的答案 对你来说是一个正确的答案,为什么不重要。系统 linker 本身 是决定目标文件是否与位置无关的最终权威。 除了尝试将目标文件 link 放入 DSO 之外,任何单行测试都只是一种尝试 对 linker 进行第二次猜测:如果它的判决不同于 linker 意味着测试失败,而不是 linker。

而且您已经知道 link 人的判决。它已尝试 link libxml2.a(uri.o) 进入 DSO 并发现它不能,因为它包含一个非位置无关的 搬迁记录.

你得到的 /usr/local/lib/libxml2.a 是建立在传统的 默认假设其中存档的目标文件不需要编译为 与位置无关的代码(使用 -fPIC),因为静态库只会 被输入到 link 非位置无关可执行文件的时代。如果你想 link 一些 PI 二进制文件,然后你将 link 它与共享库 libxml2.so, 根据定义,这是 PI。您的 libxml2.a 还使用编译器构建 默认情况下不会发出 PI 对象代码。有可能你现在的 编译器仍然具有越来越过时的特性,但您不需要找到 出。

您需要将本地 libxml2 安装替换为对象所在的安装 libxml2 中的文件已使用 fPIC 编译。如果您已经知道该怎么做,则可以跳过其余部分并继续学习。

如果你在某处得到了构建的libxml2的源码包 并安装并且你想坚持那个版本,然后 cd 到它的根目录和 运行:

make uninstall

否则,通过以 root 身份删除所有文件和 symlinks 匹配来删除安装 /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 目标文件,您将能够 link 您的 反对它的共享库。

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

./configure -h

事前求助,and/or求教。