Linkitysprosessi paljastuu – staattiset ja dynaamiset kirjastot
Statisen ja dynaamisen kirjaston luominen
Staattisessa kirjastossa binääritiedostojen (tiedostopääte .o
) objektikoodi yhdistetään yhdeksi arkistotiedostoksi, jonka tiedostopääte on .a
. Tämä arkisto muistuttaa työkalupakkia, joka sisältää kaikki työkalut, joita voidaan käyttää ohjelmissa, jotka kutsuvat kyseistä kirjastoa linkityksen aikana. Työkalut lisätään paikkoihin, joissa niitä tarvitaan. Alla olevassa kuvassa minulla on sarja .c
-tiedostoja.
Koska kirjasto on objektikoodin arkisto, minun on muunnettava kaikki nämä .c
-tiedostot .o
-tiedostoiksi seuraavalla komennolla:
gcc -Wall -Wextra -Werror -pedantic -c *.c
Vaihtoehto -c
pysäyttää käännöksen kääntämisen juuri ennen linkittämistä sen jälkeen, kun objektikooditiedostot on luotu. Minulla on nyt kaikki objektikooditiedostot:
Jos suoritan komennon ar -rc libholbertonschool.a *.o
, voin arkistoida nämä tiedostot yhteen .a
-kirjastotiedostoon. Komento ar
on arkistointia varten, -r
-vaihtoehto siirtää jäsenet, joilla on pääte .o
, ja -c
-vaihtoehto luo arkiston, jos sitä ei ole olemassa. Kirjastotiedosto alkaa etuliitteellä lib
ja sillä on .a
-pääte. Viimeinen vaihe, joka on tarpeen joissakin järjestelmissä, on indeksoida arkiston sisältö linkittämisen nopeuttamiseksi. Tämä voidaan tehdä käyttämällä ranlib libholbertonschool.a
. Minulla on nyt kirjasto, joka sisältää objektikoodin kaikille yllä olevan kuvan funktioille.
Staattisen kirjaston käyttäminen
Käyttääkseni tätä kirjastoa jonkin testitiedoston kanssa minun on käännettävä testitiedosto kirjaston kanssa jommallakummalla seuraavista kahdesta komennosta:
gcc test.c ./libholbertonschool.a -o exename
gcc test.c -L. -lholbertonschool -o exename
Kummallakin komennolla saadaan aikaan sama juttu, mutta jälkimmäisellä komennolla päästään hiukan enemmän kryptiseen asiaan. Vaihtoehto -L.
etsii kirjastoja nykyisestä hakemistosta, ja holbertonschool
:n yhteydessä oleva -l
etsii implisiittisesti kirjastotiedostoa, jossa oletetaan lib
-etuliite ja .a
-suffiksi. Ilman kääntämistä kirjastotiedoston kanssa gcc
heittää virheen, koska funktioita, joita se yrittää linkittää, ei ole annettu. Tarjoamalla kirjaston kääntämisen yhteydessä kääntäjä voi nyt etsiä kirjastosta tarvitsemansa funktiot ja lisätä ne sinne, missä niitä tarvitaan.
Dynaamiset kirjastot
Dynaamisten kirjastojen luominen eroaa hieman staattisista kirjastoista, mutta käsitteet ovat yleisesti ottaen samat. Minulla on sama määrä .c
-tiedostoja ja otsikkotiedosto, joka määrittelee niiden prototyypit tiedostossa nimeltä lists.h
.
Luoaksemme dynaamisen kirjaston, jossa on .so
(joka tarkoittaa jaettua objektia), voidaan syöttää seuraava kääntämiskomento:
gcc -fPIC -Wall -Werror -Wextra -pedantic *.c -shared -o libholberton.so
Lippukirjain -fPIC
tarkoittaa Position Independent Code (sijainnista riippumaton koodi), joka vaaditaan dynaamista linkitystä varten. Tämän merkitys on juuri se, miltä se kuulostaa – koska dynaamisesti linkitettyjä kirjastoja voidaan tallentaa mihin tahansa muistiin, mihin ne sopivat, tämä lippu sallii kirjastotiedoston käytön riippumatta siitä, mihin se on tallennettu.
Lippu -shared
sallii jaetun arkiston luomisen, ja -o
-vaihtoehdon avulla voimme nimetä tulostiedoston uudelleen muotoon libholberton.so
.
Tämän komennon suorittamisen jälkeen minulla on nyt jaettu kirjasto!
Dynaamisen kirjaston käyttäminen
Sitotaan, että minulla on seuraavanlainen koodi:
#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);
}
Voin kääntää ohjelman seuraavalla koodilla:
gcc -Wall -pedantic -Werror -Wextra -L. 0-main.c -lholberton -o len
Aivan kuten staattisten kirjastojen kohdalla, -L.
-vaihtoehdot etsivät hakemistosta kirjastotiedostoja ja holberton
:n alkuun liitetty -l
on implisiittinen haku kirjastotiedostoille, joilla on etuliite lib
, loppuliite .so
ja holberton
näiden kahden välissä.
Käyttääkseni juuri luomaani kirjastotiedostoa minun on varmistettava, että kääntäjä pystyy löytämään kaikki muistissa olevat kirjastotiedostot ja että ne on ladattu muistiin oikein aluksi. Jos suoritan nyt ldd len
, näen seuraavaa:
Rivillä libholberton.so => not found
kerrotaan, että äsken luomani dynaamisen kirjastokirjaston riippuvuus ei täyty. Tämän korjaamiseksi on ymmärrettävä ympäristömuuttuja $LD_LIBRARY_PATH
. Linuxissa tämä muuttuja on kaksoispisteellä erotettu luettelo hakemistoista, joista järjestelmä etsii kirjastotiedostoja. Yllä olevasta kuvasta näet, että tämän muuttujan kaiku tämänhetkisessä tilassa osoittaa, että se on tyhjä ja näin ollen yritykseni suorittaa ohjelma (len
) ei toimi, koska jaettua kirjastoa ei voida ladata.
Nykyinen hakemistoni näyttää tältä:
Kuten näette, kirjastotiedosto sijaitsee samassa hakemistossa kuin päätiedostoni ja otsikkotiedostoni (nykyinen työhakemisto). Tarkkaile seuraavaa kuvaa:
Komento export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
päivittää ympäristömuuttujan $LD_LIBRARY_PATH
merkinnällä .:
, joka ilmaisee, että järjestelmän pitäisi hakea kirjastotietokannat senhetkisestä työhakemistosta. Komento export
tekee tästä muutoksesta globaalin, jotta mikä tahansa komentotulkki voi käyttää samaa arvoa. Näin ollen, kun kaikuin muuttujaan, näen päivitykseni. Kun suoritan ldd len
uudelleen, näen, että libholberton.so
on osoitteessa 0x00007fb9216b9000
, joka on todennäköisesti sen sijainti nykyisessä työhakemistossa muistissa. Näin ollen suoritettavan ohjelman riippuvuus jaetusta kirjastosta täyttyy nyt ja ohjelma palauttaa 9
, joka on sanan ”Holberton
” pituus.