Repository Debian mengemas puluhan ribu package, tetapi kadang kebutuhan kita jatuh di luar jangkauannya: versi terbaru yang belum sempat dikemas, opsi kompilasi yang tidak diaktifkan pengempannya, atau software kecil yang belum dikemas siapa pun. Untuk kondisi seperti itu, jalur tertua di dunia Unix tetap terbuka: mengambil source code lalu membangunnya sendiri. Kabar baiknya, toolchain yang dibutuhkan — compiler gcc dan build automation make — sudah terpasang di lingkungan ini, sehingga seluruh contoh pada Chapter ini benar-benar dijalankan, bukan sekadar dibayangkan.

Toolchain: gcc, make, dan Paket -dev #

Kompilasi adalah penerjemahan source code menjadi instruksi mesin. Tiga komponen berperan di dalamnya:

KomponenPeran
gcccompiler keluarga GNU: menerjemahkan C menjadi object file, lalu menggabungkannya menjadi binary
makebuild automation: membandingkan waktu modifikasi file, lalu hanya membangun ulang yang berubah
libc6-devheader dan pustaka pengembangan libc — termasuk stdio.h yang kita #include
build-essentialmetapackage: menarik gcc, g++, make, dan libc6-dev sekaligus

Perhatikan baris libc6-dev — inilah wajah konsep paket -dev. Package biasa membawa file yang dibutuhkan program saat berjalan, sedangkan package berakhiran -dev membawa file yang dibutuhkan saat mengompilasi: deklarasi header dan tautan ke pustaka. Kita sudah melihat build-essential menarik gcc dan make lewat relasi Depends pada Chapter Package Dependencies . Gejala kekurangan toolchain sangat khas: compiler berhenti dengan pesan fatal error: stdio.h: No such file or directory — obatnya satu kalimat, sudo apt install build-essential.

Kompilasi Pertama: dari halo.c ke Binary #

gcc sebenarnya pengemudi empat tahap — preprosesor, compiler, assembler, lalu linker — tetapi kita cukup memanggilnya sekali. Program C terkecil yang masih berguna kita tulis dengan heredoc, lalu langsung dikompilasi dan dijalankan:

bash
cat > halo.c << 'AKHIR'
#include <stdio.h>

int main(void)
{
    printf("Halo dari C!\n");
    return 0;
}
AKHIR
gcc -Wall -o halo halo.c
./halo

Output yang Dihasilkan:

text
Halo dari C!

