Library archive pada dasarnya adalah file-file object (file .o
) yang di cpio
-kan dalam satu file.
Jika kita me-link program kita dengan library archive, maka objek-objek yang kita butuhkan yang ada di library archive ini akan di-copy kan ke executable kita. Keuntungan dari link dengan cara ini adalah kita tidak memerlukan lagi library tersebut untuk menjalankan executable kita, sehingga terjamin bahwa program akan berjalan di semua tempat. Sedangkan kerugiannya adalah executable kita menjadi lebih besar, karena copy tadi.
Catatan :
Untuk melihat objek-objek yang ada di suatu program atau library archive, gunakan perintah nm
:
$ cd /usr/lib
$ nm libc.a
sysdep.o:
U __errno_location
00000000 T __syscall_error
00000002 T __syscall_error_1
00000000 B _errno
00000000 B errno
set-init.o:
00000000 T __libc_init
U __start___libc_subinit
U __stop___libc_subinit
...
(output terlalu panjang, jadi tidak ditampilkan seluruhnya di dokumen ini) Angka numeric pada output nm
menunjukkan alamat fungsi/variabel pada objek (?). Huruf T, U, dan B merupakan nama segmen dalam objek ('T' menunjukkan segmen TEXT, 'U' adalah ?, 'B' adalah ?).
Sama dengan library archive, library shared juga berisi objek-objek, dimana masing-masing objek berisi fungsi-fungsi dan variabel-variabel. Bedanya adalah, setiap objek di library mengandung relocation information yang memungkinkan objek itu diload secara dinamis oleh run-time dynamic linker (ld.so
).
Jika kita me-link program kita dengan shared library, maka tidak ada objek yang di-copy dari library. Sebagai gantinya, linker (yaitu ld
) akan mencatat nama library dan objek-objek yang dibutuhkan dalam executable kita. Kemudian pada saat run-time, dynamic linker (ld.so
) akan mencari kembali objek-objek yang diimport itu di library-library dinamis yang ada.
Keuntungannya:
Sedangkan kerugiannya adalah, ketika program berjalan, library-library yang dibutuhkan oleh program harus terinstall di komputer tersebut.
Catatan :
Untuk melihat suatu program tergantung pada library shared apa saja, kita gunakan perintah ldd
:
$ ldd /usr/bin/gcc
libc.so.6 => /lib/libc.so.6 (0x40003000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000)
Output ldd
di atas menunjukkan bahwa program gcc
di-link secara dinamis dengan dua library, yaitu libc.so.6
(library C) dan ld-linux.so.2
(library untuk dynamic loader). Selanjutnya, nama file di belakang tanda panah (==>
menunjukkan library yang match, dan angka hexadesimal menunjukkanoffset(?).
Proses me-link aplikasi dengan library archive sering disebut sebagai static linking, karena adanya proses pengkopian objek di atas.
Misalnya kita ingin me-link program kita dengan libhello.a
yang ada di current directory kita gunakan perintah ini:
$ gcc -o hello hello.c libhello.a
berdasarkan ekstensi .a
pada libhello.a
, gcc
otomatis tahu bahwa libhello.a
adalah static library untuk di-link (tidak perlu di-compile).
Alternatif lain, kita pakai -lhello
setelah nama-nama file objek :
$ gcc -o hello hello.c -L. -lhello
option -L.
menunjukkan memerintahkan linker untuk menambahkan current curectory ('.'
) dalam search path-nya (defaultnya linker hanya mencari di trusted direktory yaitu /lib
dan /usr/lib
), sedangkan option -lhello
memerintahkan linker untuk me-link dengan libhello.a
(perhatikan bahwa kita tidak perlu menyebutkan awalan lib
dan ekstension .a
untuk nama library kita).
Jadi beda perintah pertama dengan kedua adalah pada perintah kedua gcc
akan menambahkan nama library pada option -l
dengan awalan lib
dan akhiran .a
serta akan mencari library itu di beberapa search path yang default.
Alternatif lain untuk me-link adalah menggunakan linker ld
. Namun perintahnya sedikit agak rumit karena selain kita harus tahu library-libary apa yang harus diikutkan dan kita harus menentukan juga startup file-nya:
$ ld -o hello /lib/crt0.o hello.o -lc
(Note: command belum di test)
jadi bedanya me-link dengan gcc
dan ld
adalah gcc
akan melakukan pekerjaan tersebut untuk kita.
Jika pada suatu direktori terdapat library yang sama tapi jenisnya berbeda (misalnya, di direktori /lib
terdapat libc.a
dan libc.so.6
), secara default, linker akan me-link program kita dengan shared library.
Untuk memaksa agar linker menggunakan yang static/archive library, gunakan option -static
pada pemanggilan gcc
:
$ gcc -o hello hello.o main.o -static -lc
$ # untuk membuktikan bahwa hello benar-benar static:
$ ldd hello
not a dynamic executable
Penempatan option -l
pada pemanggilan gcc
sangat penting untuk diperhatikan.
Kalau option -lc
(link dengan libc.a
) kita tempatkan setelah main.o
dan hello.o
:
$ gcc -o hello hello.o main.o -static -nodefaultlibs -lc
maka linking akan sukses (catatan: option -nodefaultlibs
kita sebutkan agar linker tidak me-link dengan libc
, karena kita ingin me-link-nya secara manual dengan option -lc
).
Sedangkan kalau option -lc
kita tempatkan sebelum hello.o
dan main.o
:
$ gcc -o hello -static -nodefaultlibs -lc hello.o main.o
hello.o: In function `print_hello':
hello.o(.text+0x9): undefined reference to `puts'
main.o: In function `main':
main.o(.text+0x9): undefined reference to `printf'
$
maka linking akan gagal.
Kok bisa?
Ini berkaitan dengan cara kerja linker untuk library archive. Ketika linker memproses file objek, dia akan mencatat nama-nama variabel/fungsi yang direferensi (diimport) oleh file objek itu. Kemudian ketika sampai pada library archive, linker akan men-scan/melihat apakah ada objek yang berisi fungsi/variabel yang diimport. Jika ada, maka objek itu akan dicopykan ke executable.
Jika library archive kita tempatkan di depan, maka library archive ini akan diproses/di-scan terlebih dahulu. Dalam proses itu, linker memutuskan bahwa tidak ada objek yang diimport dari libary ini (karena linker belum memproses file-file objek kita), sehingga tidak ada objek yang dicopykan ke executable.
Default kelakuan linker adalah men-scan library archive sekali saja (seperti ilustrasi di atas). Jika kita ingin agar linker men-scan library archive beberapa kali untuk mencari objek-objek yang diimport, gunakan option -(
pada ld
(bagaimana kalau dari gcc? -Wl,-(
(?)). Dengan demikian (diharapkan) posisi penempatan option -l
menjadi bebas.
Perintah untuk me-link dengan library shared sama saja. Perintah ini:
$ gcc -o testcurses testcurses.o -lncurses
akan me-link file testcurses.o
dengan library libncurses.so
yang ada di direktori default (trusted directory: /lib
atau /usr/lib
). Jika si library berada di direktori selain direktori default, maka seperti biasa kita tambahkan option -L
pada gcc
.
Contoh: misalkan kita hendak me-link program test_xpm.c
dengan /usr/X11R6/lib/libXpm.so
:
$ gcc -o test_xpm test_xpm.c -L/usr/X11R6/lib -lXpm
Perhatikan bahwa linker akan mencari file dengan akhiran .so
(saja), bukan yang berakhiran .so.x
atau .so.x.y
(dimana x dan y adalah nomor versi). Untuk memahami hal ini, mari kita membahas versi library dan symbolic link pada library shared.
Biasanya library shared mempunyai nomor versi:
$ cd /usr/lib
$ ls -l libqt.so*
lrwxrwxrwx 1 root root 10 Nov 7 14:04 libqt.so -> libqt.so.1
lrwxrwxrwx 1 root root 13 Nov 7 14:04 libqt.so.1 -> libqt.so.1.31
-rwxr-xr-x 1 root root 1236509 Oct 17 1997 libqt.so.1.31
terlihat di atas, bahwa libqt
yang 'sesungguhnya' adalah file libqt.so.1.31
, sedangkan file-file libqt
yang lain adalah symbolic link. Nomor-nomor setelah ekstensi .so
menunjukkan nomor versi: major version number, diikuti dengan minor version number (pada libqt.so.1.31
atas, major version numbernya adalah 1 dan minor version number adalah 31). Kadang-kadang library juga mempunyai nomor ketiga, yang menunjukkan versi yang lebih detil lagi (lebih minor(?)).
Konvensi dari para developer adalah, jika major version number-nya berubah, berarti ada perubahan yang mendasar di library itu yang mungkin akan sama sekali tidak kompatibel dengan versi sebelumnya. Contohnya libc: dari libc.so.5
ke libc.so.6
, Motif: dari libXm.so.1
ke libXm.so.2
, dst.
Nomor versi ini disebutkan ketika kita membuat library shared itu, yaitu dengan option -soname
. Contohnya:
$ gcc -o libhello.so.1.0.0 -shared hello.c \
-Wl,-soname=/usr/local/lib/libhello.so.1
Detail dari option pembuatan library di atas untuk sementara kita abaikan dulu (akan dibahas di bab
selanjutnya. Untuk sementara cukup kita tahu bahwa library shared mempunyai atribut soname
.
Biasanya, library-library itu di-symbolic link secara bertahap, dari .so
ke .so.x
, dari .so.x
ke .so.x.y
, dari .so.x.y
ke .so.x.y.z
, dst. Misalnya dari .so
ke .so.1
, dari .so.1
ke .so.1.0
, dan dari .so.1.0
ke file yang sebenarnya .so.1.0.0
.
Yang bertugas membuat symbolic link ini adalah ldconfig
. Program ini membuat symbolic link berdasarkan atribut soname
yang dipunyai oleh suatu library.
Misalnya kita punya library libhello.so.1.0.0
yang soname
-nya adalah /usr/local/lib/libhello.1
. Library ini kita taruh di direktori /usr/local/lib
:
$ cd /usr/local/lib
$ ls
libhello.so.1.0.0
$
Ketika kita menjalankan ldconfig
, maka program ini akan mengupdate symbolic link yang sesuai untuk shared library kita:
# /sbin/ldconfig -lv libhello.s.1.0.0
/sbin/ldconfig: version 970402
libhello.so.1 => libhello.so.1.0.0 (changed)
# ls -l
lrwxrwxrwx 1 root root 17 Nov 13 15:56 libhello.so.1 -> libhello.so.1.0.0
-rwxrwxr-x 1 root root 3727 Nov 13 15:50 libhello.so.1.0.0
seperti terlihat di atas, perintah ldconfig
akan membuat symbolic link baru libhello.so.1
(atau mengupdate jika file ini sudah ada). Dan jika kita perhatikan, maka symbolic link yang dibuat/diupdate adalah sama dengan nama soname
dari library itu.
Maksud dari topmost .so
adalah symbolic link dengan akhiran .so
saja, nggak ada akhiran nomor versinya. Symbolic link ini ada masalah khusus.
Masalahnya adalah, ada konvensi diantara developer bahwa mereka tidak membuat soname
yang nggak ada nomor versinya. Jadi paling tidak akan disebutkan major version number-nya dalam soname
. (kenapa?)
Akibatnya adalah symbolic link untuk topmost .so
tidak akan dibuat/diupdate oleh ldconfig
. Padahal topmost .so
inilah yang dipakai oleh gcc
.
Untungnya, tanggung jawab untuk membuat topmost symbolic link ini biasanya diambil alih oleh distribusi Linux (?), sehingga kita tidak perlu repot-repot mengupdate-nya.
Tapi jika kita membuat shared library sendiri, maka kita tetap berkewajiban membuat topmost .so
ini:
$ ln -s libhello.so.1 libhello.so
Pada saat linking (bukan pada saat run-time), secara default ld
akan mencari library-library di trusted direktory (/lib
dan /usr/lib
). Jika library letaknya bukan di kedua direktori default tersebut, maka kita harus menambahkan option -L
pada pemanggilan gcc
.
Contoh: misalnya kita ingin me-link file hello.o
kita dengan libMesaGL.a
yang ada di direktori /usr/X11R6/lib
, maka kita gunakan perintah ini:
$ gcc -o hello hello.o -L/usr/X11R6/lib -lMesaGL
(next question: apakah environment variable bisa berpengaruh? GCC_EXEC_PREFIX, LIBRARY_PATH, etc?)
Environment variabel LD_LIBRARY_PATH
berguna untuk menambahkan search path dalam mencari library-library yang dibutuhkan oleh executable pada saat run-time, bukan pada saat development/linking. Pada saat linking, gunakan option -L
pada gcc
.