تتيح حزمة Android NDK استخدام CMake لتجميع رمز C وC++ البرمجي لتطبيقك. تتناول هذه الصفحة كيفية استخدام
CMake مع NDK من خلال ExternalNativeBuild في المكوّن الإضافي لنظام Gradle المتوافق مع Android أو عند
استدعاء CMake مباشرةً.
ملف سلسلة أدوات CMake
تتيح حزمة NDK استخدام CMake من خلال ملف سلسلة أدوات. ملفات Toolchain هي ملفات CMake
تخصّص سلوك سلسلة الأدوات للتجميع المتبادل. يوجد ملف سلسلة الأدوات المستخدَم في NDK في NDK على المسار <NDK>/build/cmake/android.toolchain.cmake.
يتم تقديم مَعلمات الإصدار، مثل واجهة التطبيق الثنائية (ABI) وminSdkVersion وما إلى ذلك، في سطر الأوامر عند استدعاء cmake. للحصول على قائمة بالوسيطات المتوافقة، يُرجى الاطّلاع على قسم وسيطات سلسلة الأدوات.
ملف سلسلة الأدوات "الجديد"
في إصدارات NDK السابقة، تم تجربة تنفيذ جديد لملف سلسلة الأدوات من شأنه تقليل الاختلافات في السلوك بين استخدام ملف سلسلة أدوات NDK واستخدام دعم CMake المدمج. تطلّب ذلك قدرًا كبيرًا من العمل (الذي لم يكتمل)، ولكنه لم يحسّن السلوك فعليًا، لذلك لم نعد نتابع هذا الأمر.
يتضمّن ملف سلسلة الأدوات "الجديد" تراجعات في السلوك مقارنةً بملف سلسلة الأدوات "القديم". الإعداد التلقائي هو سير العمل المقترَح. إذا كنت تستخدم -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF، ننصحك بإزالة هذه العلامة من الإصدار. لم يصل ملف سلسلة الأدوات الجديد إلى مستوى التكافؤ مع ملف سلسلة الأدوات القديم، لذا من المحتمل حدوث تراجعات في السلوك.
على الرغم من أنّنا ننصح بعدم استخدام ملف سلسلة الأدوات الجديد، لا توجد حاليًا أي خطط لإزالته من NDK. سيؤدي ذلك إلى تعطيل عمليات الإنشاء التي تعتمد على الاختلافات في السلوك بين ملفات سلسلة الأدوات الجديدة والقديمة، وللأسف، فإنّ إعادة تسمية الخيار لتوضيح أنّ "القديم" هو في الواقع الخيار المقترَح سيؤدي أيضًا إلى تعطيل مستخدمي هذا الخيار. إذا كنت تستخدم ملف سلسلة الأدوات الجديد بدون مشاكل، لن تحتاج إلى نقل البيانات، ولكن يُرجى العِلم أنّ أي أخطاء يتم الإبلاغ عنها في سلوك ملف سلسلة الأدوات الجديد لن يتم إصلاحها على الأرجح، وبدلاً من ذلك ستحتاج إلى نقل البيانات.
الاستخدام
Gradle
يتم استخدام ملف سلسلة أدوات CMake تلقائيًا عند استخدام
externalNativeBuild. لمزيد من المعلومات، يمكنك الاطّلاع على دليل إضافة رمز C وC++ إلى مشروعك في "استوديو Android".
سطر الأوامر
عند الإنشاء باستخدام 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 إصدارات لهدف واحد لكل إصدار. لاستهداف أكثر من واجهة تطبيق ثنائية (ABI) واحدة لنظام التشغيل Android، يجب إنشاء حزمة لكل واجهة. ننصحك باستخدام أدلة إصدارات مختلفة لكل واجهة ABI لتجنُّب حدوث تعارض بين الإصدارات.
| القيمة | الملاحظات |
|---|---|
armeabi-v7a |
|
armeabi-v7a with NEON |
هو مطابق لـ armeabi-v7a. |
arm64-v8a |
|
x86 |
|
x86_64 |
ANDROID_ARM_MODE
يحدّد هذا الإعداد ما إذا كان سيتم إنشاء تعليمات arm أو thumb لـ armeabi-v7a. وليس لها أي تأثير في واجهات التطبيقات الثنائية الأخرى. لمزيد من المعلومات، يُرجى الاطّلاع على مستندات واجهات التطبيقات الثنائية (ABI) لنظام التشغيل Android.
| القيمة | الملاحظات |
|---|---|
| ذراع | |
| إبهام | الإعداد التلقائي |
ANDROID_NATIVE_API_LEVEL
اسم بديل لـ ANDROID_PLATFORM.
ANDROID_PLATFORM
يحدّد هذا العنصر الحدّ الأدنى لمستوى واجهة برمجة التطبيقات الذي يتوافق مع التطبيق أو المكتبة. تتوافق هذه القيمة مع minSdkVersion للتطبيق.
Gradle
عند استخدام المكوّن الإضافي لنظام Gradle المتوافق مع Android، يتم ضبط هذه القيمة تلقائيًا لتتطابق مع minSdkVersion للتطبيق، ويجب عدم ضبطها يدويًا.
سطر الأوامر
عند استدعاء CMake مباشرةً، يتم ضبط هذه القيمة تلقائيًا على أدنى مستوى لواجهة برمجة التطبيقات متوافق مع حزمة NDK المستخدَمة. على سبيل المثال، مع NDK r20، يتم ضبط هذه القيمة تلقائيًا على مستوى واجهة برمجة التطبيقات 16.
يتم قبول تنسيقات متعددة لهذه المَعلمة:
android-$API_LEVEL$API_LEVELandroid-$API_LETTER
يتيح لك تنسيق $API_LETTER تحديد android-N بدون الحاجة إلى تحديد الرقم المرتبط بهذا الإصدار. لاحظ أن بعض الإصدارات
حصلت على زيادة في واجهة برمجة التطبيقات دون زيادة في الحروف. يمكن تحديد واجهات برمجة التطبيقات هذه
من خلال إلحاق اللاحقة -MR1. على سبيل المثال، مستوى واجهة برمجة التطبيقات 25 هو android-N-MR1.
ANDROID_STL
يحدّد هذا الإعداد مكتبة STL التي سيتم استخدامها لهذا التطبيق. لمزيد من المعلومات، يُرجى الاطّلاع على دعم مكتبة C++. سيتم استخدام "c++_static" تلقائيًا.
| القيمة | الملاحظات |
|---|---|
| c++_shared | صيغة المكتبة المشتركة من libc++. |
| c++_static | هو صيغة المكتبة الثابتة من libc++. |
| بلا قيمة | لا تتوفّر مكتبة C++ عادية. |
| النظام | نظام STL |
إدارة علامات برنامج التجميع
إذا كنت بحاجة إلى تمرير علامات معيّنة إلى برنامج التجميع أو الرابط لعملية الإنشاء، يُرجى الرجوع إلى مستندات CMake حول set_target_compile_options ومجموعة الخيارات ذات الصلة. يحتوي قسم "انظر أيضًا" في أسفل تلك الصفحة على بعض الأدلة المفيدة.
بشكل عام، من أفضل الممارسات تطبيق علامات برنامج التجميع على أضيق نطاق متاح. إنّ العلامات التي تريد تطبيقها على جميع أهدافك (مثل -Werror) من غير الملائم تكرارها لكل وحدة، ولكن نادرًا ما يجب تطبيقها على مستوى العالم (CMAKE_CXX_FLAGS)، لأنّ ذلك قد يكون له تأثيرات غير مرغوب فيها على التبعيات التابعة لجهات خارجية في مشروعك. في هذه الحالات، يمكن تطبيق العلامات على مستوى الدليل (add_compile_options).
بالنسبة إلى مجموعة فرعية ضيقة من علامات برنامج التجميع، يمكن أيضًا ضبطها في ملف build.gradle
باستخدام cppFlags أو سمات مشابهة. يجب عدم إجراء ذلك. ستكون للعلامات التي يتم تمريرها إلى CMake من Gradle سلوكيات أسبقية مفاجئة، وفي بعض الحالات، ستلغي العلامات التي تم تمريرها ضمنيًا من خلال عملية التنفيذ المطلوبة لإنشاء رمز Android. يُفضَّل دائمًا التعامل مع سلوك CMake
مباشرةً في CMake. إذا كنت بحاجة إلى التحكّم في علامات برنامج التجميع لكل إصدار من مكوّن Android Gradle الإضافي buildType،
يُرجى الاطّلاع على العمل مع أنواع إصدارات مكوّن Android Gradle الإضافي في CMake.
العمل مع أنواع إصدارات AGP في CMake
إذا كنت بحاجة إلى تخصيص سلوك CMake ليتوافق مع buildType مخصّص في Gradle، استخدِم نوع الإصدار هذا لتمرير علامة CMake إضافية (ليست علامة برنامج تجميع) يمكن لنصوص إصدار CMake البرمجية قراءتها. على سبيل المثال، إذا كانت لديك تنويعات تصميم "مجانية" و "مدفوعة"
يتم التحكّم فيها من خلال ملف 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
عند تصحيح أخطاء إصدارات CMake، من المفيد معرفة وسيطات الإصدار المحدّدة التي يستخدمها Gradle عند التجميع المتبادل لنظام التشغيل Android.
يحفظ المكوّن الإضافي لنظام Gradle المتوافق مع Android وسيطات الإصدار التي يستخدمها لتنفيذ إصدار CMake لكل زوج من واجهات ABI ونوع الإصدار في 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، اتّبِع مستندات الاعتمادية في "استوديو Android" لاستيرادها واستخدامها. إذا لم تكن تستخدم 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 في مستودع git الخاص بمجموعة NDK.
الإبلاغ عن المشكلات
إذا واجهت أي مشاكل في NDK أو ملف سلسلة أدوات CMake، يمكنك الإبلاغ عنها من خلال أداة تتبُّع المشاكل android-ndk/ndk على GitHub. بالنسبة إلى المشاكل في Gradle أو المكوّن الإضافي لنظام Gradle المتوافق مع Android، يُرجى الإبلاغ عن خطأ في "استوديو Android" بدلاً من ذلك.