NDK CMake工程中引入其他C++三方库
在Android NDK CMake工程中引入其他C++三方库时,有以下几种常见的依赖方式:
1. 源码依赖
如果三方库的源代码包含在你的项目目录中,并且它有自己的CMake配置,可以使用add_subdirectory
将三方库的构建过程集成到你的项目中。
示例:
假设三方库的源代码位于third_party/SomeLibrary
目录下。
# CMakeLists.txt# 添加三方库的构建
add_subdirectory(third_party/SomeLibrary)# 添加可执行文件目标
add_library(native-lib SHARED native-lib.cpp)# 将三方库链接到目标
target_link_libraries(native-lib PRIVATE SomeLibrary)
2. 预编译库依赖
如果三方库已经预先编译成.so
或.a
文件,可以使用add_library
和target_link_libraries
来引入这些预编译库。
适用场景:第三方库已提供针对 Android 的预编译动态库(.so
)和头文件。
示例:
假设三方库的预编译.so
文件位于libs/${ANDROID_ABI}/libSomeLibrary.so
。
# CMakeLists.txt# 添加预编译库
add_library(SomeLibrary SHARED IMPORTED)
set_target_properties(SomeLibrary PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libSomeLibrary.so)# 添加可执行文件目标
add_library(native-lib SHARED native-lib.cpp)# 将预编译库链接到目标
target_link_libraries(native-lib PRIVATE SomeLibrary)
方式 1:预编译动态库(.so
)
步骤:
-
放置文件:
- 将
.so
文件按 ABI 分类放入src/main/jniLibs/abi/
目录(如armeabi-v7a/libmylib.so
)。 - 将头文件放入
src/main/cpp/include/
目录。
- 将
-
配置
CMakeLists.txt
:# 设置头文件路径 include_directories(src/main/cpp/include)# 导入动态库(以 openssl 为例) add_library(openssl SHARED IMPORTED) set_target_properties(openssl PROPERTIESIMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libssl.so )# 添加自己的目标(如共享库) add_library(native-lib SHAREDsrc/main/cpp/native-lib.cpp )# 链接第三方库和系统库(如 log) target_link_libraries(native-libopenssllog # Android 系统日志库 )
方式 2:预编译静态库(.a
)
步骤:
-
放置文件:
- 将
.a
文件放入src/main/jniLibs/abi/
目录。 - 头文件放入
src/main/cpp/include/
。
- 将
-
配置
CMakeLists.txt
:# 导入静态库(如 libpng) add_library(png STATIC IMPORTED) set_target_properties(png PROPERTIESIMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libpng.a )# 链接静态库 target_link_libraries(native-libpnglog )
3. 使用FetchContent
模块(CMake 3.11+)
如果三方库可以从远程位置(如Git仓库)获取,可以使用FetchContent
模块在构建过程中自动下载和构建三方库。
示例:
假设三方库的Git地址为https://github.com/someuser/SomeLibrary.git
。
# CMakeLists.txt# 启用FetchContent模块
include(FetchContent)# 下载并构建三方库
FetchContent_Declare(SomeLibraryGIT_REPOSITORY https://github.com/someuser/SomeLibrary.gitGIT_TAG main
)
FetchContent_MakeAvailable(SomeLibrary)# 添加可执行文件目标
add_library(native-lib SHARED native-lib.cpp)# 将三方库链接到目标
target_link_libraries(native-lib PRIVATE SomeLibrary)
4. 手动指定源文件
如果三方库的源代码是一个简单的库,没有复杂的构建系统,可以直接将源文件添加到你的CMake工程中。
示例:
假设三方库的源文件位于third_party/SomeLibrary/src
目录下,头文件位于third_party/SomeLibrary/include
目录下。
# CMakeLists.txt# 添加三方库的源文件
add_library(SomeLibrary STATIC)
target_sources(SomeLibrary PRIVATEthird_party/SomeLibrary/src/file1.cppthird_party/SomeLibrary/src/file2.cpp
)
target_include_directories(SomeLibrary PRIVATEthird_party/SomeLibrary/include
)# 添加可执行文件目标
add_library(native-lib SHARED native-lib.cpp)# 将三方库链接到目标
target_link_libraries(native-lib PRIVATE SomeLibrary)
步骤:
-
将源码放入项目目录:
- 将第三方库的源码放在
thirdparty/
目录下(如thirdparty/openssl
)。
- 将第三方库的源码放在
-
配置
CMakeLists.txt
:# 将第三方库的源码目录加入子目录编译 add_subdirectory(${CMAKE_SOURCE_DIR}/thirdparty/openssl)# 添加自己的目标 add_library(native-lib SHARED src/main/cpp/native-lib.cpp)# 链接编译后的库 target_link_libraries(native-libopenssl # 假设第三方库生成的库名为 openssllog )
5. 使用include_directories
指定头文件路径
如果需要引入三方库的头文件,可以使用include_directories
指定头文件路径。
示例:
假设三方库的头文件位于third_party/SomeLibrary/include
目录下。
# CMakeLists.txt# 指定头文件路径
include_directories(third_party/SomeLibrary/include)# 添加可执行文件目标
add_library(native-lib SHARED native-lib.cpp)# 如果是预编译库,还需要指定库文件路径并链接
# add_library(SomeLibrary SHARED IMPORTED)
# set_target_properties(SomeLibrary PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libSomeLibrary.so)
# target_link_libraries(native-lib PRIVATE SomeLibrary)
方式 4:系统库查找(find_package
)
步骤:
-
确保库已安装:
- 第三方库需在系统中安装(如通过 NDK 或包管理器安装)。
-
配置
CMakeLists.txt
:# 查找已安装的 OpenCV 库 find_package(OpenCV REQUIRED)# 添加目标并链接 add_library(native-lib SHARED src/main/cpp/native-lib.cpp) target_include_directories(native-lib PRIVATE ${OpenCV_INCLUDE_DIRS}) target_link_libraries(native-lib ${OpenCV_LIBS} log)
方式 5:自动下载编译(ExternalProject_Add
)
步骤:
- 配置
CMakeLists.txt
:# 下载并编译第三方库(如 gtest) include(ExternalProject) ExternalProject_Add(gtestGIT_REPOSITORY https://github.com/google/googletest.gitCMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/gtest )# 添加目标并链接 add_library(gtest-lib INTERFACE) target_include_directories(gtest-lib INTERFACE${CMAKE_BINARY_DIR}/gtest/include ) target_link_libraries(gtest-lib INTERFACE${CMAKE_BINARY_DIR}/gtest/lib/libgtest.a )# 使用 gtest add_executable(my_test test.cpp) target_link_libraries(my_test gtest-lib)
关键配置说明
-
头文件路径:
include_directories( # 传统方式src/main/cpp/includethirdparty/include )# 推荐使用 target_include_directories target_include_directories(native-lib PRIVATE${CMAKE_SOURCE_DIR}/src/main/cpp/include )
-
动态库路径的动态化:
- 使用
${ANDROID_ABI}
变量自动适配不同 ABI:set(LIB_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}) set_target_properties(png PROPERTIESIMPORTED_LOCATION ${LIB_DIR}/libpng.so )
- 使用
-
依赖传递性:
- 如果第三方库依赖其他库(如
libcrypto.so
),需逐层导入:add_library(crypto SHARED IMPORTED) set_target_properties(crypto PROPERTIESIMPORTED_LOCATION ${LIB_DIR}/libcrypto.so ) target_link_libraries(openssl PRIVATE crypto) # openssl 依赖 crypto
- 如果第三方库依赖其他库(如
总结:依赖方式对比
- 源码依赖:适用于三方库的源代码已经包含在项目目录中,并且有CMake配置。
- 预编译库依赖:适用于三方库已经预先编译成
.so
或.a
文件。 FetchContent
:适用于从远程位置获取并自动构建三方库。- 手动指定源文件:适用于简单的三方库,直接将源文件添加到工程中。
include_directories
:适用于需要引入三方库的头文件。
| 方式 | 是否需要源码 | 适用场景 | 优点 | 缺点 |
|------------------------|--------------|-----------------------------------|-------------------------------|-------------------------------|
| 预编译动态库(.so
) | 不需要 | 第三方提供预编译动态库 | 快速集成,无需编译 | 需确保 ABI 兼容性 |
| 预编译静态库(.a
) | 不需要 | 第三方提供静态库 | 静态链接,无依赖传递问题 | 文件体积较大 |
| 源码编译(add_subdirectory
) | 需要 | 需自定义编译或库未提供预编译文件 | 灵活配置,支持修改源码 | 需处理交叉编译及依赖 |
| 系统库(find_package
) | 不需要 | 系统已安装且提供 CMake 配置文件 | 自动化配置,简洁 | 依赖系统环境 |
| 自动下载(ExternalProject
) | 需要 | 需自动管理源码下载和编译 | 自动化流程,便于版本控制 | 构建时间较长 |
通过以上方法,可以根据第三方库的提供形式和项目需求,灵活选择最合适的依赖方式。