Bahasa: 日本語 | Español | Français | Português | 中文 | Bahasa Indonesia | English
Sebelumnya | Berikutnya | Daftar Isi | Versi asli bahasa Inggris (gnu.org)

2 Pengantar makefile

Untuk memberi tahu make apa yang Anda inginkan agar dilakukan, Anda memerlukan file yang disebut makefile. Paling sering, makefile memberi tahu make cara mengompilasi dan menautkan program.

Pada bab ini, kita akan membahas sebuah makefile sederhana yang menjelaskan cara mengompilasi dan menautkan editor teks yang terdiri atas delapan file sumber C dan tiga file header. makefile juga dapat memberi tahu make cara menjalankan perintah lain-lain yang hanya dijalankan ketika diminta secara eksplisit (misalnya, menghapus file tertentu sebagai pekerjaan pembersihan). Untuk melihat contoh makefile yang lebih kompleks, lihat Contoh makefile yang kompleks.

Ketika make mengompilasi ulang editor ini, setiap file sumber C yang berubah harus dikompilasi ulang. Jika sebuah file header berubah, untuk amannya, semua file sumber C yang meng-#include file header tersebut harus dikompilasi ulang. Setiap kali kompilasi dilakukan, sebuah file objek dihasilkan dari file sumber yang bersangkutan. Terakhir, jika ada satu saja file sumber yang dikompilasi ulang, semua file objek — baik yang baru dibuat maupun yang tersisa dari kompilasi sebelumnya — harus ditautkan untuk menghasilkan editor executable yang baru.

2.1 Bentuk sebuah aturan

Makefile sederhana terdiri atas kumpulan “aturan” dengan bentuk berikut:

target … : prerequisitesrecipe
        …
        …

Target biasanya adalah nama file yang dihasilkan oleh program; contoh target adalah file executable atau file objek. Target juga bisa berupa nama aksi yang harus dijalankan, misalnya clean (lihat Target semu (phony)).

Prasyarat (prerequisite, dahulu disebut dependensi) adalah file yang digunakan sebagai input untuk membuat target. Target sering kali bergantung pada beberapa file.

Resep (recipe, isi yang dijalankan oleh aturan) adalah aksi yang dijalankan oleh make. Resep dapat berisi lebih dari satu perintah, baik yang ditulis pada baris yang sama maupun masing-masing pada barisnya sendiri. [Penting] Anda harus meletakkan karakter tab di awal setiap baris resep! Ini adalah hal yang membingungkan dan sering menjebak orang yang tidak berhati-hati. Jika Anda ingin memulai resep dengan karakter selain tab, Anda dapat mengatur variabel .RECIPEPREFIX ke karakter lain (lihat Variabel khusus lainnya).

Biasanya, resep berada dalam aturan yang memiliki prasyarat, dan berfungsi untuk membuat ulang file target ketika salah satu prasyaratnya berubah. Akan tetapi, aturan yang menentukan resep untuk target tidak harus memiliki prasyarat. Misalnya, aturan yang berisi perintah penghapusan terkait target clean tidak memiliki prasyarat.

Jadi, aturan menjelaskan bagaimana dan kapan membuat ulang file tertentu yang menjadi target dari aturan tersebut. make menjalankan resep terhadap prasyarat untuk membuat atau memperbarui target. Aturan juga dapat menjelaskan bagaimana dan kapan menjalankan aksi. Lihat Menulis aturan.

makefile juga dapat berisi teks selain aturan, tetapi makefile yang sederhana cukup berisi aturan saja. Aturan yang sebenarnya mungkin terlihat sedikit lebih rumit daripada templat ini, tetapi semuanya pada dasarnya mengikuti pola yang sama.

2.2 Makefile sederhana

Berikut ini adalah makefile sederhana yang menjelaskan bagaimana file executable bernama edit bergantung pada delapan file objek, yang pada gilirannya bergantung pada delapan file sumber C dan tiga file header.

Dalam contoh ini, semua file C meng-#include defs.h, tetapi hanya file yang mendefinisikan perintah pengeditan yang meng-#include command.h, dan hanya file tingkat rendah yang mengubah buffer editor yang meng-#include buffer.h.

edit : main.o kbd.o command.o display.o \
       insert.o search.o files.o utils.o
        cc -o edit main.o kbd.o command.o display.o \
                   insert.o search.o files.o utils.o

