دمج أنظمة إنشاء C/C++ مخصصة باستخدام Ninja (تجريبي)

إذا كنت لا تستخدم CMake أو ndk-build ولكنك تريد الدمج الكامل لكل من مكوّن Android Gradle الإضافي (AGP) C/C++ وإنشاء Android Studio، يمكنك إنشاء نظام إصدار مخصّص بلغة C/C++ من خلال إنشاء نص برمجي بلغة واجهة يكتب معلومات الإصدار بتنسيق ملف إصدار Ninja.

تمت إضافة الدعم التجريبي لأنظمة إنشاء C/C++ المخصصة إلى Android Studio وAGP. تتوفر هذه الميزة بدءًا من إصدار Android Studio Dolphin | 2021.3.1 Canary 4.

نظرة عامة

هناك نمط شائع لمشروعات C/C++ ، خاصة تلك التي تستهدف منصات متعددة، هو إنشاء مشروعات لكل من هذه المنصات من بعض التمثيل الأساسي. ومن الأمثلة البارزة على هذا النمط CMake. يمكن لأداة CMake إنشاء مشاريع لنظامي التشغيل Android وiOS والأنظمة الأساسية الأخرى من تمثيل أساسي واحد، محفوظًا في ملف CMakeLists.txt.

في حين أن CMake مدعوم بشكل مباشر بواسطة AGP، هناك منشئات مشروعات أخرى متاحة غير مدعومة بشكل مباشر:

هذه الأنواع من منشئات المشروعات إما تدعم Ninja كتمثيل للخلفية لإصدار C/C++ أو يمكن تكييفها لإنشاء Ninja كتمثيل خلفية.

عند ضبط إعدادات مشروع AGP بشكل صحيح، يتم تمكين المستخدمين من تنفيذ ما يلي عند استخدام الجهاز لإنشاء نظام مشروع C/C++ متكامل:

  • يمكنك إنشاء التطبيقات باستخدام سطر الأوامر و"استوديو Android".

  • يمكنك تعديل المصادر التي حصلت على دعم كامل لخدمات اللغات (على سبيل المثال، الانتقال إلى التعريف) في "استوديو Android".

  • يمكنك استخدام برامج تصحيح أخطاء "استوديو Android" لتصحيح الأخطاء في العمليات الأصلية والمختلطة.

كيفية تعديل إصدارك لاستخدام نص برمجي مخصص لإعداد لغة C/C++

يشرح هذا القسم خطوات استخدام نص برمجي مخصَّص لإعداد C/C++ من AGP.

الخطوة 1: تعديل ملف build.gradle على مستوى الوحدة للإشارة إلى نص برمجي للإعدادات

لتفعيل دعم Ninja في AGP، يمكنك إعداد experimentalProperties في ملف build.gradle على مستوى الوحدة:

