CMake 配置与构建
源:Add C and C++ code to your project
CMake 是 Android NDK 推荐的构建系统,用于编译 Kotlin/Native JNI 库。本文详细讲解如何配置 CMake 构建 Kotlin/Native 动态库。
构建系统概览
Kotlin/Native 自动构建
Kotlin Multiplatform 插件会自动生成 CMake 配置:
kotlin
// build.gradle.kts
kotlin {
androidNativeArm64()
androidNativeX64()
targets.withType<KotlinNativeTarget> {
binaries {
sharedLib {
baseName = "mylib"
// 自动生成 CMakeLists.txt
}
}
}
}生成的库文件:
build/bin/
├── androidNativeArm64/releaseShared/libmylib.so
└── androidNativeX64/releaseShared/libmylib.soAndroid Gradle 集成
将生成的库集成到 Android 项目:
kotlin
// app/build.gradle.kts
android {
sourceSets {
getByName("main") {
// 指定 JNI 库路径
jniLibs.srcDirs(
"../shared/build/bin/androidNativeArm64/releaseShared",
"../shared/build/bin/androidNativeX64/releaseShared"
)
}
}
// 或使用任务依赖自动构建
tasks.preBuild {
dependsOn(":shared:linkReleaseSharedAndroidNativeArm64")
dependsOn(":shared:linkReleaseSharedAndroidNativeX64")
}
}手动 CMake 配置
基础 CMakeLists.txt
如果需要更细粒度的控制,可以手动编写 CMake:
cmake
# CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(mylib)
# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 添加 Kotlin/Native 生成的源码
add_library(mylib SHARED
# Kotlin/Native 编译生成的 C 文件
${CMAKE_SOURCE_DIR}/build/generated/klib/mylib.c
)
# 设置输出目录
set_target_properties(mylib PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}
)
# 链接 Android 库
target_link_libraries(mylib
android
log
)多架构支持
cmake
# 检测目标架构
if(ANDROID_ABI STREQUAL "arm64-v8a")
# ARM64 特定配置
add_definitions(-DARCH_ARM64)
elseif(ANDROID_ABI STREQUAL "x86_64")
# x86_64 特定配置
add_definitions(-DARCH_X86_64)
endif()
# 架构特定的源文件
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
target_sources(mylib PRIVATE
src/arm64/optimized.cpp
)
else()
target_sources(mylib PRIVATE
src/generic/fallback.cpp
)
endif()优化配置
编译优化
cmake
# Release 优化
if(CMAKE_BUILD_TYPE STREQUAL "Release")
# 启用 LTO(链接时优化)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
# 优化标志
target_compile_options(mylib PRIVATE
-O3 # 最高优化级别
-ffast-math # 快速数学运算
-fno-exceptions # 禁用异常(减小体积)
-fno-rtti # 禁用 RTTI
-fvisibility=hidden # 隐藏符号
)
# 链接优化
target_link_options(mylib PRIVATE
-Wl,--gc-sections # 移除未使用的段
-Wl,--strip-all # 移除符号表
)
endif()
# Debug 配置
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_options(mylib PRIVATE
-g # 生成调试信息
-O0 # 禁用优化
-fno-omit-frame-pointer
)
endif()SIMD 优化
cmake
# ARM NEON 支持
if(ANDROID_ABI MATCHES "^arm")
target_compile_options(mylib PRIVATE
-mfpu=neon
-mfloat-abi=softfp
)
target_compile_definitions(mylib PRIVATE
USE_NEON=1
)
endif()
# ARM64 默认支持 NEON
if(ANDROID_ABI STREQUAL "arm64-v8a")
target_compile_definitions(mylib PRIVATE
USE_NEON=1
)
endif()
# x86 SSE 支持
if(ANDROID_ABI MATCHES "^x86")
target_compile_options(mylib PRIVATE
-msse4.2
)
target_compile_definitions(mylib PRIVATE
USE_SSE=1
)
endif()第三方库集成
集成预编译库
cmake
# 添加预编译的 OpenCV
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/libs/opencv)
add_library(opencv SHARED IMPORTED)
set_target_properties(opencv PROPERTIES
IMPORTED_LOCATION ${OpenCV_DIR}/libs/${ANDROID_ABI}/libopencv_core.so
)
target_include_directories(mylib PRIVATE
${OpenCV_DIR}/include
)
target_link_libraries(mylib
opencv
)集成源码库
cmake
# 添加子项目(如 libyuv)
add_subdirectory(${CMAKE_SOURCE_DIR}/third_party/libyuv)
target_link_libraries(mylib
yuv
)Android NDK 库
链接系统库
cmake
# 查找 Android NDK 库
find_library(log-lib log)
find_library(android-lib android)
find_library(jnigraphics-lib jnigraphics)
find_library(mediandk-lib mediandk)
find_library(EGL-lib EGL)
find_library(GLESv3-lib GLESv3)
target_link_libraries(mylib
${log-lib}
${android-lib}
${jnigraphics-lib}
${mediandk-lib}
${EGL-lib}
${GLESv3-lib}
)常用 NDK 库列表
| 库名 | 用途 |
|---|---|
log | Android 日志 (__android_log_print) |
android | Android API |
jnigraphics | Bitmap 操作 |
mediandk | MediaCodec, Camera |
EGL | OpenGL 上下文 |
GLESv2/GLESv3 | OpenGL ES |
OpenSLES | 音频 |
z | zlib 压缩 |
camera2ndk | Camera2 Native API |
完整示例
项目结构
native-lib/
├── CMakeLists.txt
├── src/
│ ├── main.cpp
│ ├── processor.cpp
│ └── utils.cpp
├── include/
│ ├── processor.h
│ └── utils.h
└── libs/
├── arm64-v8a/
├── armeabi-v7a/
└── x86_64/CMakeLists.txt 完整配置
cmake
cmake_minimum_required(VERSION 3.18.1)
project(native-processor CXX)
# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# 头文件路径
include_directories(
${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/third_party/include
)
# 源文件
set(SOURCES
src/main.cpp
src/processor.cpp
src/utils.cpp
)
# 创建动态库
add_library(native-processor SHARED ${SOURCES})
# 查找 NDK 库
find_library(log-lib log)
find_library(android-lib android)
find_library(jnigraphics-lib jnigraphics)
# 编译选项
target_compile_options(native-processor PRIVATE
-Wall
-Wextra
$<$<CONFIG:Release>:-O3>
$<$<CONFIG:Release>:-ffast-math>
$<$<CONFIG:Debug>:-g>
$<$<CONFIG:Debug>:-O0>
)
# 链接选项
target_link_options(native-processor PRIVATE
$<$<CONFIG:Release>:-Wl,--gc-sections>
$<$<CONFIG:Release>:-Wl,--strip-all>
)
# 链接库
target_link_libraries(native-processor
${log-lib}
${android-lib}
${jnigraphics-lib}
)
# 设置输出目录
set_target_properties(native-processor PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/../app/src/main/jniLibs/${ANDROID_ABI}
)app/build.gradle.kts 集成
kotlin
android {
defaultConfig {
ndk {
abiFilters += listOf("arm64-v8a", "x86_64")
}
}
externalNativeBuild {
cmake {
path = file("src/main/cpp/CMakeLists.txt")
version = "3.22.1"
}
}
buildTypes {
release {
externalNativeBuild {
cmake {
arguments += listOf(
"-DCMAKE_BUILD_TYPE=Release",
"-DANDROID_STL=c++_shared"
)
cFlags += "-O3"
cppFlags += "-O3"
}
}
ndk {
debugSymbolLevel = "FULL" // 生成调试符号
}
}
debug {
externalNativeBuild {
cmake {
arguments += "-DCMAKE_BUILD_TYPE=Debug"
cFlags += "-g"
}
}
}
}
}调试与优化
生成编译数据库
cmake
# 生成 compile_commands.json(用于 IDE 支持)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)查看编译命令
bash
# 查看详细编译过程
./gradlew :app:externalNativeBuildDebug --info
# 查看 CMake 缓存
cat app/.cxx/Debug/arm64-v8a/CMakeCache.txt性能分析
cmake
# 启用性能分析
if(ENABLE_PROFILING)
target_compile_options(mylib PRIVATE
-pg
-fno-omit-frame-pointer
)
target_link_options(mylib PRIVATE
-pg
)
endif()常见问题
问题1:找不到 NDK
kotlin
// build.gradle.kts
android {
ndkVersion = "26.1.10909125"
}问题2:ABI 不匹配
cmake
# 确保 ABI 一致
message(STATUS "Building for ABI: ${ANDROID_ABI}")
if(NOT ANDROID_ABI)
message(FATAL_ERROR "ANDROID_ABI not set")
endif()问题3:符号未定义
cmake
# 确保符号可见
target_compile_options(mylib PRIVATE
-fvisibility=default # 或在代码中使用 __attribute__((visibility("default")))
)问题4:库加载失败
kotlin
// 检查库文件路径
println(System.mapLibraryName("mylib")) // 输出: libmylib.so
// 检查 ABI
println(Build.SUPPORTED_ABIS.joinToString())掌握 CMake 配置能够让你完全控制 Native 库的构建过程,优化性能、集成第三方库、以及解决复杂的构建问题。