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:

cpp matematika.h
#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;
}
cpp matematika.cpp
#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();
}
cpp utama.cpp
#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:

bash
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:

text
matematika.o
7372 libmatematika.a

Perhatikan 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:

bash
g++ -std=c++23 -Wall -Wextra utama.cpp -L. -lmatematika -o utama-statis
./utama-statis

Output yang Dihasilkan:

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

Hasilnya 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:

bash
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:

text
16552 libmatematika.so

Perintah 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:

bash
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:

text
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.2

ldd — 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:

AspekStatic (.a)Dynamic (.so)
DistribusiProgram mandiri, satu fileProgram + library harus ikut disebarkan
Update libraryKompilasi ulang programGanti .so, program ikut menerima perbaikan
Ukuran executableLebih besar (kode disalin)Lebih kecil (kode dipakai bersama)
KecepatanSedikit lebih cepat, tanpa resolusi runtimeAda biaya kecil saat memuat
Versi berlubangTidak ada risiko ketidakcocokanWaspada 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 .