Android JNI项目中部分文件链接spdlog失败问题求助
问题概述
开发Android JNI项目时,采用CMake构建,分为静态库NativeUtils和主动态库drivermonitor,依赖spdlog日志库。NativeUtils中部分源文件调用spdlog::info等函数时出现链接错误,提示spdlog相关符号未定义,但同库内其他文件无此问题。
链接错误信息
: && /home/kartik/Android/Sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ --target=aarch64-none-linux-android26 --sysroot=/home/kartik/Android/Sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fno-limit-debug-info -static-libstdc++ -Wl,--build-id=sha1 -Wl,--no-rosegment -Wl,--fatal-warnings -Wl,--gc-sections -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libdrivermonitor.so -o /home/kartik/Projects/DriverMonitor/service/build/intermediates/cxx/Debug/3n3s6c4k/obj/arm64-v8a/libdrivermonitor.so CMakeFiles/drivermonitor.dir/src/AiProcessor.cpp.o CMakeFiles/drivermonitor.dir/src/DriverMonitor.cpp.o CMakeFiles/drivermonitor.dir/src/DriverMonitorNative.cpp.o CMakeFiles/drivermonitor.dir/src/FrameCounter.cpp.o CMakeFiles/drivermonitor.dir/src/NetworkWrapper.cpp.o CMakeFiles/drivermonitor.dir/src/PreProcess.cpp.o CMakeFiles/drivermonitor.dir/test/NativePreProc.cpp.o deps/NativeUtils/libNativeUtils.a /home/kartik/Projects/DriverMonitor/deps/Snpe/lib/arm64-v8a/libSNPE.so /home/kartik/Projects/DriverMonitor/deps/fastcv/lib/arm64-v8a/libfastcv.a /home/kartik/Projects/DriverMonitor/deps/Snpe/lib/arm64-v8a/libc++_shared.so _deps/fmt-build/libfmtd.a _deps/spdlog-build/libspdlogd.a /home/kartik/Android/Sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/26/liblog.so /home/kartik/Android/Sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/26/libandroid.so /home/kartik/Android/Sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/26/libmediandk.so /home/kartik/Android/Sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/26/libjnigraphics.so -pthread -llog -lc++_shared /home/kartik/Android/Sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/26/liblog.so -latomic -lm && : ld: error: undefined symbol: spdlog::details::log_msg::log_msg(spdlog::source_loc, fmt::v10::basic_string_view<char>, spdlog::level::level_enum, fmt::v10::basic_string_view<char>) >>> referenced by logger.h:134 (_deps/spdlog-src/include/spdlog/logger.h:134) >>> AImageWrapper.cpp.o:(spdlog::logger::log(spdlog::source_loc, spdlog::level::level_enum, fmt::v10::basic_string_view<char>)) in archive deps/NativeUtils/libNativeUtils.a
各模块CMake配置
依赖模块CMakeLists.txt
cmake_minimum_required(VERSION 3.22) project(SupportLibs) find_library(native-media mediandk) find_library(native-log log) find_library(native-trace android) find_library(native-graphics jnigraphics) include(FetchContent) FetchContent_Declare(fmt GIT_REPOSITORY https://github.com/fmtlib/fmt GIT_TAG 10.0.0) FetchContent_Declare(spdlog GIT_REPOSITORY https://github.com/gabime/spdlog GIT_TAG v1.12.0) FetchContent_MakeAvailable(fmt spdlog) add_subdirectory(Snpe) add_subdirectory(fastcv) add_subdirectory(NativeUtils)
NativeUtils模块CMakeLists.txt
cmake_minimum_required(VERSION 3.22) project(NativeUtils) file(GLOB sources src/*.cpp) file(GLOB headers include/*.hpp) add_library(NativeUtils STATIC "${sources}" "${headers}") print_list("${sources}") target_include_directories(NativeUtils PUBLIC inc) target_link_libraries(NativeUtils PUBLIC snpe c++_shared) target_link_libraries(NativeUtils PRIVATE ${native-log} fmt::fmt spdlog::spdlog fastcv) target_compile_features(NativeUtils PRIVATE cxx_std_17)
主库drivermonitor的CMakeLists.txt
cmake_minimum_required(VERSION 3.22) project(DriverMonitor CXX) macro(print_list) foreach(arg ${ARGV}) message(" ${arg}") endforeach() endmacro() set(distribution_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../deps) add_subdirectory(${distribution_DIR} ${CMAKE_CURRENT_BINARY_DIR}/deps) file(GLOB headers inc/drivermonitor/*.h) file(GLOB sources src/*.cpp test/*.cpp) add_library(drivermonitor SHARED "${headers}" "${sources}") target_compile_features(drivermonitor PRIVATE cxx_std_17) target_include_directories(drivermonitor PRIVATE inc) target_link_libraries( drivermonitor PRIVATE NativeUtils snpe fastcv c++shared fmt::fmt spdlog::spdlog ${native-log} ${native-trace} ${native-media} ${native-graphics} )
排查与解决方法
1. 调整依赖可见性
NativeUtils中使用PRIVATE链接spdlog和fmt,导致主库drivermonitor无法自动继承这些依赖的链接顺序。将NativeUtils的链接配置改为PUBLIC,CMake会自动处理依赖库的链接顺序,确保spdlog在NativeUtils之后被链接,让链接器能正确找到符号:
# 修改NativeUtils的target_link_libraries target_link_libraries(NativeUtils PRIVATE ${native-log} fastcv) target_link_libraries(NativeUtils PUBLIC snpe c++_shared fmt::fmt spdlog::spdlog)
2. 检查fmt与spdlog版本兼容性
当前使用fmt 10.0.0和spdlog 1.12.0,spdlog 1.12.0发布时fmt 10尚未正式推出,存在API不兼容问题(如错误中出现的fmt::v10::basic_string_view可能未被spdlog 1.12.0支持)。将fmt版本降级到与spdlog 1.12.0兼容的9.x版本(如9.1.0):
FetchContent_Declare(fmt GIT_REPOSITORY https://github.com/fmtlib/fmt GIT_TAG 9.1.0)
3. 修正头文件路径
NativeUtils的target_include_directories指定了PUBLIC inc,但实际头文件放在include目录,路径不匹配可能导致部分源文件未正确包含spdlog头文件,编译出不匹配的符号。修正路径:
target_include_directories(NativeUtils PUBLIC include)
4. 确认链接顺序
如果上述方法无效,手动调整主库drivermonitor的链接顺序,将spdlog和fmt放在NativeUtils之后,确保链接器处理NativeUtils的未定义符号时,能从后续的spdlog库中找到对应实现:
target_link_libraries( drivermonitor PRIVATE snpe fastcv c++shared ${native-log} ${native-trace} ${native-media} ${native-graphics} NativeUtils fmt::fmt spdlog::spdlog )
内容的提问来源于stack exchange,提问作者Kartik Aiyer

