开发rowen.so动态库:未链接jsoncpp无报错、链接后无法检测依赖的问题
关于rowen共享库与jsoncpp链接的问题
我正在开发名为“rowen”的so文件,库内包含一个封装jsoncpp部分功能的json相关模块(路径为Libs/json/json.cpp)。
Q1:在print函数中调用jsoncpp的write接口,但未链接jsoncpp时并未出现报错,原因是什么?
相关代码
json.hpp
#include <jsoncpp/json/json.h> namespace Json { inline void print(Json::Value& __param, std::string __title); }
json.cpp
namespace Json { void print(Json::Value& __param, std::string __title) { Json::StyledWriter style_writer; std::string output = style_writer.write(__param); printf("=========== %s ===========================\n", __title.c_str()); printf("%s\n", output.c_str()); } }
CMake配置片段
根目录CMakeLists.txt
cmake_minimum_required(VERSION 3.20) project(Rowen-Libraries) set(rowenSources ) # set libraries (default) include(Libs/core/import.cmake) # set libraries (optional) OPTION(ENABLE_JSON "Enable Json Wrapping Library" ON) if (ENABLE_JSON) include(Libs/json/import.cmake) endif() # build shared libraries add_library(rowen SHARED ${rowenSources})
Libs/json/import.cmake
insert(${CMAKE_CURRENT_LIST_DIR}/json.hpp) # include to rowenIncludes insert(${CMAKE_CURRENT_LIST_DIR}/json.inl) # include to rowenIncludes insert(${CMAKE_CURRENT_LIST_DIR}/json.cpp) # include to rowenSources # Check for pkg-config find_package(PkgConfig REQUIRED) pkg_check_modules(JSONCPP REQUIRED jsoncpp) link_libraries(${JSONCPP_LIBRARIES}) # ${JSONCPP_LIBRARIES} print "jsoncpp"
原因分析
- 编译阶段仅需函数声明:编译器只需要头文件中提供的
Json::StyledWriter::write函数声明就能通过编译,不检查实际实现是否存在,因此编译生成目标文件时不会报错。 - 共享库默认允许未定义符号:构建共享库(.so)时,链接器默认采用延迟绑定(lazy binding)策略,不会强制检查所有符号的存在性,仅在运行时实际调用该函数时才会解析符号。如果测试过程中没有调用
print函数,或者未开启-Wl,--no-undefined这类强制检查未定义符号的选项,链接阶段就不会报错。
Q2:已配置链接jsoncpp,但通过ldd、nm等工具无法检测到该依赖,原因是什么?如何让librowen.so必须依赖libjsoncpp才能使用?
相关命令执行结果
$ ldd librowen.so linux-vdso.so.1 (0x0000007fb750f000) libpthread.so.0 => /lib/aarch64-linux-gnu/libpthread.so.0 (0x0000007fb745a000) libstdc++.so.6 => /usr/lib/aarch64-linux-gnu/libstdc++.so.6 (0x0000007fb72c6000) libgcc_s.so.1 => /lib/aarch64-linux-gnu/libgcc_s.so.1 (0x0000007fb72a2000) libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000007fb7149000) /lib/ld-linux-aarch64.so.1 (0x0000007fb74e3000) libm.so.6 => /lib/aarch64-linux-gnu/libm.so.6 (0x0000007fb7090000) $ nm -D librowen.so | grep jsoncpp # 无输出 $ objdump -T librowen.so | grep jsoncpp # 无输出
原因分析
- CMake链接命令作用时机错误:全局
link_libraries命令的作用可靠性低于目标专属的target_link_libraries,且当前CMakeLists中目标创建与模块导入的顺序可能导致链接配置未正确作用于rowen库。 - 未被引用的符号被优化移除:如果
Json::print函数没有被librowen.so的其他代码引用,且开启了链接时优化(LTO),编译器会将这个未被使用的函数整个移除,导致jsoncpp的符号没有被引用,链接器也就不会将libjsoncpp添加为依赖。 - json.cpp未被正确编译进库:如果
insert函数没有正确将json.cpp路径加入rowenSources变量,该文件不会被编译进librowen.so,自然不会产生对jsoncpp的依赖。
解决方法
- 改用目标专属链接命令:替换全局
link_libraries为CMake推荐的target_link_libraries,确保链接配置仅作用于rowen目标:- 调整根目录CMakeLists.txt顺序,先创建目标再导入json模块:
cmake_minimum_required(VERSION 3.20) project(Rowen-Libraries) set(rowenSources ) # set libraries (default) include(Libs/core/import.cmake) # build shared libraries add_library(rowen SHARED ${rowenSources}) # set libraries (optional) OPTION(ENABLE_JSON "Enable Json Wrapping Library" ON) if (ENABLE_JSON) include(Libs/json/import.cmake) endif() - 修改Libs/json/import.cmake中的链接命令:
# 替换原link_libraries行 target_link_libraries(rowen PRIVATE ${JSONCPP_LIBRARIES})
- 调整根目录CMakeLists.txt顺序,先创建目标再导入json模块:
- 验证jsoncpp代码是否被编译进库:在CMake中添加日志验证
rowenSources是否包含json.cpp:
若未包含,检查message(STATUS "rowenSources content: ${rowenSources}")insert函数的实现是否正确将文件路径添加到变量中。 - 强制保留未被引用的符号:如果
print函数未被其他代码引用导致被优化,可在函数声明中添加__attribute__((used))标记强制保留:namespace Json { __attribute__((used)) void print(Json::Value& __param, std::string __title) { // 原函数代码 } } - 验证动态依赖:使用
readelf -d librowen.so查看动态段,确认是否存在NEEDED条目指向libjsoncpp.so。如果配置正确,该条目会被自动添加。
内容的提问来源于stack exchange,提问作者mystes
相关产品推荐
相关产品推荐

