Reusability with Archive and Shared Library pada 2-diving-into-system | belajar system-programming | Peskom Guide
Home

Reusability with Archive and Shared Library

Last Updated : 09 December 2024 / 16 min read

Reusability mungkin adalah salah satu kata paling favorit bagi para developer. Pokoknya kalo mereka menemukan 1 fungsi yang mereka harus copy dan paste di 1 atau lebih tempat, itu artinya kode tersebut tidaklah reusable dan wajib di refactor .

Proses refactoring kode yang paling umum adalah dengan mengumpulkan kode atau fungsi-fungsi tersebut ke 1 tempat yang sama dan yang dapat diakses oleh bagian manapun dari program kita yang membutuhkannya. Bahkan tidak jarang kalau sekumpulan kode atau fungsi tersebut berada diluar program kita atau berada di tempat lain yang berbeda dengan program kita.

Kita bisa melihat pengaplikasian library secara langsung pada contoh kode hello world dibawah:

hello-world.c
 #include <stdio.h>
 
int main() {
  printf("Hello, World!\n");
  return 0;
}  

Fungsi printf merupakan salah satu fungsi dari standard library yang dimiliki oleh bahasa C. Dan tentu saja C standard library ini meliputi dari banyak sekali fungsi-fungsi yang bisa kita sebagai developer gunakan untuk membantu kita dalam membuat program.

Umumnya jika kita punya semacam C Compiler terinstal dalam mesin kita, maka jangan khawatir karena biasanya standard library juga telah terinstal juga di mesin kita.

Ketika kita melakukan proses linking untuk membuat file exectable dari program kita, linker akan selalu mencari fungsi-fungsi dari C standard library yang kita gunakan dalam program kita, dan secara otomatis akan langsung menghubungkan juga fungsi-fungsi tersebut ke dalam program kita. it just works .

Namun proses penghubungan library dengan program kita yang secara otomatis terjadi itu hanya berlaku untuk standard library saja. Untuk library diluar standard library , maka kita wajib menghubungkannya sendiri saat proses linking . Jika kita tidak melakukannya, biasanya proses linking akan gagal dengan error seperti undefined symbols , dll.

Fokus kita disini adalah membahas bagaimana cara kita dapat membuat dan menghubungkan library sendiri ke dalam program kita. Dan tergantung dari jenis library apa yang ingin kita buat, maka cara menghubungkannya juga berbeda satu sama lainnya.

Archive and Shared Library

Tergantung dari kebutuhan kita, kita dapat membuat library dalam 2 bentuk, yaitu archive library dan shared library . archive library bisa juga disebut dengan static library dan shared library bisa juga disebut dengan dynamic library . Dan karena ada 2 jenis library, maka kita juga memiliki 2 cara untuk menghubungkan library ke dalam program kita.

Perbedaan utama dari archive library dan shared library adalah, archive library akan dikompilasi langsung ke dalam program kita dengan cara static linking dimana fungsi-fungsi dalam archive library akan di-copy langsung ke dalam program kita saat proses compilation dilakukan. Tentu saja hal ini menyebabkan ukuran dari program kita menadi besar, namun keuntungannya adalah, program kita dapat berdiri sendiri.

Sedangkan fungsi-fungsi dalam shared library tidak akan di-copy langsung ke dalam program kita. Fungsi-fungsi tersebut hanya akan dihubungkan saat proses linking dilakukan. Keuntungannya adalah, ukuran dari program kita akan lebih kecil, namun kekurangannya adalah, program kita tidak dapat berdiri sendiri karena program kita menjadi bergantung pada fungsi-fungsi yang berada diluar sistem kita.

Pada mayoritas sistem, archive library biasanya memiliki ekstensi .a (archive) pada linux atau .lib pada windows dan shared library biasanya memiliki ekstensi .so (shared object) pada linux dan .dll (dynamic link library) pada windows.

Buat pengguna windows dibawah windows 10, pasti sudah tidak asing dengan error dll hell . Error ini seringkali terjadi karena program yang kita jalankan membutuhkan file dll yang komputer kita tidak miliki atau terjadi error pada file dll yang program kita gunakan.

Biasanya anak zaman dulu udah biasa harus download file dll satuan di internet dan taruh file tersebut di suatu lokasi dalam komputer kita (umumnya system32 ). Dan kalo masih gagal juga, mungkin versi dll nya yang kurang cocok. Inilah masalah-masalah yang bisa kita temui dari dynamic linking .

Linking our program to archive and shared library

Seperti yang sudah pernah kita bahas sebelumnya , dalam proses membuat file executable dari program kita, linker akan mencoba menggabungkan satu atau beberapa object file yang akan menghasilkan file executable .

