Při vývoji softwaru je příkaz ar v Linuxu neocenitelným nástrojem pro vytváření knihoven funkcí. Tento návod vám ukáže, jak krok za krokem vytvořit statickou knihovnu, provést její úpravy a začlenit ji do programu. Vše bude doprovázeno příklady kódu.
Příkaz `ar` je skutečný veterán, který se poprvé objevil již v roce 1971. Jeho název odkazuje na původní záměr použití – archivaci souborů. Archivní soubor je v podstatě kontejner, který sdružuje více souborů do jednoho. Uživatelé, kteří hledají tuto funkcionalitu dnes, se ale obracejí spíše na nástroje jako je `tar`.
Nicméně, příkaz `ar` si stále zachovává své specifické využití, zejména při vytváření statických knihoven, které jsou klíčové při vývoji softwaru. Mimo to, `ar` se také používá pro konstrukci balíčkových souborů, jako jsou například soubory „.deb“, které se využívají v distribucích Debian Linux a jeho odnožích, jako je Ubuntu.
V tomto průvodci se podíváme na kroky potřebné k sestavení a modifikaci statické knihovny. Dále si ukážeme, jak takovou knihovnu použít v programu. Pro demonstraci si vytvoříme knihovnu pro kódování a dekódování textových řetězců.
Je důležité zdůraznit, že se jedná o rychlý a jednoduchý příklad pro demonstraci. Nejedná se o zabezpečenou metodu šifrování pro citlivá data. Použijeme jednoduchou substituční šifru, kde se každé písmeno posune o jednu pozici v abecedě (A se stane B, B se stane C, atd.).
Funkce cipher_encode()
a cipher_decode()
Pro naše účely si vytvoříme adresář pojmenovaný „library“. Později v něm vytvoříme podadresář „test“.
V adresáři „library“ budeme mít dva soubory. První, nazvaný `cipher_encode.c`, bude obsahovat funkci cipher_encode()
:
void cipher_encode(char *text) { for (int i=0; text[i] != 0x0; i++) { text[i]++; } } // konec funkce cipher_encode
Druhý soubor, `cipher_decode.c`, bude obsahovat funkci cipher_decode()
:
void cipher_decode(char *text) { for (int i=0; text[i] != 0x0; i++) { text[i]--; } } // konec funkce cipher_decode
Soubory obsahující programovací instrukce se nazývají zdrojové soubory. Naše knihovna `libcipher.a` bude obsahovat zkompilované verze těchto dvou zdrojových souborů. Dále si vytvoříme hlavičkový soubor `libcipher.h`, který bude obsahovat definice obou funkcí.
Každý, kdo bude mít k dispozici naši knihovnu a hlavičkový soubor, bude moci tyto funkce použít ve svých programech. Nemusí tak znovu vytvářet potřebné funkce, ale jednoduše využije kopie z naší knihovny.
Kompilace cipher_encode.c
a cipher_decode.c
Ke kompilaci zdrojových souborů použijeme `gcc`, což je standardní GNU kompilátor. Použitím volby `-c` (kompilovat, ne linkovat) sdělujeme kompilátoru, aby zdrojové soubory zkompiloval, ale nepokračoval dále. Tímto způsobem vytvoříme tzv. objektové soubory. Linker `gcc` by běžně spojil všechny objektové soubory dohromady a vytvořil spustitelný program. My ale tento krok přeskočíme a vytvoříme pouze objektové soubory.
Nejprve zkontrolujeme, zda máme všechny soubory, které potřebujeme:
ls -l
Vypíše se seznam souborů a potvrdíme přítomnost obou zdrojových souborů. Nyní je zkompilujeme pomocí `gcc` do objektových souborů:
gcc -c cipher_encode.c
gcc -c cipher_decode.c
Pokud vše proběhne bez problémů, `gcc` nezobrazí žádný výstup.
Kompilací se vygenerují dva objektové soubory se stejným názvem jako zdrojové soubory, ale s příponou „.o“. Tyto soubory musíme přidat do knihovny.
ls -l
Vytvoření knihovny libcipher.a
Pro vytvoření souboru knihovny, který je vlastně archivní soubor, použijeme příkaz `ar`.
Použijeme volbu `-c` (vytvořit), volbu `-r` (přidat s nahrazením), pro přidání objektových souborů do knihovny a volbu `-s` (index) pro vytvoření indexu souborů uvnitř knihovny.
Knihovnu nazveme `libcipher.a`. Tento název zadáme na příkazové řádce spolu s názvy objektových souborů:
ar -crs libcipher.a cipher_encode.o cipher_decode.o
Po vypsání obsahu adresáře zjistíme, že jsme úspěšně vytvořili soubor `libcipher.a`.
ls -l
Pomocí volby `-t` (tabulka) s příkazem `ar` můžeme zobrazit moduly obsažené uvnitř souboru knihovny.
ar -t libcipher.a
Vytvoření hlavičkového souboru libcipher.h
Hlavičkový soubor `libcipher.h` bude součástí každého programu, který používá knihovnu `libcipher.a`. Tento soubor musí obsahovat definice funkcí, které se v knihovně nacházejí.
Pro vytvoření hlavičkového souboru musíme do textového editoru, jako je `gedit`, zadat definice funkcí. Soubor pojmenujeme „libcipher.h“ a uložíme ho do stejného adresáře jako soubor `libcipher.a`:
void cipher_encode(char *text); void cipher_decode(char *text);
Použití knihovny libcipher
Nejspolehlivější způsob, jak otestovat naši knihovnu, je napsat program, který ji bude používat. Nejdříve vytvoříme adresář pojmenovaný „test“:
mkdir test
Následně do nového adresáře zkopírujeme knihovnu a hlavičkový soubor:
cp libcipher.* ./test
Nyní se přesuneme do nového adresáře:
cd test
Zkontrolujeme, že soubory byly zkopírovány:
ls -l
Nyní vytvoříme testovací program. Do editoru vložíme následující kód a uložíme jej jako „test.c“ v adresáři „test“:
#include#include #include "libcipher.h" int main(int argc, char *argv[]) { char text[]="How-To Geek loves Linux"; puts(text); cipher_encode(text); puts(text); cipher_decode(text); puts(text); exit (0); } // konec funkce main
Program funguje takto:
- Načte hlavičkový soubor `libcipher.h`, aby mohl používat funkce knihovny.
- Vytvoří řetězec „text“ s hodnotou „How-To Geek loves Linux“.
- Vytiskne tento řetězec na obrazovku.
- Zavolá funkci `cipher_encode()` pro zakódování řetězce a vytiskne zakódovaný řetězec.
- Zavolá funkci `cipher_decode()` pro dekódování řetězce a vytiskne dekódovaný řetězec.
Pro vygenerování spustitelného programu musíme zkompilovat program `test.c` a propojit ho s knihovnou. Volba `-o` (výstup) udává kompilátoru, jak se má generovaný spustitelný soubor jmenovat.
gcc test.c libcipher.a -o test
Pokud `gcc` po provedení příkazu tiše vrátí příkazový řádek, je vše v pořádku. Nyní otestujeme náš program:
./test
A vidíme očekávaný výstup. Program vytiskne původní text, zašifrovaný text a poté dešifrovaný text. Vše funguje správně a využívá funkce naší knihovny.
Úspěch! Ale proč se zastavit? Pojďme na to dál.
Přidání dalšího modulu do knihovny
Přidáme do knihovny další funkci. Bude se jednat o funkci, která zobrazí verzi knihovny. Vytvoříme novou funkci, zkompilujeme ji a přidáme do knihovny jako nový objektový soubor.
Do editoru vložíme následující řádky a uložíme je jako `cipher_version.c` v adresáři „library“:
#includevoid cipher_version(void) { puts("How-To Geek :: VERY INSECURE Cipher Library"); puts("Version 0.0.1 Alphan"); } // konec funkce cipher_version
Musíme také přidat definici nové funkce do hlavičkového souboru `libcipher.h`. Přidáme nový řádek na konec souboru tak, aby vypadal takto:
void cipher_encode(char *text); void cipher_decode(char *text); void cipher_version(void);
Upravený soubor `libcipher.h` uložíme.
Nyní musíme zkompilovat soubor `cipher_version.c`, abychom získali objektový soubor `cipher_version.o`:
gcc -c cipher_version.c
Vytvořili jsme soubor `cipher_version.o`. Nyní ho přidáme do knihovny `libcipher.a` pomocí následujícího příkazu. Volba `-v` (verbose) zajistí, že `ar` vypíše informaci o tom, co provedl:
ar -rsv libcipher.a cipher_version.o
Nový objektový soubor byl přidán do knihovny a `ar` zobrazí potvrzení. „A“ znamená, že modul byl „added“ – přidán.
Můžeme použít volbu `-t` (tabulka), abychom viděli, jaké moduly jsou v knihovně obsažené.
ar -t libcipher.a
V knihovně jsou nyní tři moduly. Pojďme využít novou funkci.
Použití funkce cipher_version()
Odstraníme starou knihovnu a hlavičkový soubor z testovacího adresáře, zkopírujeme tam nové soubory a poté se opět přesuneme do testovacího adresáře.
Nejprve odstraníme staré verze souborů:
rm ./test/libcipher.*
Potom zkopírujeme nové verze do adresáře „test“:
cp libcipher.* ./test
Přesuneme se do adresáře „test“:
cd test
Nyní můžeme upravit program `test.c`, aby používal novou funkci. Přidáme do něj volání funkce `cipher_version()` před první řádek s `puts(text);`.
#include#include #include "libcipher.h" int main(int argc, char *argv[]) { char text[]="How-To Geek loves Linux"; // nový řádek přidán sem cipher_version(); puts(text); cipher_encode(text); puts(text); cipher_decode(text); puts(text); exit (0); } // konec funkce main
Upravený kód uložíme jako `test.c`. Nyní ho zkompilujeme a otestujeme, jestli nová funkce funguje:
gcc test.c libcipher.a -o test
Spustíme novou verzi programu:
Nová funkce funguje! Na začátku výstupu vidíme informace o verzi knihovny.
Může ale nastat problém.
Nahrazení modulu v knihovně
Toto není první verze knihovny, ale druhá. Číslo verze v našem programu je nesprávné. První verze knihovny neobsahovala funkci `cipher_version()`, ta je až v této. Měla by být verze „0.0.2“. Musíme funkci `cipher_version()` v knihovně nahradit opravenou verzí.
Naštěstí je to s příkazem `ar` velmi jednoduché.
Nejprve upravíme soubor `cipher_version.c` v adresáři „library“. Změníme text „Version 0.0.1 Alpha“ na „Version 0.0.2 Alpha“. Upravený kód by měl vypadat takto:
#includevoid cipher_version(void) { puts("How-To Geek :: VERY INSECURE Cipher Library"); puts("Version 0.0.2 Alphan"); } // konec funkce cipher_version
Uložíme soubor. Musíme ho znovu zkompilovat, abychom získali nový objektový soubor `cipher_version.o`:
gcc -c cipher_version.c
Nyní nahradíme existující modul `cipher_version.o` v knihovně novou zkompilovanou verzí.
K přidání nových modulů do knihovny jsme již použili volbu `-r` (přidat s nahrazením). Pokud ji použijeme na modul, který už v knihovně existuje, příkaz `ar` nahradí starou verzi novou. Volba `-s` (index) aktualizuje index knihovny a volba `-v` (verbose) nám řekne, co udělala.
ar -rsv libcipher.a cipher_version.o
Tentokrát `ar` hlásí, že nahradil modul `cipher_version.o`. „r“ znamená replaced – nahrazeno.
Použití aktualizované funkce cipher_version()
Nyní bychom měli použít naši upravenou knihovnu a zkontrolovat, zda funguje správně.
Zkopírujeme soubory knihovny do adresáře „test“:
cp libcipher.* ./test
Přesuneme se do adresáře „test“:
cd ./test
Musíme znovu zkompilovat testovací program s novou knihovnou:
gcc test.c libcipher.a -o test
A nyní můžeme náš program otestovat:
./test
Výstup z testovacího programu je nyní takový, jaký jsme očekávali. V řetězci verze se zobrazuje správné číslo verze a šifrovací i dešifrovací rutiny fungují.
Odstranění modulů z knihovny
Ačkoli se zdá škoda to udělat, zkusme odstranit soubor `cipher_version.o` z naší knihovny.
Pro tento účel použijeme volbu `-d` (smazat). Volba `-v` (verbose) nám umožní vidět, co příkaz `ar` provede. Nakonec použijeme `-s` (index) pro aktualizaci indexu v knihovně.
ar -dsv libcipher.a cipher_version.o
`ar` hlásí, že modul odstranil. „d“ znamená „deleted“ – smazáno.
Pokud se podíváme na moduly uvnitř knihovny, uvidíme, že máme opět jen dva moduly:
ar -t libcipher.a
Pokud se chystáte odstranit moduly z knihovny, nezapomeňte odstranit i jejich definice z hlavičkového souboru.
Sdílení kódu
Knihovny umožňují sdílení kódu praktickým, ale soukromým způsobem. Kdokoli, komu dáte knihovnu a hlavičkový soubor, může vaši knihovnu používat, aniž by měl přístup k vašemu zdrojovému kódu.