Odhalení procesu propojování – statické a dynamické knihovny
Vytvoření statické a dynamické knihovny
U statické knihovny se objektový kód z binárních souborů (přípona .o
) spojí do jednoho archivního souboru s příponou .a
. Tento archiv je podobný sadě nástrojů, která obsahuje všechny nástroje, jež mohou být použity v programech, které danou knihovnu volají při linkování. Nástroje jsou vloženy na místa, kde jsou potřeba. Na obrázku níže mám řadu souborů .c
.
Protože knihovna je archivem objektového kódu, musím všechny tyto soubory .c
převést na soubory .o
pomocí následujícího příkazu:
gcc -Wall -Wextra -Werror -pedantic -c *.c
Volba -c
zastaví proces kompilace těsně před linkováním po vygenerování souborů objektového kódu. Nyní mám všechny soubory objektového kódu:
Pokud spustím příkaz ar -rc libholbertonschool.a *.o
, mohu tyto soubory archivovat do jediného knihovního souboru .a
. Příkaz ar
slouží k archivaci, volba -r
k přesunu členů s příponou .o
a volba -c
k vytvoření archivu, pokud neexistuje. Soubor knihovny začíná předponou lib
a má příponu .a
. Posledním krokem, který je v některých systémech nutný, je indexování obsahu archivu pro urychlení linkování. To lze provést pomocí ranlib libholbertonschool.a
. Nyní mám knihovnu, která obsahuje objektový kód pro všechny funkce na obrázku výše.
Použití statické knihovny
Chci-li tuto knihovnu použít s nějakým testovacím souborem, musím testovací soubor s knihovnou zkompilovat pomocí jednoho z následujících dvou příkazů:
gcc test.c ./libholbertonschool.a -o exename
gcc test.c -L. -lholbertonschool -o exename
Oba příkazy dělají totéž, ale druhý je o něco záhadnější. Volba -L.
vyhledává knihovny v aktuálním adresáři a -l
, která je spojena s holbertonschool
, vyhledává soubor knihovny implicitně, přičemž se předpokládá prefix lib
a přípona .a
. Bez kompilace s knihovním souborem gcc
vyhodí chybu, protože funkce, které se snaží linkovat, nejsou k dispozici. Poskytnutím knihovny při kompilaci může nyní kompilátor vyhledat potřebné funkce v knihovně a vložit je tam, kde jsou potřeba.
Dynamické knihovny
Vytváření dynamických knihoven se mírně liší od statických knihoven, ale koncepty jsou obecně stejné. Mám stejný počet souborů .c
a hlavičkový soubor, který definuje jejich prototypy, v souboru nazvaném lists.h
.
Pro vytvoření dynamické knihovny, která má .so
(což znamená sdílený objekt), lze zadat následující kompilační příkaz:
gcc -fPIC -Wall -Werror -Wextra -pedantic *.c -shared -o libholberton.so
Příznak -fPIC
znamená Position Independent Code, který je vyžadován pro dynamické linkování. Jeho význam je přesně takový, jak zní – protože dynamicky linkované knihovny mohou být uloženy kdekoli v paměti, kam se vejdou, umožňuje tento příznak použít soubor knihovny bez ohledu na to, kde je uložen.
Příznak -shared
umožňuje vytvořit sdílený archiv a volba -o
nám umožňuje přejmenovat výstupní soubor na libholberton.so
.
Po spuštění tohoto příkazu mám nyní sdílenou knihovnu!
Použití dynamické knihovny
Řekněme, že mám následující kód:
#include "holberton.h"
#include <stdlib.h>
#include <stdio.h>/**
* main - check the code for Holberton School students.
*
* Return: Always EXIT_SUCCESS.
*/
int main(void)
{
printf("%d\n", _strlen("Holberton"));
return (EXIT_SUCCESS);
}
Mohu zkompilovat program s následujícím kódem:
gcc -Wall -pedantic -Werror -Wextra -L. 0-main.c -lholberton -o len
Stejně jako u statických knihoven volba -L.
vyhledá v adresáři soubory knihovny a -l
, která je připojena na začátek holberton
, je implicitní vyhledání souborů knihovny, které mají předponu lib
, příponu .so
a holberton
mezi nimi.
Chci-li použít právě vytvořený knihovní soubor, musím se ujistit, že překladač je schopen najít všechny knihovní soubory v paměti a že jsou na začátku správně načteny v paměti. Pokud nyní spustím ldd len
, uvidím následující:
Řádek libholberton.so => not found
mi říká, že závislost na právě vytvořené dynamické knihovně není splněna. Abychom to napravili, je třeba rozumět proměnné prostředí $LD_LIBRARY_PATH
. V Linuxu je tato proměnná seznam adresářů oddělených dvojtečkou, do kterých systém hledá soubory knihoven. Na obrázku výše vidíte, že echo této proměnné při aktuálním stavu ukazuje, že je prázdná, a proto můj pokus o spuštění programu (len
) nefunguje, protože sdílenou knihovnu nelze načíst.
Můj aktuální adresář vypadá takto:
Jak vidíte, soubor knihovny se nachází ve stejném adresáři jako můj hlavní soubor a hlavičkový soubor (aktuální pracovní adresář). Všimněte si následujícího obrázku:
Příkaz export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
aktualizuje proměnnou prostředí $LD_LIBRARY_PATH
o .:
, což znamená, že systém má hledat knihovny v aktuálním pracovním adresáři. Příkaz export
provede tuto změnu globálně, takže ke stejné hodnotě může přistupovat libovolný shell. Když tedy dám proměnné echo, uvidím své aktualizace. Při opětovném spuštění ldd len
vidím, že libholberton.so
je na adresním místě 0x00007fb9216b9000
, což je pravděpodobně její umístění v aktuálním pracovním adresáři v paměti. Závislost spustitelného souboru na sdílené knihovně je tedy nyní splněna a program vrací 9
, což je délka slova „Holberton
„.