Artinya, linker akan menjelajahi directory dan file system dalam komputer kita untuk mencari file-file yang dibutuhkan yang dalam kasus ini merupakan library yang program kita gunakan dan fungsi-fungsi dalam library tersebut.

Ada beberapa cara yang bisa kita lakukan untuk membuat agar linker dapat mencari archive atau shared library yang ingin kita gunakan dalam program kita. Berikut 3 cara yang paling umum:

  1. Menyimpan directory yang akan ditelusuri oleh linker menggunakan environment variable .
  2. Menggabungkan option -L/<directory> dan -l<library> pada saat menjalankan command linker .
  3. Menaruh lokasi library kita ( fullpath ) bersamaan dengan command linker saat melakukan proses linking .

Ketiga cara ini akan kita lihat praktiknya nanti. Tapi umumnya, kita mau melakukan compilation terhadap program kita yang dimana program kita akan tetap berjalan meskipun library yang kita hubungkan telah berubah lokasi dari lokasi awal saat kita melakukan proses linking .

inilah sebabnya penggunaan fullpath untuk menghubungkan shared library dan program kita saat proses linking sangatlah problematik. Karena ketika lokasi library kita berubah maka kita tidak dapat mengganti lokasi shared library tersebut sehingga program kita akan menghasilkan error.

Beda cerita ketika kita ngomongin library yang di-provide sama sistem operasi yang kita gunakan. Karena umumnya, mereka akan selalu berada di 1 lokasi yang sama. Contohnya, kumpulan file dengan ekstensi dll di folder system32 pada sistem operasi windows.

How to create archive and shared library

Perlu diingat, bahwa proses menghubungkan archive library dengan program kita disebut dengan static linking dan proses menghubungkan shared library dengan program kita disebut dengan dynamic linking . Kita perlu sepakat dengan penamaan disini agar tidak bingung nanti.

Nah, sebelum melakukan proses linking , kita terlebih dahulu perlu tahu cara membuat archive library dan shared library . Jadi sebelum melakukan proses linking , pertama-tama kita perlu untuk melakukan proses compilation terlebih dahulu.

Sebagai contoh saya ingin membuat library untuk membantu saya melakukan proses matematika dasar seperti tambah, kurang, kali, dan bagi:

simpleMath.c
 #include <stdio.h>
 
#if WINDOWS
__declspec(dllexport) void __cdecl add(int *total, int adder )
#else
void add(int *total, int adder )
#endif
{
    printf("function add was called\n");
    *total += adder;
}
 
#if WINDOWS
__declspec(dllexport) void __cdecl substract(int *total, int sub)
#else
void substract(int *total, int sub)
#endif
{
    printf("function substract was called\n");
    *total -= sub;
}
 
#if WINDOWS
__declspec(dllexport) void __cdecl multiply(int *total, int mul)
#else
void multiply(int *total, int mul)
#endif
{
    printf("function multiply was called\n");
    *total *= mul;
}
 
#if WINDOWS
__declspec(dllexport) void __cdecl divide(int *total, int div)
#else
void divide(int *total, int div)
#endif
{
    printf("function divide was called\n");
    *total /= div;
}  

Karena fungsi-fungsi yang kita buat pada file simpleMath.c ini bersifat umum, maka kita bisa membuat fungsi-fungsi tersebut sebagai sebuah library yang bisa kita gunakan dalam 1 atau lebih program kita nantinya.

Creating archive library

Mari kita mulai dengan membuat archive library dari source file simpleMath.c kita.

Pertama-tama kita perlu melakukan proses compilation terhadap source file simpleMath.c kita. Proses compilation tersebut tidaklah berbeda dengan proses compilation yang sudah kita lakukan sebelumnya ketika kita ingin membuat file executable dari program main kita.

compilation on linux machine
 cc -c simpleMath.c # atau gcc -c simpleMath.c  

Atau pada platform windows:

compilation on windows
 cl -c -DWINDOWS simpleMath.c  

Seperti yang sudah pernah kita bahas sebelumnya , proses compilation tersebut akan menghasilkan file object file dari source file kita dengan ekstensi .o pada linux atau .obj pada windows yang dalam kasus ini berupa file simpleMath.o atau simpleMath.obj .

Dari object file ini, kita dapat membuat archive library . Pada platform linux atau sistem-sistem unix, umumnya kita akan menggunakan command ar untuk membuat archive library . Pada platform windows, umumnya akan menggunakan command lib untuk membuat archive library .

Pada platform linux pada umumnya, apple darwin, dan HP-UX kita bisa gunakan command:

create archive library on linux machine, apple darwin, and HP-UX
 ar rv libsm.a simpleMath.o  

Pada platform solaris:

create archive library on solaris machine
 ar rv -S libsm.a simpleMath.o  

Pada platform AIX:

create archive library on aix machine
 ar -rv libsm.a simpleMath.o  

