Proces łączenia ujawniony – biblioteki statyczne i dynamiczne

paź 19, 2021
admin

Tworzenie biblioteki statycznej i dynamicznej

W przypadku biblioteki statycznej kod obiektowy z plików binarnych (rozszerzenie .o) jest łączony w jeden plik archiwum z rozszerzeniem .a. Archiwum to jest podobne do skrzynki narzędziowej, która zawiera wszystkie narzędzia, które mogą być użyte w programach wywołujących tę bibliotekę podczas łączenia. Narzędzia są wstawiane w miejscach, w których są potrzebne. Na poniższym obrazku mam serię plików .c.

Ponieważ biblioteka jest archiwum kodu obiektowego, muszę przekonwertować wszystkie te pliki .c na pliki .o za pomocą następującego polecenia:

gcc -Wall -Wextra -Werror -pedantic -c *.c

Opcja -c zatrzymuje proces kompilacji tuż przed łączeniem po wygenerowaniu plików kodu obiektowego. Mam teraz wszystkie pliki z kodem obiektowym:

Jeśli uruchomię polecenie ar -rc libholbertonschool.a *.o, mogę zarchiwizować te pliki w jeden plik biblioteki .a. Polecenie ar służy do archiwizacji, opcja -r służy do przenoszenia plików o rozszerzeniu .o, a opcja -c służy do tworzenia archiwum, jeśli ono nie istnieje. Plik biblioteki zaczyna się od prefiksu lib i ma rozszerzenie .a. Ostatnim krokiem, który jest konieczny w niektórych systemach, jest indeksowanie zawartości archiwum w celu przyspieszenia łączenia. Można to zrobić za pomocą ranlib libholbertonschool.a. Mam teraz bibliotekę, która zawiera kod obiektowy dla wszystkich funkcji z powyższego obrazka.

Używanie biblioteki statycznej

Aby użyć tej biblioteki z jakimś plikiem testowym, muszę skompilować plik testowy z biblioteką za pomocą jednego z dwóch następujących poleceń:

gcc test.c ./libholbertonschool.a -o exename

gcc test.c -L. -lholbertonschool -o exename

Oba te polecenia robią to samo, ale drugie jest nieco bardziej tajemnicze. Opcja -L. wyszukuje biblioteki w bieżącym katalogu, a -l, która jest połączona z holbertonschool, wyszukuje plik biblioteki niejawnie, gdzie zakłada się prefiks lib i sufiks .a. Bez kompilacji z plikiem biblioteki, gcc wyrzuci błąd, ponieważ funkcje, które próbuje połączyć, nie są dostarczone. Dostarczając bibliotekę w kompilacji, kompilator może teraz przeszukiwać bibliotekę w poszukiwaniu potrzebnych funkcji i wstawiać je tam, gdzie są potrzebne.

Biblioteki dynamiczne

Tworzenie bibliotek dynamicznych różni się nieco od bibliotek statycznych, ale koncepcje są generalnie takie same. Mam taką samą liczbę plików .c i plik nagłówkowy, który definiuje ich prototypy w pliku o nazwie lists.h.

Aby utworzyć bibliotekę dynamiczną, która ma .so (oznaczającą obiekt współdzielony), można wprowadzić następujące polecenie kompilacji:

gcc -fPIC -Wall -Werror -Wextra -pedantic *.c -shared -o libholberton.so

Flaga -fPIC oznacza kod niezależny od pozycji, który jest wymagany przy łączeniu dynamicznym. Znaczenie tego jest dokładnie takie, jak brzmi – ponieważ dynamicznie linkowane biblioteki mogą być przechowywane w dowolnym miejscu w pamięci, gdzie pasują, ta flaga pozwala na użycie pliku biblioteki niezależnie od tego, gdzie jest przechowywany.

Flaga -shared pozwala na utworzenie współdzielonego archiwum, a opcja -o pozwala nam zmienić nazwę pliku wyjściowego na libholberton.so.

Po uruchomieniu tego polecenia mam teraz współdzieloną bibliotekę!

Używanie biblioteki dynamicznej

Powiedzmy, że mam następujący kod:

#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);
}

Mogę skompilować program z następującym kodem:

gcc -Wall -pedantic -Werror -Wextra -L. 0-main.c -lholberton -o len 

Tak jak w przypadku bibliotek statycznych, opcje -L. przeszukują katalog w poszukiwaniu plików bibliotek, a -l, które jest dołączone na początku holberton, jest niejawnym wyszukiwaniem plików bibliotek, które mają przedrostek lib, przyrostek .so i holberton pomiędzy tymi dwoma.

Aby użyć pliku biblioteki, który właśnie utworzyłem, muszę się upewnić, że kompilator jest w stanie znaleźć wszystkie pliki biblioteki w pamięci i że są one prawidłowo załadowane do pamięci na początek. Jeśli teraz uruchomię ldd len, zobaczę, co następuje:

Linia libholberton.so => not found mówi mi, że zależność od biblioteki dynamicznej, którą właśnie utworzyłem, nie jest spełniona. Aby to naprawić, należy zrozumieć zmienną środowiskową $LD_LIBRARY_PATH. W Linuksie, zmienna ta jest rozdzieloną dwukropkami listą katalogów, do których system zagląda w poszukiwaniu plików bibliotek. Na powyższym obrazku widać, że echo tej zmiennej przy obecnym stanie pokazuje, że jest ona pusta, a zatem moja próba uruchomienia programu (len) nie działa, ponieważ biblioteka współdzielona nie może zostać załadowana.

Mój bieżący katalog wygląda tak:

Jak widać, plik biblioteki znajduje się w tym samym katalogu, co mój plik główny i plik nagłówkowy (bieżący katalog roboczy). Zwróć uwagę na następujący obrazek:

Komenda export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH aktualizuje zmienną środowiskową $LD_LIBRARY_PATH za pomocą .:, która wskazuje, że system powinien przeszukać bieżący katalog roboczy w poszukiwaniu bibliotek. Polecenie export czyni tę zmianę globalną, tak że każda powłoka może uzyskać dostęp do tej samej wartości. Tak więc, kiedy robię echo zmiennej, widzę moje aktualizacje. Uruchamiając ldd len ponownie, widzę, że libholberton.so znajduje się w lokalizacji adresowej 0x00007fb9216b9000, która jest prawdopodobnie jego lokalizacją w bieżącym katalogu roboczym w pamięci. Tak więc, zależność pliku wykonywalnego od biblioteki współdzielonej jest teraz spełniona i program zwraca 9, która jest długością słowa „Holberton„.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.