Cross-compiling Scala في مشروع Gradle

من الشائع جدًا بالنسبة لمشاريع Scala توفير قطع أثرية ثنائية تم تجميعها لعدة إصدارات من برنامج التحويل البرمجي Scala. كقاعدة عامة ، لغرض إنشاء عدة إصدارات من قطعة أثرية واحدة في مجتمع ما ، من المعتاد استخدام SBT ، حيث تكون هذه الميزة خارج الصندوق مباشرة ويتم تهيئتها في سطرين. لكن ماذا لو أردنا الخلط وخلق بناء للتجميع المتقاطع دون استخدام SBT؟


بالنسبة إلى أحد مشاريع Java الخاصة بي ، قررت إنشاء واجهة Scala. تاريخياً ، يتم تجميع المشروع بأكمله باستخدام Gradle ، وقد تقرر إضافة الواجهة إلى نفس المشروع مثل وحدة فرعية. يمكن لـ Gradle ككل تجميع وحدات Scala مع التحذير الذي لم يتم الإعلان عن أي دعم تجميعي. هناك تذكرة مفتوحة في عام 2017 واثنين من المكونات الإضافية ( 1 ، 2 ) تعد بإضافة هذه الميزة إلى مشروعك ، ولكن هناك مشاكل معهم ، ترتبط عادةً بنشر الأعمال الفنية. وليس هناك ما هو أكثر بشكل عام. قررت التحقق من صعوبة تكوين البنية للتجميع المتقاطع بدون مكونات إضافية ورسائل نصية قصيرة.


أولا ، نحن تصف النتيجة المرجوة. أرغب في تجميع مجموعة المصادر نفسها من خلال ثلاثة إصدارات من برنامج التحويل البرمجي لـ Scala: 2.11 و 2.12 و 2.13 (في الوقت الحالي 2.13.0-RC2 الأحدث). ونظرًا لأن Scala 2.13 يحتوي على مجموعة من التغييرات غير المتوافقة مع الإصدارات السابقة في المجموعات ، أود أن أكون قادرًا على إضافة مجموعات مصادر إضافية لرمز خاص بكل من المترجمين. مرة أخرى ، في SBT ، تتم إضافة كل هذا إلى بضعة أسطر من التكوين. دعونا نرى ما يمكن القيام به في Gradle.


هيكل المشروع


الصعوبة الأولى التي يجب على المرء مواجهتها هي أن إصدار برنامج التحويل البرمجي يتم حسابه من إصدار التبعية المعلنة على مكتبة scala. بالإضافة إلى ذلك ، يجب أيضًا تغيير كافة التبعيات التي تحتوي على بادئة لإصدار Scala من برنامج التحويل البرمجي. أي لكل إصدار من المحول البرمجي ، يجب أن تكون قائمة التبعية مختلفة. بالإضافة إلى ذلك ، مجموعة العلامات لإصدارات مختلفة من المحول البرمجي مختلفة بالفعل. تمت إعادة تسمية بعض الأعلام بين الإصدارات ، بينما تم تمييز بعضها ببساطة على أنها قديمة أو تمت إزالتها تمامًا. قررت أن محاولة التعرف على جميع الفروق الدقيقة في برامج التحويل البرمجي المختلفة في ملف بناء واحد تبدو مهمة صعبة للغاية كما أن دعمها الإضافي أكثر صعوبة. لذلك ، قررت استكشاف طرق أخرى ممكنة لحل هذه المشكلة. ولكن ماذا لو أنشأنا العديد من بنيات التكوينات لنفس بنية دليل المشروع؟


في الإعلان الخاص بإدراج وحدات فرعية في مشروع Gradle ، يمكنك تحديد الدليل حيث سيتم تحديد موقع جذر الوحدة الفرعية واسم الملف المسؤول عن التكوين الخاص به. دعونا نحدد نفس الدليل للعديد من عمليات الاستيراد وننشئ عدة نسخ من النص البرمجي للبناء لكل إصدار من المحول البرمجي.


settings.gradle
rootProject.name = 'test' include 'java-library' include 'scala-facade_2.11' project(':scala-facade_2.11').with { projectDir = file('scala-facade') buildFileName = 'build-2.11.gradle' } include 'scala-facade_2.12' project(':scala-facade_2.12').with { projectDir = file('scala-facade') buildFileName = 'build-2.12.gradle' } include 'scala-facade_2.13' project(':scala-facade_2.13').with { projectDir = file('scala-facade') buildFileName = 'build-2.13.gradle' } 

ليس سيئًا ، ولكن من وقت لآخر ، يمكن أن نحصل على أخطاء تجميع غريبة تتعلق بحقيقة أن البرامج النصية الثلاثة للبناء تستخدم نفس دليل البناء. يمكننا إصلاح هذا عن طريق تعيينهم لكل بناء:


بناء 2.12.gradle
 plugins { id 'scala' } buildDir = 'build-2.12' clean { delete 'build-2.12' } // ... 

الآن انها جميلة جدا. مع مشكلة واحدة فقط ، سيؤدي هذا التصميم إلى جعل IDE المفضل لديك مجنونًا ، وعلى الأرجح يجب إجراء مزيد من التحرير لمشروعك باستخدام الأدوات. اعتقدت أن هذه ليست مشكلة كبيرة ، لأنه يمكنك دائمًا التعليق ببساطة على الواردات الزائدة من الوحدات الفرعية وتحويل البنية المتقاطعة إلى بنية عادية ، والتي من المحتمل أن تعمل مع IDE الخاص بك.


ماذا عن مجموعات مصادر إضافية؟ مرة أخرى ، مع وجود ملفات منفصلة ، اتضح أن هذا الأمر بسيط للغاية ، وأنشئ دليلًا جديدًا وقم بتكوينه كمجموعة مصدر.


بناء 2.12.gradle
 // ... sourceSets { compat { scala { srcDir 'src/main/scala-2.12-' } } main { scala { compileClasspath += compat.output } } test { scala { compileClasspath += compat.output runtimeClasspath += compat.output } } } // ... 

بناء 2.13.gradle
 // ... sourceSets { compat { scala { srcDir 'src/main/scala-2.13+' } } main { scala { compileClasspath += compat.output } } test { scala { compileClasspath += compat.output runtimeClasspath += compat.output } } } // ... 

يبدو الهيكل النهائي للمشروع كما يلي:


المشروع النهائي


هنا يمكنك أيضًا فصل القطع الشائعة الفردية في ملفات التكوين الخارجية واستيرادها في البنية لتقليل عدد التكرارات. لكن بالنسبة لي ، فقد اتضح جيدًا ، معتبرًا ، معزولًا ، ومتوافقًا مع جميع الإضافات الممكنة لـ Gradle.


إجمالاً ، تم حل المشكلة ، وكانت مرونة Gradle كافية للتعبير عن الإعداد غير التافه تمامًا بأناقة تمامًا ، ومن الممكن استخدام Scala cross build ليس فقط باستخدام SBT ، وإذا كنت تستخدم Gradle لسبب أو لآخر لإنشاء مشروع Scala ، فإن التجميع المتقاطع فرصة لك متاح أيضا. آمل أن يكون هذا المنشور مفيدًا. شكرا لاهتمامكم

Source: https://habr.com/ru/post/ar452552/


All Articles