Sangat umum bagi proyek Scala untuk menyediakan artefak biner yang dikompilasi untuk beberapa versi dari kompiler Scala. Sebagai aturan, untuk tujuan membuat beberapa versi dari satu artefak di sebuah komunitas, sudah lazim untuk menggunakan SBT, di mana fitur ini tepat di luar kotak dan dikonfigurasikan dalam beberapa baris. Tetapi bagaimana jika kita ingin bingung dan membuat build untuk kompilasi silang tanpa menggunakan SBT?
Untuk salah satu proyek Java saya, saya memutuskan untuk membuat fasad Scala. Secara historis, seluruh proyek dirakit menggunakan Gradle, dan diputuskan untuk menambahkan fasad ke proyek yang sama dengan submodule. Gradle secara keseluruhan dapat mengkompilasi modul Scala dengan peringatan bahwa tidak ada dukungan lintas-kompilasi yang telah dinyatakan. Ada tiket terbuka di tahun 2017 dan beberapa plugin ( 1 , 2 ) yang berjanji untuk menambahkan fitur ini ke proyek Anda, tetapi ada masalah dengan mereka, biasanya terkait dengan publikasi artefak. Dan tidak ada yang lebih umum. Saya memutuskan untuk memeriksa betapa sulitnya untuk benar-benar mengkonfigurasi build untuk kompilasi silang tanpa plugin dan SMS khusus.
Pertama, kami menggambarkan hasil yang diinginkan. Saya ingin kumpulan sumber yang sama dikompilasi oleh tiga versi kompiler Scala: 2.11, 2.12 dan 2.13 (saat ini 2.13.0-RC2 terbaru). Dan karena ada banyak perubahan yang tidak kompatibel ke belakang dalam koleksi di Scala 2.13, saya ingin dapat menambahkan set sumber tambahan untuk kode khusus untuk setiap kompiler. Sekali lagi, di SBT, ini semua ditambahkan ke beberapa baris konfigurasi. Mari kita lihat apa yang bisa dilakukan di Gradle.

Kesulitan pertama yang harus Anda hadapi adalah bahwa versi kompiler dihitung dari versi ketergantungan yang dideklarasikan pada scala-library. Plus, semua dependensi yang memiliki awalan untuk versi Scala dari kompiler juga perlu diubah. Yaitu Untuk setiap versi kompiler, daftar ketergantungan harus berbeda. Selain itu, set flag untuk versi yang berbeda dari kompiler sebenarnya berbeda. Beberapa bendera diganti namanya di antara versi, sementara beberapa hanya ditandai sebagai usang atau dihapus sama sekali. Saya memutuskan bahwa mencoba menangkap semua nuansa dari berbagai kompiler dalam satu file build sepertinya tugas yang terlalu sulit dan dukungan lebih lanjutnya bahkan lebih sulit. Karena itu, saya memutuskan untuk mencari kemungkinan cara lain untuk menyelesaikan masalah ini. Tetapi bagaimana jika kita membuat beberapa konfigurasi untuk struktur direktori proyek yang sama?
Dalam deklarasi untuk menyertakan submodula dalam proyek Gradle, Anda dapat menentukan direktori tempat akar submodule dan nama file yang bertanggung jawab atas konfigurasinya akan ditemukan. Mari tentukan direktori yang sama untuk beberapa impor dan buat beberapa salinan skrip build untuk setiap versi kompiler.
setting.gradlerootProject.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' }
Tidak buruk, tetapi dari waktu ke waktu kita bisa mendapatkan kesalahan kompilasi aneh yang terkait dengan fakta bahwa ketiga skrip build menggunakan direktori build yang sama. Kami dapat memperbaiki ini dengan mengaturnya untuk setiap bangunan:
build-2.12.gradle plugins { id 'scala' } buildDir = 'build-2.12' clean { delete 'build-2.12' } // ...
Sekarang sangat indah. Dengan hanya satu masalah, pembangunan seperti itu akan membuat gila IDE favorit Anda, dan kemungkinan besar pengeditan lebih lanjut dari proyek Anda harus dilakukan dengan menggunakan instrumen. Saya pikir ini bukan masalah besar, karena Anda selalu dapat mengomentari kelebihan impor submodul dan mengubah susunan silang menjadi susunan biasa, yang kemungkinan besar IDE Anda tahu cara kerjanya.
Bagaimana dengan set sumber tambahan? Sekali lagi, dengan file terpisah, ini ternyata cukup sederhana, buat direktori baru dan konfigurasikan sebagai set sumber.
build-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 } } } // ...
build-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 } } } // ...
Struktur akhir proyek terlihat seperti ini:

Di sini Anda juga dapat memisahkan masing-masing bagian umum menjadi file konfigurasi eksternal dan mengimpornya ke dalam build untuk mengurangi jumlah pengulangan. Tetapi bagi saya itu ternyata cukup baik, deklaratif, terisolasi, dan kompatibel dengan semua plugin Gradle yang mungkin.
Secara total, masalahnya terpecahkan, fleksibilitas Gradle cukup untuk mengekspresikan pengaturan yang tidak sepele cukup elegan, dan membangun lintas Scala dimungkinkan tidak hanya menggunakan SBT, dan jika karena satu dan lain hal Anda menggunakan Gradle untuk membangun proyek Scala, kompilasi silang sebagai peluang untuk Anda juga tersedia. Saya harap seseorang posting ini akan bermanfaat. Terima kasih atas perhatian anda