Program yang terdiri atas banyak modul memerlukan tempat yang menyatakan berkas mana saja yang dibangun dan bagaimana pembagiannya, serta pustaka apa yang dibutuhkan. Cabal menampung semua itu dalam satu berkas .cabal yang menjadi pusat proyek, dan menyediakan dua perintah utama, yaitu cabal build untuk membangun dan cabal run untuk menjalankan. Topik ini membahas anatomi berkas .cabal, pembagian pustaka dan executable, keluaran build, serta cara menyatakan dependensi.
Anatomi berkas .cabal#
Berkas .cabal dinamai mengikuti nama proyeknya dan berisi properti umum di bagian atas, lalu satu blok untuk setiap komponen yang dibangun. Proyek contoh pada topik ini bernama penghitung-kata, dan berkasnya terbagi menjadi satu pustaka serta satu executable.
cabal-version: 2.4
name: penghitung-kata
version: 0.1.0.0
synopsis: Penghitung kata sederhana
description: Menghitung jumlah kata pada teks masukan.
build-type: Simple
library
exposed-modules: Penghitung
hs-source-dirs: src
build-depends: base
default-language: Haskell2010
executable penghitung-kata
main-is: Main.hs
hs-source-dirs: app
build-depends: base, penghitung-kata
default-language: Haskell2010Bagian atas menyatakan versi format cabal-version, nama, dan keterangan proyek. Blok library mengekspor modul Penghitung yang dicari pada direktori src, sedangkan blok executable menyatakan berkas main-is pada direktori app. Baris build-depends pada executable memuat dua nama, yaitu base yang selalu diperlukan dan penghitung-kata yang merujuk pustaka proyek yang sama, sehingga executable berhak mengimpor modul-modul pustakanya. Struktur direktori proyek mengikuti penentuan itu, yaitu src/Penghitung.hs untuk pustaka dan app/Main.hs untuk program utamanya.
Pustaka dan program utama#
Pustaka proyek menampung logika yang ingin diuji dan digunakan ulang, sedangkan executable hanya berisi pengikat main yang memanggil pustakanya. Kedua berkas berikut menunjukkan pembagian itu.
-- tidak-dijalankan
-- Modul penghitung kata dari pustaka proyek
module Penghitung (banyakKata, kataPanjang) where
banyakKata :: String -> Int
banyakKata = length . words
kataPanjang :: String -> Int
kataPanjang = length . filter panjang . words
where
panjang w = length w > 5Modul Penghitung tidak berisi main, sehingga modul tersebut bukan program yang dijalankan melainkan satuan pustaka yang diimpor. Eksekusi berada pada executable berikut.
-- tidak-dijalankan
-- Program utama yang memakai pustaka proyek
module Main (main) where
import Penghitung (banyakKata, kataPanjang)
main :: IO ()
main = do
let teks = "Haskell memakai modul untuk memecah program"
putStrLn (teks ++ ": " ++ show (banyakKata teks) ++ " kata")
putStrLn ("kata panjang: " ++ show (kataPanjang teks))Pemisahan ini bukan sekadar kebiasaan, melainkan konsekuensi dari struktur komponen, karena import Penghitung pada executable sah hanya karena build-depends executable memuat nama pustakanya. Program uji, benchmark, dan executable kedua kemudian menambah bloknya sendiri pada berkas .cabal yang sama, semuanya berbagi pustaka yang identik.
Membangun dan menjalankan#
Dua perintah berikut dieksekusi dari direktori proyek, dan keduanya dijalankan berurutan karena cabal run pada eksekusi pertama ikut membangun dahulu apabila belum ada hasil build-nya.
# bangun seluruh komponen proyek dari direktori proyek
cabal buildResolving dependencies...
Build profile: -w ghc-9.6.6 -O1
In order, the following will be built (use -v for more details):
- penghitung-kata-0.1.0.0 (lib) (first run)
- penghitung-kata-0.1.0.0 (exe:penghitung-kata) (first run)
Configuring library for penghitung-kata-0.1.0.0...
Preprocessing library for penghitung-kata-0.1.0.0...
Building library for penghitung-kata-0.1.0.0...
[1 of 1] Compiling Penghitung ( src/Penghitung.hs, dist-newstyle/build/x86_64-linux/ghc-9.6.6/penghitung-kata-0.1.0.0/build/Penghitung.o, dist-newstyle/build/x86_64-linux/ghc-9.6.6/penghitung-kata-0.1.0.0/build/Penghitung.dyn_o )
Configuring executable 'penghitung-kata' for penghitung-kata-0.1.0.0...
Preprocessing executable 'penghitung-kata' for penghitung-kata-0.1.0.0...
Building executable 'penghitung-kata' for penghitung-kata-0.1.0.0...
[1 of 1] Compiling Main ( app/Main.hs, dist-newstyle/build/x86_64-linux/ghc-9.6.6/penghitung-kata-0.1.0.0/x/penghitung-kata/build/penghitung-kata/penghitung-kata-tmp/Main.o )
[2 of 2] Linking dist-newstyle/build/x86_64-linux/ghc-9.6.6/penghitung-kata-0.1.0.0/x/penghitung-kata/build/penghitung-kata/penghitung-kataKeluaran memperlihatkan urutan kerja Cabal, yaitu memecah dependensi, menyusun rencana berupa satu pustaka dan satu executable, lalu membangun keduanya berurutan. Hasil build disimpan pada direktori dist-newstyle yang seluruh isinya adalah artefak yang dapat dibangun ulang kapan pun, sehingga direktori itu tidak ikut disimpan pada repositori. Baris yang tercetak mengikuti versi GHC dan Cabal yang terpasang, sehingga nomor versi pada keluaran berbeda antarmesin, sedangkan bentuk tahapannya sama.
# jalankan executable proyek
cabal run penghitung-kataHaskell memakai modul untuk memecah program: 6 kata
kata panjang: 4Perintah cabal run mengeksekusi biner hasil build tanpa perlu mencari lokasinya di dalam dist-newstyle, dan apabila ada berkas sumber yang berubah sejak build terakhir, perintah itu membangun ulang bagian yang perlu sebelum program berjalan. Apabila tidak ada perubahan, pemanggilan berikutnya langsung menjalankan program tanpa mencetak tahapan build.
Perintah ketiga yang sering digunakan pada masa pengembangan adalah cabal repl, yaitu perintah untuk memasuki sesi GHCi yang memuat modul pustaka proyek sehingga fungsinya dapat dicoba satu per satu tanpa menjalankan program utuhnya. Perintah cabal test dan cabal benchmark menyusul pola yang sama, yaitu masing-masing membangun komponen pengujian dan tolok ukur yang dideklarasikan pada berkas .cabal sebelum mengeksekusinya. Seluruh perintah itu berbagi hasil build pada dist-newstyle, sehingga perpindahan di antara perintah-perintah tersebut tidak membangun ulang apa pun yang sudah selesai, dan alur kerjanya tetap sama dari proyek kecil sampai proyek yang memiliki banyak komponen.
Menyatakan dependensi#
Pustaka di luar base dinyatakan pada build-depends dengan nama paketnya, misalnya text untuk tipe teks yang efisien atau containers untuk peta dan himpunan, sehingga barisnya berbentuk build-depends: base, text, containers. Versi yang diizinkan dapat diperketat dengan batas rentang seperti base >= 4.17 && < 5, kebiasaan yang mencegah proyek dibangun pada versi yang belum diuji. Sebelum build pertama pada mesin yang baru, indeks paket diperbarui melalui cabal update agar daftar paket yang tersedia terkini, dan setelah itu build yang memerlukan pustaka baru mengunduh serta membangunnya secara otomatis.
Kesalahan umum#
Kesalahan pertama adalah menggunakan modul pustaka proyek dari executable tanpa mendaftarkan pustakanya pada build-depends executable. Compiler melaporkan bahwa modul itu tidak ditemukan meskipun berkasnya ada, karena izin impor mengikuti daftar dependensi, bukan isi direktori. Perbaikannya berupa menambahkan nama pustaka pada baris build-depends blok yang membutuhkannya.
Kesalahan kedua berupa menempatkan berkas sumber di luar hs-source-dirs yang dinyatakan, misalnya menyimpan Main.hs di akar proyek sementara bloknya menunjuk app. Gejala yang muncul tetap berupa modul yang tidak ditemukan, sehingga pencocokan antara lokasi berkas dan deklarasi blok menjadi pemeriksaan pertama ketika build gagal. Kesalahan ketiga berupa mengubah cabal-version ke nilai yang lebih tinggi daripada Cabal yang terpasang, sehingga berkas proyek ditolak sebelum build dimulai, dan perbaikannya berupa menurunkan nilai itu atau memperbarui Cabal.
Ringkasan#
- Berkas
.cabalmenyatakan properti proyek dan satu blok untuk setiap komponen, yaitulibrarydanexecutable. build-dependsmengatur izin impor, termasuk pustaka proyek sendiri yang dirujuk dengan namanya.cabal buildmenyusun rencana dan membangun kedist-newstyle, sedangkancabal runmenjalankan hasilnya dan membangun ulang apabila ada perubahan.- Dependensi dinyatakan sebagai nama paket beserta batas versinya, dan indeks paket diperbarui melalui
cabal update.
Referensi#
- The Cabal user guide — cabal.readthedocs.io — Panduan resmi Cabal beserta perintah build dan run.
- Package descriptions — cabal.readthedocs.io
— Format berkas
.cabal, termasuk blok library dan executable. - GHC Users Guide: Separate compilation — haskell.org — Cara GHC menemukan modul dan berkas antarmukanya.