Satu panggilan gcc sebenarnya menjalankan empat tahap berbeda — preprocessor, compiler, assembler, lalu linker — yang masing-masing menghasilkan file antara berbeda. Memahami tahapan ini penting karena saat kompilasi gagal, pesan error menyebut tahap mana yang bersalah. Pada Chapter ini kita menjalankan keempat tahap secara manual, membedakan gcc dari g++, lalu belajar membaca dua keluarga pesan error yang paling sering menghentikan build.
Empat Tahap di Balik Satu Perintah #
Empat tahap kompilasi bekerja seperti jalur perakitan: tiap tahap menerima hasil tahap sebelumnya, dan driver gcc menyediakan satu opsi untuk berhenti di tiap tahap:
| Tahap | Program kerja | Hasil | Opsi penghenti |
|---|---|---|---|
| Preprocessing | preprocessor | halo.i — header dan macro terurai | -E |
| Compilation | compiler | halo.s — kode assembly | -S |
| Assembly | assembler | halo.o — object file ELF | -c |
| Linking | linker | halo — executable | (default) |
Ekstensi .i, .s, dan .o adalah konvensi driver; tahap pertama menerapkan semua arahan # sehingga hasilnya C murni tanpa arahan preprocessor.
Menyusuri Empat Tahap Secara Manual #
Kita pakai program kecil berisi satu #define agar kerja preprocessor terlihat; tiap langkah berhenti di satu tahap lalu memeriksa hasilnya:
cat > halo.c << 'AKHIR'
#include <stdio.h>
#define NAMA "Budi"
int main(void)
{
printf("Halo, %s!\n", NAMA);
return 0;
}
AKHIR
gcc -E halo.c | wc -l
gcc -S halo.c
grep -n "main:" halo.s
gcc -c halo.c
file halo.o
gcc -o halo halo.o
./haloOutput yang Dihasilkan:
819
11:main:
halo.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
Halo, Budi!Bedah tiap langkah dan hasilnya:
gcc -E halo.c | wc -l: preprocessing saja —#includediganti isistdio.hbeserta rantai header-nya, danNAMAdiganti"Budi". Hasilnya ratusan baris di mesin uji; angkanya berbeda antar distro, jadiwc -ldipakai alih-alih menampilkan semuanya.gcc -S halo.clalugrep -n "main:" halo.s: kompilasi ke assembly —halo.sberisi instruksi x86-64 yang masih terbaca manusia;grepmenemukan labelmaindi baris 11 (bisa bergeser antar versi compiler).gcc -c halo.clalufile halo.o: assembly menjadi object file — kode mesin dalam ELF, tetapi masih relocatable: alamat belum final karena belum digabung.gcc -o halo halo.o: linking — linker merangkaihalo.odengan startup code dan pustaka lalu menyelesaikan semua alamat. Output./halomembuktikanNAMAsudah tergantikan"Budi"sejak tahap pertama.
gcc versus g++ #
gcc dan g++ adalah dua pintu masuk ke compiler yang sama, tetapi g++ memperlakukan file sebagai C++ dan menautkan pustaka standar C++ (libstdc++) saat linking. Nama C++ juga di-mangling — tipe dikodekan ke nama simbol, misalnya std::cout menjadi _ZSt4cout. Perbedaan kecil ini melahirkan jebakan klasik:
cat > halo.cpp << 'AKHIR'
#include <iostream>
int main()
{
std::cout << "Halo dari C++!\n";
return 0;
}
AKHIR
g++ -Wall -o halo_pp halo.cpp
./halo_pp
gcc -c halo.cpp
gcc -o salah halo.o 2>&1Output yang Dihasilkan:
Halo dari C++!
/usr/bin/ld: halo.o: warning: relocation against `_ZSt4cout' in read-only section `.text'
/usr/bin/ld: halo.o: in function `main':
halo.cpp:(.text+0x11): undefined reference to `std::cout'
/usr/bin/ld: halo.cpp:(.text+0x19): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit statusApa yang terjadi pada blok di atas:
g++ -Wall -o halo_pp halo.cppdan./halo_pp: jalur yang benar —libstdc++ikut ditautkan dan program berjalan lancar.gcc -c halo.cpp: tahap kompilasi tetap berhasil — penerjemah C++ di dalamgccikut dipanggil untuk file.cpp.gcc -o salah halo.o 2>&1: jebakannya — tahap link gagal karenagcctidak menautkanlibstdc++, padahal object file butuh definisistd::coutdari pustaka itu.
Opsi yang Paling Sering Dipakai #
Driver gcc punya ratusan opsi, tetapi sekelompok kecil menyumbang mayoritas pemakaian sehari-hari:
| Opsi | Peran |
|---|---|
-o nama | menamai file hasil |
-Wall | mengaktifkan kelompok warning paling berguna |
-O2 | optimalkan kecepatan (huruf O besar, bukan nol) |
-g | sertakan info debug untuk gdb |
-Idir | tambah lokasi pencarian header |
-Ldir | tambah lokasi pencarian pustaka |
-lnama | tautkan pustaka libnama.so/libnama.a |
Tiga opsi terakhir bekerja sebagai satu tim dan paling baik dipahami lewat praktik — contoh berikut sekaligus memakai -Wall -O2, menaruh header di inc/, mengemas fungsi ke pustaka statis dengan ar, lalu menautkannya:
mkdir -p inc src
cat > inc/sapa.h << 'AKHIR'
int sapa(int n);
AKHIR
cat > src/sapa.c << 'AKHIR'
#include "sapa.h"
int sapa(int n)
{
return n + 1;
}
AKHIR
cat > utama.c << 'AKHIR'
#include <stdio.h>
#include "sapa.h"
int main(void)
{
printf("hasil: %d\n", sapa(40));
return 0;
}
AKHIR
gcc -Wall -O2 -Iinc -c src/sapa.c -o sapa.o
ar rcs libsapa.a sapa.o
gcc -Wall -O2 -Iinc -c utama.c -o utama.o
gcc -o program utama.o -L. -lsapa
./programOutput yang Dihasilkan:
hasil: 41Bedah opsi-opsi yang bekerja di balik layar:
-Iinc: menambahinc/ke pencarian header sehingga#include "sapa.h"ketemu walau tidak sefolder — tanpanya compiler keluar denganfatal error: sapa.h: No such file or directory.ar rcs libsapa.a sapa.o: archiverarmenggabungkan object file menjadi arsip pustaka statis dengan konvensilib+ nama +.a— justru nama tengahnya,sapa, yang dipakai opsi berikutnya.-L. -lsapa:-L.menambah direktori kerja ke pencarian pustaka, lalu-lsapamemerintahkan linker mencarilibsapa.a/libsapa.so. Karena yang ada versi statis, kodesapa.odisalin langsung ke dalamprogram.
Pustaka nyata seperti libssl ditautkan dengan pola yang sama; di proyek besar pkg-config yang menghitung opsi ini — materi Chapter pkg-config dan Linking di akhir section ini.
Membaca Pesan Error Kompilasi #
Dua keluarga error mendominasi build C/C++. Keluarga pertama berhenti di tahap kompilasi dengan format file:baris:kolom:
printf '#include <tidakada.h>\nint main(void)\n{\n return 0;\n}\n' > gagal.c
gcc -o gagal gagal.c 2>&1Output yang Dihasilkan:
gagal.c:1:10: fatal error: tidakada.h: No such file or directory
1 | #include <tidakada.h>
| ^~~~~~~~~~~~
compilation terminated.Pesan fatal error: tidakada.h: No such file or directory berarti preprocessor gagal menemukan header — biasanya salah ketik atau package -dev pemiliknya belum terpasang. Keluarga kedua berhenti saat link dengan format undefined reference, seperti pada halo.cpp: simbol dipanggil tapi definisinya tidak ditemukan — penyebab klasiknya fungsi yang lupa didefinisikan atau opsi -l yang hilang. Keduanya selalu menuliskan nama file plus lokasi persis; membaca pesan dari baris pertama menghemat waktu lebih banyak daripada hafalan opsi. Rujukan lengkap: gcc(1)
, g++(1)
, dan ld(1)
.
Empat tahap dan dua keluarga error di atas adalah wajah dunia bahasa compiled. Bab berikutnya berpindah model: Python, yang source-nya dibaca langsung interpreter tanpa kompilasi manual — dan justru karena itu memunculkan persoalan versi serta dependensi yang khas.