【问题标题】:Linker PIC error when statically linking a library built with PIC enabled静态链接启用 PIC 构建的库时出现链接器 PIC 错误
【发布时间】:2020-05-18 16:32:30
【问题描述】:

我正在使用 g++-9 和 CMake(在 Xenial 上,在 Travis 上)构建一个库 (libproj),因此我可以将它静态链接到 Rust 板条箱中。我的build.rs 使用以下配置设置并运行 CMake:

cmake proj-7.0.1
-DBUILD_SHARED_LIBS=ON
-DBUILD_TESTING=OFF
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_CXX_FLAGS="-std=c++11 -fPIC"
-DCMAKE_INSTALL_PREFIX=[path snipped]/out
-DCMAKE_C_FLAGS= -ffunction-sections -fdata-sections -fPIC -m64
-DCMAKE_C_COMPILER=/usr/bin/gcc-9
-DCMAKE_CXX_COMPILER=/usr/bin/g++-9
-DCMAKE_ASM_FLAGS= -ffunction-sections -fdata-sections -fPIC -m64
-DCMAKE_ASM_COMPILER=/usr/bin/gcc-9

Which builds and installs libproj successfully.

然后我告诉 cargo 静态链接它:

cargo:root=[path snipped]/out
cargo:rustc-link-search=native=[path snipped]/out/lib
cargo:rustc-link-lib=static=proj

但是,链接步骤失败,说我不能在共享对象中使用重定位:

note: /usr/bin/ld: [path snipped]/out/lib/libproj.a(4D_api.cpp.o): relocation
R_X86_64_32 against `.rodata.str1.8' can not be used when making a
shared object; recompile with -fPIC`

[path snipped]/out/lib/libproj.a(4D_api.cpp.o): error adding symbols: Bad value
collect2: error: ld returned 1 exit status

我在这里做错了什么?我还尝试按照install instructionsBUILD_SHARED_LIBS 设置为OFF,将libproj 构建为静态库,但这没有任何效果。

更新:

我已经成功为 g++ 启用了 PIC(默认情况下它只为 gcc 启用)

running: "cmake" "-Wdev" "--debug-output" "[snipped]/proj-7.0.1" "-DCMAKE_CXX_FLAGS=-std=c++11" "-DCMAKE_CXX_FLAGS=-fPIC" "-DBUILD_SHARED_LIBS=OFF" "-DCMAKE_INSTALL_PREFIX=[snipped]/out" "-DCMAKE_C_FLAGS= -ffunction-sections -fdata-sections -fPIC -m64" "-DCMAKE_C_COMPILER=/usr/bin/gcc-9" "-DCMAKE_CXX_COMPILER=/usr/bin/g++-9" "-DCMAKE_ASM_FLAGS= -ffunction-sections -fdata-sections -fPIC -m64" "-DCMAKE_ASM_COMPILER=/usr/bin/gcc-9" "-DCMAKE_BUILD_TYPE=Debug" "-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON"

导致以下 g++-9 调用,其中包括-fPIC

/usr/bin/g++-9  -DCURL_ENABLED -DMUTEX_pthread -DPROJ_LIB=\"/[snip]/proj\" -DTIFF_ENABLED -I/[snip]/src -I/[snip]/include -I/[snip]/src -I/usr/include/x86_64-linux-gnu  -fPIC -g -fvisibility=hidden   -Wall -Wextra -Wswitch -Wshadow -Wunused-parameter -Wmissing-declarations -Wformat -Wformat-security -std=c++11 -o CMakeFiles/proj.dir/aasincos.cpp.o -c /[snip]/proj/proj-7.0.1/src/aasincos.cpp

但是,我知道得到一个完全不同的错误(数千行),看起来我的静态库没有正确链接到 c++11 标准库:

Error:
undefined reference to std::allocator<char>::allocator()

更新 2:

我已经设法从ld 中删除了-nodefaultlibs 标志。最新的 g++ 调用:

/usr/bin/g++-9   -I/[snipped]/src -I/[snipped]/include -I/[snipped]/src -isystem /[snipped]/include -isystem /[snipped]/googletest  -fPIC -g -fvisibility=hidden   -Wall -Wextra -Wswitch -Wshadow -Wunused-parameter -Wmissing-declarations -Wformat -Wformat-security -pthread -std=c++11 -o CMakeFiles/proj_context_test.dir/proj_context_test.cpp.o -c /[snipped]/proj_context_test.cpp

我已经设法将lstdc++ 添加到链接器调用中:

"cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-m64" "-L" "/[snip]/lib" "/home/travis/build/georust/proj-sys/target/debug/deps/proj_sys-95cbd73f2c3f0bde.20tasg77xuhsj5z6.rcgu.o" "/home/travis/build/georust/proj-sys/target/debug/deps/proj_sys-95cbd73f2c3f0bde.57y4784ihm3qw715.rcgu.o" "-o" "/[snip]/deps/proj_sys-95cbd73f2c3f0bde" "/home/travis/build/georust/proj-sys/target/debug/deps/proj_sys-95cbd73f2c3f0bde.3kiafs23968zh4mj.rcgu.o" "-Wl,--gc-sections" "-pie" "-Wl,-zrelro" "-Wl,-znow" "-L" "/home/travis/build/georust/proj-sys/target/debug/deps" "-L" "/home/travis/build/georust/proj-sys/target/debug/build/proj-sys-aff2ac9d43b77886/out/lib" "-L" "/home/travis/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-lsqlite3" "-lcurl" "-ltiff" "-lstdc++" "-Wl,-Bstatic" "-Wl,--whole-archive" "-lproj" "-Wl,--no-whole-archive" [trimmed rlib details] "-Wl,--end-group" "/home/travis/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-2541f1e09df1c67d.rlib" "-Wl,-Bdynamic" "-ldl" "-lrt" "-lpthread" "-lgcc_s" "-lc" "-lm" "-lrt" "-lpthread" "-lutil" "-lutil"

