Skip to content

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.so

Android 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 库列表

库名用途
logAndroid 日志 (__android_log_print)
androidAndroid API
jnigraphicsBitmap 操作
mediandkMediaCodec, Camera
EGLOpenGL 上下文
GLESv2/GLESv3OpenGL ES
OpenSLES音频
zzlib 压缩
camera2ndkCamera2 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 库的构建过程,优化性能、集成第三方库、以及解决复杂的构建问题。