تتيح حزمة تطوير البرامج الأصلية (Android NDK) لنظام التشغيل Android استخدام CMake لتجميع رموز C وC++ لتطبيقك. توضّح هذه الصفحة كيفية استخدام CMake مع حزمة NDK من خلال ExternalNativeBuild في المكوّن الإضافي Android Gradle أو عند استدعاء CMake مباشرةً.
ملف سلسلة أدوات CMake
يتوافق NDK مع CMake من خلال ملف مجموعة أدوات. ملفات Toolchain هي ملفات CMake
تخصّص سلوك Toolchain للترجمة البرمجية المتوافقة مع أنظمة متعددة. يقع ملف مجموعة الأدوات المستخدَمة مع NDK في NDK على المسار <NDK>/build/cmake/android.toolchain.cmake.
يتم تقديم مَعلمات الإنشاء، مثل ABI وminSdkVersion وما إلى ذلك، في سطر الأوامر عند استدعاء cmake. للاطّلاع على قائمة بالوسيطات المتوافقة، راجِع قسم وسيطات Toolchain.
ملف سلسلة الأدوات "الجديد"
جرّبت إصدارات 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
وسيطات مجموعة الأدوات
يمكن تمرير الوسيطات التالية إلى ملف مجموعة أدوات CMake. في حال الإنشاء باستخدام Gradle، أضِف وسيطات إلى android.defaultConfig.externalNativeBuild.cmake.arguments كما هو موضّح في مستندات ExternalNativeBuild. في حال الإنشاء من سطر الأوامر، مرِّر الوسيطات إلى CMake باستخدام -D. على سبيل المثال، لمنع armeabi-v7a من الإنشاء باستخدام ميزة Neon، عليك تمرير -DANDROID_ARM_NEON=FALSE.
ANDROID_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) المستخدَمة. على سبيل المثال، مع الإصدار 20 من NDK، تكون هذه القيمة تلقائية على مستوى واجهة برمجة التطبيقات 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. إذا كنت بحاجة إلى التحكّم في علامات المترجم لكل buildType من AGP،
اطّلِع على استخدام أنواع الإصدارات في AGP مع CMake.
العمل مع أنواع الإصدارات في AGP باستخدام CMake
إذا كنت بحاجة إلى تخصيص سلوك CMake لنوع تصميم Gradle مخصّص buildType، استخدِم نوع التصميم هذا لتمرير علامة 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_ لتجنُّب التعارض أو الخلط مع العلامات الحالية.
يمكنك الاطّلاع على مثال على حزمة تطوير البرامج (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 test في مستودع NDK git.
الإبلاغ عن المشكلات
إذا واجهت أي مشاكل في NDK أو ملف سلسلة أدوات CMake، يمكنك الإبلاغ عنها من خلال أداة تتبُّع المشاكل android-ndk/ndk على GitHub. بالنسبة إلى مشاكل Gradle أو "المكوّن الإضافي لنظام Gradle المتوافق مع Android"، يُرجى الإبلاغ عن خطأ في "استوديو Android" بدلاً من ذلك.