undefined reference error 仍然存在。

【问题讨论】:

    标签: c++ cmake rust g++


    【解决方案1】:

    从您的示例中可以看出,CMAKE_CXX_FLAGS 周围有引号,CMAKE_C_FLAGS 周围没有引号。看起来很奇怪。

    我自己用cmake + 你的标志和make VERBOSE=1 构建了libgproj

    我可以看到,在没有 fPICm64fdata-sections 的情况下编译的 C 文件。我想,原因是在CMAKE_C_FLAGS 周围的引号中。我在Travis看到你的登录,有cmake的配置来自cargo

    "cmake" "/home/travis/build/georust/proj-sys/PROJSRC/proj/proj-7.0.1" "-DBUILD_SHARED_LIBS=ON" "-DBUILD_TESTING=OFF" "-DCMAKE_BUILD_TYPE=Release" "-DCMAKE_CXX_FLAGS=-std=c++11 -fPIC" "-DCMAKE_INSTALL_PREFIX=/home/travis/build/georust/proj-sys/target/debug/build/proj-sys-03a5fe6428bb060a/out" "-DCMAKE_C_FLAGS= -ffunction-sections -fdata-sections -fPIC -m64" "-DCMAKE_C_COMPILER=/usr/bin/gcc-9" "-DCMAKE_CXX_COMPILER=/usr/bin/g++-9" "-DCMAKE_ASM_FLAGS= -ffunction-sections -fdata-sections -fPIC -m64" "-DCMAKE_ASM_COMPILER=/usr/bin/gcc-9"
    

    请注意,-DCMAKE_C_FLAGSCMAKE_CXX_FLAGS 使用它们的值转义,而不是值本身。我想,这些选项会在 shell 中:

    cmake -DCMAKE_C_FLAGS= -ffunction-sections -fdata-sections -fPIC -m64 -DCVMAKE_CXX_FLAGS=-std=c++11 -fPIC
    

    我试过这个命令,不带引号,cmake 只是忽略了未知选项。所以它不会失败。

    如果可以的话,我建议你在 cmake 配置中添加 cmake 选项 -DCMAKE_VERBOSE_MAKEFILE:BOOL=ONVERBOSE=1make 选项中,然后你可以在 Travis 中看到传递给 gcc 的真实编译选项。

    你会看到这样的东西:

    [ 19%] Building C object src/CMakeFiles/proj.dir/wkt1_generated_parser.c.o
    cd [some path]/PROJ/cmake_build/src && /usr/bin/cc -DCURL_ENABLED -DMUTEX_pthread 
    -DPROJ_LIB=\"/usr/local/share/proj\" -DTIFF_ENABLED -I[some path]PROJ/src -I[some 
    path]/PROJ/include -I[some path]/PROJ/cmake_build/src  -O3 -DNDEBUG - 
    fvisibility=hidden   -Wall -Wextra -Wswitch -Wshadow -Wunused-parameter -Wmissing- 
    declarations -Wformat -Wformat-security -Wmissing-prototypes -std=c99 -o 
    CMakeFiles/proj.dir/wkt1_generated_parser.c.o   -c [some 
    path]/PROJ/src/wkt1_generated_parser.c
    

    结论:

    1. 您可以尝试添加详细信息以查看真正的编译选项。

    2. 如果在第一步之后有必要,您可以尝试正确转义选项。

    我还想指出,我的测试中的SHARED_BUILD_LIBS=ON 禁止构建您要链接的静态库。当我将共享库构建设置选项设置为OFF 时,构建了静态库。

    【讨论】:

    • 好的,这很有用!我设法将-fPIC 调用传递给g++-9,并显式构建了一个静态库,但我现在遇到了一组完全不同的错误,看起来c++11 stdlib 没有正确链接。
    • 尝试使用define -D_GLIBCXX_USE_CXX11_ABI=0 C++11有ABI变化。通常此类错误与 std::string 相关。当您链接具有不同 CXX_11_ABI 的库或二进制文件时需要此定义。
    • 好的,我在 Travis 看到了。问题是 libproj 需要 libstdc++ 作为运行时。但我可以在您的 Travis 中看到您使用的是 -nodefaultlibs。此选项禁用与所有标准库的链接,因此您有数千个未解析的所有标准库函数的引用。
    • 我不明白这里到底在做什么:... sys/target/debug/deps/proj_sys-6b64516d7397f682.31egxm16liuikgs0.rcgu.o" "-Wl,--gc-sections" "-pie" "-Wl,-zrelro" "-Wl,-znow" "-nodefaultlibs" "-L" ... 最后我可以看到"-lgcc_s" 所以你明确地链接 gcc_s,但没有链接 libstdc++。您可以尝试使用 -static-libstdc++ 将 libstdc++ 静态链接到 libproj。通常这不是一个好主意,但我现在不知道如何使用 C++ 库构建 rust 代码。如果有办法将 libstdc++ 链接到 rust 代码,你可以试试。
    • 我认为,如果你可以手动添加 gcc_s 到链接,你也可以使用选项 -lstdc++ 添加 libstdc++。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 2021-02-08
    相关资源
    最近更新 更多