CMake

Android NDK 支援使用 CMake 為應用程式編譯 C 和 C++ 程式碼。本頁面說明如何透過 Android Gradle 外掛程式的 ExternalNativeBuild,或透過直接叫用 CMake,將 NDK 與 CMake 搭配使用。

CMake 工具鏈檔案

NDK 透過工具鏈檔案支援 CMake。工具鏈檔案是 CMake 檔案,用於自訂跨平台程式碼編譯的工具鏈行為。用於 NDK 的工具鏈檔案位於 NDK 的 <NDK>/build/cmake/android.toolchain.cmake 中。

叫用 cmake 時,指令列會提供 ABI、minSdkVersion 等建構參數。如需支援的引數清單,請參閱「工具鍊引數」一節。

使用方式

Gradle

使用 externalNativeBuild 時,系統會自動使用 CMake 工具鏈檔案。詳情請參閱 Android Studio 的將 C 和 C++ 程式碼新增至專案指南。

指令列

在 Gradle 之外使用 CMake 進行建構時,必須將工具鏈檔案及其引數傳遞至 CMake,例如:

$ cmake \
    -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
    -DANDROID_ABI=$ABI \
    -DANDROID_PLATFORM=android-$MINSDKVERSION \
    $OTHER_ARGS

工具鏈引數

下列引數可傳遞至 CMake 工具鏈檔案。如要使用 Gradle 進行建構,請按照 ExternalNativeBuild 文件中的說明,將引數新增至 android.defaultConfig.externalNativeBuild.cmake.arguments。如果是透過指令列進行建構,請使用 -D 將引數傳遞至 CMake。例如,如要強制 armeabi-v7a 一律採用 Neon 支援進行建構,請傳遞 -DANDROID_ARM_NEON=TRUE

ANDROID_ABI

目標 ABI。如需瞭解支援的 ABI,請參閱 Android ABI

Gradle

Gradle 會自動提供這個引數。請勿在您的 build.gradle 檔案中明確設定這個引數。如要控管 ABI Gradle 的目標,請依照 Android ABI 中所述使用 abiFilters

指令列

CMake 針對每項建構作業的單一目標進行建構。如要設定多個 Android ABI 目標,則必須為每個 ABI 建構一次。建議針對每個 ABI 使用不同的建構目錄,以免建構作業之間發生衝突。

附註
armeabi-v7a
armeabi-v7a with NEON -DANDROID_ABI=armeabi-v7a -DANDROID_ARM_NEON=ON 相同。
arm64-v8a
x86
x86_64

ANDROID_ARM_MODE

指定是否為 armeabi-v7a 產生 arm 或 thumb 指令。不會影響其他 ABI。詳情請參閱 Android ABI 說明文件。

附註
arm
thumb 預設行為。

ANDROID_ARM_NEON

為 armeabi-v7a 啟用或停用 NEON。不會影響其他 ABI。如果是 API 級別 (minSdkVersionANDROID_PLATFORM) 23 以上級別,則預設為 true,否則為 false。詳情請參閱 Neon 支援說明文件。

附註
TRUE API 級別 23 以上級別的預設值。
FALSE API 級別 22 以上級別的預設值。

ANDROID_LD

請選取要使用的連結器。lld 目前是 NDK 的實驗功能,但可透過這個引數啟用。

附註
lld 啟用 lld。
default 針對指定 ABI 使用預設連結器。

ANDROID_NATIVE_API_LEVEL

ANDROID_PLATFORM 的別名。

ANDROID_PLATFORM

指定應用程式或程式庫支援的最低 API 級別。這個值對應應用程式的 minSdkVersion

Gradle

使用 Android Gradle 外掛程式時,系統會自動將這個值設為與應用程式的 minSdkVersion 相符,因此不應手動設定。

指令列

直接叫用 CMake 時,這個值會預設為使用的 NDK 所支援的最低 API 級別。例如,針對 NDK r20,這個值預設為 API 級別 16。

這個參數支援多種格式:

  • android-$API_LEVEL
  • $API_LEVEL
  • android-$API_LETTER

$API_LETTER 格式可讓您指定 android-N,而無需確定該版本編號。請注意,部分版本增加了 API,但字母沒有增加。您可以透過附加 -MR1 後置字串來指定這些 API。例如,API 級別 25 是 android-N-MR1

ANDROID_STL

指定這個應用程式要使用的 STL。詳情請參閱 C++ 程式庫支援。根據預設,系統會使用 c++_static