Bedah program dan perintahnya baris per baris:

  1. Baris 1 (#include <stdio.h>): memuat deklarasi fungsi input/output standar — tanpa baris ini, compiler tidak mengenal printf.
  2. Baris 3–7 (fungsi main): titik masuk program; eksekusi binary dimulai dari fungsi ini.
  3. Baris 5 (printf): menulis satu baris teks ke stdout; \n menandai akhir baris.
  4. Baris 6 (return 0): mengembalikan exit code 0, tanda sukses — konsep yang kita kenal dari Chapter Exit Codes .
  5. gcc -Wall -o halo halo.c: -Wall mengaktifkan kelompok warning agar kejanggalan terlihat sebelum menjadi bug, dan -o halo menamai binary hasil (tanpa -o hasilnya bernama a.out). Diamnya gcc adalah kabar baik: tanpa warning, tanpa error.
  6. ./halo: menjalankan binary baru; awalan ./ wajib karena direktori kerja tidak termasuk dalam PATH.

Makefile: Resep Build yang Diingat make #

Satu file bisa dijalankan langsung dengan gcc, tetapi proyek nyata berisi puluhan file — dan mengompilasi semuanya setiap perubahan kecil adalah pemborosan. make mengatasinya dengan aturan sederhana: sebuah target dibangun ulang hanya bila prasyaratnya lebih baru, dilihat dari waktu modifikasi file. Aturan itu ditulis dalam Makefile:

bash
cat > halo.c << 'AKHIR'
#include <stdio.h>

int main(void)
{
    printf("Halo dari C!\n");
    return 0;
}
AKHIR
cat > Makefile << 'AKHIR'
all: halo

halo: halo.c
	gcc -Wall -o halo halo.c

clean:
	rm -f halo
AKHIR
rm -f halo
make
./halo
make halo
make clean
ls

Output yang Dihasilkan:

text
gcc -Wall -o halo halo.c
Halo dari C!
make: 'halo' is up to date.
rm -f halo
Makefile
halo.c

Bedah Makefile dan eksekusinya:

  1. Baris 1 (all: halo): target pertama menjadi target default, sehingga make tanpa argumen membangunnya; all adalah nama kebiasaan untuk “seluruh hasil”.
  2. Baris 3–4 (halo: halo.c dan resepnya): aturan membangun target halo dari prasyarat halo.c; baris resep wajib diawali karakter TAB — bukan spasi.
  3. rm -f halo dan make: penghapusan di awal memastikan keadaan bersih, dan make menampilkan tiap resep sebelum menjalankannya.
  4. make halo: karena halo barusan dibuat dan lebih baru dari halo.c, make menolak bekerja dengan alasan up to date — penghematan inilah alasan make ada.
  5. make clean: target tanpa prasyarat untuk menghapus hasil build, ditutup ls sebagai konfirmasi bahwa halo sudah terhapus.

Jabatan TAB itu serius. Menulis resep dengan spasi biasa menghasilkan error yang paling sering dijumpai pemula Makefile:

bash
printf 'all:\n echo halo\n' > Makefile
make 2>&1

Output yang Dihasilkan:

text
Makefile:2: *** missing separator.  Stop.

printf sengaja menulis baris resep dengan spasi di depan, bukan TAB, dan make langsung menolaknya: pesan missing separator berarti awalan resep tidak ditemukan. Editor yang diam-diam mengubah TAB menjadi spasi adalah penyebab klasiknya — sebagian editor punya mode khusus untuk Makefile. Rincian sintaks make ada di make(1) , dan opsi compiler di gcc(1) .

Alur Klasik Tarball: configure, make, make install #

Software yang didistribusikan sebagai source biasanya berbentuk arsip tarball berisi source code dan script persiapan. Alur pembangunannya telah menjadi standar de facto selama puluhan tahun:

bash
tar -xf program-1.2.3.tar.gz
cd program-1.2.3
./configure --prefix=/usr/local
make
sudo make install

Peran tiap langkah: tar -xf mengekstrak arsip menjadi folder program-1.2.3/. Script ./configure memeriksa sistem — apakah compiler ada, apakah pustaka yang dibutuhkan tersedia dalam versi cocok — lalu menulis Makefile yang disesuaikan; opsi --prefix menentukan lokasi pemasangan nanti. Selanjutnya make menjalankan Makefile hasil configure, dan sudo make install menyalin binary, pustaka, serta dokumentasi ke lokasi target — butuh root karena tujuannya di luar home directory. Sebagai contoh tampilan, pembukaan ./configure pada proyek nyata berbentuk seperti ini:

text
checking for gcc... gcc
checking whether the C compiler works... yes
checking for stdio.h... yes
configure: creating ./config.status
config.status: creating Makefile

Baris-baris checking adalah pemeriksaan sistem tadi; dua baris terakhir menandakan Makefile berhasil ditulis dan siap dijalankan make. Proyek modern sebagian bermigrasi ke CMake atau Meson, tetapi hasil akhirnya sama: satu set aturan build yang menjembatani source code menjadi binary.

make install dan Wilayah /usr/local #

Langkah sudo make install menimbulkan pertanyaan penting: mengapa targetnya /usr/local, bukan /usr? Jawabannya ada pada pembagian wilayah dalam Filesystem Hierarchy Standard:

LokasiDiisi olehIsi tipikal
/usr/bin, /usr/libpackage manager (dpkg, dnf, pacman)software dari repository
/usr/local/bin, /usr/local/libadministrator, lewat make installhasil kompilasi sendiri

/usr/local direservasikan khusus untuk software yang dibangun sendiri sehingga tidak pernah bertabrakan dengan milik package manager. Perilaku make install bisa kita lihat dengan aman tanpa root — cukup arahkan PREFIX ke folder kerja:

bash
cat > halo.c << 'AKHIR'
#include <stdio.h>

int main(void)
{
    printf("Halo dari C!\n");
    return 0;
}
AKHIR
cat > Makefile << 'AKHIR'
PREFIX ?= /usr/local

all: halo

halo: halo.c
	gcc -Wall -o halo halo.c

install: halo
	install -D halo $(PREFIX)/bin/halo

clean:
	rm -f halo
AKHIR
rm -f halo
make install PREFIX="$PWD/akar-lokal"
akar-lokal/bin/halo
ls akar-lokal/bin

Output yang Dihasilkan:

text
gcc -Wall -o halo halo.c
install -D halo /home/budi/akar-lokal/bin/halo
Halo dari C!
halo

Bedah baris-baris pentingnya:

  1. PREFIX ?= /usr/local (baris 1 Makefile): operator ?= berarti “pakai nilai ini hanya bila belum ditentukan”, sehingga make install PREFIX=... di baris perintah bisa menimpanya tanpa mengubah file.
  2. install -D halo $(PREFIX)/bin/halo: perintah install menyalin file sekaligus membuat direktori tujuannya — inilah yang dikerjakan sudo make install sesungguhnya, hanya saja ke /usr/local.
  3. make install PREFIX="$PWD/akar-lokal": memakai folder kerja sebagai target sehingga tidak butuh root. Path /home/budi pada output mengikuti folder kerja di mesin masing-masing.

Agar Hasil Kompilasi Tetap Terlacak #

Kelemahan make install klasik ada pada jejaknya: penghapusan bergantung pada target uninstall yang kebetulan disediakan — jika memang disediakan. Dua alat bantu menjawabnya. checkinstall dulu paling populer: alat ini mengintip eksekusi make install, mencatat file yang disentuhnya, lalu mengemasnya menjadi file .deb sehingga tercatat di database dpkg dan bisa dilepas dengan apt remove — sayangnya checkinstall sudah lama tidak hadir di repository Debian, meski masih tersedia di Ubuntu; cara manualnya membangun .deb dengan dpkg-deb --build sudah kita praktikkan di Chapter apt dan dpkg . Alternatif lain adalah GNU stow: tiap program dipasang ke foldernya sendiri di bawah /usr/local/stow/, lalu stow membuat symlink dari /usr/local/bin ke sana — mengganti versi cukup menghapus tautan lama tanpa menyentuh binary. Rinciannya ada di stow(8) .

Alur di atas menuntut toolchain yang sehat: compiler terpasang, header -dev lengkap, dan ruang disk cukup. Ketika salah satunya absen, kompilasi berhenti dengan pesan error yang — sama seperti pesan apt — dirancang untuk dibaca sampai habis. Kebiasaan membaca dan menindaklanjuti pesan error itu adalah materi Chapter berikutnya: Troubleshooting Packages.