Sebagian besar kode C produksi tidak menulis sendiri semua fungsi—program memakai ratusan library eksternal seperti libm (matematika), libz (kompresi), libcrypto (kriptografi), libcurl (HTTP), atau libsqlite3 (database). Mengkonsumsi library eksternal melibatkan tiga langkah: (1) menyertakan header dengan #include, (2) menyuruh compiler menemukan header lewat -I, dan (3) menyuruh linker menemukan library lewat -L dan -l. Pada distribusi modern, lokasi header dan flag link dikelola oleh pkg-config sehingga pengguna tidak perlu menghafal path. Pada chapter ini kita akan memakai libm, libz, dan mendemonstrasikan integrasi pkg-config dengan libcrypto.

Library Standar: libm #

Library libm berisi fungsi matematika standar: sqrt, pow, sin, cos, log, exp. Berbeda dari fungsi standar C seperti printf (yang sudah otomatis di-link), fungsi libm berada di library terpisah dan harus di-link eksplisit dengan flag -lm. Pada beberapa toolchain (misalnya MSVC), libm sudah digabung ke main C runtime, tetapi di Linux/gcc tetap perlu flag.

c
/* File: ekst_libm.c - demo libm: sqrt, pow, sin, log */
#define _DEFAULT_SOURCE
#include <stdio.h>
#include <math.h>

int main(void) {
    double x = 2.0;
    printf("sqrt(%.1f) = %.6f\n", x, sqrt(x));
    printf("pow(%.1f, 10) = %.6f\n", x, pow(x, 10.0));
    printf("sin(pi/4) = %.6f\n", sin(M_PI / 4.0));
    printf("log(e)   = %.6f\n", log(M_E));
    return 0;
}

Compile dan jalankan:

bash
gcc -std=c11 -Wall -Wextra -o ekst_libm ekst_libm.c -lm
./ekst_libm

Output yang Dihasilkan:

text
sqrt(2.0) = 1.414214
pow(2.0, 10) = 1024.000000
sin(pi/4) = 0.707107
log(e)   = 1.000000

