Android平台CMake引入BoringSSL依赖时链接失败排查及方案咨询
问题描述
我用C++和CMake开发Android平台的库,尝试引入BoringSSL作为依赖,当前代码实现如下:
add_library(mylib STATIC foo.cpp bar.cpp .....) ExternalProject_Add( boringssl GIT_REPOSITORY "https://github.com/google/boringssl.git" GIT_TAG "origin/master" SOURCE_DIR "external/boringssl" STEP_TARGETS crypto ssl CMAKE_ARGS "-DOPENSSL_SMALL=TRUE" ) add_dependencies(mylib boringssl) target_link_directories(mylib PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/external/boringssl/install/lib") target_link_libraries(mylib PRIVATE crypto ssl)
链接mylib时出现错误:ld.lld: error: unable to find library -lcrypto 和 -lssl,奇怪的是,虽然用了target_link_directories,但链接命令行里并没有包含.../boringssl/install/lib目录。该目录在配置阶段不存在(因为ExternalProject_Add在构建阶段运行),但这应该不是问题吧?
我肯定哪里操作错了,问题出在哪?
延伸问题
想把BoringSSL作为我的库的依赖项,除了ExternalProject_Add之外,最优的实现方式是什么?
编辑补充
以下是链接命令行(我的库名为srtc),可以看到缺少指定的链接目录:
--target=aarch64-none-linux-android29 --sysroot=/mnt/android/sdk/ndk/27.2.12479018/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-exceptions -fno-rtti -fno-limit-debug-info -static-libstdc++ -Wl,--build-id=sha1 -Wl,--no-rosegment -Wl,--no-undefined-version -Wl,--fatal-warnings -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libsrtctest.so -o /home/kman/Android/proj-srtc/build/intermediates/cxx/Debug/5963472j/obj/arm64-v8a/libsrtctest.so CMakeFiles/srtctest.dir/jni_class_map.cpp.o CMakeFiles/srtctest.dir/jni_error.cpp.o CMakeFiles/srtctest.dir/jni_util.cpp.o CMakeFiles/srtctest.dir/jni_peer_connection.cpp.o CMakeFiles/srtctest.dir/srtctest_main.cpp.o srtc/libsrtc.a -landroid -llog -lcrypto -lssl -latomic -lm && : ld.lld: error: unable to find library -lcrypto ld.lld: error: unable to find library -lssl
解决方案
一、当前链接错误的原因
target_link_directories时机问题:CMake在配置阶段会解析该命令,但此时BoringSSL的安装目录尚未生成,CMake会直接忽略这个不存在的路径,导致链接阶段找不到库目录。ExternalProject_Add配置缺失:没有指定安装路径和安装命令,BoringSSL默认不会将编译好的库输出到你指定的install/lib目录;同时STEP_TARGETS未正确关联到库的安装流程,依赖关系不完整。- 未建立导入目标:直接使用
crypto和ssl作为链接目标,但CMake没有感知到这两个库的实际路径,无法自动添加链接目录。
修复当前代码的步骤
修改ExternalProject_Add配置,补充安装相关参数,通过导入目标的方式让CMake识别BoringSSL的库文件:
add_library(mylib STATIC foo.cpp bar.cpp .....) ExternalProject_Add( boringssl GIT_REPOSITORY "https://github.com/google/boringssl.git" GIT_TAG "master" SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/boringssl" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/external/boringssl" INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/external/boringssl/install" CMAKE_ARGS "-DOPENSSL_SMALL=TRUE" "-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>" "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" # 传递Android工具链配置 "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" STEP_TARGETS install ) # 获取BoringSSL的安装路径,并导入静态库目标 ExternalProject_Get_Property(boringssl INSTALL_DIR) add_library(crypto STATIC IMPORTED GLOBAL) set_target_properties(crypto PROPERTIES IMPORTED_LOCATION "${INSTALL_DIR}/lib/libcrypto.a" INTERFACE_INCLUDE_DIRECTORIES "${INSTALL_DIR}/include" ) add_library(ssl STATIC IMPORTED GLOBAL) set_target_properties(ssl PROPERTIES IMPORTED_LOCATION "${INSTALL_DIR}/lib/libssl.a" INTERFACE_INCLUDE_DIRECTORIES "${INSTALL_DIR}/include" ) # 确保导入目标在BoringSSL安装完成后才可用 add_dependencies(crypto boringssl_install) add_dependencies(ssl boringssl_install) # 关联依赖 target_link_libraries(mylib PRIVATE crypto ssl)
修改后:
- 明确指定安装目录,BoringSSL会将编译好的库和头文件输出到目标路径
- 通过
IMPORTED目标让CMake感知到库的实际位置,避免target_link_directories的时机问题 - 建立了严格的依赖链,确保BoringSSL安装完成后再链接你的库
二、除ExternalProject_Add之外的最优实现方式
1. 使用CMake FetchContent(推荐)
CMake 3.11+支持的FetchContent模块可以在配置阶段下载并构建依赖,直接集成到主构建流程,比ExternalProject_Add更简洁:
include(FetchContent) FetchContent_Declare( boringssl GIT_REPOSITORY https://github.com/google/boringssl.git GIT_TAG master ) FetchContent_MakeAvailable(boringssl) add_library(mylib STATIC foo.cpp bar.cpp .....) target_link_libraries(mylib PRIVATE ssl crypto)
优势:
- 无需手动处理依赖顺序和路径,CMake自动管理
- 支持IDE索引,可直接跳转至BoringSSL源码
- 构建流程与主项目同步,避免多阶段构建的冲突
2. 预编译BoringSSL库
如果需要稳定的依赖版本,可提前为Android各架构预编译BoringSSL,然后直接导入预编译库:
# 导入预编译的crypto库 add_library(crypto STATIC IMPORTED) set_target_properties(crypto PROPERTIES IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/prebuilt/boringssl/${ANDROID_ABI}/libcrypto.a" INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/prebuilt/boringssl/include" ) # 导入预编译的ssl库 add_library(ssl STATIC IMPORTED) set_target_properties(ssl PROPERTIES IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/prebuilt/boringssl/${ANDROID_ABI}/libssl.a" INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/prebuilt/boringssl/include" ) add_library(mylib STATIC foo.cpp bar.cpp) target_link_libraries(mylib PRIVATE ssl crypto)
优势:
- 构建速度快,无需每次编译BoringSSL
- 版本可控,避免源码构建的不确定性
3. 使用Android NDK内置的BoringSSL
从NDK 17开始,Android NDK已内置BoringSSL作为默认SSL库,可直接链接系统提供的库:
add_library(mylib STATIC foo.cpp bar.cpp) target_link_libraries(mylib PRIVATE log android ssl crypto)
优势:
- 无需额外管理依赖,NDK自动处理
- 符合Android平台标准配置,兼容性好
- 注意:NDK内置的BoringSSL版本与官方可能存在差异,部分特性可能被裁剪
内容的提问来源于stack exchange,提问作者Kostya Vasilyev
相关产品推荐
相关产品推荐