附註
c++_shared libc++ 的共用程式庫變化版本。
c++_static libc++ 的靜態程式庫變化版本。
不支援 C++ 標準程式庫。
系統 系統 STL

瞭解 CMake 建構指令

對 CMake 建構問題進行偵錯時,建議您先瞭解 Gradle 在針對 Android 進行跨平台程式碼編譯時使用的特定建構引數。

Android Gradle 外掛程式會針對每個 ABI 及與 build_command.txt 配對的建構類型的 CMake 建構作業,儲存執行此類作業時使用的建構引數。這些檔案位於以下目錄中:

<project-root>/<module-root>/.cxx/cmake/<build-type>/<ABI>/

下列程式碼片段顯示 CMake 引數範例,用於建構指定 armeabi-v7a 架構的 hello-jni 範例版本,並進行偵錯。

                    Executable : ${HOME}/Android/Sdk/cmake/3.10.2.4988404/bin/cmake
arguments :
-H${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/src/main/cpp
-DCMAKE_FIND_ROOT_PATH=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/.cxx/cmake/universalDebug/prefab/armeabi-v7a/prefab
-DCMAKE_BUILD_TYPE=Debug
-DCMAKE_TOOLCHAIN_FILE=${HOME}/Android/Sdk/ndk/22.1.7171670/build/cmake/android.toolchain.cmake
-DANDROID_ABI=armeabi-v7a
-DANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
-DANDROID_PLATFORM=android-23
-DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a
-DCMAKE_ANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
-DCMAKE_MAKE_PROGRAM=${HOME}/Android/Sdk/cmake/3.10.2.4988404/bin/ninja
-DCMAKE_SYSTEM_NAME=Android
-DCMAKE_SYSTEM_VERSION=23
-B${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/.cxx/cmake/universalDebug/armeabi-v7a
-GNinja
jvmArgs :


                    Build command args: []
                    Version: 1

使用預建程式庫

如果需要匯入的預先建構程式庫以 AAR 發布,請按照 Studio 的依附元件文件匯入及使用。如果您使用的不是 AGP,可以按照 https://google.github.io/prefab/example-workflow.html 操作,但遷移至 AGP 可能會更簡單。

針對並非以 AAR 發布的程式庫,如要瞭解如何搭配 CMake 使用預先建構的程式庫,請參閱 CMake 手冊中與 IMPORTED 目標相關的 add_library 說明文件。

建構第三方程式碼

在您的 CMake 專案中建構第三方程式碼的方法有很多,您可以根據自己的情況,選擇最適合的選項。最好的選項通常是完全不這麼做。請改為針對程式庫建構 AAR,並在應用程式中使用。您不一定要發布 AAR。可能是 Gradle 專案內部的資料。

如果沒有這個選項:

  • 將第三方來源供應商 (即複製) 整合至存放區,並使用 add_subdirectory 進行建構。只有在其他程式庫也使用 CMake 建構時,才能使用此方法。
  • 定義 ExternalProject
  • 從專案中單獨建構程式庫,然後按照「使用預先建構的程式庫」將程式庫匯入為預先建構程式庫。

CMake 中的 YASM 支援

NDK 針對建構以 YASM 編寫的組譯程式碼提供 CMake 支援,以便在 x86 和 x86-64 架構上執行。YASM 是 x86 和 x86-64 架構的開放原始碼組譯工具,以 NASM 組譯工具為基礎。

如要使用 CMake 建構組譯程式碼,請在專案的 CMakeLists.txt 中進行下列變更:

  1. 呼叫 enable_language,並將值設為 ASM_NASM
  2. 如要建構共用程式庫,請呼叫 add_library;如要建構可執行的二進位檔,則呼叫 add_executable。在引數中傳遞來源檔案清單,其中包含 YASM 中組合程式的 .asm 檔案,以及相關聯 C 程式庫或函式的 .c 檔案。

下列程式碼片段展示如何設定 CMakeLists.txt,以將 YASM 程式建構為共用程式庫。

cmake_minimum_required(VERSION 3.6.0)

enable_language(ASM_NASM)

add_library(test-yasm SHARED jni/test-yasm.c jni/print_hello.asm)

如需查看示範將 YASM 程式建構為執行檔的範例,請參閱 NDK Git 存放區中的 YASM 測試

回報問題

如果您遇到 NDK 或其 CMake 工具鍊檔案的相關問題,請透過 GitHub 的 android-ndk/ndk Issue Tracker 回報問題。針對 Gradle 或 Android Gradle 外掛程式的問題,請改為回報 Studio 錯誤