Mari kita telaah baris-baris kode di atas:

  1. Baris 2 (#define _DEFAULT_SOURCE): Menyalakan feature test macro glibc untuk membuka simbol non-standar seperti M_PI dan M_E. Tanpa macro ini, gcc -std=c11 (yang menyalakan mode strict ISO) tidak melihat konstanta tersebut dan compiler error 'M_PI' undeclared. Ini adalah jebakan umum saat pertama kali memakai math.h di mode strict.
  2. Baris 4 (#include <math.h>): Header berisi deklarasi fungsi sqrt, pow, dll. Tanda <...> menyuruh compiler mencari di path standar (/usr/include).
  3. Flag -lm: Menyuruh linker link dengan libm.so. Urutan penting: library harus muncul setelah object file yang memakainya. gcc -lm foo.c salah; gcc foo.c -lm benar. Linker GNU bersifat left-to-right dan hanya menarik symbol yang sudah dirujuk saat ia melihat library.
  4. M_PI, M_E: Konstanta double dari math.h (glibc extension). M_PI = 3.14159..., M_E = 2.71828.... Bila Anda menulis kode portable, gunakan acos(-1.0) untuk mendapatkan π dan exp(1.0) untuk e.

Library Eksternal: libz #

libz (zlib) adalah library kompresi deflate yang dipakai oleh gzip, PNG, HTTP gzip encoding. Library adalah contoh baik API eksternal: header <zlib.h> menyatakan tipe Bytef, uLong, dan fungsi compress, uncompress, compressBound.

c
/* File: ekst_libz.c - kompresi zlib */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zlib.h>

int main(void) {
    printf("Versi zlib: %s\n", zlibVersion());

    const char *pesan = "Halo Dunia! Halo Dunia! Halo Dunia! Halo Dunia!";
    uLong panjang_sumber = (uLong) strlen(pesan);
    uLong panjang_buffer = compressBound(panjang_sumber);
    unsigned char *buf = (unsigned char *) malloc(panjang_buffer);
    if (!buf) { perror("malloc"); return 1; }

    int rc = compress(buf, &panjang_buffer,
                      (const Bytef *) pesan, panjang_sumber);
    if (rc != Z_OK) {
        fprintf(stderr, "compress gagal: %d\n", rc);
        free(buf);
        return 1;
    }
    printf("Asli:        %lu byte\n", panjang_sumber);
    printf("Terkompresi: %lu byte\n", panjang_buffer);

    /* Dekompresi untuk verifikasi */
    unsigned char hasil[256];
    uLong panjang_hasil = sizeof(hasil);
    int rc2 = uncompress(hasil, &panjang_hasil, buf, panjang_buffer);
    if (rc2 != Z_OK) {
        fprintf(stderr, "uncompress gagal: %d\n", rc2);
        free(buf);
        return 1;
    }
    hasil[panjang_hasil] = '\0';
    printf("Hasil:       %s\n", (char *) hasil);

    free(buf);
    return 0;
}

Compile dan jalankan:

bash
gcc -std=c11 -Wall -Wextra -o ekst_libz ekst_libz.c -lz
./ekst_libz

Output yang Dihasilkan:

text
Versi zlib: 1.3.1
Asli:        47 byte
Terkompresi: 23 byte
Hasil:       Halo Dunia! Halo Dunia! Halo Dunia! Halo Dunia!

Mari kita telaah baris-baris kode di atas:

  1. Baris 5 (#include <zlib.h>): Header library eksternal. Header ini biasanya terinstal di /usr/include/zlib.h saat paket zlib1g-dev dipasang. Bila Anda mendapat error zlib.h: No such file or directory, install paket dev.
  2. Baris 7 (zlibVersion()): Mengembalikan string versi library. Berguna untuk diagnostik saat output bervariasi antar versi.
  3. Baris 11 (compressBound(panjang_sumber)): Mengembalikan ukuran buffer maksimum yang dibutuhkan kompresi. Kita tidak tahu berapa output kompresi sebelumnya, jadi alokasikan worst case.
  4. Baris 16 (compress(buf, &panjang_buffer, ...)): Parameter panjang_buffer adalah in-out: saat masuk berisi ukuran buffer, saat keluar berisi ukuran aktual hasil kompresi. Pola in-out parameter sangat umum di API C.
  5. Flag -lz: Link dengan libz.so. Seperti -lm, library harus muncul setelah object file di command line.

Integrasi pkg-config #

Untuk library besar seperti libcrypto, libcurl, atau glib, flag compile bisa rumit: ada beberapa path include, beberapa library, dan opsi tambahan. Tool pkg-config mengotomatiskan ini dengan membaca file .pc yang dipasang bersama library.

bash
pkg-config --cflags --libs zlib
pkg-config --cflags --libs libcrypto

Output yang Dihasilkan:

text
-lz 
-lcrypto 

pkg-config mengembalikan flag yang dapat langsung disisipkan ke gcc lewat command substitution backtick atau $(...):

bash
gcc -std=c11 -Wall -Wextra -o ekst_libz ekst_libz.c $(pkg-config --cflags --libs zlib)

Mari kita uraikan:

  1. pkg-config --cflags zlib: Mengembalikan flag compiler (biasanya -I/path/to/include). Untuk zlib yang sudah terinstal di path standar, output kosong—tidak ada flag tambahan.
  2. pkg-config --libs zlib: Mengembalikan flag linker (-lz). Kombinasi --cflags --libs memberi semua flag sekaligus.
  3. Substitusi $(...): Shell mengeksekusi perintah di dalam tanda kurung dan menyisipkan output sebagai argumen gcc. Sama dengan backtick `pkg-config --libs zlib`, tetapi lebih mudah dibaca bersarang.
  4. Untuk libcrypto: pkg-config --cflags --libs libcrypto mengembalikan -lcrypto saja—tidak ada flag include khusus. Untuk library yang lebih kompleks (misalnya glib-2.0), output dapat berisi -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -lglib-2.0.

Mendokumentasikan Dependensi #

Library yang Anda distribusikan harus menjelaskan dependensi eksternalnya. Konvensi yang dipakai komunitas C:

  1. File README.md menyebut library eksternal yang dibutuhkan (misalnya “membutuhkan zlib ≥ 1.2.11”).
  2. File Makefile atau build script memakai pkg-config untuk menemukan library secara otomatis.
  3. Untuk distribusi paket (Debian .deb, RPM .rpm), dependensi dinyatakan di kontrol paket (Depends:) sehingga manajer paket otomatis memasang prerequisite.