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.
/* 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:
gcc -std=c11 -Wall -Wextra -o ekst_libm ekst_libm.c -lm
./ekst_libmOutput yang Dihasilkan:
sqrt(2.0) = 1.414214
pow(2.0, 10) = 1024.000000
sin(pi/4) = 0.707107
log(e) = 1.000000Mari kita telaah baris-baris kode di atas:
- Baris 2 (
#define _DEFAULT_SOURCE): Menyalakan feature test macro glibc untuk membuka simbol non-standar sepertiM_PIdanM_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 memakaimath.hdi mode strict. - Baris 4 (
#include <math.h>): Header berisi deklarasi fungsisqrt,pow, dll. Tanda<...>menyuruh compiler mencari di path standar (/usr/include). - Flag
-lm: Menyuruh linker link denganlibm.so. Urutan penting: library harus muncul setelah object file yang memakainya.gcc -lm foo.csalah;gcc foo.c -lmbenar. Linker GNU bersifat left-to-right dan hanya menarik symbol yang sudah dirujuk saat ia melihat library. M_PI,M_E: Konstanta double darimath.h(glibc extension).M_PI = 3.14159...,M_E = 2.71828.... Bila Anda menulis kode portable, gunakanacos(-1.0)untuk mendapatkan π danexp(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.
/* 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:
gcc -std=c11 -Wall -Wextra -o ekst_libz ekst_libz.c -lz
./ekst_libzOutput yang Dihasilkan:
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:
- Baris 5 (
#include <zlib.h>): Header library eksternal. Header ini biasanya terinstal di/usr/include/zlib.hsaat paketzlib1g-devdipasang. Bila Anda mendapat errorzlib.h: No such file or directory, install paket dev. - Baris 7 (
zlibVersion()): Mengembalikan string versi library. Berguna untuk diagnostik saat output bervariasi antar versi. - Baris 11 (
compressBound(panjang_sumber)): Mengembalikan ukuran buffer maksimum yang dibutuhkan kompresi. Kita tidak tahu berapa output kompresi sebelumnya, jadi alokasikan worst case. - Baris 16 (
compress(buf, &panjang_buffer, ...)): Parameterpanjang_bufferadalah in-out: saat masuk berisi ukuran buffer, saat keluar berisi ukuran aktual hasil kompresi. Pola in-out parameter sangat umum di API C. - Flag
-lz: Link denganlibz.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.
pkg-config --cflags --libs zlib
pkg-config --cflags --libs libcryptoOutput yang Dihasilkan:
-lz
-lcrypto pkg-config mengembalikan flag yang dapat langsung disisipkan ke gcc lewat command substitution backtick atau $(...):
gcc -std=c11 -Wall -Wextra -o ekst_libz ekst_libz.c $(pkg-config --cflags --libs zlib)Mari kita uraikan:
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.pkg-config --libs zlib: Mengembalikan flag linker (-lz). Kombinasi--cflags --libsmemberi semua flag sekaligus.- Substitusi
$(...): Shell mengeksekusi perintah di dalam tanda kurung dan menyisipkan output sebagai argumengcc. Sama dengan backtick`pkg-config --libs zlib`, tetapi lebih mudah dibaca bersarang. - Untuk
libcrypto:pkg-config --cflags --libs libcryptomengembalikan-lcryptosaja—tidak ada flag include khusus. Untuk library yang lebih kompleks (misalnyaglib-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:
- File
README.mdmenyebut library eksternal yang dibutuhkan (misalnya “membutuhkan zlib ≥ 1.2.11”). - File
Makefileatau build script memakaipkg-configuntuk menemukan library secara otomatis. - Untuk distribusi paket (Debian
.deb, RPM.rpm), dependensi dinyatakan di kontrol paket (Depends:) sehingga manajer paket otomatis memasang prerequisite.