CMake

Android NDK תומך בשימוש ב-CMake כדי להדר את קוד C ו-C++ לאפליקציה שלכם. בדף הזה מוסבר איך משתמשים CMake באמצעות NDK באמצעות ExternalNativeBuild של הפלאגין של Android Gradle או כאשר בהפעלה ישירה של CMake.

קובץ ה-toolchain של CMake

NDK תומך ב-CMake באמצעות קובץ Toolchain. קובצי Toolchain הם קובצי CMake להתאמה אישית של ההתנהגות של ה-toolchain לביצוע הידור מוצלב. שרשרת הכלים משמש עבור ה-NDK נמצא ב-NDK ב- <NDK>/build/cmake/android.toolchain.cmake

פרמטרים של build כמו ABI , minSdkVersion וכו' ניתנים בפקודה כשמפעילים את cmake. לרשימת ארגומנטים נתמכים אפשר לעיין במאמר הקטע Toolchain instances.

"החדש" קובץ Toolchain

בשלב מוקדם יותר, קבוצות NDK ניסו הטמעה חדשה של קובץ Toolchain יצמצם את ההבדלים בהתנהגות בין השימוש בקובץ ה-toolchain של ה-NDK באמצעות התמיכה המובנית של CMake. בסופו של דבר, נדרש נפח משמעותי עבודה (שלא הושלמה), אבל לא שיפרה בפועל את ההתנהגות, ולכן אנחנו כבר לא מטפלים בנושא הזה.

"החדש" לקובץ Toolchain יש רגרסיות של התנהגות בהשוואה לקובץ ה-toolchain "מדור קודם". Toolchain. פעולת ברירת המחדל היא תהליך העבודה המומלץ. אם אתם באמצעות -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF, אנחנו ממליצים להסיר את הדגל הזה מה-build שלך. קובץ ה-toolchain החדש מעולם לא זהה לזה של הגרסה הקודמת קובץ Toolchain, ולכן סביר להניח שיש רגרסיות של התנהגות.

למרות שמומלץ לא להשתמש בקובץ Toolchain החדש, אין כרגע להסיר אותו מה-NDK. פעולה כזו תפגע בגרסאות build שמסתמכות על את ההבדלים בהתנהגות בין קובצי ה-toolchain החדשים לקבצים הקודמים, למרבה הצער, שינוי השם של האפשרות כדי להבהיר ש"מדור קודם" הוא למעשה מומלץ גם לגרום נזק למשתמשים באפשרות הזו. אם אתם שמחים להשתמש את קובץ ה-toolchain החדש שאין צורך להעביר, אבל חשוב לדעת שיש באגים ההתנהגות החדשה של קובץ ה-toolchain לא תטופל, ובמקום זאת שתצטרכו לבצע את ההעברה.

שימוש

גרדל

השימוש בקובץ Toolchain של CMake הוא אוטומטי כשמשתמשים externalNativeBuild צפייה בקטעים הוספת קוד C ו-C++ של Android Studio לקבלת מידע נוסף על הפרויקט.

שורת הפקודה

כשמפתחים באמצעות CMake מחוץ ל-Gradle, קובץ ה-toolchain עצמו יש להעביר את הארגומנטים שלו ל-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 אם בונים משורת הפקודה, מעבירים את הארגומנטים יוצרים ביחד עם -D. לדוגמה, כדי לאלץ את Armeabi-v7a לא לבנות באמצעות ניאון תמיכה, צריך להעביר את -DANDROID_ARM_NEON=FALSE.

ANDROID_ABI

ממשק ה-ABI של היעד. מידע נוסף על ממשקי ABI נתמכים מופיע במאמר ממשקי ABI של Android.

גרדל

הארגומנט הזה מופיע ב-Gradle באופן אוטומטי. לא להגדיר במפורש ארגומנט בקובץ build.gradle. כדי לקבוע לאילו יעדים של ABIs Gradle: להשתמש ב-abiFilters כפי שמתואר בממשקי ABI של Android.

שורת הפקודה

יצירת גרסאות build ליעד אחד בכל build. כדי לטרגט ליותר ממכשיר Android אחד צריך ליצור ממשק ABI פעם אחת לכל ABI. מומלץ להשתמש בגרסת build אחרת של כל ממשק ABI כדי למנוע התנגשויות בין גרסאות build.

ערך הערות
armeabi-v7a
armeabi-v7a with NEON בדיוק כמו במלון armeabi-v7a.
arm64-v8a
x86
x86_64

ANDROID_ARM_MODE

המדיניות קובעת אם ליצור הוראות לזרוע או לזרוע הבקרה עבור Armeabi-v7a. לא השפעה על ממשקי ABI אחרים. מידע נוסף זמין במאמר ממשקי ABI של Android התיעוד.

ערך הערות
זרוע
אגודל פעולת ברירת המחדל.

ANDROID_NATIVE_API_LEVEL

כינוי עבור ANDROID_PLATFORM.

ANDROID_PLATFORM

מציינת את רמת ה-API המינימלית שנתמכת על ידי האפליקציה או הספרייה. הזה תואם לערך minSdkVersion של האפליקציה.

גרדל

כשמשתמשים בפלאגין Android Gradle, הערך הזה מוגדר באופן אוטומטי בתור תואם ל-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 של המערכת

ניהול דגלי מהדר

אם אתם צריכים להעביר דגלים ספציפיים ל-compiler או ל-linker ב-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.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_ כדי למנוע התנגשות או בלבול עם דגלים קיימים.

אפשר לראות דוגמה בדוגמה של Sanitizers NDK.

הסבר על הפקודה של CMake build

במהלך ניפוי באגים של CMake, כדאי לדעת מהו ה-build הספציפי ארגומנטים שבהם Gradle משתמשת במהלך הידור צולב ל-Android.

הפלאגין Android Gradle שומר את ארגומנטים של ה-build שבהם הוא משתמש כדי לבצע יצירת גרסת build לכל ממשק 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:

  1. קוראים לפונקציה enable_language שהערך שלו מוגדר ל-ASM_NASM.
  2. תלוי אם בונים ספרייה משותפת או קובץ הפעלה בינארי, קוראים לפונקציה 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 לביצוע הבדיקה במאגר ה-GIT של NDK.

דיווח על בעיות

אם נתקלתם בבעיות ב-NDK או בקובץ ה-toolchain של CMake, אפשר לדווח עליהן דרך הכלי למעקב אחרי בעיות android-ndk/ndk ב-GitHub. ל-Gradle או אם יש בעיות בפלאגין Android Gradle, אפשר לדווח על באג ב-Studio במקום זאת.