Pada platform Windows (beda sendiri):

create archive library on windows machine
 lib simpleMath.obj -out:libsm.lib  

Seperti yang bisa kita lihat. Pada kebanyakan platform, archive library akan menghasilkan file dengan ekstensi .a , sedangkan pada platform windows akan menghasilkan file dengan ekstensi .lib .

Creating shared library

Proses pembuatan shared library juga agak sedikit mirip-mirip dengan proses pembuatan archive library . Hanya saja pada proses compilation kita wajib menggunakan flag -fPIC pada platform linux dan +Z pada HP-UX. Jika compilation berhasil, seperti biasa kita akan mendapatkan file dengan ekstensi .o (linux) atau .obj (windows).

Setelah compilation menjadi object file berhasil, biar gak perlu lama-lama, kita juga bakalan langsung akan melakukan proses linking dengan command ld atau gcc pada linux dan link pada windows.

Berikut contoh proses compilation pada platform linux:

Compiling shared library on linux machine
 # bikin object file dulu
cc -c -fPIC simpleMath.c
# atau
gcc -c -fPIC simpleMath.c
 
# selanjutnya bisa pake comamnd ini
ld -shared -o libsm.so simpleMath.o
# atau
gcc -shared -WL,-soname,libsm.so -o libsm.so simpleMath.o -lc  

Pada solaris:

Compiling shared library on solaris machine
 gcc -c -fPIC -m64 simpleMath.c -o simpleMath.o
gcc -G -m64 -o libsm.so simpleMath.o -lc  

Pada platform HP-UX:

Compiling shared library on hp-ux machine
 cc -c +Z simpleMath.c
ld -b -o libsm.so simpleMath.o -lc  

Pada apple darwin:

Compiling shared library on apple darwin machine
 cc -c -fPIC simpleMath.c -o simpleMath.o
ld -dylib -o libsm.so simpleMath.o -lc  

Pada platform windows (sama aja kayak compile buat archive library ):

Compiling shared library on windows machine
 cl -c -DWINDOWS simpleMath.c
link -dll -out:libsm.dll -nologo -map:libsm.map simpleMath.obj  

Hasil dari proses compilation dan linking diatas akan menghasilkan file dengan ekstensi .so (share object) pada linux, .dll (dynamic link library) pada windows, dan .sl pada HP-UX.

Linking and using archive and shared library to our program

Sebelum kita mulai menghubungkan archive library dan shared library ke dalam program kita, mari kita buat program utama kita yang akan menggunakan fungsi-fungsi dari archive library dan shared library tersebut.

main.c
 #include <stdio.h>
 
void add(int *total, int adder);
void substract(int *total, int sub);
void multiply(int *total, int mul);
void divide(int *total, int div);
 
int main() {
  int total = 0;
 
  add(&total, 10);
  substract(&total, 5);
  multiply(&total, 2);
  divide(&total, 2);
 
  printf("Total: %d\n", total);
 
  return 0;
}  

Lalu kita compile program kita tersebut menjadi object file dengan command:

compilation on linux machine
 cc -c main.c -o main.o
# atau
gcc -c main.c -o main.o  

Ketika proses compilation berhasil dan menghasilkan object file , maka kita bisa lanjut ke proses linking .

Linking to archive library (static library)

pertama-tama mari kita mulai dari archive library .

Ada 2 jenis archive library , yaitu yang kita buat sendiri dan yang disediakan oleh sistem operasi kita. Disini kita ingin fokus kepada archive library yang telah kita buat sendiri sebelumnya. Namun cara yang sama juga berlaku pada archive library yang disediakan oleh sistem kita.

Cara menghubungkan archive library ke program kita sebenarnya cukup simpel. Intinya adalah dengan menggunakan flag -l<library> sebagai flag option pada command linker kita.

Sebagai contoh, jika static library kita bernama libsm.a , maka kita akan menambahkan flag -lsm pada command linker kita. Inilah kenapa convention library kita selalu diawali dengan kata lib .

1 Hal lain yang perlu kita perhatikan juga adalah, kita perlu menggunakan flag -static (linux) atau -Bstatic (beberapa platform lain) juga pada command linker kita.

Dan yang terakhir adalah, kita perlu menaruh lokasi dari archive library kita menggunakan flag -L<path of library> pada command linker kita setelah command -l<lib> .

Berikut merupakan contoh command linker untuk menghubungkan archive library kita ke program kita pada platform linux:

linking to archive library on linux machine
 cc -static -o main main.o -L. -lsm
# atau
gcc -static -o main main.o -L. -lsm  

Pada solaris:

linking to archive library on solaris machine
 gcc -m64 -Bstatic -o main main.o ./libsm.a  

Pada AIX:

