Kita sudah membuktikan sendiri pada Chapter Separate Compilation bahwa build yang benar adalah pekerjaan menjalankan aturan: file .cpp berubah → kompilasi ulang .o-nya; header berubah → kompilasi ulang semua yang memakainya; baru kemudian link. Mengetik semua itu dengan tangan untuk tiga file sudah melelahkan, untuk tiga ratus file mustahil. Karena itu tahun 1976 Stuart Feldman menulis make — tool yang membaca aturan build dari file bernama Makefile, membandingkan stempel waktu antar file, dan hanya menjalankan perintah yang benar-benar perlu. Hampir setengah abad kemudian, make masih dipasang bawaan di praktis semua sistem Unix, dan memahaminya adalah tiket masuk ke semua build system modern, termasuk CMake.

Makefile Pertama Kita #

Kita bangun ulang modul matematika (isi ketiga filenya persis seperti pada Chapter Header dan Source Files: matematika.h, matematika.cpp, utama.cpp), kali ini dengan otak build-nya:

makefile
CXX      := g++
CXXFLAGS := -std=c++23 -Wall -Wextra
OBJS     := utama.o matematika.o

utama: $(OBJS)
	$(CXX) $(OBJS) -o $@

%.o: %.cpp
	$(CXX) $(CXXFLAGS) -c $< -o $@

clean:
	rm -f utama $(OBJS)

.PHONY: clean

Bedah strukturnya, satu blok per satu aturan:

  1. Tiga variabel — CXX, CXXFLAGS, dan OBJS menyimpan nama compiler, flag, dan daftar object file. Mengubah flag kompilasi berarti mengubah satu baris, bukan enam.
  2. utama: $(OBJS) — target bernama utama bergantung pada prerequisites utama.o dan matematika.o. Bila salah satu prerequisite lebih baru dari target, recipe di bawahnya dijalankan.
  3. Recipe target utama — baris yang diawali TAB: $(CXX) $(OBJS) -o $@. Automatic variable $@ berarti “target aturan ini”, jadi recipe-nya tetap benar bila nama target diganti.
  4. %.o: %.cpp — pattern rule: untuk setiap .cpp yang dibutuhkan, cara membuat pasangan .o-nya sama. $< berarti prerequisite pertama, yaitu file .cpp miliknya.
  5. clean + .PHONY — target utilitas untuk menghapus hasil build. .PHONY memberi tahu make bahwa clean bukan nama file sungguhan, sehingga selalu dijalankan meski kebetulan ada file bernama clean.

Menjalankan make #

Cukup ketik make di folder yang berisi Makefile — make memilih target pertama (utama) dan menuntaskan seluruh rantai dependensinya. Log di bawah ini hasil eksekusi nyata di lingkungan praktikum:

bash
make

Output yang Dihasilkan:

text
g++ -std=c++23 -Wall -Wextra -c utama.cpp -o utama.o
g++ -std=c++23 -Wall -Wextra -c matematika.cpp -o matematika.o
g++ utama.o matematika.o -o utama

Program siap dijalankan, dan outpunya persis seperti versi manual kita:

bash
./utama

Output yang Dihasilkan:

text
8 + 5 = 13
8 x 5 = 40
9 kuadrat = 81
Rata-rata = 81.6667

Sekarang bagian yang membuat make layak dipakai — jalankan make lagi tanpa mengubah apa pun:

bash
make

Output yang Dihasilkan:

text
make: 'utama' is up to date.

Make membandingkan stempel waktu: utama lebih baru daripada kedua .o, dan kedua .o lebih baru daripada .cpp-nya, maka tidak ada pekerjaan. Lakukan perubahan pada satu file — touch matematika.cpp mensimulasikannya — dan make langsung tahu batas minimal pekerjaannya:

bash
touch matematika.cpp
make

Output yang Dihasilkan:

text
g++ -std=c++23 -Wall -Wextra -c matematika.cpp -o matematika.o
g++ utama.o matematika.o -o utama

Hanya matematika.o yang dikompilasi ulang; utama.o dibiarkan apa adanya, lalu link diulang. Inilah incremental build yang pada Chapter lalu kita lakukan manual — sekarang otomatis. Terakhir, target utilitas:

bash
make clean

Output yang Dihasilkan:

text
rm -f utama utama.o matematika.o

Aturan Emas: Recipe Memakai TAB #

Satu jebakan historis wajib Anda tahu sejak hari pertama: baris recipe harus diawali karakter TAB, bukan spasi. Editor yang menyemprot spasi di tempat TAB — sengaja atau tidak — merusak Makefile dengan pesan yang seadanya:

text
Makefile-rusak:7: *** missing separator.  Stop.

Pesan missing separator ini hampir selalu berarti TAB yang hilang di baris yang disebut, dan ia jadi bahan lelucon tetap di komunitas make. Pastikan editor Anda menampilkan whitespace, dan bila menyalin Makefile dari internet, curigai baris recipe yang kehilangan TAB-nya di jalan.

Posisi make dalam Kehidupan C++ #

make tidak tahu apa-apa tentang C++ — ia tool umum untuk “jika file A lebih baru dari file B, jalankan perintah ini”. Sifat umum itu kekuatannya (dipakai dari C sampai dokumentasi LaTeX), tetapi juga batasnya: kita sendiri yang harus menulis daftar file, pattern rule, dan dependensi header. Build system modern seperti CMake tidak menggantikan make — melainkan menggantikan pekerjaan menulis Makefile-nya: kita mendeskripsikan proyek dalam bahasa yang lebih tinggi, dan CMake yang membuat Makefile atau build file lain untuk kita. Bagaimana persisnya ia bekerja itulah topik Chapter berikutnya.

Referensi: Manual GNU Make .