main.o : main.c defs.h
        cc -c main.c
kbd.o : kbd.c defs.h command.h
        cc -c kbd.c
command.o : command.c defs.h command.h
        cc -c command.c
display.o : display.c defs.h buffer.h
        cc -c display.c
insert.o : insert.c defs.h buffer.h
        cc -c insert.c
search.o : search.c defs.h buffer.h
        cc -c search.c
files.o : files.c defs.h buffer.h command.h
        cc -c files.c
utils.o : utils.c defs.h
        cc -c utils.c
clean :
        rm edit main.o kbd.o command.o display.o \
           insert.o search.o files.o utils.o

Di sini kita memecah baris panjang menjadi dua baris menggunakan garis miring terbalik (backslash) dan baris baru; ini setara dengan menulis satu baris panjang, tetapi cara ini lebih mudah dibaca. Lihat Membagi baris panjang.

Untuk menggunakan makefile ini membuat file executable bernama edit, ketikkan:

make

Untuk menggunakan makefile ini menghapus file executable dan semua file objek dari direktori, ketikkan:

make clean

Dalam makefile contoh ini, target mencakup file executable edit serta file objek seperti main.o dan kbd.o. Prasyaratnya adalah file seperti main.c dan defs.h. Bahkan, setiap file .o merupakan target sekaligus prasyarat. Resepnya mencakup cc -c main.c dan cc -c kbd.c.

Jika target berupa file, target tersebut perlu dikompilasi ulang atau ditautkan ulang apabila salah satu prasyaratnya berubah. Selain itu, prasyarat yang dihasilkan secara otomatis harus diperbarui terlebih dahulu. Dalam contoh ini, edit bergantung pada masing-masing dari delapan file objek; file objek main.o bergantung pada file sumber main.c dan file header defs.h.

Resep dapat mengikuti setiap baris yang berisi target dan prasyarat. Resep-resep ini menunjukkan cara memperbarui file target. Untuk membedakan resep dari baris lain dalam makefile, setiap baris resep harus diawali dengan karakter tab (atau karakter lain yang ditentukan oleh variabel .RECIPEPREFIX; lihat Variabel khusus lainnya). (Perlu diingat bahwa make sama sekali tidak tahu bagaimana resep itu bekerja. Andalah yang bertanggung jawab menyediakan resep yang memperbarui file target dengan benar. Yang dilakukan make hanyalah menjalankan resep yang Anda tentukan ketika file target perlu diperbarui.)

Target clean bukan file, melainkan sekadar nama aksi. Karena Anda biasanya tidak ingin menjalankan aksi dalam aturan ini secara otomatis, clean bukan prasyarat dari aturan mana pun. Akibatnya, make tidak akan pernah melakukan apa pun terhadapnya kecuali Anda memintanya secara khusus. Perhatikan bahwa aturan ini bukan hanya bukan prasyarat dari aturan lain, tetapi juga tidak memiliki prasyarat sama sekali, sehingga satu-satunya tujuan aturan ini adalah menjalankan resep yang ditentukan. Target yang tidak merujuk pada file, melainkan sekadar aksi, disebut target semu (phony). Untuk informasi tentang jenis target ini, lihat Target semu (phony); untuk cara membuat make mengabaikan error dari rm atau perintah lainnya, lihat Error dalam resep.

2.3 Bagaimana make memproses makefile

Secara default, make mulai memproses dari target pertama (kecuali target yang namanya diawali dengan ., kecuali jika nama tersebut juga mengandung satu atau lebih /). Ini disebut sasaran default (default goal). (Sasaran adalah target yang pada akhirnya berusaha diperbarui oleh make.) Perilaku ini dapat diubah melalui baris perintah (lihat Argumen untuk menentukan sasaran) atau dengan variabel khusus .DEFAULT_GOAL (lihat Variabel khusus lainnya).

Dalam contoh sederhana pada bagian sebelumnya, sasaran default adalah memperbarui program executable edit; itulah sebabnya kita meletakkan aturan tersebut di awal.

Oleh karena itu, jika Anda memberikan perintah berikut:

make

