ב-Android NDK יש תמיכה בשימוש ב-CMake כדי לקמפל קוד C ו-C++ לאפליקציה. בדף הזה נסביר איך להשתמש ב-CMake באמצעות NDK דרך ExternalNativeBuild
של הפלאגין Android Gradle, או בהפעלה ישירה של CMake.
קובץ toolchain של CMake
NDK תומך ב-CMake באמצעות קובץ Toolchain. קובצי ערכת כלים הם קובצי CMake שמתאימים אישית את ההתנהגות של ערכת הכלים לצורך הידור חוצה-פלטפורמות. קובץ toolchain שמשמש את NDK נמצא ב-NDK בכתובת <NDK>/build/cmake/android.toolchain.cmake
.
פרמטרים של build כמו ABI, minSdkVersion
וכו' מצוינים בשורת הפקודה כשמריצים את cmake
. רשימת הארגומנטים הנתמכים מופיעה בקטע ארגומנטים של ערכת כלים.
קובץ toolchain ה'חדש'
בגרסאות קודמות של NDK ניסו להטמיע גרסה חדשה של קובץ toolchain, שצפויה לצמצם את ההבדלים בהתנהגות בין השימוש בקובץ toolchain של NDK לבין השימוש בתמיכה המובנית של CMake. בסופו של דבר, התהליך הזה דרש כמות משמעותית של עבודה (שעדיין לא הושלמה), אבל לא שיפר את ההתנהגות בפועל, ולכן אנחנו לא ממשיכים בכך.
בקובץ toolchain ה'חדש' יש נסיגה בהתנהגות בהשוואה לקובץ toolchain ה'ישן'. התנהגות ברירת המחדל היא תהליך העבודה המומלץ. אם אתם משתמשים ב--DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF
, מומלץ להסיר את הדגל הזה מה-build. קובץ כלי הפיתוח החדש אף פעם לא הגיע לסטטוס זהה לקובץ כלי הפיתוח הקודם, ולכן סביר להניח שיהיו נסיגות בהתנהגות.
אנחנו ממליצים לא להשתמש בקובץ החדש של כלי הפיתוח, אבל אין כרגע תוכניות להסיר אותו מ-NDK. הפעולה הזו תגרום לשיבושים בגרסאות build שמסתמכות על ההבדלים בהתנהגות בין קבצי כלי הפיתוח מהדור הקודם לבין קבצי כלי הפיתוח החדשים. לצערנו, שינוי השם של האפשרות כדי להבהיר שהאפשרות 'מהדור קודם' היא המומלצת גם כן יגרום לשיבושים אצל המשתמשים באפשרות הזו. אם אתם מרוצים מהשימוש בקובץ החדש של כלי הפיתוח, אין צורך לבצע את ההעברה. עם זאת, חשוב לדעת שסביר להניח שלא נתקן באגים שדווחו לגבי התנהגות הקובץ החדש של כלי הפיתוח, ובמקום זאת תצטרכו לבצע את ההעברה.
שימוש
Gradle
כשמשתמשים ב-externalNativeBuild
, המערכת משתמשת בקובץ של CMake toolchain באופן אוטומטי. מידע נוסף זמין במדריך הוספת קוד C ו-C++ לפרויקט שלכם של Android Studio.
שורת הפקודה
כשמבצעים build באמצעות CMake מחוץ ל-Gradle, צריך להעביר ל-CMake את קובץ כלי הפיתוח ואת הארגומנטים שלו. לדוגמה:
$ cmake \
-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=$ABI \
-DANDROID_PLATFORM=android-$MINSDKVERSION \
$OTHER_ARGS
ארגומנטים של ערכת כלים
ניתן להעביר את הארגומנטים הבאים לקובץ Toolchain של CMake. אם אתם משתמשים ב-Gradle, מוסיפים ארגומנטים ל-android.defaultConfig.externalNativeBuild.cmake.arguments
כפי שמתואר במסמכים של ExternalNativeBuild. אם אתם בונים משורת הפקודה, מעבירים את הארגומנטים ל-CMake באמצעות -D
. לדוגמה, כדי לאלץ את armeabi-v7a לא לבנות עם תמיכה ב-Neon, מעבירים את הערך -DANDROID_ARM_NEON=FALSE
.
ANDROID_ABI
ממשק ה-ABI היעד. מידע נוסף על ממשקי ABI נתמכים מופיע במאמר ממשקי ABI של Android.
Gradle
הארגומנט הזה מופיע ב-Gradle באופן אוטומטי. אין להגדיר את הארגומנט הזה באופן מפורש בקובץ build.gradle
. כדי לקבוע לאילו ממשקי ABI יופנה Gradle, משתמשים ב-abiFilters
כפי שמתואר בקטע ממשקי ABI של Android.
שורת הפקודה
CMake יוצר גרסאות build ליעד יחיד לכל build. כדי לטרגט יותר מממשק ABI אחד ל-Android, צריך לבצע build פעם אחת לכל ממשק ABI. מומלץ להשתמש בספריות build שונות לכל ABI כדי למנוע התנגשויות בין גרסאות build.
ערך | הערות |
---|---|
armeabi-v7a |
|
armeabi-v7a with NEON |
בדיוק כמו במלון armeabi-v7a . |
arm64-v8a |
|
x86 |
|
x86_64 |
ANDROID_ARM_MODE
קובע אם ליצור הוראות arm או thumb עבור armeabi-v7a. אין לה השפעה על ממשקי ABI אחרים. מידע נוסף זמין במסמכי העזרה בנושא Android ABIs.
ערך | הערות |
---|---|
זרוע | |
אגודל | התנהגות ברירת המחדל. |
ANDROID_NATIVE_API_LEVEL
כינוי ל-ANDROID_PLATFORM.
ANDROID_PLATFORM
מציין את רמת ה-API המינימלית שנתמכת באפליקציה או בספרייה. הערך הזה תואם ל-minSdkVersion
של האפליקציה.
גרדל
כשמשתמשים ב-Android Gradle Plugin, הערך הזה מוגדר באופן אוטומטי כך שיתאים ל-minSdkVersion
של האפליקציה, ואין להגדיר אותו באופן ידני.
שורת הפקודה
כשמפעילים את CMake ישירות, הערך הזה מוגדר כברירת מחדל לרמת ה-API הנמוכה ביותר שנתמכת ב-NDK שבשימוש. לדוגמה, ב-NDK r20 הערך שמוגדר כברירת מחדל הוא רמת API 16.
המערכת מקבלת פורמטים שונים של הפרמטר הזה:
android-$API_LEVEL
$API_LEVEL
android-$API_LETTER
הפורמט $API_LETTER
מאפשר לציין את android-N
בלי שתצטרכו לקבוע את המספר שמשויך למהדורה הזו. חשוב לדעת שחלק מהגרסאות קיבלו הגדלה של API בלי הגדלה של מספר האותיות. כדי לציין את ממשקי ה-API האלה, צריך לצרף את הסיומת -MR1
. לדוגמה, רמת API 25 היא android-N-MR1
.
ANDROID_STL
מציינת באיזה STL להשתמש עבור האפליקציה הזו. למידע נוסף, ראו תמיכה בספריית C++. כברירת מחדל, המערכת תשתמש ב-c++_static
.
ערך | הערות |
---|---|
c++_shared | גרסת הספרייה המשותפת של libc++. |
c++_static | גרסת הספרייה הסטטית של libc++. |
ללא | אין תמיכה בספרייה הרגילה של C++. |
מערכת | ה-STL של המערכת |
ניהול דגלים של מהדר
אם אתם צריכים להעביר דגלים ספציפיים למהדר או למקשר של ה-build, תוכלו לעיין במסמכי התיעוד של CMake לגבי set_target_compile_options ולמשפחת האפשרויות הקשורה. בקטע 'מידע נוסף' שבתחתית הדף מופיעים כמה רמזים מועילים.
באופן כללי, השיטה המומלצת היא להחיל את דגלים של המהדר בטווח המצומצם ביותר הזמין. לא נוח לחזור על דגלים שרוצים להחיל על כל היעדים (כמו -Werror
) בכל מודול, אבל עדיין נדיר להחיל אותם באופן גלובלי (CMAKE_CXX_FLAGS
), כי הם עלולים להשפיע לרעה על יחסי התלות בצד שלישי בפרויקט. במקרים כאלה, אפשר להחיל את הדגלים ברמת הספרייה (add_compile_options
).
בשביל קבוצת משנה מצומצמת של דגלי מהדר, אפשר להגדיר אותם גם בקובץ build.gradle באמצעות cppFlags
או מאפיינים דומים. לא מומלץ לעשות זאת. לסימונים שיועברו ל-CMake מ-Gradle יהיו התנהגות קדימות מפתיעה, ובמקרים מסוימים הם יבטלו דגלים שמועברים באופן לא מפורש על ידי ההטמעה שנדרשים ליצירת הקוד של Android. תמיד עדיף לטפל בהתנהגות של CMake ישירות ב-CMake. אם אתם צריכים לשלוט בדגלי מהדר עבור כל AGP buildType
, תוכלו לקרוא את המאמר עבודה עם סוגי build של AGP ב-CMake.
עבודה עם סוגי גרסאות build של AGP ב-CMake
אם אתם צריכים להתאים את ההתנהגות של CMake ל-Gradle buildType
מותאם אישית, השתמשו בסוג ה-build הזה כדי להעביר דגל CMake נוסף (לא דגל מהדר) שהסקריפטים של CMake build יוכלו לקרוא. לדוגמה, אם יש לכם וריאנטים של build מסוג 'free' ו-'premium' שנשלטים על ידי build.gradle.kts, ואתם צריכים להעביר את הנתונים האלה ל-CMake:
android {
buildTypes {
free {
externalNativeBuild {
cmake {
arguments.add("-DPRODUCT_VARIANT_PREMIUM=OFF")
}
}
}
premium {
externalNativeBuild {
cmake {
arguments.add("-DPRODUCT_VARIANT_PREMIUM=ON")
}
}
}
}
}
לאחר מכן, בקובץ CMakeLists.txt:
if (DPRODUCT_VARIANT_PREMIUM)
# Do stuff for the premium build.
else()
# Do stuff for the free build.
endif()
אתם קובעים את שם המשתנה, אבל חשוב להימנע משימוש בקידומת ANDROID_
, APP_
או CMAKE_
כדי למנוע התנגשות או בלבול עם הדגלים הקיימים.
דוגמה לכך מופיעה בדוגמה של NDK ל-Sanitizers.
הסבר על פקודת ה-build של CMake
כשמנסים לנפות באגים בבעיות של יצירת גרסאות build ב-CMake, כדאי לדעת אילו ארגומנטים ספציפיים ליצירת גרסאות build Gradle משתמש בהם כשמבצעים הידור חוצה (cross-compilation) ל-Android.
הפלאגין של Android Gradle שומר את ארגומנטים ה-build שבהם הוא משתמש כדי להריץ build של CMake לכל צמד של ABI וסוג build ב-build_command.txt
. הקבצים האלה נמצאים בספרייה הבאה:
<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 מפורטות במסמכי העזרה של add_library
לגבי יעדים של IMPORTED
במדריך CMake.
פיתוח קוד של צד שלישי
יש כמה דרכים לפתח קוד של צד שלישי כחלק מפרויקט CMake, והאפשרות שתתאים לכם תלויה במצב שלכם. ברוב המקרים, האפשרות הטובה ביותר היא לא לעשות זאת בכלל. במקום זאת, יוצרים קובץ AAR לספרייה ומשתמשים בו באפליקציה. אין צורך לפרסם את ה-AAR הזה. היא יכולה להיות פנימית בפרויקט Gradle שלכם.
אם האפשרות הזו לא זמינה:
- מעתיקים את המקור של הצד השלישי למאגר ומשתמשים ב-add_subdirectory כדי ליצור אותו. הפעולה הזו פועלת רק אם הספרייה השנייה בנויה גם היא באמצעות CMake.
- מגדירים ExternalProject.
- צריך ליצור את הספרייה בנפרד מהפרויקט, ולאחר מכן לייבא אותה כספרייה מוכנה מראש לפי ההוראות במאמר שימוש בספריות מוכנות מראש.
תמיכה ב-YASM ב-CMake
ה-NDK מספק תמיכה ב-CMake לקוד הרכבה של מבנים שנכתבו ב-YASM להרצה בארכיטקטורות x86 ו-x86-64. YASM הוא מאסם בקוד פתוח לארכיטקטורות x86 ו-x86-64, שמבוסס על המאסם NASM.
כדי ליצור קוד אסמבלר באמצעות CMake, מבצעים את השינויים הבאים בקובץ CMakeLists.txt
של הפרויקט:
- קוראים לפונקציה
enable_language
שהערך שלו מוגדר ל-ASM_NASM
. - בהתאם ליצירה של ספרייה משותפת או קובץ בינארי להפעלה, קוראים ל-
add_library
או ל-add_executable
. בארגומנטים, מעבירים רשימה של קובצי מקור שמכילים את הקבצים.asm
של תוכנית האסיפה ב-YASM ואת הקבצים.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 כקובץ הפעלה מופיעה ב-yasm test במאגר NDK git.
דיווח על בעיות
אם תיתקלו בבעיות ב-NDK או בקובץ Toolchain של CMake, תוכלו לדווח עליהן דרך המעקב אחר בעיות android-ndk/ndk ב-GitHub. אם מדובר בבעיות ב-Gradle או בפלאגין של Android Gradle, דווחו על באג ב-Studio במקום זאת.