make adalah program yang membaca Makefile dan menjalankan perintah-perintah di dalamnya. Walaupun konsepnya sederhana — make membaca target, prerequisite, dan recipe — program ini punya banyak flag command-line yang mengubah perilakunya. Pada chapter ini kita akan mempraktikkan workflow sehari-hari (make, make clean, make install), memahami flag umum (-n, -B, -j), dan mengamati bagaimana make memilih target yang dijalankan secara default. Menguasai flag-flag ini membuat kita bisa membaca CI script dan Makefile proyek open-source tanpa kebingungan.

Verifikasi Instalasi make #

bash
make --version

Output yang Dihasilkan:

text
GNU Make 4.4.1
Built for x86_64-pc-linux-gnu

Pesan di atas menunjukkan versi GNU Make (4.4.1) dan arsitektur target (x86_64-pc-linux-gnu). GNU Make adalah implementasi standar make di sistem GNU/Linux; alternatif lain adalah BSD Make yang ada di FreeBSD/macOS.

Workflow Standar: make, make clean, make install #

Kita pakai Makefile dari chapter sebelumnya. Struktur proyek:

text
greet.h, greet.c   -- library greet
main.c              -- program utama
Makefile            -- script build

make — Build Target Default #

Tanpa argumen, make memilih target pertama di Makefile sebagai target default. Makefile kita mendefinisikan $(TARGET) (app) sebagai target pertama, sehingga make membangun executable app:

bash
make

Output yang Dihasilkan:

text
gcc -std=c11 -Wall -Wextra -c main.c -o main.o
gcc -std=c11 -Wall -Wextra -c greet.c -o greet.o
gcc -std=c11 -Wall -Wextra main.o greet.o -o app

make menjalankan recipe dalam urutan dependensi: pertama mengompilasi main.o (karena app bergantung padanya), lalu greet.o, lalu link keduanya menjadi app. Bila kita menjalankan make lagi tanpa mengubah apa pun, make melaporkan target sudah up-to-date:

bash
make

Output yang Dihasilkan:

text
make: 'app' is up to date.

make membandingkan timestamp file target (app) dengan timestamp prerequisite (main.o, greet.o). Karena target lebih baru, tidak ada yang perlu dilakukan.

make clean — Hapus Artifact Build #

Target clean menghapus object file dan executable hasil build:

bash
make clean

Output yang Dihasilkan:

text
rm -f main.o greet.o app

Setelah clean, direktori kerja kembali bersih. Target clean biasanya dideklarasikan sebagai .PHONY (bukan file target) — lihat chapter Makefile.

make install — Install ke Lokasi Sistem #

Makefile profesional biasanya punya target install yang menyalin executable ke lokasi sistem. Pola idiomatik memakai DESTDIR untuk pengujian tanpa benar-benar memodifikasi sistem:

makefile
install: $(TARGET)
	install -m 0755 $(TARGET) $(DESTDIR)/usr/local/bin/$(TARGET)
bash
mkdir -p fake_root/usr/local/bin
DESTDIR=$(pwd)/fake_root make install
ls -l fake_root/usr/local/bin/

Output yang Dihasilkan:

text
install -m 0755 app /tmp/test_make/fake_root/usr/local/bin/app
total 16
-rwxr-x-x 1 z z 16016 Oct 13 07:38 app

Variabel DESTDIR dipakai sistem build (Autoconf, CMake, Makefile manual) untuk mendukung staged install — proses install ke direktori sementara yang nantinya di-tar atau di-package oleh maintainer distro. Tanpa DESTDIR, kita perlu sudo untuk menulis ke /usr/local/bin. Dengan DESTDIR, kita bisa menguji install tanpa hak root.

Mari kita telaah perintah install -m 0755 $(TARGET) $(DESTDIR)/usr/local/bin/$(TARGET):

  1. install: program dari GNU Coreutils yang menyalin file sambil mengatur permission dan ownership. Berbeda dari cp, install mempertahankan permission mode yang kita tentukan, bukan permission file sumber.
  2. -m 0755: atur permission mode 0755 (owner read/write/execute, group/others read/execute). Inilah mode standar executable.
  3. $(TARGET): file sumber (app di direktori kerja).
  4. $(DESTDIR)/usr/local/bin/$(TARGET): tujuan akhir, dengan prefix $(DESTDIR). Bila DESTDIR kosong (default), install ke /usr/local/bin/app (membutuhkan sudo). Bila DESTDIR=/tmp/test_make/fake_root, install ke /tmp/test_make/fake_root/usr/local/bin/app (tidak butuh sudo).

