Utilizați funcția ar din Linux pentru a crea biblioteci de funcții personalizate în timpul dezvoltării software. Acest tutorial vă va explica cum să creați o bibliotecă statică, cum să o modificați și cum să o utilizați într-un program, inclusiv exemple de cod.
Comanda ar este un instrument vechi, datând din 1971. Numele „ar” provine din scopul său inițial, acela de a crea fișiere arhivă. Un fișier arhivă este un singur fișier care funcționează ca un container pentru mai multe fișiere. Fișierele pot fi adăugate, eliminate sau extrase dintr-o arhivă. Deși inițial ar era folosit frecvent pentru gestionarea arhivelor, în prezent, alte utilitare, cum ar fi tar, au preluat această funcție.
Cu toate acestea, comanda ar este încă folosită în anumite scopuri specializate, în special la crearea bibliotecilor statice utilizate în dezvoltarea de software. De asemenea, ar este folosită pentru a crea pachete, cum ar fi fișierele „.deb” utilizate în distribuțiile Debian Linux și derivatele sale, precum Ubuntu.
Vom parcurge procesul de creare și modificare a unei biblioteci statice și vom arăta cum poate fi folosită biblioteca într-un program. Pentru aceasta, vom crea o bibliotecă statică pentru a cripta și decripta șiruri de text.
Important de reținut este că acesta este un exemplu simplificat în scop demonstrativ. Criptarea utilizată este o cifră de substituție elementară, unde fiecare literă este înlocuită cu litera următoare din alfabet (A devine B, B devine C, etc.). Nu este recomandată pentru date sensibile.
Funcțiile `cipher_encode()` și `cipher_decode()`
Vom lucra într-un director numit „bibliotecă” și vom crea ulterior un subdirector numit „test”.
În directorul „bibliotecă”, vom avea două fișiere. Într-un fișier numit `cipher_encode.c`, vom avea funcția `cipher_encode()`:
void cipher_encode(char *text) { for (int i=0; text[i] != 0x0; i++) { text[i]++; } }
Funcția complementară `cipher_decode()` se va afla într-un fișier text numit `cipher_decode.c`:
void cipher_decode(char *text) { for (int i=0; text[i] != 0x0; i++) { text[i]--; } }
Fișierele care conțin codul programului se numesc fișiere sursă. Vom crea un fișier bibliotecă numit `libcipher.a`. Acesta va conține versiunile compilate ale fișierelor sursă. Vom crea de asemenea un fișier text numit `libcipher.h`, un fișier header care va include declarațiile funcțiilor din noua noastră bibliotecă.
Orice dezvoltator care are biblioteca și fișierul header va putea folosi funcțiile în propriile sale programe, fără a rescrie codul.
Compilarea fișierelor `cipher_encode.c` și `cipher_decode.c`
Pentru a compila fișierele sursă, vom utiliza `gcc`, compilatorul GNU standard. Opțiunea `-c` (compilare, fără linkare) îi indică lui `gcc` să compileze fișierele și să se oprească. Astfel, va produce un fișier intermediar, numit fișier obiect, pentru fiecare fișier sursă. În mod normal, linker-ul `gcc` va lua toate fișierele obiect și le va combina pentru a crea un program executabil. Însă, în cazul nostru, evităm acest pas prin utilizarea opțiunii `-c`, deoarece avem nevoie doar de fișierele obiect.
Să verificăm dacă avem fișierele necesare.
ls -l
Verificăm că cele două fișiere de cod sursă sunt prezente. Să le compilăm folosind `gcc` pentru a produce fișierele obiect.
gcc -c cipher_encode.c
gcc -c cipher_decode.c
În cazul unui proces reușit, nu ar trebui să apară nicio ieșire de la `gcc`.
Acest proces generează două fișiere obiect cu același nume ca fișierele de cod sursă, dar cu extensia `.o`. Acestea sunt fișierele pe care trebuie să le includem în fișierul bibliotecă.
ls -l
Crearea bibliotecii `libcipher.a`
Pentru a crea fișierul bibliotecă – care este de fapt un fișier arhivă – vom utiliza comanda `ar`.
Utilizăm opțiunea `-c` (creare) pentru a crea fișierul bibliotecă, opțiunea `-r` (adăugare cu înlocuire) pentru a adăuga fișierele în fișierul bibliotecă și opțiunea `-s` (index) pentru a crea un index al fișierelor din interiorul fișierului bibliotecă.
Fișierul bibliotecă va fi numit `libcipher.a`. Acest nume, împreună cu numele fișierelor obiect, va fi furnizat pe linia de comandă.
ar -crs libcipher.a cipher_encode.o cipher_decode.o
Dacă listăm fișierele din director, vom observa că acum avem un fișier numit `libcipher.a`.
ls -l
Prin utilizarea opțiunii `-t` (tabel) împreună cu comanda `ar`, putem vizualiza modulele din fișierul bibliotecă.
ar -t libcipher.a
Crearea fișierului header `libcipher.h`
Fișierul `libcipher.h` va fi inclus în orice program care folosește biblioteca `libcipher.a`. Acest fișier header trebuie să conțină declarațiile funcțiilor prezente în bibliotecă.
Pentru a crea fișierul header, vom introduce declarațiile funcțiilor într-un editor de text, de exemplu `gedit`. Salvăm fișierul sub numele `libcipher.h` în același director cu fișierul `libcipher.a`.
void cipher_encode(char *text); void cipher_decode(char *text);
Utilizarea bibliotecii `libcipher`
Singura modalitate sigură de a testa noua noastră bibliotecă este să scriem un mic program care să o folosească. Mai întâi, creăm un director numit `test`.
mkdir test
Vom copia biblioteca și fișierul header în noul director.
cp libcipher.* ./test
Intrăm în noul director.
cd test
Verificăm dacă cele două fișiere sunt prezente.
ls -l
Acum creăm un mic program care va folosi biblioteca pentru a verifica dacă funcționează corect. Vom introduce următorul cod într-un editor. Vom salva fișierul cu numele `test.c` în directorul test.
#include <stdio.h> #include <stdlib.h> #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); }
Fluxul programului este simplu:
- Include fișierul `libcipher.h` pentru a putea accesa declarațiile funcțiilor din bibliotecă.
- Creează un șir numit `text` și stochează în el textul „How-To Geek loves Linux”.
- Afișează șirul pe ecran.
- Apelează funcția `cipher_encode()` pentru a cripta șirul și afișează șirul criptat pe ecran.
- Apelează funcția `cipher_decode()` pentru a decripta șirul și afișează șirul decriptat pe ecran.
Pentru a genera programul de testare, trebuie să compilăm programul `test.c` și să îl legăm de bibliotecă. Opțiunea `-o` (ieșire) îi spune lui `gcc` cum să numească programul executabil pe care îl generează.
gcc test.c libcipher.a -o test
Dacă `gcc` revine la promptul de comandă fără a afișa niciun mesaj, totul este în regulă. Acum putem testa programul nostru.
./test
Programul afișează rezultatul așteptat. Textul simplu, urmat de textul criptat, și apoi de textul decriptat. Acest lucru demonstrează funcționalitatea bibliotecii create.
Succes! Dar de ce să ne oprim aici?
Adăugarea unui nou modul în bibliotecă
Să adăugăm o altă funcție bibliotecii noastre. Vom adăuga o funcție pe care programatorul o poate utiliza pentru a afișa versiunea bibliotecii. Va trebui să creăm funcția, să o compilăm și să adăugăm noul fișier obiect la fișierul bibliotecii existente.
Introducem următoarele rânduri într-un editor. Salvăm conținutul editorului într-un fișier numit `cipher_version.c`, în directorul bibliotecii.
#include <stdio.h> void cipher_version(void) { puts("How-To Geek :: VERY INSECURE Cipher Library"); puts("Version 0.0.1 Alphan"); }
Trebuie să adăugăm declarația noii funcții în fișierul header `libcipher.h`. Adăugăm o nouă linie la sfârșitul fișierului, astfel încât să arate astfel:
void cipher_encode(char *text); void cipher_decode(char *text); void cipher_version(void);
Salvați fișierul modificat `libcipher.h`.
Trebuie să compilăm fișierul `cipher_version.c` pentru a obține fișierul obiect `cipher_version.o`.
gcc -c cipher_version.c
Această comandă creează un fișier `cipher_version.o`. Putem adăuga acest fișier obiect în biblioteca `libcipher.a` utilizând următoarea comandă. Opțiunea `-v` (verboză) va face ca `ar` să ne informeze despre operațiunile efectuate.
ar -rsv libcipher.a cipher_version.o
Noul fișier obiect este adăugat în fișierul bibliotecă. `ar` afișează o confirmare. „a” înseamnă „adăugat”.
Putem folosi opțiunea `-t` (tabel) pentru a vizualiza ce module se află în fișierul bibliotecă.
ar -t libcipher.a
Acum, fișierul bibliotecă conține trei module. Să folosim noua funcție.
Utilizarea funcției `cipher_version()`
Vom elimina vechea bibliotecă și fișierul header din directorul de test, apoi vom copia noile fișiere și vom intra înapoi în directorul de test.
Vom șterge versiunile vechi ale fișierelor.
rm ./test/libcipher.*
Vom copia noile versiuni în directorul de test.
cp libcipher.* ./test
Intrăm în directorul de test.
cd test
Acum putem modifica programul `test.c` pentru a utiliza noua funcție din bibliotecă.
Trebuie să adăugăm o linie nouă în programul `test.c`, care să apeleze funcția `cipher_version()`. Această linie o vom adăuga înainte de linia `puts(text);`.
#include <stdio.h> #include <stdlib.h> #include "libcipher.h" int main(int argc, char *argv[]) { char text[]="How-To Geek loves Linux"; // linie nouă adăugată aici cipher_version(); puts(text); cipher_encode(text); puts(text); cipher_decode(text); puts(text); exit (0); }
Salvați modificările în fișierul `test.c`. Acum îl putem compila și verifica funcționarea noii funcții.
gcc test.c libcipher.a -o test
Să executăm noua versiune a programului `test`:
Noua funcție funcționează. Putem vedea versiunea bibliotecii la începutul ieșirii programului.
Dar ar putea apărea o problemă.
Înlocuirea unui modul în bibliotecă
Aceasta nu este prima versiune a bibliotecii; este a doua. Numărul de versiune este incorect. Prima versiune nu conținea funcția `cipher_version()`. A doua versiune o are. Prin urmare, aceasta ar trebui să fie versiunea „0.0.2”. Trebuie să înlocuim funcția `cipher_version()` din bibliotecă cu cea corectată.
Din fericire, comanda `ar` face această operațiune foarte simplă.
Mai întâi, edităm fișierul `cipher_version.c` din directorul bibliotecii. Modificăm textul „Versiunea 0.0.1 Alpha” în „Versiunea 0.0.2 Alpha”. Codul ar trebui să arate astfel:
#include <stdio.h> void cipher_version(void) { puts("How-To Geek :: VERY INSECURE Cipher Library"); puts("Version 0.0.2 Alphan"); }
Salvați fișierul. Trebuie să îl compilăm din nou pentru a crea un nou fișier obiect `cipher_version.o`.
gcc -c cipher_version.c
Acum vom înlocui obiectul `cipher_version.o` existent din bibliotecă cu noua versiune compilată.
Am utilizat anterior opțiunea `-r` (adăugare cu înlocuire) pentru a adăuga module noi în bibliotecă. Când o utilizăm cu un modul care există deja în bibliotecă, `ar` va înlocui versiunea veche cu cea nouă. Opțiunea `-s` (index) va actualiza indexul bibliotecii, iar opțiunea `-v` (verboză) va face ca comanda `ar` să ne comunice acțiunea efectuată.
ar -rsv libcipher.a cipher_version.o
De data aceasta, `ar` raportează că a înlocuit modulul `cipher_version.o`. „r” înseamnă „înlocuit”.
Utilizarea funcției `cipher_version()` actualizate
Ar trebui să folosim biblioteca modificată și să verificăm dacă funcționează corect.
Vom copia fișierele bibliotecii în directorul de testare.
cp libcipher.* ./test
Intrăm în directorul de testare.
cd ./test
Trebuie să recompilăm programul nostru de testare cu noua bibliotecă.
gcc test.c libcipher.a -o test
Și acum putem testa programul nostru.
./test
Rezultatul afișat de program este cel așteptat. Numărul corect al versiunii este afișat în șirul de versiune, iar funcțiile de criptare și decriptare funcționează corect.
Ștergerea modulelor dintr-o bibliotecă
Chiar dacă poate părea regretabil după atâta muncă, haideți să ștergem fișierul `cipher_version.o` din fișierul bibliotecă.
Pentru a face acest lucru, vom folosi opțiunea `-d` (ștergere). Vom folosi și opțiunea `-v` (verboză) pentru a primi informații despre acțiunile efectuate de `ar`, precum și opțiunea `-s` (index) pentru a actualiza indexul bibliotecii.
ar -dsv libcipher.a cipher_version.o
Comanda `ar` raportează că a eliminat modulul. „d” înseamnă „șters”.
Dacă solicităm comenzii `ar` să listeze modulele din fișierul bibliotecii, vom observa că numărul modulelor a revenit la două.
ar -t libcipher.a
Dacă doriți să eliminați module dintr-o bibliotecă, rețineți să eliminați și declarația acestora din fișierul header al bibliotecii.
Distribuirea codului dumneavoastră
Bibliotecile facilitează partajarea codului într-un mod practic și privat. Oricine are fișierul bibliotecă și fișierul header poate utiliza biblioteca dumneavoastră, dar codul sursă rămâne privat.