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 級別 (minSdkVersion
或 ANDROID_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++ 的靜態程式庫變化版本。 |
none | 不支援 C++ 標準程式庫。 |
system | 系統 STL |
瞭解 CMake 建構指令
如要對 CMake 建構問題進行偵錯,建議您先瞭解 Gradle 在為 Android 進行跨平台程式碼編譯時使用哪些特定建構引數。
Android Gradle 外掛程式會針對每個 ABI 及與 build_command.txt
配對的建構類型的 CMake 建構作業,儲存執行此類作業時使用的建構引數。這些檔案位於以下目錄中:
<project-root>/<module-root>/.cxx/cmake/<build-type>/<ABI>/
您可以使用 CMake 引數建構 hello-jni
範例的可偵錯版本並指定 armeabi-v7a
架構,如以下程式碼片段範例所示:
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
中進行下列變更:
- 呼叫
enable_language
,並將值設為ASM_NASM
。 - 如要建構共用程式庫,請呼叫
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 錯誤。