Flag make Penting #

-n (dry run): Tampilkan Perintah Tanpa Menjalankan #

bash
make -n clean

Output yang Dihasilkan:

text
rm -f main.o greet.o app

Flag -n (alias --dry-run) menampilkan perintah yang akan dijalankan, tetapi tidak benar-benar menjalankannya. Berguna untuk memeriksa apa yang akan make lakukan sebelum commit ke build.

-B (always make): Paksa Rebuild Semua #

bash
make -B

Output yang Dihasilkan:

text
gcc -std=c11 -Wall -Wextra -c main.c -o main.o
gcc -std=c11 -Wall -Wextra -c greet.c -o greet.o
gcc -std=c11 -Wall -Wextra main.o greet.o -o app

Flag -B mengabaikan timestamp dan menganggap semua target out-of-date. Berguna bila kita menduga cache build rusak atau bila kita mengubah flag compiler (misalnya menambah -O2) dan ingin memastikan semua object file dikompilasi ulang.

-j<N>: Build Paralel #

bash
make -j2

Output yang Dihasilkan:

text
gcc -std=c11 -Wall -Wextra -c main.c -o main.o
gcc -std=c11 -Wall -Wextra -c greet.c -o greet.o
gcc -std=c11 -Wall -Wextra main.o greet.o -o app

Flag -j2 menyuruh make menjalankan hingga 2 recipe secara paralel. Pada proyek besar dengan banyak file, -j$(nproc) (semua core CPU) bisa mempercepat build 4-8 kali. Makefile kita terlalu kecil untuk menunjukkan efek paralel yang signifikan, tetapi urutan baris tetap menarik — main.o dan greet.o bisa dibangun paralel karena tidak saling bergantung, sedangkan app harus menunggu keduanya selesai.

-C <dir>: Build di Direktori Lain #

bash
make -C /tmp/test_make clean

Output yang Dihasilkan:

text
make: Entering directory '/tmp/test_make'
rm -f main.o greet.o app
make: Leaving directory '/tmp/test_make'

Flag -C <dir> mengganti direktori kerja make ke <dir> sebelum membaca Makefile. Berguna untuk membangun sub-proyek atau dependency eksternal dari Makefile induk: cd /path/to/dep && make ekuivalen dengan make -C /path/to/dep.

Menentukan Target dari Command Line #

make menerima target sebagai argumen posisi:

bash
make clean
make run
make main.o        # build hanya satu target
make -B main.o     # rebuild paksa satu target

Bila beberapa target disebut, make memprosesnya berurutan:

bash
make clean run

Perintah di atas menjalankan clean terlebih dahulu, lalu run. Bila clean gagal (exit non-zero), make berhenti dan tidak menjalankan run.

Override Variabel dari Command Line #

Variabel Makefile bisa di-override dari command line:

bash
make CC=clang CFLAGS="-std=c11 -O2 -Wall"

Karena override command line memiliki prioritas lebih tinggi dari deklarasi di Makefile, perintah di atas mengompilasi dengan Clang alih-alih GCC. Pola ini sering dipakai di CI untuk menguji build dengan beberapa compiler.

bash
make V=1

Output yang Dihasilkan:

text
rm -f main.o greet.o app
gcc -std=c11 -Wall -Wextra -c main.c -o main.o
gcc -std=c11 -Wall -Wextra -c greet.c -o greet.o
gcc -std=c11 -Wall -Wextra main.o greet.o -o app

Konvensi proyek open-source: V=1 (verbose) menampilkan command line lengkap yang dijalankan make. Makefile kita sudah menampilkan command secara default (karena recipe eksplisit), tetapi Makefile yang memakai @ untuk menyembunyikan command akan menampilkan output tambahan saat V=1.