Shared library (file .so di Linux, .dylib di macOS, .dll di Windows) adalah kode library yang dimuat ke memori hanya sekali oleh OS dan dipakai bersama oleh banyak executable. Berbeda dengan static library yang menyalin kode ke setiap executable, shared library tetap terpisah dari executable dan dimuat saat program dimulai (atau bahkan saat fungsi pertama dipanggil). Pada chapter ini kita akan membuat shared library dengan flag -fPIC dan -shared, menggunakannya dari program utama, serta memahami peran LD_LIBRARY_PATH dan -Wl,-rpath.
Apa itu Position-Independent Code #
Shared library dimuat OS ke alamat memori yang tidak diketahui saat kompilasi. Karena itu, semua kode di shared library harus position-independent — tidak boleh mengandung alamat absolut. Flag -fPIC menyuruh GCC menghasilkan kode yang hanya memakai alamat relatif terhadap instruction pointer (RIP-relative addressing di x86-64).
Library kode kita tetap sama dengan chapter sebelumnya — perbedaannya hanya pada flag kompilasi:
/* mylib.h */
#ifndef MYLIB_H
#define MYLIB_H
int tambah(int a, int b);
int kurang(int a, int b);
#endif/* mylib.c */
#include "mylib.h"
int tambah(int a, int b) {
return a + b;
}
int kurang(int a, int b) {
return a - b;
}Membuat Shared Library #
Langkah pertama adalah mengompilasi mylib.c dengan flag -fPIC, lalu men-link dengan flag -shared:
gcc -std=c11 -Wall -Wextra -fPIC -c mylib.c -o mylib.o
gcc -shared -o libmylib.so mylib.o
file libmylib.soOutput yang Dihasilkan:
libmylib.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=5babb0c350b6472ba93fb262baa2cb709c0f91a1, not strippedKata kunci shared object menandakan file ini adalah shared library. Bandingkan dengan object file biasa yang berlabel relocatable, atau executable yang berlabel executable.
Sebagai alternatif, kita bisa menyatukan kedua langkah di atas menjadi satu perintah:
gcc -std=c11 -Wall -Wextra -fPIC -shared -o libmylib.so mylib.cMari kita telaah flag-flag yang dipakai di atas:
-fPIC(Position-Independent Code): menyuruh GCC menghasilkan kode mesin yang memakai alamat relatif terhadap instruction pointer. Tanpa flag ini, kode di shared library akan berisi alamat absolut yang salah saat library dimuat ke alamat acak oleh OS.-shared: menyuruh linker menghasilkan shared library alih-alih executable. Linker tidak menyertakan C runtime (crt0.o,crti.o) karena library tidak punya entry point_start.-o libmylib.so: nama file output. Konvensi Linux: shared library berawalanlibdan berakhiran.so(shared object).
Menggunakan Shared Library dari Program #
Program utama sama seperti chapter Static Library:
#include <stdio.h>
#include "mylib.h"
int main(void) {
printf("5 + 3 = %d\n", tambah(5, 3));
printf("10 - 4 = %d\n", kurang(10, 4));
return 0;
}Kompilasi dan link dengan flag -L. -lmylib — GCC akan mencari libmylib.so di direktori saat ini:
gcc -std=c11 -Wall -Wextra -L. main.c -lmylib -o appSaat kita mencoba menjalankan app tanpa pengaturan tambahan, runtime dynamic linker tidak bisa menemukan libmylib.so:
./appOutput yang Dihasilkan:
./app: error while loading shared libraries: libmylib.so: cannot open shared object file: No such file or directoryError ini muncul karena runtime dynamic linker (ld-linux-x86-64.so.2) mencari shared library hanya di path standar (/lib, /usr/lib, dll) — bukan direktori kerja saat ini. Ada dua solusi umum.
Solusi 1: Variabel LD_LIBRARY_PATH #
Cara cepat: set variabel environment LD_LIBRARY_PATH agar memuat direktori library:
LD_LIBRARY_PATH=. ./appOutput yang Dihasilkan:
5 + 3 = 8
10 - 4 = 6Verifikasi dengan ldd:
LD_LIBRARY_PATH=. ldd appOutput yang Dihasilkan:
linux-vdso.so.1 (0x00007ffe95fdd000)
libmylib.so => ./libmylib.so (0x00007f2208b19000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2208916000)
/lib64/ld-linux-x86-64.so.2 (0x00007f2208b25000)Baris libmylib.so => ./libmylib.so menandakan linker runtime menemukan library di direktori saat ini. Pendekatan LD_LIBRARY_PATH cocok untuk pengembangan, tetapi tidak disarankan untuk produksi karena variabel ini mempengaruhi seluruh proses yang dijalankan user.
Solusi 2: RPATH dengan -Wl,-rpath #
Cara lebih permanen: tanam path library ke executable dengan flag -Wl,-rpath. Flag -Wl, meneruskan argumen berikutnya ke linker ld (bukan ke GCC):
gcc -std=c11 -Wall -Wextra -L. -Wl,-rpath=. main.c -lmylib -o app_rpath
./app_rpathOutput yang Dihasilkan:
5 + 3 = 8
10 - 4 = 6Sekarang app_rpath bisa dijalankan tanpa LD_LIBRARY_PATH karena path . sudah tertanam di section .dynamic executable. Perintah ldd memperlihatkan ini:
ldd app_rpathOutput yang Dihasilkan:
linux-vdso.so.1 (0x00007fff54378000)
libmylib.so => ./libmylib.so (0x00007f1ffce11000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1ffcc0e000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1ffce1d000)Memeriksa Simbol Ekspor Shared Library #
Perintah nm -D menampilkan dynamic symbol table shared library — daftar simbol yang diekspor untuk dipakai executable lain:
nm -D libmylib.so | grep -E "tambah|kurang"Output yang Dihasilkan:
000000000000110d T kurang
00000000000010f9 T tambahFlag -D penting karena shared library punya dua symbol table: satu internal (static, seperti object file biasa) dan satu dynamic (yang dilihat runtime linker). Tanpa -D, nm menampilkan symbol table internal yang berisi lebih banyak simbol lokal — tidak semua diekspor.
Perbandingan dengan Static Library #
| Aspek | Static Library (.a) | Shared Library (.so) |
|---|---|---|
| Format | Archive berisi object file | ELF shared object |
| Ukuran executable | Besar (kode library tertanam) | Kecil (hanya referensi) |
| Dependency runtime | Tidak ada | Membutuhkan file .so saat dijalankan |
| Update library | Perlu re-link executable | Cukup ganti file .so |
| Memory usage | Setiap proses punya copy kode | Satu copy di memori untuk semua proses |
| Compile flag | -c lalu ar rcs | -fPIC -c lalu -shared |
| Link flag | -L. -l<name> | -L. -l<name> -Wl,-rpath=... |
| Distribusi | Self-contained | Perlu disertakan file .so |