Linkingprocessen afsløret – statiske og dynamiske biblioteker

okt 19, 2021
admin

Skabelse af et statisk og dynamisk bibliotek

For et statisk bibliotek kombineres objektkoden fra binære filer (udvidelse .o) i en enkelt arkivfil med en udvidelse .a. Dette arkiv svarer til en værktøjskasse, der indeholder alle de værktøjer, der kan bruges i programmer, der kalder det pågældende bibliotek under sammenkobling. Værktøjerne indsættes på de steder, hvor der er behov for dem. I billedet nedenfor har jeg en række .c-filer.

Da et bibliotek er et arkiv med objektkode, skal jeg konvertere alle disse .c-filer til .o-filer ved hjælp af følgende kommando:

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

Optionen -c stopper kompileringsprocessen lige før linkning, efter at der er genereret objektkodefiler. Jeg har nu alle objektkodefilerne:

Hvis jeg kører kommandoen ar -rc libholbertonschool.a *.o, kan jeg arkivere disse filer i en enkelt .a biblioteksfil. Kommandoen ar er til arkivering, indstillingen -r er til flytning af medlemmer, der har filtypenavnet .o, og indstillingen -c er til oprettelse af arkivet, hvis det ikke findes. En biblioteksfil starter med et præfiks lib og har filtypenavnet .a. Det sidste trin, der er nødvendigt på nogle systemer, er at indeksere arkivets indhold for at fremskynde linkningen. Dette kan gøres med ranlib libholbertonschool.a. Jeg har nu et bibliotek, der indeholder objektkode for alle funktionerne i billedet ovenfor.

Brug af det statiske bibliotek

For at bruge dette bibliotek med en eller anden testfil skal jeg kompilere testfilen med biblioteket ved hjælp af en af følgende to kommandoer:

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

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

Både disse gør det samme, men den anden er lidt mere kryptisk. Indstillingen -L. søger efter biblioteker i den aktuelle mappe, og -l, der er forbundet med holbertonschool, søger implicit efter biblioteksfilen, hvor der antages et lib præfiks og .a suffiks. Uden at kompilere med en biblioteksfil vil gcc kaste en fejl, da de funktioner, som den forsøger at linke, ikke leveres. Ved at levere et bibliotek i kompileringen kan compileren nu søge i biblioteket efter de funktioner, den har brug for, og indsætte dem, hvor de er nødvendige.

Dynamiske biblioteker

Skabelse af dynamiske biblioteker er lidt anderledes end statiske biblioteker, men koncepterne er generelt de samme. Jeg har det samme antal .c-filer og den headerfil, der definerer deres prototyper, i en fil kaldet lists.h.

For at oprette det dynamiske bibliotek, som har et .so (står for shared object), kan følgende kompileringskommando indtastes:

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

Flaget -fPIC står for Position Independent Code, som er påkrævet for dynamisk linkning. Betydningen af dette er præcis, hvad det lyder som – da dynamisk linkede biblioteker kan gemmes hvor som helst i hukommelsen, hvor de passer ind, gør dette flag det muligt at bruge biblioteksfilen, uanset hvor den er gemt.

Med -shared-flaget kan der oprettes et delt arkiv, og med -o-optionen kan vi omdøbe outputfilen til libholberton.so.

Efter at have kørt denne kommando har jeg nu et delt bibliotek!

Anvendelse af det dynamiske bibliotek

Lad os sige, at jeg har følgende kode:

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

Jeg kan kompilere programmet med følgende kode:

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

Nøjagtig som med de statiske biblioteker søger -L.-indstillingerne i mappen efter biblioteksfiler, og -l, der er tilføjet i begyndelsen af holberton, er en implicit søgning efter biblioteksfiler, der har et præfiks lib, et suffiks .so og holberton mellem de to.

For at kunne bruge den biblioteksfil, jeg netop har oprettet, skal jeg sikre mig, at compileren er i stand til at finde alle biblioteksfiler i hukommelsen, og at de er korrekt indlæst i hukommelsen til at begynde med. Hvis jeg nu kører ldd len, kan jeg se følgende:

Retten libholberton.so => not found fortæller mig, at afhængigheden af det dynamiske bibliotek, jeg netop har oprettet, ikke er opfyldt. For at løse dette skal miljøvariablen $LD_LIBRARY_PATH forstås. I Linux er denne variabel en liste med kolonadskillelse over mapper, som systemet kigger ind i for at finde biblioteksfiler. På billedet ovenfor kan du se, at et ekko af denne variabel i den aktuelle tilstand viser, at den er tom, og dermed virker mit forsøg på at køre programmet (len) ikke, fordi det delte bibliotek ikke kan indlæses.

Min aktuelle mappe ser således ud:

Som du kan se, ligger biblioteksfilen i samme mappe som min hovedfil og headerfil (nuværende arbejdsmappe). Bemærk følgende billede:

Kommandoen export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH opdaterer miljøvariablen $LD_LIBRARY_PATH med et .:, der angiver, at systemet skal søge i den aktuelle arbejdskatalog efter biblioteker. Kommandoen export gør denne ændring global, så enhver skal kan få adgang til den samme værdi. Når jeg således ekkoer variablen, kan jeg se mine opdateringer. Hvis jeg kører ldd len igen, kan jeg se, at libholberton.so befinder sig på adresseplacering 0x00007fb9216b9000, hvilket sandsynligvis er dens placering i den aktuelle arbejdsmappe i hukommelsen. Dermed er den eksekverbare computers afhængighed af det delte bibliotek nu opfyldt, og programmet returnerer 9, som er længden af ordet “Holberton“.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.