make akan membaca makefile di direktori saat ini dan mulai memproses aturan pertama. Dalam contoh ini, aturan pertama adalah untuk menautkan ulang edit; tetapi sebelum make dapat memproses aturan ini sepenuhnya, ia harus terlebih dahulu memproses aturan untuk file yang menjadi prasyarat edit — dalam hal ini, file objek. Setiap file ini diproses menurut aturannya masing-masing. Aturan-aturan tersebut menginstruksikan agar setiap file .o diperbarui dengan mengompilasi file sumbernya. Kompilasi ulang dilakukan jika file sumber, atau salah satu file header yang tercantum sebagai prasyarat, lebih baru daripada file objek, atau jika file objek tersebut belum ada.

Aturan-aturan lain diproses karena target-targetnya muncul sebagai prasyarat dari sasaran. Jika suatu aturan tidak menjadi prasyarat dari sasaran (atau dari sesuatu yang menjadi prasyarat sasaran, dan seterusnya), aturan tersebut tidak akan diproses, kecuali Anda memberi tahu make secara eksplisit untuk melakukannya (misalnya dengan perintah seperti make clean).

Sebelum mengompilasi ulang file objek, make juga mempertimbangkan pembaruan prasyaratnya, yaitu file sumber dan file header. makefile ini tidak menentukan apa pun yang harus dilakukan terhadap file-file tersebut — file .c dan .h bukan target dari aturan mana pun — sehingga make tidak melakukan apa-apa terhadap file-file ini. Namun, untuk program C yang dihasilkan secara otomatis, seperti yang dibuat oleh Bison atau Yacc, make akan memperbaruinya pada tahap ini sesuai dengan aturannya masing-masing.

Setelah selesai mengompilasi ulang file objek yang diperlukan, make memutuskan apakah akan menautkan ulang edit. Penautan ulang dilakukan jika file edit belum ada, atau jika salah satu file objek lebih baru daripada edit. Jika sebuah file objek baru saja dikompilasi ulang, file tersebut menjadi lebih baru daripada edit, sehingga edit akan ditautkan ulang.

Oleh karena itu, jika kita mengubah file insert.c lalu menjalankan make, make akan mengompilasi file tersebut untuk memperbarui insert.o, lalu menautkan edit. Jika kita mengubah file command.h lalu menjalankan make, make akan mengompilasi ulang file objek kbd.o, command.o, dan files.o, lalu menautkan file edit.

2.4 Variabel membuat makefile lebih sederhana

Dalam contoh sebelumnya, kita harus mencantumkan semua file objek sebanyak dua kali dalam aturan edit (ditampilkan kembali di sini):

edit : main.o kbd.o command.o display.o \
              insert.o search.o files.o utils.o
        cc -o edit main.o kbd.o command.o display.o \
                   insert.o search.o files.o utils.o

Duplikasi semacam ini rawan kesalahan; jika sebuah file objek baru ditambahkan ke sistem, kita mungkin menambahkannya ke satu daftar tetapi lupa menambahkannya ke daftar yang lain. Kita dapat menghilangkan risiko ini dan menyederhanakan makefile dengan menggunakan variabel. Variabel memungkinkan string teks didefinisikan sekali saja, lalu disisipkan di banyak tempat kemudian (lihat Cara menggunakan variabel).

Sudah menjadi praktik standar bagi setiap makefile untuk memiliki sebuah variabel bernama objects, OBJECTS, objs, OBJS, obj, atau OBJ yang berisi daftar semua nama file objek. Variabel objects semacam itu didefinisikan dengan menuliskan baris berikut dalam makefile:

objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o

Dengan begitu, di setiap tempat kita ingin menempatkan daftar nama file objek, kita dapat menyisipkan nilai variabel tersebut dengan menuliskan $(objects) (lihat Cara menggunakan variabel).

Jika kita menggunakan variabel untuk file objek, keseluruhan makefile sederhana tadi menjadi seperti berikut:

objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o

edit : $(objects)
        cc -o edit $(objects)
main.o : main.c defs.h
        cc -c main.c
kbd.o : kbd.c defs.h command.h
        cc -c kbd.c
command.o : command.c defs.h command.h
        cc -c command.c
display.o : display.c defs.h buffer.h
        cc -c display.c
insert.o : insert.c defs.h buffer.h
        cc -c insert.c
search.o : search.c defs.h buffer.h
        cc -c search.c
