按照github上LIVOX-SDK官网的流程编译Livox-SDK和livox_ros_driver时出现如下错误:

/usr/bin/ld: /usr/local/lib/liblivox_sdk_static.a(device_discovery.cpp.o): relocation R_X86_64_TPOFF32 against symbol `_ZGVZN6spdlog7details2os9thread_idEvE3tid' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: /usr/local/lib/liblivox_sdk_static.a(livox_sdk.cpp.o): relocation R_X86_64_PC32 against symbol `stderr@@GLIBC_2.2.5' 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
make[2]: *** [CMakeFiles/livox_ros2_driver.dir/build.make:462:liblivox_ros2_driver.so] 错误 1
make[1]: *** [CMakeFiles/Makefile2:80:CMakeFiles/livox_ros2_driver.dir/all] 错误 2
make: *** [Makefile:141:all] 错误 2
---
Failed   <<< livox_ros2_driver [10.3s, exited with code 2]

这个错误的核心原因是:你正在尝试将 静态库(liblivox_sdk_static.a)链接到一个共享库(.so,但该静态库的目标文件(.o)没有使用 -fPIC 编译,导致无法生成位置无关的代码(Position-Independent Code),而共享库必须依赖位置无关代码才能正常链接。

可以这样解决,先打开Livox-SDK中sdk_core中的CMakeLists.txt文件,然后有两种解决方法,选择一种即可:

1)在第四行add_library之前加上一行

set(CMAKE_POSITION_INDEPENDENT_CODE ON)

2)或在第四行add_library之后加上一行

target_compile_options(${SDK_LIBRARY} PRIVATE -fPIC)

1. CMAKE_POSITION_INDEPENDENT_CODE 生效的前提:必须在目标定义前设置

CMAKE_POSITION_INDEPENDENT_CODE 是一个 “全局 / 目标级” 的开关,它的作用范围是在它被设置之后定义的目标。如果你的 CMakeLists.txt 中,add_library(${SDK_LIBRARY} STATIC ...) 这行代码写在 set(CMAKE_POSITION_INDEPENDENT_CODE ON) 之前,那么这个全局开关对 SDK_LIBRARY 目标是无效的(因为目标已经被定义了,CMake 不会回溯应用配置)。

target_compile_options(${SDK_LIBRARY} PRIVATE -fPIC)直接针对已定义的目标添加编译选项,无论目标是在之前还是之后定义(只要在编译前执行),都会生效。这也是它更 “可靠” 的原因之一。

2. CMake 对静态库的 PIC 处理有默认差异

CMake 中,CMAKE_POSITION_INDEPENDENT_CODE 的默认行为因目标类型和平台而异:

  • 对于共享库(SHARED),CMake 会默认启用 PIC(等价于隐式设置了 -fPIC),因为共享库必须依赖位置无关代码。
  • 对于静态库(STATIC),CMake 默认不启用 PIC(除非平台强制要求,比如某些嵌入式系统),因为静态库本身被链接到可执行文件时,不需要位置无关代码。

当你手动设置 CMAKE_POSITION_INDEPENDENT_CODE ON 时,理论上会强制所有后续目标(包括静态库)启用 PIC,但如果你的项目中存在其他配置(比如某些第三方模块、工具链文件)显式覆盖了这个开关(例如 set(CMAKE_POSITION_INDEPENDENT_CODE OFF)),就可能导致全局设置失效。

target_compile_options目标级别的显式配置,优先级高于全局开关,因此即使有其他全局配置冲突,也能保证 -fPIC 被应用到 SDK_LIBRARY 目标上。

3. 总结:为什么 target_compile_options 更有效?

  • 它直接作用于目标,不受 “设置时机”(目标定义前后)的影响;
  • 目标级配置优先级高于全局配置,能避免被其他隐式设置覆盖;
  • 对于静态库,CMake 对全局 PIC 开关的处理更 “保守”,显式添加 -fPIC 更直接可靠。

如果后续需要调整,建议保持 target_compile_options(${SDK_LIBRARY} PRIVATE -fPIC) 的写法,同时确保它在 add_library(${SDK_LIBRARY} ...) 之后调用(虽然 CMake 允许在目标定义前用 target_* 命令,但习惯上在目标定义后写更清晰)。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