Chapter Linking dan Symbols menutup dengan sepotong janji: linker tidak hanya menyambung object file milik kita sendiri, ia juga bisa menarik simbol dari kumpulan kode yang sudah dikemas rapi — library. Pada Chapter ini kita wujudkan janji itu dengan tangan sendiri: mengemas modul matematika yang sudah kita bangun pada Chapter Header dan Source Files menjadi static library .a, lalu menjadi dynamic library .so, me-link program pemakainya ke keduanya, dan menjalankan hasilnya sungguhan. Dengan itu, tawaran -l yang sering Anda lihat di panduan kompilasi — -lmatematika, -lfmt, -lboost_system — akhirnya berhenti menjadi teka-teki.
Dua Rasa Library #
Sebelum praktik, luruskan istilahnya. Library adalah arsip berisi satu atau lebih object file beserta indeks simbolnya — persis bahan yang sudah kita kenal, hanya dikemas untuk dipakai ulang. Ada dua rasa: static library (.a di Linux) disalin utuh ke dalam executable saat link, sehingga program jadi mandiri; dynamic library (.so) tidak disalin — executable hanya mencatat kebutuhannya, dan kode library dimuat saat program berjalan. Keduanya dibuat dari object file yang sama; yang membedakan hanya cara pengemasan dan saat kode itu diikat ke program.
Kita mulai dari bahan mentahnya — modul matematika yang sudah lama kita kenal:
#include <vector>
// Deklarasi (prototype): implementasinya ada di matematika.cpp
int tambah(int a, int b);
int kali(int a, int b);
double rataRata(const std::vector<int>& nilai);
// Fungsi kecil satu baris: inline, boleh langsung didefinisikan di header
inline int kuadrat(int x) {
return x * x;
}#include "matematika.h"
int tambah(int a, int b) {
return a + b;
}
int kali(int a, int b) {
return a * b;
}
double rataRata(const std::vector<int>& nilai) {
if (nilai.empty()) {
return 0.0;
}
double total = 0.0;
for (int n : nilai) {
total += n;
}
return total / nilai.size();
}#include <iostream>
#include <vector>
#include "matematika.h"
int main() {
std::cout << "8 + 5 = " << tambah(8, 5) << "\n";
std::cout << "8 x 5 = " << kali(8, 5) << "\n";
std::cout << "9 kuadrat = " << kuadrat(9) << "\n";
std::vector<int> nilai {80, 75, 90};
std::cout << "Rata-rata = " << rataRata(nilai) << "\n";
return 0;
}Membuat Static Library dengan ar #
Bahan pertama adalah object file biasa — persis seperti pada Chapter Separate Compilation. Kemudian tool ar (archiver) mengemasnya menjadi arsip .a dengan opsi rcs: r memasukkan file, c membuat arsip bila belum ada, s menulis indeks simbol yang dibutuhkan linker:
g++ -std=c++23 -Wall -Wextra -c matematika.cpp
ar rcs libmatematika.a matematika.o
ar t libmatematika.a
ls -l libmatematika.a | awk '{print $5, $9}'Output yang Dihasilkan:
matematika.o
7372 libmatematika.aPerhatikan konvensi penamaannya yang wajib diikuti: lib + nama + .a, sehingga libmatematika.a dipanggil lewat flag -lmatematika — linker yang menambahkan awalan lib dan akhiran .a sendiri. Sekarang link program pemakai ke library tadi: -L. menambahkan folder sekarang ke daftar tempat mencari library, dan -lmatematika meminta library itu:
g++ -std=c++23 -Wall -Wextra utama.cpp -L. -lmatematika -o utama-statis
./utama-statisOutput yang Dihasilkan:
8 + 5 = 13
8 x 5 = 40
9 kuadrat = 81
Rata-rata = 81.6667Hasilnya identik dengan versi yang kita link langsung dari matematika.cpp — dan memang seharusnya: static library hanyalah kemasan untuk object file yang sama. Kode tambah, kali, dan rataRata kini tertubuh di dalam utama-statis; program itu tidak butuh libmatematika.a lagi saat dijalankan.
Membuat Dynamic Library dengan -fPIC -shared #
Versi dinamis butuh satu persiapan: kode harus dikompilasi sebagai position-independent code (-fPIC) — machine code yang bekerja tanpa peduli alamat mana ia dimuat, karena lokasi di memori baru diketahui saat program berjalan. Pengemasnya bukan ar melainkan opsi linker -shared:
g++ -std=c++23 -Wall -Wextra -fPIC -c matematika.cpp
g++ -shared matematika.o -o libmatematika.so
ls -l libmatematika.so | awk '{print $5, $9}'Output yang Dihasilkan:
16552 libmatematika.soPerintah link pemakainya sama persis dengan versi statis — -L. -lmatematika. Kita jalankan dengan satu tambahan: LD_LIBRARY_PATH=. memberi tahu dynamic loader untuk juga mencari library di folder sekarang, karena folder proyek bukan lokasi standar library sistem:
g++ -std=c++23 -Wall -Wextra utama.cpp -L. -lmatematika -o utama-dinamis
LD_LIBRARY_PATH=. ./utama-dinamis
ldd utama-dinamis | awk '{print $1}'Output yang Dihasilkan:
8 + 5 = 13
8 x 5 = 40
9 kuadrat = 81
Rata-rata = 81.6667
linux-vdso.so.1
libmatematika.so
libstdc++.so.6
libgcc_s.so.1
libc.so.6
libm.so.6
/lib64/ld-linux-x86-64.so.2ldd — yang sudah kita pakai pada Chapter Proses Kompilasi dan Linking — membuktikan perbedaannya: libmatematika.so kini terdaftar sebagai dependensi runtime utama-dinamis, sejajar dengan libstdc++.so.6 dan teman-temannya. Hapus atau ganti file .so itu, dan program tadi menolak berjalan.
Kapan Memilih Mana #
Satu catatan praktis dari eksperimen kita: sebelum membuat .so kita menghapus libmatematika.a terlebih dulu. Pasalnya, bila keduanya ada dengan nama sama, linker memilih .so secara bawaan — perilaku yang nyata ini sering membuat orang heran kenapa perubahannya tidak terasa. Adapun pertimbangan memilih di proyek nyata:
| Aspek | Static (.a) | Dynamic (.so) |
|---|---|---|
| Distribusi | Program mandiri, satu file | Program + library harus ikut disebarkan |
| Update library | Kompilasi ulang program | Ganti .so, program ikut menerima perbaikan |
| Ukuran executable | Lebih besar (kode disalin) | Lebih kecil (kode dipakai bersama) |
| Kecepatan | Sedikit lebih cepat, tanpa resolusi runtime | Ada biaya kecil saat memuat |
| Versi berlubang | Tidak ada risiko ketidakcocokan | Waspada program yang menuntut versi .so lama |
Rule of thumb yang sehat untuk pemula: static untuk kemudahan distribusi, dynamic untuk pemakaian luas — pustaka sistem seperti libstdc++ dinamis justru karena dipakai ribuan program sekaligus. Seluk-beluk menyebarkan hasil build ini kita dalami pada Section Deployment dan Distribusi.
Sekarang kita bisa mengemas dan me-link library dengan tangan. Tetapi bayangkan proyek dengan puluhan file: mengulang urutan -c, ar, dan link setiap kali satu baris berubah bukan pekerjaan manusia. Chapter berikutnya menyodorkan penyelesaiannya yang sudah berumur hampir setengah abad: make dan Makefile.
Referensi: Link Options di dokumentasi GCC .