files.o : files.c defs.h buffer.h command.h
        cc -c files.c
utils.o : utils.c defs.h
        cc -c utils.c
clean :
        rm edit $(objects)

2.5 Membiarkan make menyimpulkan resep

Anda tidak perlu menuliskan resep untuk mengompilasi setiap file sumber C satu per satu, karena make dapat menyimpulkannya sendiri: make memiliki aturan implisit untuk memperbarui file .o dari file .c dengan nama yang bersesuaian, menggunakan perintah cc -c. Misalnya, make akan menggunakan resep cc -c main.c -o main.o untuk mengompilasi main.c menjadi main.o. Oleh karena itu, kita dapat menghilangkan resep dari aturan untuk file objek. Lihat Menggunakan aturan implisit.

Ketika file .c digunakan secara otomatis seperti ini, file .c tersebut juga otomatis ditambahkan ke daftar prasyarat. Oleh karena itu, jika kita menghilangkan resepnya, kita juga dapat menghilangkan file .c dari daftar prasyarat.

Jika kita menerapkan kedua perubahan ini sekaligus, dan juga menggunakan variabel objects yang diusulkan sebelumnya, seluruh contoh menjadi seperti berikut:

objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o

edit : $(objects)
        cc -o edit $(objects)

main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h

.PHONY : clean
clean :
        rm edit $(objects)

Beginilah cara kita menulis makefile dalam praktik yang sebenarnya. (Seluk-beluk yang terkait dengan clean dijelaskan di tempat lain. Lihat Target semu (phony) dan Error dalam resep.)

Karena aturan implisit sangat praktis, fitur ini menjadi penting. Anda akan sering melihatnya digunakan.

2.6 Gaya makefile lainnya

Jika objek dalam makefile dibuat hanya dengan aturan implisit, ada gaya penulisan makefile alternatif yang mungkin. Dalam gaya ini, entri dikelompokkan berdasarkan prasyaratnya, bukan berdasarkan targetnya. Berikut ini contohnya:

objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o

edit : $(objects)
        cc -o edit $(objects)

$(objects) : defs.h
kbd.o command.o files.o : command.h
display.o insert.o search.o files.o : buffer.h

Di sini, defs.h diberikan sebagai prasyarat dari semua file objek; command.h dan buffer.h menjadi prasyarat dari file objek tertentu yang dicantumkan untuk masing-masing.

Apakah gaya ini lebih baik adalah masalah selera. Gaya ini lebih ringkas, tetapi sebagian orang tidak menyukainya karena mereka merasa lebih jelas jika semua informasi tentang setiap target dikumpulkan di satu tempat.

2.7 Aturan untuk membersihkan direktori

Mengompilasi program bukan satu-satunya hal yang mungkin ingin Anda tuliskan aturannya. makefile umumnya juga menjelaskan cara melakukan beberapa pekerjaan lain selain mengompilasi program: misalnya, cara menghapus semua file objek dan file executable agar direktori menjadi clean (bersih).

Aturan make untuk membersihkan editor contoh kita dapat ditulis seperti berikut:

clean:
        rm edit $(objects)

Dalam praktiknya, Anda mungkin ingin menulis aturan dengan cara yang sedikit lebih rumit agar dapat menangani situasi yang tidak terduga. Anda dapat melakukannya seperti berikut:

.PHONY : clean
clean :
        -rm edit $(objects)

Cara ini mencegah make menjadi bingung jika ada file sungguhan bernama clean, dan membuatnya tetap melanjutkan proses meskipun rm menghasilkan error. (Lihat Target semu (phony) dan Error dalam resep.)

Aturan semacam ini sebaiknya tidak diletakkan di awal makefile, karena kita tidak ingin aturan ini dijalankan secara default! Oleh karena itu, dalam makefile contoh ini, kita ingin aturan edit, yang mengompilasi ulang editor, tetap menjadi sasaran default.

Karena clean bukan prasyarat dari edit, aturan ini sama sekali tidak akan dijalankan jika kita menjalankan perintah make tanpa argumen. Untuk menjalankan aturan ini, Anda harus mengetikkan make clean. Lihat Cara menjalankan make.


Sebelumnya | Berikutnya | Daftar Isi | Versi asli bahasa Inggris (gnu.org)