android {
  defaultConfig {
    externalNativeBuild {
      experimentalProperties["ninja.abiFilters"] = [ "x86", "arm64-v8a" ]
      experimentalProperties["ninja.path"] = "source-file-list.txt"
      experimentalProperties["ninja.configure"] = "configure-ninja"
      experimentalProperties["ninja.arguments"] = [
            "\${ndk.moduleMakeFile}",
            "--variant=\${ndk.variantName}",
            "--abi=Android-\${ndk.abi}",
            "--configuration-dir=\${ndk.configurationDir}",
            "--ndk-version=\${ndk.moduleNdkVersion}",
            "--min-sdk-version=\${ndk.minSdkVersion}"
       ]
     }
   }

يتم تفسير الخصائص بواسطة AGP كما يلي:

  • "ninja.abiFilters" هي قائمة بواجهات ABI التي يجب إنشاؤها. القيم الصالحة هي: x86 وx86-64 وarmeabi-v7a وarm64-v8a.

  • ninja.path عبارة عن مسار لملف مشروع C/C++. يمكن أن يكون تنسيق هذا الملف أي صيغة تريدها. ستؤدي التغييرات التي يتم إجراؤها على هذا الملف إلى ظهور إشعار بشأن مزامنة Gradle في "استوديو Android".

  • ninja.configure هو مسار إلى ملف نص برمجي سيتم تنفيذه من خلال Gradle عند اللزوم لإعداد مشروع C/C++. يتم إعداد مشروع عند الإصدار الأول، أو أثناء مزامنة Gradle في "استوديو Android"، أو عندما يتغيّر أحد إعدادات النص البرمجي الخاص بالإعدادات.

  • ninja.arguments هي قائمة بالوسيطات التي سيتم تمريرها إلى النص البرمجي المحدد بواسطة ninja.configure. يمكن أن تشير العناصر في هذه القائمة إلى مجموعة من وحدات الماكرو التي تعتمد قيمها على سياق الإعداد الحالي في AGP:

    • ${ndk.moduleMakeFile} هو المسار الكامل إلى ملف ninja.configure. لذلك في المثال، ستكون C:\path\to\configure-ninja.bat.

    • ${ndk.variantName} هو اسم خيار AGP الحالي الذي يتم إنشاؤه. على سبيل المثال، تصحيح الأخطاء أو الإصدار.

    • ${ndk.abi} هو اسم واجهة AGP ABI الحالية التي يتم إنشاؤها. على سبيل المثال، x86 أو arm64-v8a.

    • ${ndk.buildRoot} هو اسم مجلد يتم إنشاؤه بواسطة AGP والذي يكتب النص البرمجي مخرجاته إليه. سيتم توضيح تفاصيل ذلك في الخطوة 2: إنشاء النص البرمجي للإعدادات.

    • ${ndk.ndkVersion} هو إصدار NDK المراد استخدامه. وتكون هذه عادةً هي القيمة التي يتم تمريرها إلى android.ndkVersion في ملف build.gradle أو قيمة تلقائية في حال عدم توفّر أي قيمة.

    • ${ndk.minPlatform} هو الحد الأدنى من نظام Android الأساسي المستهدَف الذي يطلبه منتدى AGP.

  • ninja.targets هي قائمة بأهداف Ninja المحددة التي يجب إنشاؤها.

الخطوة 2: إنشاء النص البرمجي للإعدادات

إنّ الحد الأدنى من مسؤولية النص البرمجي للإعدادات (configure-ninja.bat في المثال السابق) هو إنشاء ملف build.ninja يعمل على تجميع جميع المخرجات الأصلية للمشروع وربطها، وذلك عند تصميمه باستخدام Ninja. وتشمل هذه الملفات عادةً ملفات .o (كائن) و.a (أرشيف) و.so (عنصر مشترك).

يمكن للنص البرمجي للإعدادات كتابة ملف build.ninja في مكانَين مختلفَين حسب احتياجاتك.

  • إذا كان من المقبول اختيار موقع AGP، سيكتب النص البرمجي للضبط build.ninja في موقع المجموعة في وحدة الماكرو ${ndk.buildRoot}.

  • إذا كان النص البرمجي للإعدادات بحاجة إلى اختيار موقع ملف build.ninja، سيكتب أيضًا ملفًا باسم build.ninja.txt في الموقع المحدّد في وحدة الماكرو ${ndk.buildRoot}. يحتوي هذا الملف على المسار الكامل إلى ملف build.ninja الذي كتبه النص البرمجي للإعدادات.

بنية ملف build.ninja

بشكل عام، سيعمل معظم البنية التي تمثّل بدقة إصدارًا متوافقًا مع Android C/C++. في ما يلي العناصر الأساسية التي يحتاج إليها AGP وAndroid Studio:

  • قائمة ملفات المصدر C/C++ مع العلامات التي تحتاج إليها Clang لتجميعها.

  • قائمة مكتبات الإخراج وتكون هذه الملفات عادةً ملفات .so (عنصر مشترك)، ولكن يمكن أن تكون أيضًا .a (أرشيف) أو ملفات قابلة للتنفيذ (بدون إضافة).

إذا كنت بحاجة إلى أمثلة حول طريقة إنشاء ملف build.ninja، يمكنك الاطّلاع على ناتج CMake عند استخدام منشئ build.ninja.

في ما يلي مثال على نموذج build.ninja مصغر.

rule COMPILE
   command = /path/to/ndk/clang -c $in -o $out {other flags}
rule LINK
   command = /path/to/ndk/clang $in -o $out {other flags}

build source.o : COMPILE source.cpp
build lib.so : LINK source.o

أفضل الممارسات

بالإضافة إلى المتطلبات (قائمة ملفات المصدر ومكتبات الإخراج)، إليك بعض أفضل الممارسات المقترَحة.

تعريف المخرجات المُسمّاة باستخدام قواعد phony

إذا أمكن، ننصح بأن تستخدم بنية build.ninja قواعد phony لتقديم نتائج ذات أسماء يمكن للمستخدمين قراءتها. على سبيل المثال، إذا كان لديك مُخرج مُسمّى c:/path/to/lib.so، يمكنك منحه اسمًا يمكن للإنسان قراءته على النحو التالي.

build curl: phony /path/to/lib.so

والفائدة من ذلك هي أنّه يمكنك بعد ذلك تحديد هذا الاسم كهدف إصدار في ملف build.gradle. على سبيل المثال:

android {
  defaultConfig {
    externalNativeBuild {
      ...
      experimentalProperties["ninja.targets"] = [ "curl" ]

تحديد هدف "الكل"

عند تحديد هدف all، ستكون هذه المجموعة هي المجموعة التلقائية للمكتبات التي ينشئها AGP عندما لا يتم تحديد أي أهداف بشكل صريح في ملف build.gradle.

rule COMPILE
   command = /path/to/ndk/clang $in -o $out {other flags}
rule LINK
   command = /path/to/ndk/clang $in -o $out {other flags}

build foo.o : COMPILE foo.cpp
build bar.o : COMPILE bar.cpp
build libfoo.so : LINK foo.o
build libbar.so : LINK bar.o
build all: phony libfoo.so libbar.so

تحديد طريقة إصدار بديلة (اختياري)

تتمثل حالة الاستخدام الأكثر تقدمًا في إدراج نظام إنشاء حالي لا يعتمد على Ninja. في هذه الحالة، لا يزال عليك تمثيل جميع المصادر مع علاماتها إلى جانب مكتبات الإخراج حتى يتمكن "استوديو Android" من تقديم ميزات خدمة اللغة المناسبة، مثل الإكمال التلقائي وتعريف الانتقال إلى المحتوى. مع ذلك، يمكنك تأجيل استخدام AGP إلى نظام الإصدار الأساسي أثناء الإصدار الفعلي.

لتحقيق ذلك، يمكنك استخدام نتيجة إصدار Ninja مع إضافة محددة .passthrough.

كمثال أكثر تحديدًا، لنفترض أنك ترغب في تضمين MSBuild. سينشئ النص البرمجي للإعدادات build.ninja كالمعتاد، ولكنه سيضيف أيضًا هدف مرور يحدد كيفية استدعاء AGP لـ MSBuild.

rule COMPILE
   command = /path/to/ndk/clang $in -o $out {other flags}
rule LINK
   command = /path/to/ndk/clang $in -o $out {other flags}

rule MBSUILD_CURL
  command = /path/to/msbuild {flags to build curl with MSBuild}

build source.o : COMPILE source.cpp
build lib.so : LINK source.o
build curl : phony lib.so
build curl.passthrough : MBSUILD_CURL

تقديم ملاحظات وآراء

هذه الميزة تجريبية، لذا يهمّنا معرفة ملاحظاتك. يمكنك تقديم الملاحظات من خلال القنوات التالية:

  • للحصول على ملاحظات عامة، أضِف تعليقًا على هذا الخطأ.

  • للإبلاغ عن خطأ، افتح "استوديو Android" وانقر على مساعدة > إرسال ملاحظات. يُرجى التأكد من الرجوع إلى "أنظمة إنشاء C/C++ المخصصة" للمساعدة في توجيه الخطأ.

  • للإبلاغ عن خطأ إذا لم يكن "استوديو Android" مثبّتًا على جهازك، يمكنك الإبلاغ عن الخطأ باستخدام هذا النموذج.