Saya Suka Makefile
(switowski.com)- Meski tool build baru terus bermunculan, Makefile tetap berguna sebagai tool dasar yang ringan untuk mengelompokkan tugas berulang dalam proyek
- Berkat perintah konvensional seperti
make,make build,make install, danmake dev, kita bisa cepat mencoba membangun, memasang, atau menjalankan server pengembangan pada proyek yang baru pertama kali dilihat - Walau stack berbeda-beda seperti Jekyll, Hugo, 11ty, framework web Python, Docker, atau gulp, Makefile berperan sebagai antarmuka eksekusi bersama
- Pada proyek pribadi, beberapa target sederhana seperti
dev,build, dandeploysering kali sudah cukup dibandingkan memakai conditional atau flag - GNU Make tersebar luas, dan kalaupun tidak tersedia, perintah shell di dalam Makefile bisa dijalankan langsung, sehingga bebannya kecil bahkan di lingkungan terbatas
Menggabungkan perintah yang berbeda di tiap proyek ke satu titik masuk
- Makefile digunakan untuk membungkus proyek yang cara build, menjalankan, dan deploy-nya berbeda-beda ke dalam kumpulan perintah yang familier
- Jika proyek yang baru pertama kali dilihat memiliki
Makefile, biasanya perintah berikut bisa dicoba terlebih dahulumakemake buildmake install
- Saat membuka kembali proyek pribadi lama, proyek bisa dikonfigurasi agar cukup menjalankan
make devuntuk menangani tahap build yang diperlukan sekaligus menjalankan server pengembangan - Meski stack teknologinya berbeda seperti Jekyll, Hugo, 11ty, atau berbagai framework web Python, titik masuk yang sama tetap bisa dipertahankan
- Bahkan saat menggunakan Docker atau gulp, Makefile tidak menggantikan tool tersebut, melainkan bekerja sebagai lapisan orkestrasi
- Contoh:
make buildmembangun image Docker yang diperlukan sambil meneruskan argumen tambahan khusus proyek
- Contoh:
Cara penggunaan sederhana pada proyek pribadi
- Penggunaan Makefile berfokus pada kumpulan perintah shell, bukan fitur yang kompleks
- Tidak memakai fitur seperti conditional atau flag
- Unit kerja make secara teknis adalah target, tetapi dalam praktiknya diperlakukan seperti task
- Bisa juga dibuat sebagai fungsi skrip bash, tetapi Makefile dianggap lebih mudah dan cepat
- Tugas yang sering dipakai pada proyek pribadi biasanya hanya 2–3 buah
dev: memulai server pengembanganbuild: membangun proyek jika diperlukandeploy: men-deploy atau memublikasikan proyekwatch: digunakan sebagai tugas tambahan untuk menjalankan ulang build secara otomatis saat file sumber berubah
- Makefile blog saat ini hanya memiliki satu target, yaitu
dev- Di bawah
dev:, menjalankannpm run dev
- Di bawah
- Pada proyek pribadi yang lebih kompleks, tugas berikut digabungkan dengan Makefile
dev: menjalankan server pengembangan denganbundle exec jekyll servebuild: membangun aset dengannpm run gulp buildwatch: memantau folder tertentu dengannpm run gulp watchdeploy: setelah build Jekyll di lingkungan produksi, menjalankanmake encryptdannetlify deploy --prodencrypt: mengenkripsi file HTML di folder_sitedengannpx staticrypt
Batasan dan kelebihan yang perlu diketahui
- Dalam contoh, phony targets dihilangkan, tetapi jika ada file bernama
dev,build,watch,deploy, atauencrypt, Makefile mungkin tidak berjalan seperti yang diharapkan- Pembaca Hacker News menyarankan menambahkan phony target dalam kasus seperti ini
- GNU Make adalah perangkat lunak untuk menjalankan makefile, kemungkinan besar sudah terpasang di Linux, dan juga begitu umum di MacBook sampai-sampai pemasangan terpisah mungkin tidak terasa pernah dilakukan
- Karena Make tidak membutuhkan banyak dependensi tambahan, ia bisa berguna di lingkungan terbatas yang sulit atau tidak memungkinkan untuk memasang paket karena alasan keamanan
- Kalaupun Make tidak tersedia, perintah di dalam Makefile bisa disalin langsung ke shell dan dijalankan
- Sebaliknya, jika gulp tidak ada di server, ada perbedaan bahwa kode JavaScript sulit ditempel begitu saja ke terminal untuk dijalankan
- Meski menemukan tool build baru yang lebih baik dan lebih cepat, Make tetap bisa terus dimanfaatkan sebagai lapisan perintah bersama untuk mengelola berbagai tool dan konfigurasi
2 komentar
Untuk
makefileyang tidak mendefinisikan dependensi, menggantinya denganjustfilememberikan kegunaan yang lebih baik.Opini Hacker News
Tidak perlu berkecil hati dengan komentar di thread ini yang mengatakan “Anda menggunakan make dengan cara yang salah.” Salah satu alasan Make adalah alat yang bagus adalah karena ia bisa dimulai dengan lebih sederhana daripada kelihatannya
Tidak memakai
.PHONYmemang bisa menimbulkan masalah, tetapi untuk proyek kecil, jebakan itu mungkin baru akan terinjak setahun kemudian, dan saat itu pun kemungkinan besar selesai setelah menggaruk-garuk kepala sekitar satu jam. Dalam 99% kasus, Anda bisa langsung mulai tanpa perlu memikirkan “cara yang benar”, dan Make hanya menuntut kompleksitas secukupnya agar tidak runtuhMake menerima berkas input dan dependensi, lalu membuat tepat satu berkas output. Aturan yang tidak membuat output seperti
install,all,clean, atau semua target dalam tulisan ini, harus bergantung pada target ajaib khusus seperti.PHONY;.PHONYbelum ada di POSIX 2017 (IEEE Std 1003.1-2017, https://pubs.opengroup.org/onlinepubs/9699919799/utilities/m...) dan baru masuk ke standar saat ini (IEEE Std 1003.1-2024, https://pubs.opengroup.org/onlinepubs/9799919799/utilities/m...). Jika ingin membuat banyak berkas seperti berkas objek, modul, atau header yang sudah dikompilasi sebelumnya, Anda harus merangkai sendiri trik yang rapuh. Tidak semua Make adalah GNU Make; keluarga nix seperti BSD dan Solaris/Illumos juga masih adaIni bukan berarti Make tidak berguna. Ia berguna untuk proyek yang cukup kompleks, tetapi belum sampai membutuhkan sistem build yang “lebih baik”. Masalahnya, proyek seperti itu akan makin kompleks seiring bertambahnya kode, dan akhirnya memiliki skrip/program yang menghasilkan Makefile atau sebagian darinya, sehingga terbentuk sistem meta-build sementara
Masalah yang lebih besar bukan memakainya, melainkan mengusulkannya sebagai solusi untuk “semua orang”. Dan begitu ada direktori atau berkas seperti
buildataudevdi root proyek, Makefile itu akan berhenti bekerjaSekarang saya memang beralih ke pnpm, tetapi tetap saja saya tidak menganggapnya terlalu kompleks. Memang perlu tahu sintaksnya sampai batas tertentu, tetapi itu masih lebih mudah daripada membuat alat-alat lain bekerja dengan benar sejak awal
.PHONYyang begitu diributkan orangSederhana, mudah dibaca, bisa diubah, bisa dikomposisikan, dan sudah terpasang di mana-mana. Ia melakukan apa yang tertulis di permukaan, dan hampir tidak lebih dari itu
Sebagai catatan, ketika harus berurusan dengan sistem build musiman atau sistem build mimpi buruk di proyek lain, saya juga membungkusnya dengan make
Semua orang harus mulai dari suatu tempat, dan begitu sudah berjalan, perbaikan bertahap bisa ditambahkan dengan mudah
$@. Keseluruhan Makefile bisa membuat jumlah output berapa pun karena aturan bisa bergantung pada aturan lainDari sini muncul aturan praktis yang rapi untuk target phony. Jika recipe tidak menyentuh
$@, maka$@harus ditandai sebagai phony. Mengelola target phony sebagai daftar membuatnya jauh lebih mudahphonies :=phonies += somethingsomething:./do-somethingphonies += something-elsesomething-else: something./do-something-else# touches $@ and thus does not need to be phonycreate-file:./generate-some-output > $@.PHONY: $(phonies)Makefile adalah teknologi yang buruk. Namun, karena sedikit tidak seburuk kebanyakan sistem build lain yang kita buat, ia menjadi berguna dalam arti masokistis
Sistem build biasanya terlalu mendasar sehingga menjadi kacau saat membangun sesuatu yang lebih dari mainan, atau terlalu rumit sehingga pengetahuan awal, birokrasi, sinkronisasi, dan boilerplate-nya berlebihan, atau tidak memiliki pustaka standar sehingga pola build yang sama tersebar menjadi 10 ribu implementasi yang tidak kompatibel, atau terlalu membatasi sehingga harus bermigrasi saat kebutuhan bertambah, atau terlalu banyak keajaiban, atau sintaksnya sulit dipahami dan tidak konsisten
Lebih dari separuh perangkat lunak yang saya pakai hanya menggunakan Makefile biasa dan sesekali skrip configure. Tanpa autotools, cukup menjalankan
./configuresecara opsional lalumake,make install, dan semuanya langsung berjalan. Ini sama sekali bukan setup mainan, melainkan tersusun dari program-program kecil yang melakukan satu hal dengan baikMake dan cara kerjanya, setidaknya bagi saya, mudah dipahami. Menurut saya pengalaman buruk yang dialami orang sering kali lebih disebabkan konfigurasi build yang buruk pada proyek kompleks atau kurangnya pengetahuan yang diperlukan, bukan Make itu sendiri
Tidak adanya pustaka standar memang dimaksudkan sebagai independensi dari alat, sehingga dapat diterapkan secara umum pada berbagai alat, bahasa, dan penggunaan. Saya melihatnya sebagai fitur, bukan cacat. Lapisan sederhananya adalah pelacakan dependensi, dan target serta dependensinya juga jelas, jadi sulit disebut magis. Sintaksnya memang jelas bisa dibuat lebih baik
Satu-satunya sistem build umum yang mencakup banyak bahasa adalah
makeatau sistem yang menargetkanmakeseperti CMake. Alasan ini kurang bagus adalah karenamakememang kurang bagus.makesangat sulit digunakan dengan benar, punya masalah seperti recursive make dan non-recursive make, memiliki banyak varian yang tidak kompatibel seperti Unix/POSIX make, BSD make, GNU make, dan Windowsnmake, serta cukup jelekMeski begitu,
makeyang digunakan dengan benar cukup bagus. Sungguh beruntung adamakesebagai penyebut bersama terkecilCukup konyol bahwa Make bahkan tidak bisa menangani subdirektori dengan rapi. Saya penasaran apakah ada yang lebih baik daripada Make. Ada Ninja, tetapi itu tidak dirancang untuk ditulis langsung oleh manusia
Menurutmu seberapa besar? Bukankah kira-kira 20%, 40%, atau 70% benar?
Saya sangat menyukai Make. Selama 20 tahun terakhir, untuk setiap pekerjaan atau proyek yang saya sentuh, saya selalu menulis setidaknya satu
Tidak ada yang pintar di dalamnya, hanya kumpulan potongan dengan beberapa variabel. Misalnya
make run,make test,make lintmake recentmenjalankan lint lalu mengeksekusi skrip yang paling baru dimodifikasi. Ini bisa dilakukan dengan Bash atau shell lain, tetapi kalau begitu kita tersedot ke dunia developer dan hanya menambah kompleksitas tanpa nilai tambah. Make hanyalah bahasa khusus domain untuk “file seperti ini dibuat dari file seperti ini, lalu jalankan satu atau dua perintah ini saat itu”. Karena itulah ia luar biasa kuatPuluhan tahun lalu saya membuat framework pengujian dengan Java, dan memungkinkan pengujian serta kelas dependensi ditentukan dengan sintaks mirip make. Ada kumpulan kelas pengujian yang mendefinisikan “paket pengujian acuan”, lalu lapisan kelas pengujian lain yang bergantung padanya hanya dijalankan jika bagian depan berhasil
Saya tidak tahu mengapa sekarang semuanya dibuat begitu rumit. Saya selalu menyarankan untuk berpegang pada alat Unix standar dan caranya, yaitu cara yang sudah teruji waktu. Kecuali jika benar-benar tidak mungkin melakukannya begitu. Waktu itu terbatas, jadi saya ingin menggunakannya untuk hal-hal inti dalam pemecahan masalah seperti desain sistem/program, pemodelan, struktur, pola, dan sebagainya; sisanya sekunder
Mengetahui bahwa
make testakan berjalan, apa pun stack, bahasa, atau repositorinya, adalah penyelamat besarMakefile pada proyek sebelumnya punya empat perintah utama:
build,test,frontend,deploy. build dan test memanggil maven, frontend memanggil npm, deploy memanggil docker dan awsSemua alat ini memiliki pelacakan status, caching, dan pemrosesan inkremental sendiri, tetapi tidak melaporkan apa yang telah mereka lakukan. Karena itu, kita tidak bisa menulis aturan tingkat molekuler seperti “deploy hanya jika build diperbarui”. Sebab maven/cargo/dotnet/npm/go tidak mengekspos informasi itu
Penulis bahkan tidak memakai pelacakan dependensi berbasis mtime. Target-targetnya juga seharusnya
.PHONY, tetapi tidak ditandai demikian. Ini juga bisa diganti dengan skrip shell yang membaca$1, mencocokkannya, lalu menentukan apa yang harus dilakukanhttps://just.systems/
.PHONY: $(MAKECMDGOALS)./build.sh devmemang kurang jelas dibandingmake dev. Alasan lain memakai Make meskipun sama sekali tidak ada tahap non-phony adalah karena nanti, jika diperlukan, tahap seperti itu bisa ditambahkan. Tentu saja saya setuju bahwa penulis seharusnya menandai{dev,build,deploy}sebagai phonyMakefile miliknya mungkin bisa diperbaiki secara teknis, tetapi yang lebih penting adalah pengalaman “mulai” yang konsisten saat masuk ke sebuah proyek
Orang-orang ingin alat ini melakukan banyak hal lain seperti bahasa skrip, pelacak dependensi, dan sebagainya, lalu menarik masuk alat yang membengkak. Baru tidak selalu berarti lebih baik. Autoconf dan automake bukan make
Secara teknis, semua target make ini mencari berkas dengan nama yang sama seperti nama target. Setiap target sebenarnya harus didefinisikan sebagai
.PHONYDulu saya juga selalu memakai Makefile seperti ini, tetapi beberapa tahun terakhir beralih ke just dan justfile. Perilaku seperti ini menjadi bawaan dan secara umum lebih mudah dipakai. Hal-hal seperti parameter juga lebih sederhana
https://github.com/casey/just
:Tentu saja sekarang sudah terlalu terlambat
Rasanya sudah waktunya ada semacam distribusi coreutils baru yang membundel alat-alat baru dan berguna seperti just dan ripgrep, lalu terpasang di mana pun kita ingin memakainya
Menarik bahwa make memicu perdebatan sepanas ini. Mirip perdebatan lama vi vs emacs yang setengah perang agama
Saya sepenuhnya setuju dengan tulisan asli, dan menurut saya khususnya cerdas untuk membungkus alat build yang lebih canggih sekalipun dengan Makefile tingkat atas. Keuntungannya adalah standardisasi. Tidak perlu mengingat apa pun; kalau itu proyek yang saya tulis, saya tahu cukup mengetik
makedan semuanya akan berjalanMisalnya ketika orang yang memakai C ingin mengompilasi proyek Rust, ia tidak perlu mencari cara memakai cargo; cukup ketik
makeataugmake. Saya berusaha mematuhi POSIX tanpa memakai fitur khusus GNU, tetapi juga benar bahwa hampir 100% make di dunia nyata adalah gmakeUsulan untuk memakai
makeyang tak lekang oleh waktu sebagai semacam penggerak sistem build tingkat atas sepertinya masih akan bekerja 250 tahun lagicargo buildMake sendiri sangat bagus, tetapi pada sebagian besar kasus saya bekerja di proyek C, yang dipakai adalah kombinasi cmake/autotools dan pemasangan paket global, dan hal-hal seperti itu sering harus dicari lagi
Saya setuju dengan sentimen di sini, tetapi saya sedang menulis ulang banyak hal menjadi Justfile
https://github.com/casey/just
Banyak keanehan khas Makefile bisa dihindari
Benar, Make itu hebat. Saya memakainya untuk sangat banyak hal. Ini cara yang bagus untuk otomasi tugas
Misalnya situs web pribadi saya memakai Makefile untuk memanggil skrip bash yang membangun ulang halaman web yang diperbarui, melakukan git push ke server, lalu git hook di server memanggil Make untuk melakukan deployment. Namun saya tidak ingin memasukkan gumpalan biner yang sering berubah seperti PDF materi kuliah ke repositori Git. Tidak masalah. Di Makefile ada target
uploadsyang hanya mengunggah PDF yang berubah ke server, dan target ini adalah dependensi dari targetdeployyang melakukan git push, jadi saya tidak perlu memikirkannyaSelain itu, PDF materi kuliah yang diperbarui otomatis dimasukkan ke tree sumber situs web oleh Makefile lain. Dengan Makefile itu, saya bisa membuat PDF yang saya pakai dari sumber LaTeX, atau membuat versi alternatif untuk mahasiswa dari sumber yang sama, misalnya versi tanpa jawaban soal latihan, lalu menerbitkannya otomatis ke versi situs web lokal dan mengunggahnya ke situs web yang diperbarui kapan pun saya mau
Ini semacam rantai Makefile tanpa akhir. Saya suka Makefile
Dalam kasus seperti ini, yang benar-benar dibutuhkan penulis bukan make, melainkan just
https://just.systems/man/en/
Sebagai runner tugas, make tidak buruk, tetapi sekarang ada alternatif yang lebih baik seperti just, sebagaimana disebut di komentar lain
Sebagai sistem build, make baik-baik saja sampai Anda terbentur kekurangannya. make/Makefile tidak distandardisasi, itulah sebabnya automake ada. Jadi alih-alih menulis Makefile langsung, Anda memakai template lalu membiarkannya menghasilkan makefile yang sebenarnya. Kalau Anda memiliki seluruh toolchain sendiri, itu tidak masalah, tetapi kebanyakan orang tidak demikian, jadi ini dilakukan untuk menjamin Makefile yang portabel
make tidak bisa melakukan resolusi dependensi jenis apa pun dan berasumsi bahwa apa yang dibutuhkan sudah ada persis di sana. Karena itu muncullah skrip configure, dan karena skrip configure juga bukan standar, Anda akhirnya membuat skrip configure dengan autoconf/autoreconf sebelum menjalankan target make
make dan alat-alat di sekitarnya seperti automake/autoconf/autoreconf memakai mtime saat menentukan apakah input sudah usang. Anda bisa terjebak dalam situasi ketika setelah menjalankan autoconf/autoreconf/automake/configure pun input tetap dianggap usang secara permanen sehingga tidak ada yang bisa dibuild. Sebagai catatan, banyak sistem build baik-baik saja memakai mtime selama pelacakan dependensinya tepat
Secara keseluruhan, cacat desain mendasar make adalah ia selaras dengan filosofi Unix, yaitu “lakukan satu hal dengan baik”. Satu hal itu adalah “build ulang target jika inputnya sudah usang”, tetapi ini adalah alat yang sangat terbatas, sehingga sistem build modern harus menumpuk banyak pekerjaan di atasnya agar berguna lebih dari sekadar runner tugas dasar
maketidak bisa melakukan resolusi dependensi?dependency:...target: dependency...make configure. Ini menyiapkan hal-hal yang dibutuhkan untukmake [build]Karena itu kita akhirnya memakai touchfile; memang berantakan, tetapi masih bekerja lebih baik daripada banyak hal lain. Saya terutama mengatakan ini sambil melihat caching docker build