Cabal, yang diuraikan pada topik Proyek Cabal, bukan satu-satunya cara mengorganisasi proyek Haskell, dan mengetahui pilihan lain membuat keputusan alat lebih tepat. Stack adalah alat build alternatif yang paling luas digunakan, yang mengelola versi GHC sendiri dan mengunci seluruh dependensi proyek pada satu snapshot yang teruji. Topik ini membahas peran Stack, alur kerjanya yang berbeda dari Cabal, pertimbangan memilih keduanya, serta alternatif lain yang tersedia pada ekosistem.
Peran Stack#
Stack dibangun di atas pustaka Cabal yang sama, sehingga berkas .cabal proyek tetap sah, tetapi alur kerjanya berbeda pada dua hal utama. Pertama, Stack memasang dan mengelola versi GHC miliknya sendiri pada direktori tersendiri, sehingga versi GHC proyek tidak bergantung pada GHCup maupun pemasangan sistem. Kedua, setiap proyek menunjuk satu snapshot, yaitu kumpulan paket pada versi tertentu yang sudah teruji untuk dibangun bersama, sehingga dua mesin yang membaca snapshot yang sama memperoleh dependensi yang identik.
Perintah-perintahnya mengikuti bentuk yang mirip Cabal, sebagaimana alur kerja build pada panduan resminya.
# tidak-dijalankan
# bangun proyek dengan Stack
stack build
# jalankan executable proyek
stack exec penghitung-kataKedua perintah di atas tidak dapat dieksekusi di lingkungan contoh jalur ini karena Stack tidak terpasang di sana, sehingga bentuknya dipaparkan sebagaimana dinyatakan pada dokumentasi resminya. Pemetaan kebiasaan perintah dari Cabal berlangsung langsung, yaitu cabal build menjadi stack build, sedangkan cabal run menjadi stack exec beserta nama executable-nya.
Berkas stack.yaml#
Proyek Stack menambah satu berkas konfigurasi bernama stack.yaml di samping berkas .cabal yang sudah ada. Berkas yang dihasilkan perintah stack init menunjuk snapshot pilihannya, dan bagian terpentingnya cukup pendek untuk dibaca sekaligus.
# contoh baris snapshot pada berkas stack.yaml
snapshot: lts-24.43 # A Stackage LTS Haskell snapshot
packages:
- .Baris snapshot memilih snapshot LTS yang digunakan proyek, dan seluruh paket yang tercantum pada snapshot itu dijamin dapat dibangun bersama, sedangkan paket yang tidak ada di dalamnya diambil pada versi yang dinyatakan proyek itu sendiri. Daftar packages menyatakan lokasi proyek lokal, yaitu direktori berkas .cabal-nya. Proses stack build pertama pada mesin baru memasang GHC sesuai snapshot lalu membangun dependensi sekali, dan build berikutnya menggunakan hasil yang sudah ada.
Memilih antara Cabal dan Stack#
Keduanya membangun proyek yang sama, sehingga pilihannya lebih merupakan keputusan alur kerja daripada keputusan teknis. Tabel berikut merangkum perbedaan yang paling menentukan.
| Aspek | Cabal | Stack |
|---|---|---|
| Sumber GHC | dipasang oleh pengguna melalui GHCup | dipasang Stack sesuai snapshot |
| Penentuan dependensi | terbuka, dipecahkan saat build | terkunci pada snapshot yang teruji |
| Berkas konfigurasi proyek | .cabal saja | .cabal beserta stack.yaml |
| Kebiasaan pada proyek besar | tergantung tim | lazim pada proyek multi paket |
| Perintah utama | cabal build, cabal run | stack build, stack exec |
Proyek tunggal dengan dependensi sederhana berjalan nyaman dengan Cabal, karena jumlah paket yang perlu dijaga masih sedikit. Proyek dengan belasan paket atau tim yang membutuhkan hasil build yang identik antarmesin memperoleh manfaat snapshot Stack, karena seluruh versi terkunci sekali untuk semua anggota. Keduanya juga dapat hidup berdampingan pada satu mesin tanpa saling mengganggu, sehingga peralihan pada satu proyek tidak mengubah proyek lainnya.
Alternatif lain di luar keduanya#
Dua nama lain muncul cukup sering pada diskusi perkakas Haskell. Pertama, Nix, yaitu pengelola paket yang membangun lingkungan pengembangan secara reproduktif dari satu berkas deklarasi, sehingga GHC, Cabal, dan seluruh dependensi sistem terkunci bersama. Pendekatan ini menuntut pembelajaran tambahan di luar Haskell itu sendiri. Kedua, GHCup yang digunakan sejak modul pembuka jalur ini, yaitu pemasang versi GHC, Cabal, dan HLS yang melengkapi keduanya, karena Stack dan Cabal sama-sama bekerja di atas GHC yang disediakan GHCup maupun yang disediakan Stack sendiri.
Kesalahan umum#
Kesalahan pertama adalah menganggap wajib memilih satu alat untuk seluruh pekerjaan Haskell, padahal keputusannya milik proyek, karena berkas .cabal yang ditulis untuk Cabal tetap digunakan Stack tanpa perubahan. Kebiasaan yang aman berupa memulai dengan Cabal lalu menambah stack.yaml ketika proyek atau tim menuntut snapshot, sehingga peralihannya murah.
Kesalahan kedua berupa mencampur GHC hasil Stack dengan GHC hasil GHCup pada satu sesi build, keadaan yang memunculkan pesan modul tidak ditemukan meskipun paketnya terpasang, karena kedua GHC menyimpan pustakanya pada tempat yang berbeda. Apabila dua sumber GHC itu ada pada satu mesin, pastikan proyek dibangun secara konsisten dengan satu alat, dan perintah stack path atau ghc --version dari terminal yang sama memperjelas GHC mana yang sedang digunakan.
Ringkasan#
- Stack membangun proyek di atas pustaka Cabal dengan dua tambahan utama, yaitu GHC miliknya sendiri dan snapshot dependensi yang terkunci.
- Proyek Stack menambah berkas
stack.yamlyang berisi pemilihan snapshot dan daftar paket lokal, sedangkan berkas.cabaltetap digunakan apa adanya. - Pilihan antara Cabal dan Stack menyangkut alur kerja, yaitu keterbukaan versi versus keterkuncian snapshot, dan keduanya dapat berdampingan.
- Nix menawarkan penguncian yang lebih luas hingga tingkat sistem, sedangkan GHCup tetap menjadi pemasang GHC dan perkakas pendamping keduanya.
Referensi#
- The Haskell Tool Stack — docs.haskellstack.org — Dokumentasi resmi Stack beserta panduan build-nya.
- Install and upgrade — docs.haskellstack.org — Cara pemasangan Stack pada berbagai sistem operasi.
- The essential Haskell Stack guide — docs.haskellstack.org
— Alur kerja build, snapshot, dan
stack.yamlpada panduan resmi. - YAML configuration: project-specific options — docs.haskellstack.org
— Format
stack.yaml, termasuk barissnapshotyang dikutip pada topik ini. - Nix manual — nixos.org — Dokumentasi resmi Nix untuk lingkungan yang dibangun secara deklaratif.