Linux je svým způsobem série statických a dynamických knihoven, které jsou na sobě závislé. Pro nové uživatele systémů založených na Linuxu může být celá manipulace s knihovnami záhadou. Ale se zkušenostmi může být obrovské množství sdíleného kódu zabudovaného do operačního systému výhodou při psaní nových aplikací.
Abychom vám pomohli dostat se do kontaktu s tímto tématem, připravil jsem malý příklad aplikace, který ukazuje nejběžnější metody, které fungují na běžných distribucích Linuxu (tyto nebyly testovány na jiných systémech). Chcete-li pokračovat v tomto praktickém kurzu pomocí vzorové aplikace, otevřete příkazový řádek a zadejte:
$ git klon https://github.com/hANSIc99/library_sample
$ cd library_sample/
$ make
cc -c main.c -Wall -Werror
cc -c libmy_static_a.c -o libmy_static_a.o -Wall -Werror
cc -c libmy_static_b.c -o libmy_static_b.o -Wall -Werror
ar -rsv libmy_static.a libmy_static_a.o libmy_static_b.o
ar:vytvoření libmy_static.a
a - libmy_static_a.o
a - libmy_static_b.o
cc -c -fPIC libmy_shared.c -o libmy_shared.o
cc - shared -o libmy_shared.so libmy_shared.o
$ make clean
rm *.o
Po provedení těchto příkazů by měly být tyto soubory přidány do adresáře (spusťte ls
vidět je):
moje_aplikace
libmy_static.a
libmy_shared.so
O statickém propojení
Když se vaše aplikace propojí se statickou knihovnou, kód knihovny se stane součástí výsledného spustitelného souboru. To se provádí pouze jednou v době propojení a tyto statické knihovny obvykle končí .a
rozšíření.
Statická knihovna je archiv (ar) objektových souborů. Objektové soubory jsou obvykle ve formátu ELF. ELF je zkratka pro Executable and Linkable Format, který je kompatibilní s mnoha operačními systémy.
Výstup file
příkaz vám řekne, že statická knihovna libmy_static.a
je ar
typ archivu:
$ soubor libmy_static.a
libmy_static.a:aktuální archiv ar
Pomocí ar -t
, můžete nahlédnout do tohoto archivu; ukazuje dva objektové soubory:
$ ar -t libmy_static.a
libmy_static_a.o
libmy_static_b.o
Soubory archivu můžete extrahovat pomocí ar -x <archive-file>
. Extrahované soubory jsou objektové soubory ve formátu ELF:
$ ar -x libmy_static.a
$ soubor libmy_static_a.o
libmy_static_a.o:ELF 64bitový LSB přemístitelný, x86-64, verze 1 (SYSV), není odstraněn
O dynamickém propojení
Další zdroje pro Linux
- Cheat pro příkazy Linuxu
- Cheat sheet pro pokročilé příkazy systému Linux
- Bezplatný online kurz:Technický přehled RHEL
- Síťový cheat pro Linux
- Cheat sheet SELinux
- Cheat pro běžné příkazy pro Linux
- Co jsou kontejnery systému Linux?
- Naše nejnovější články o Linuxu
Dynamické propojování znamená použití sdílených knihoven. Sdílené knihovny obvykle končí .so
(zkratka pro "shared object").
Sdílené knihovny jsou nejběžnějším způsobem správy závislostí na systémech Linux. Tyto sdílené prostředky jsou načteny do paměti před spuštěním aplikace, a když několik procesů vyžaduje stejnou knihovnu, bude načtena do systému pouze jednou. Tato funkce šetří využití paměti aplikací.
Další věc, kterou je třeba poznamenat, je, že když je chyba opravena ve sdílené knihovně, bude z toho profitovat každá aplikace, která na tuto knihovnu odkazuje. To také znamená, že pokud chyba zůstane neodhalena, bude jí trpět každá odkazující aplikace (pokud aplikace používá postižené části).
Pro začátečníky může být velmi obtížné, když aplikace vyžaduje konkrétní verzi knihovny, ale linker zná pouze umístění nekompatibilní verze. V tomto případě musíte pomoci linkeru najít cestu ke správné verzi.
Ačkoli to není každodenní problém, pochopení dynamického propojení vám jistě pomůže při řešení takových problémů.
Naštěstí jsou mechanismy pro to docela jednoduché.
Chcete-li zjistit, které knihovny jsou nutné pro spuštění aplikace, můžete použít ldd
, který vytiskne sdílené knihovny používané daným souborem:
$ ldd moje_aplikace
linux-vdso.so.1 (0x00007ffd1299c000)
libmy_shared.so => nenalezeno
libc.so.4.6 => /lib c.6 (0x00007f56b869b000)
/lib64/ld-linux-x86-64.so.2 (0x00007f56b8881000)
Všimněte si, že knihovna libmy_shared.so
je součástí úložiště, ale nebyl nalezen. Je to proto, že dynamický linker, který je zodpovědný za načtení všech závislostí do paměti před spuštěním aplikace, nemůže najít tuto knihovnu ve standardních umístěních, která prohledává.
Chyby spojené s linkery nacházejícími nekompatibilní verze běžných knihoven (jako bzip2
, například) může být pro nového uživatele značně matoucí. Jedním ze způsobů, jak to obejít, je přidat složku úložiště do proměnné prostředí LD_LIBRARY_PATH
sdělit linkeru, kde má hledat správnou verzi. V tomto případě je správná verze v této složce, takže ji můžete exportovat:
$ LD_LIBRARY_PATH=$(pwd):$LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH
Nyní dynamický linker ví, kde knihovnu najít, a aplikaci lze spustit. Můžete znovu spustit ldd
k vyvolání dynamického linkeru, který zkontroluje závislosti aplikace a načte je do paměti. Adresa paměti se zobrazí za cestou k objektu:
$ ldd moje_aplikace
linux-vdso.so.1 (0x00007ffd385f7000)
libmy_shared.so => /home/stephan/library_sample/libmy_so.0.0. 0. 6 => /lib64/libc.so.6 (0x00007f3fad21d000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3fad408000)
Chcete-li zjistit, který linker je vyvolán, můžete použít file
:
$ file my_app
my_app:ELF 64bitový LSB spustitelný soubor, x86-64, verze 1 (SYSV), dynamicky propojený, interpret /lib64/ld-linux-x86-64.so.2, BuildID[ sha1]=26c677b771122b4c99f0fd9ee001e6c743550fa6, pro GNU/Linux 3.2.0, neodstraněno
Linker /lib64/ld-linux-x86–64.so.2
je symbolický odkaz na ld-2.30.so
, což je výchozí linker pro moji distribuci Linuxu:
$ soubor /lib64/ld-linux-x86-64.so.2
/lib64/ld-linux-x86-64.so.2:symbolický odkaz na ld-2.31.so
Při pohledu zpět na výstup ldd
, můžete také vidět (vedle libmy_shared.so
), že každá závislost končí číslem (např. /lib64/libc.so.6
). Obvyklé schéma pojmenování sdílených objektů je:
**lib** XYZ.so **.<MAJOR>** . **<MINOR>**
V mém systému libc.so.6
je také symbolickým odkazem na sdílený objekt libc-2.30.so
ve stejné složce:
$ soubor /lib64/libc.so.6
/lib64/libc.so.6:symbolický odkaz na libc-2.31.so
Pokud se potýkáte s problémem, že se aplikace nespustí, protože načtená knihovna má špatnou verzi, je velmi pravděpodobné, že tento problém můžete vyřešit kontrolou a přeskupením symbolických odkazů nebo zadáním správné vyhledávací cesty (viz „Dynamický zavaděč :ld.so" níže).
Další informace naleznete na ldd
manuálová stránka.
Dynamické načítání
Dynamické načítání znamená, že knihovna (např. .so
soubor) se načítá během běhu programu. To se provádí pomocí určitého programovacího schématu.
Dynamické načítání se použije, když aplikace používá pluginy, které lze za běhu upravit.
Viz dlopen
manuálová stránka pro více informací.
Dynamický nakladač:ld.so
V Linuxu se většinou zabýváte sdílenými objekty, takže musí existovat mechanismus, který zjistí závislosti aplikace a nahraje je do paměti.
ld.so
hledá sdílené objekty na těchto místech v následujícím pořadí:
- Relativní nebo absolutní cesta v aplikaci (pevně zakódovaná pomocí
-rpath
možnost kompilátoru na GCC) - V proměnné prostředí
LD_LIBRARY_PATH
- V souboru
/etc/ld.so.cache
Mějte na paměti, že přidání knihovny do archivu systémové knihovny /usr/lib64
vyžaduje oprávnění správce. Můžete zkopírovat libmy_shared.so
ručně do archivu knihovny a zprovozněte aplikaci bez nastavení LD_LIBRARY_PATH
:
zrušte nastavení LD_LIBRARY_PATH
sudo cp libmy_shared.so /usr/lib64/
Když spustíte ldd
, nyní můžete vidět cestu k archivu knihovny:
$ ldd moje_aplikace
linux-vdso.so.1 (0x00007ffe82fab000)
libmy_shared.so => /lib64/libmy_shared.so =(0x00007f00096) <> 0x00007f00096. lib64/libc.so.6 (0x00007f0a96216000)
/lib64/ld-linux-x86-64.so.2 (0x00007f0a96401000)
Přizpůsobení sdílené knihovny v době kompilace
Pokud chcete, aby vaše aplikace používala vaše sdílené knihovny, můžete během kompilace zadat absolutní nebo relativní cestu.
Upravte makefile (řádek 10) a znovu zkompilujte program vyvoláním make -B
. Poté výstup ldd
zobrazuje libmy_shared.so
je uvedena se svou absolutní cestou.
Změňte toto:
CFLAGS =-Wall -Werror -Wl,-rpath,$(shell pwd)
K tomu (nezapomeňte upravit uživatelské jméno):
CFLAGS =/home/stephan/library_sample/libmy_shared.so
Poté znovu zkompilujte:
$ make
Potvrďte, že používá absolutní cestu, kterou jste nastavili, kterou můžete vidět na řádku 2 výstupu:
$ ldd moje_aplikace
linux-vdso.so.1 (0x00007ffe143ed000)
libmy_shared.so => /lib64/libmy_shared.so (0x00007fe50_0) /redhobr/amp0 my .so (0x00007fe509268000)
libc.so.6 => /lib64/libc.so.6 (0x00007fe50909e000)
) /lib64/ld-804-so.06009 před>Toto je dobrý příklad, ale jak by to fungovalo, kdybyste vytvářeli knihovnu pro ostatní? Nová umístění knihoven lze zaregistrovat jejich zapsáním do
/etc/ld.so.conf
nebo vytvoření<library-name>.conf
soubor obsahující umístění pod/etc/ld.so.conf.d/
. Potéldconfig
musí být proveden k přepsáníld.so.cache
soubor. Tento krok je někdy nezbytný po instalaci programu, který s sebou přináší některé speciální sdílené knihovny.Viz
ld.so
manuálová stránka pro více informací.Jak zacházet s více architekturami
Obvykle existují různé knihovny pro 32bitové a 64bitové verze aplikací. Následující seznam ukazuje jejich standardní umístění pro různé distribuce Linuxu:
Rodina Red Hat
- 32bitový:
/usr/lib
- 64bitový:
/usr/lib64
Rodina Debian
- 32bitový:
/usr/lib/i386-linux-gnu
- 64bitový:
/usr/lib/x86_64-linux-gnu
Rodina Arch Linux
- 32bitový:
/usr/lib32
- 64bitový:
/usr/lib64
FreeBSD (technické, nikoli distribuce Linuxu)
- 32bit:
/usr/lib32
- 64bit:
/usr/lib
Vědět, kde tyto klíčové knihovny hledat, může způsobit, že nefunkční odkazy knihoven se stanou problémem minulosti.
I když to může být zpočátku matoucí, pochopení správy závislostí v linuxových knihovnách je způsob, jak mít pocit kontroly nad operačním systémem. Projděte si tyto kroky s jinými aplikacemi, abyste se seznámili s běžnými knihovnami a dále se učili, jak opravit jakékoli problémy s knihovnami, které by se mohly objevit.