如何构建链接非PIC静态库的C++非PIC共享库
问题分析与解决方案
核心问题
你遇到的链接错误本质上是x86_64架构下,非PIC代码构建共享库时的重定位冲突:
- 第一个错误中的
R_X86_64_PC32重定位针对std::cout,是因为std::cout属于C++标准库,默认动态链接时,非PIC代码无法生成兼容共享库的重定位类型; - 你添加的
-static选项完全错误——它会强制链接器静态链接所有依赖(包括libstdc++),但共享库本身是动态目标文件,这种混合模式会触发线程本地存储符号(如__TMC_END__)的重定位冲突; -z notext确实允许文本段重定位,但lld对x86_64下的R_X86_64_32重定位依然严格限制,除非明确告知链接器兼容非PIC代码。
正确配置调整
1. 移除错误的-static选项
删掉set_target_properties(lib_interface PROPERTIES LINK_FLAGS "-static"),该选项违背共享库的构建逻辑。
2. 修改lib_interface的CMake配置
更新lib_interface/CMakeLists.txt,添加正确的链接选项以支持加载时重定位:
add_library(lib_interface SHARED lib_interface.cpp) # 移除默认的-fPIC编译选项 set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "") # 添加链接选项:允许文本段重定位,保留重定位信息 target_link_options(lib_interface PRIVATE -Wl,-z,notext -Wl,--emit-relocs ) target_link_libraries(lib_interface PRIVATE ${CMAKE_BINARY_DIR}/lib_core/liblib_core.a )
-Wl,-z,notext:允许共享库的文本段包含重定位条目,开启加载时重定位;-Wl,--emit-relocs:强制链接器保留重定位信息,确保动态链接器加载时能修正非PIC代码的地址。
3. 统一lib_core的编译属性(可选但建议)
在lib_core/CMakeLists.txt中明确关闭PIC,确保和lib_interface的编译逻辑一致:
add_library(lib_core STATIC lib_core.cpp) # 明确禁用PIC set_target_properties(lib_core PROPERTIES POSITION_INDEPENDENT_CODE OFF)
4. 根目录CMakeLists.txt优化
将链接器选项从编译选项中拆分出来,避免污染编译流程:
cmake_minimum_required(VERSION 3.15) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_FLAGS "-pthread -Wall -fopenmp") # 单独配置可执行文件和共享库的链接器选项 set(CMAKE_EXE_LINKER_FLAGS "-fuse-ld=lld") set(CMAKE_SHARED_LINKER_FLAGS "-fuse-ld=lld") project("test LANGUAGES CXX") add_subdirectory(test_app) add_subdirectory(lib_interface) add_subdirectory(lib_core)
失败原因复盘
static选项强制静态链接所有依赖,包括libstdc++,但x86_64下共享库静态链接标准库会触发TLS符号的重定位错误;- 仅用
-z notext不足以解决问题,必须配合--emit-relocs让链接器保留必要的重定位信息,才能让动态链接器在加载时完成地址修正。
验证构建
执行以下命令重新构建:
mkdir build && cd build cmake .. make
运行test_app后应输出:
Test app start lib_interface - foo calling lib_core lib_core - bla
内容的提问来源于stack exchange,提问作者Nik
相关产品推荐
相关产品推荐

