102.3 Lecke 1
Tanúsítvány: |
LPIC-1 |
---|---|
Verzió: |
5.0 |
Témakör: |
102 A Linux telepítése és a csomagkezelés |
Fejezet: |
102.3 Megosztott könyvtárak kezelése |
Lecke: |
1/1 |
Bevezetés
Ebben a leckében a megosztott könyvtárakról (shared libraries), más néven megosztott objektumokról (shared objects) lesz szó: olyan lefordított, újrafelhasználható kódrészletek, mint például függvények vagy osztályok, amelyeket különböző programok újra és újra felhasználnak.
Először is nézzük meg, hogy mik azok a megosztott könyvtárak, hogyan lehet őket azonosítani, és hol találhatók. Ezután azt látjuk majd, hogy hogyan kell beállítani a tárolási helyüket, majd pedig azt, hogy hogyan kereshetjük meg azokat a megosztott könyvtárakat, amelyektől egy adott program függ.
A megosztott könyvtárak koncepciója
Fizikai társaikhoz hasonlóan a szoftverkönyvtárak is kódgyűjtemények, amelyek célja, hogy sok különböző program tudja használni őket; ahogyan a fizikai könyvtárak is könyveket és más forrásokat őriznek, amelyeket sok különböző ember használhat.
Ahhoz, hogy egy program forráskódjából futtatható fájlt készítsünk, két fontos lépésre van szükség. Először a compiler (fordító) a forráskódot gépi kóddá alakítja, amelyet úgynevezett objektumfájlokban (object files) tárol. Másodszor, a linker egyesíti az objektumfájlokat és linkeli őket könyvtárakhoz, hogy létrehozza a végső futtatható fájlt. Ez a linkelés történhet statikusan vagy dinamikusan. Attól függően, hogy melyik módszert választjuk, statikus könyvtárakról, vagy dinamikus linkelés esetén megosztott könyvtárakról beszélünk. Most nézzük meg a különbségeket!
- Statikus könyvtárak
-
A statikus könyvtár a programmal a linkeléskor egyesül. A könyvtár kódjának egy példánya beágyazódik a programba, és annak részévé válik. Így a program a futás során nem függ a könyvtáraktól, mivel a program már tartalmazza a könyvtár kódját. A függőségek hiánya előnynek tekinthető, mivel nem kell aggódni amiatt, hogy a használt könyvtárak mindig rendelkezésre álljanak. Hátránya, hogy a statikusan linkelt programok nagyobbak.
- Megosztott (vagy dinamikus) könyvtárak
-
Megosztott könyvtárak esetén a linker egyszerűen gondoskodik arról, hogy a program helyesen hivatkozzon a könyvtárakra. A linker azonban nem másol könyvtárkódot a programfájlba. Futtatási időben azonban a megosztott könyvtárnak rendelkezésre kell állnia, hogy a program függőségeit kielégítse. Ez egy gazdaságos megközelítés a rendszer erőforrásainak kezelésére, mivel segít csökkenteni a programfájlok méretét, és a könyvtárnak csak egy példánya töltődik be a memóriába, még akkor is, ha azt több program használja.
Megosztott objektumfájl-elnevezési konvenciók
A megosztott könyvtár neve, más néven soname, egy három elemből álló mintát követ:
-
A könyvtár neve (általában
lib
prefix-el) -
so
(ami a “shared object” rövidítése) -
A könyvtár verziószáma
Egy példa: libpthread.so.0
Ezzel szemben a statikus könyvtárak nevei .a
végződéssel végződnek, például libpthread.a
.
Note
|
Mivel a megosztott könyvtárakat tartalmazó fájloknak a program végrehajtásakor rendelkezésre kell állniuk, a legtöbb Linux rendszer tartalmaz megosztott könyvtárakat. Mivel a statikus könyvtárakra egy külön fájlban csak akkor van szükség, amikor a program linkelt, előfordulhat, hogy egy végfelhasználói rendszeren egyáltalán nincsenek. |
A glibc
(GNU C library) jó példa a megosztott könyvtárra. Debian GNU/Linux 9.9-es rendszerben a fájl neve libc.so.6
. Az ilyen, meglehetősen általános fájlnevek általában szimbolikus hivatkozások, amelyek a könyvtárat tartalmazó tényleges fájlra mutatnak, amelynek neve tartalmazza a pontos verziószámot. A glibc
esetében ez a szimbolikus link így néz ki:
$ ls -l /lib/x86_64-linux-gnu/libc.so.6 lrwxrwxrwx 1 root root 12 feb 6 22:17 /lib/x86_64-linux-gnu/libc.so.6 -> libc-2.24.so
Ez a minta, hogy a megosztott könyvtárak egy adott verzió által elnevezett fájljaira általánosabb fájlnevekkel hivatkozunk, bevett gyakorlat.
További példák a megosztott könyvtárakra: libreadline
(amely lehetővé teszi a felhasználók számára a parancssorok szerkesztését beírás közben, és támogatja az Emacs és a vi szerkesztési módokat is), libcrypt
(amely titkosítással, hasheléssel és kódolással kapcsolatos funkciókat tartalmaz), vagy libcurl
(amely egy többprotokollos fájlátviteli könyvtár).
A megosztott könyvtárak leggyakoribb helyei a Linux rendszerben a következők:
-
/lib
-
/lib32
-
/lib64
-
/usr/lib
-
/usr/local/lib
Note
|
A megosztott könyvtárak koncepciója nem kizárólag a Linuxra jellemző. A Windowsban például DLL-nek hívják őket, ami a dynamic linked libraries rövidítése. |
A megosztott könyvtárak elérési útjainak konfigurálása
A dinamikusan linkelt programokban található hivatkozásokat a dinamikus linker (ld.so
vagy ld-linux.so
) oldja fel a program futtatásakor. A dinamikus linker több könyvtárban is keres mappákat. Ezeket a mappákat a library path adja meg. A könyvtárak elérési útvonalát a /etc
mappában, nevezetesen a /etc/ld.so.conf
fájlban, illetve manapság már gyakrabban a /etc/ld.so.conf.d
mappában található fájlokban állítjuk be. Az előbbi általában csak egyetlen include
sort tartalmaz az utóbbiban található *.conf
fájlok számára:
$ cat /etc/ld.so.conf include /etc/ld.so.conf.d/*.conf
A /etc/ld.so.conf.d
mappa *.conf
fájlokat tartalmaz:
$ ls /etc/ld.so.conf.d/ libc.conf x86_64-linux-gnu.conf
Ezeknek a *.conf
fájloknak tartalmazniuk kell a megosztott könyvtárak mappáinak abszolút elérési útvonalát:
$ cat /etc/ld.so.conf.d/x86_64-linux-gnu.conf # Multiarch support /lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu
Az ldconfig
parancs gondoskodik ezen konfigurációs fájlok beolvasásáról, a fent említett szimbolikus linkek létrehozásáról, amelyek segítenek az egyes könyvtárak megtalálásában, és végül a cache fájl /etc/ld.so.cache
frissítéséről. Így az ldconfig
-t minden alkalommal el kell indítani, amikor konfigurációs fájlokat adunk hozzá vagy frissítünk.
Az ldconfig
hasznos kapcsolói:
-v
,--verbose
-
Megjeleníti a könyvtárak verziószámait, az egyes könyvtárak nevét és a létrehozott hivatkozásokat:
$ sudo ldconfig -v /usr/local/lib: /lib/x86_64-linux-gnu: libnss_myhostname.so.2 -> libnss_myhostname.so.2 libfuse.so.2 -> libfuse.so.2.9.7 libidn.so.11 -> libidn.so.11.6.16 libnss_mdns4.so.2 -> libnss_mdns4.so.2 libparted.so.2 -> libparted.so.2.0.1 (...)
Láthatjuk például, hogy a
libfuse.so.2
a tényleges megosztott objektumfájlhoz, alibfuse.so.2.9.7
-hez van linkelve. -p
,--print-cache
-
Az aktuális gyorsítótárban tárolt könyvtárak és könyvtárjelöltek listájának kinyomtatása:
$ sudo ldconfig -p 1094 libs found in the cache `/etc/ld.so.cache' libzvbi.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzvbi.so.0 libzvbi-chains.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzvbi-chains.so.0 libzmq.so.5 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzmq.so.5 libzeitgeist-2.0.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzeitgeist-2.0.so.0 (...)
Vegyük észre, hogy a gyorsítótár a linkek teljes soname-jét használja:
$ sudo ldconfig -p |grep libfuse libfuse.so.2 (libc6,x86-64) => /lib/x86_64-linux-gnu/libfuse.so.2
Ha hosszan listázzuk a /lib/x86_64-linux-gnu/libfuse.so.2
-t, akkor megtaláljuk a hivatkozást a tényleges megosztott objektumfájlra, a libfuse.so.2.9.7
-re, amely ugyanebben a mappában található:
$ ls -l /lib/x86_64-linux-gnu/libfuse.so.2 lrwxrwxrwx 1 root root 16 Aug 21 2018 /lib/x86_64-linux-gnu/libfuse.so.2 -> libfuse.so.2.9.7
Note
|
Mivel írási hozzáférést igényel az |
A fent leírt konfigurációs fájlok mellett a LD_LIBRARY_PATH
környezeti változót is használhatjuk a megosztott könyvtárak új elérési útvonalainak ideiglenes hozzáadására. Kettősponttal elválasztott (:
) mappákból áll, ahol a könyvtárakat keressük. Ha például a /usr/local/mylib
könyvtár elérési útvonalát szeretnénk hozzáadni az aktuális shell munkamenetben, akkor beírhatjuk a következőt:
$ LD_LIBRARY_PATH=/usr/local/mylib
Most ellenőrizhetjük az értékét:
$ echo $LD_LIBRARY_PATH /usr/local/mylib
Ahhoz, hogy hozzáadjuk az /usr/local/mylib
-t a shell munkamenet könyvtári elérési útvonalához, és ahhoz, hogy exportálhassuk a shellből indított összes gyermekfolyamatba, az alábbit kell beírni:
$ export LD_LIBRARY_PATH=/usr/local/mylib
Az LD_LIBRARY_PATH
környezeti változó eltávolításához írjuk be az alábbit:
$ unset LD_LIBRARY_PATH
A változtatások állandósításához írjuk be a
export LD_LIBRARY_PATH=/usr/local/mylib
a sort a Bash egyik inicializáló szkriptjébe, mint például az /etc/bash.bashrc
vagy a ~/.bashrc
.
Note
|
A |
Egy futtatható program függőségeinek keresése
Egy adott program által igényelt megosztott könyvtárak kereséséhez használjuk az ldd
parancsot, amelyet a program abszolút elérési útvonala követ. A kimenet megmutatja a megosztott könyvtárfájl elérési útvonalát, valamint azt a hexadecimális memóriacímet, ahová az betöltődött:
$ ldd /usr/bin/git linux-vdso.so.1 => (0x00007ffcbb310000) libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f18241eb000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f1823fd1000) libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f1823db6000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f1823b99000) librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f1823991000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f18235c7000) /lib64/ld-linux-x86-64.so.2 (0x00007f182445b000)
Hasonlóképpen, az ldd
-t használjuk egy megosztott objektum függőségeinek keresésére:
$ ldd /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2 (0x00007fbfed578000) linux-vdso.so.1 (0x00007fffb7bf5000)
Az -u
(vagy --unused
) opcióval az ldd
kiírja a nem használt közvetlen függőségeket (ha vannak):
$ ldd -u /usr/bin/git Unused direct dependencies: /lib/x86_64-linux-gnu/libz.so.1 /lib/x86_64-linux-gnu/libpthread.so.0 /lib/x86_64-linux-gnu/librt.so.1
A nem használt függőségek oka a linker által a bináris program készítésekor használt opciókhoz kapcsolódik. Bár a programnak nincs szüksége egy nem használt könyvtárra, az mégis linkelésre került, és az objektumfájlról szóló információban NEEDED
-ként lett megjelölve. Ezt olyan parancsokkal vizsgálhatjuk meg, mint a readelf
vagy az objdump
, amelyeket hamarosan a gondolkodtató feladatokban fogunk használni.
Gyakorló feladatok
-
Osszuk fel részekre a következő megosztott könyvtárneveket:
Teljes fájlnév Könyvtár neve so suffix Verziószám linux-vdso.so.1
libprocps.so.6
libdl.so.2
libc.so.6
libsystemd.so.0
ld-linux-x86-64.so.2
-
Fejlesztettünk egy szoftvert és egy új megosztott könyvtárat szeretnénk hozzáadni a rendszerünkhöz (
/opt/lib/mylib
). Ennek abszolút elérési útját egymylib.conf
nevű fájlba írjuk.-
Melyik mappában kell elhelyeznünk ezt a fájlt?
-
Milyen parancsot kell futtatnunk, hogy a módosítások teljeskörűen érvénybe lépjenek?
-
-
Milyen parancsot kellene használnunk a
kill
-hez szükséges megosztott könyvtárak listázására?
Gondolkodtató feladatok
-
Az
objdump
egy parancssori segédprogram, amely megjeleníti az objektumfájlok információit. Ellenőrizzük awhich objdump
segítségével, hogy telepítve van-e a rendszerünkben! Ha nincs, telepítsük fel!-
Használjuk az
objdump
-ot a-p
(vagy--private-headers
) kapcsolóval és agrep
-pel aglibc
függőségek kiírásához: -
Használjuk az
objdump
-t a-p
(vagy--private-headers
) kapcsolóval és agrep
-pel aglibc
soname kiírásához: -
Használjuk az
objdump
-t a-p
(vagy--private-headers
) kapcsolóval és agrep
-pel a Bash függőségek kiírásához:
-
Összefoglalás
Ebben a leckében megtanultuk:
-
Mi a megosztott (vagy dinamikus) könyvtár (library).
-
A megosztott és a statikus könyvtárak közötti különbségeket.
-
A megosztott könyvtárak neveit (sonames).
-
A megosztott könyvtárak előnyben részesített helyeit a Linux rendszerben, mint például a
/lib
vagy az/usr/lib
. -
A dinamikus linker
ld.so
(vagyld-linux.so
) célját. -
A megosztott könyvtárak elérési útvonalainak beállítása az
/etc/
állományok segítségével, mint például azld.so.conf
vagy azld.so.conf.d
mappában található állományok. -
Hogyan konfigurálhatjuk a megosztott könyvtárak elérési útvonalait az
LD_LIBRARY_PATH
környezeti változó segítségével. -
Hogyan keressük meg a végrehajtható és megosztott könyvtárak függőségeit.
A leckében használt parancsok:
ls
-
Mappa tartalmának kilistázása.
cat
-
Fájlok összefűzése és standard outputra való kiíratása.
sudo
-
A parancsot a rendszergazdai jogosultságokkal rendelkező superuser hajtsa végre.
ldconfig
-
A dinamikus linker futásidejű hozzárendeléseinek konfigurálása.
echo
-
Egy környezeti változó értékének kiíratása.
export
-
A környezeti változó értékének exportálása a gyerek shellekbe.
unset
-
Környezeti változó eltávolítása.
ldd
-
Egy program megosztott objektumfüggőségének kiírása.
readelf
-
ELF fájlokkal kapcsolatos információk megjelenítése (az ELF a executable and linkable format (végrehajtható és linkelhető formátum) rövidítése).
objdump
-
Objektumfájlok információinak kiírása.
Válaszok a gyakorló feladatokra
-
Osszuk fel részekre a következő megosztott könyvtárneveket:
Teljes fájlnév Könyvtár neve so suffix Verziószám linux-vdso.so.1
linux-vdso
so
1
libprocps.so.6
libprocps
so
6
libdl.so.2
libdl
so
2
libc.so.6
libc
so
6
libsystemd.so.0
libsystemd
so
0
ld-linux-x86-64.so.2
ld-linux-x86-64
so
2
-
Fejlesztettünk egy szoftvert és egy új megosztott könyvtárat szeretnénk hozzáadni a rendszerünkhöz (
/opt/lib/mylib
). Ennek abszolút elérési útját egymylib.conf
nevű fájlba írjuk.-
Melyik mappában kell elhelyeznünk ezt a fájlt?
/etc/ld.so.conf.d
-
Milyen parancsot kell futtatnunk, hogy a módosítások teljeskörűen érvénybe lépjenek?
ldconfig
-
-
Milyen parancsot kellene használnunk a
kill
-hez szükséges megosztott könyvtárak listázására?ldd /bin/kill
Válaszok a gondolkodtató feladatokra
-
Az
objdump
egy parancssori segédprogram, amely megjeleníti az objektumfájlok információit. Ellenőrizzük awhich objdump
segítségével, hogy telepítve van-e a rendszerünkben! Ha nincs, telepítsük fel!-
Használjuk az
objdump
-ot a-p
(vagy--private-headers
) kapcsolóval és agrep
-pel aglibc
függőségek kiírásához:objdump -p /lib/x86_64-linux-gnu/libc.so.6 | grep NEEDED
-
Használjuk az
objdump
-t a-p
(vagy--private-headers
) kapcsolóval és agrep
-pel aglibc
soname kiírásához:objdump -p /lib/x86_64-linux-gnu/libc.so.6 | grep SONAME
-
Használjuk az
objdump
-t a-p
(vagy--private-headers
) kapcsolóval és agrep
-pel a Bash függőségek kiírásához:objdump -p /bin/bash | grep NEEDED
-