linking to archive library on aix machine
 xlc -o main main.o -L. -lsm
#atau
xlc -o main main.o -bstatic -L. -lsm -bdynamic  

pada HP-UX dan apple darwin:

linking to archive library on hp-ux dan apple darwin machine
 cc -o main main.o ./libsm.a  

Pada platform windows:

linking to archive library on windows machine
 # Kalau file libsm.obj tidak 1 directory
set LIB=C:\myproj\lib\libtstl;%LIB% #CMD
#atau
$env:LIB="C:\myproj\lib\libtstl;$env:LIB" #powershell
 
link -lib:libsm.lib main.obj  

Dan jika kita jalankan file main executable kita, maka kita akan mendapatkan output sebagai berikut:

output
 function add was called
function substract was called
function multiply was called
function divide was called
Total: 5  

Lalu coba saja pindahkan file main executable kita ke directory lain dan kita lihat program kita tetap akan berjalan. Ini sesuai dengan kelebihan static linking yang hanya perlu compile 1x dan jalan dimanapun karena fungsi-fungsi library kita di-copy ke dalam program kita langsung.

Linking to shared library (dynamic library)

Sekarang kita masuk ke proses linking shared library ke program kita.

Proses penghubungan shared library ke program kita mirip-mirip dengan proses penghubungan archive library ke program kita. Hanya saja kita tidak perlu menambahkan flag -dynamic pada command linker kita dan menggunakan flag -L<library path> setelahnya.

1 hal yang perlu diperhatikan adalah, kita wajib mendaftarkan lokasi dari shared library yang kita hubungkan ke program kita ke dalam environment variable sebagai search path yang akan program kita gunakan di runtime.

Alasannya kenapa ? karena meskipun proses linking berhasil, program kita tetap harus mencari shared library kita saat program sedang berjalan. Berbeda dengan archive library dimana semua fungsi-fungsi pada library akan di-copy ke dalam program sehingga program tidak perlu lagi mencari fungsi-fungsi diluar program. Dengan shared library program akan selalu mencari library kita bahkan setelah proses linking berhasil dan program sedang dieksekusi.

Lalu bagaimana cara kita memberitahu program kita untuk mencari lokasi library yang dia butuhkan? yaitu dengan menggunakan environment variable , yang dimana dalam kebanyakan sistem unix bernama LD_LIBRARY_PATH .

Lokasi-lokasi yang disimpan di dalam environment LD_LIBRARY_PATH inilah yang nantinya akan ditelusuri oleh program kita saat menggunakan fungsi-fungsi dari library tersebut di runtime. Dalam kasus ketika kita menggunakan library yang bukan kita sendiri yang buat, sudah menjadi kewajiban kita juga sebagai developer untuk mendaftarkan lokasi dari shared library yang suatu program gunakan.

Dan ketika kita memindahkan lokasi dari shared library yang program kita gunakan, kita tinggal mengubah environment LD_LIBRARY_PATH kita. Inilah alasan kenapa kita harus menghindari menggunakan fullpath ketika menghubungkan shared library ke program kita. Karena nanti ketika posisi librarynya berubah, kita gak bisa mengubahnya via environment variable dan program kita akan mengeluarkan error.

Berikut merupakan contoh command linker untuk menghubungkan shared library kita ke program kita pada platform linux:

linking to shared library on linux machine
 cc -dynamic -o main main.o -L. -lsm
# atau
gcc -dynamic -o main main.o -L. -lsm  

Pada platform solaris:

linking to shared library on solaris machine
 gcc -m64 -Bdynamic -o main main.o -Wl,-Bdynamic -lsm  

pada platform AIX:

linking to shared library on aix machine
 xlc -o main main.o -bnoipath ./libsm.so # Jangan gunain flag -L atau -lsm disini  

pada platform HP-UX:

linking to shared library on hp-ux machine
 cc -dynamic -o main main.o -L. -lsm  

Pada platform apple darwin:

linking to shared library on apple darwin machine
 cc -o main main.o ./libsm.so  

Pada platform windows:

linking to shared library on windows machine
 link main.obj /LIBPATH:C:\path\to\lib libsm.lib  

Apakah konten ini membantu ? Jika ya, kami akan sangat menghargai jika Anda bisa memberikan bintang pada GitHub Repository kami dan ikuti sosial media dari komunitas Peskom di Facebook . Dukungan Anda membantu kami untuk terus berkembang! 🌟

Dan juga jika Anda menemukan kesalahan, typo, kekurangan, atau kesalahan pada artikel ini, kami sangat terbuka untuk masukan. Silakan laporkan temuan Anda melalui halaman Github Issues ini . Mari bersama-sama meningkatkan kualitas konten untuk komunitas Peskom! 🚀

Semoga semangat open source turut senantiasa menyertaimu.