GNU/Linux >> Znalost Linux >  >> Linux

K čemu slouží možnost „soname“ pro vytváření sdílených knihoven?

soname se používá k označení, jakou kompatibilitu binárních rozhraní API vaše knihovna podporuje.

SONAME se používá v době kompilace linkerem k určení skutečné verze cílové knihovny ze souboru knihovny. gcc -lNAME bude hledat libNAME .so odkaz nebo soubor pak zachyťte jeho SONAME, které bude jistě konkrétnější (např. libnuke.so odkazuje na libnuke.so.0.1.4, který obsahuje SONAME libnuke.so.0).

Za běhu se to spojí s tímto je pak nastaveno do ELF dynamické sekce NEEDED , pak by knihovna s tímto názvem (nebo odkazem na něj) měla existovat. V době spuštění SONAME je ignorován, takže stačí pouze odkaz nebo existence souboru.

Poznámka:SONAME je vynuceno pouze v době propojení/sestavení a nikoli v době spuštění.

'SONAME' knihovny lze vidět pomocí 'objdump -p soubor |grep SONAME'. 'NEEDED' binárních souborů lze vidět pomocí 'objdump -p soubor |grep NEEDED'.

[EDITACE] VAROVÁNÍ Následuje obecná poznámka, ne ta, která je nasazena v linuxu. Viz na konci.

Předpokládejme, že máte knihovnu s názvem libnuke.so.1.2 a vyvíjíte novou knihovnu libnuke:

  • pokud je vaše nová knihovna opravou z předchozí bez změny rozhraní API, měli byste ponechat stejné soname a zvýšit verzi názvu souboru. tj. soubor bude libnuke.so.1.2.1, ale soname bude stále libnuke.so.1.2.
  • pokud máte novou knihovnu, která pouze přidala novou funkci, ale nenarušila funkčnost a je stále kompatibilní s předchozí, chtěli byste použít stejné soname jako předchozí a navíc novou příponu jako .1. tj. soubor a soname budou libnuke.so.1.2.1. Jakýkoli program spojený s libnuke.1.2 bude stále fungovat s tímto. Nové programy spojené s libnuke.1.2.1 budou fungovat pouze s tímto (dokud nová subverze nepřijde jako libnuke.1.2.1.1).
  • pokud vaše nová knihovna není kompatibilní s žádnou libnuke:libnuke.so.2
  • pokud je vaše nová knihovna kompatibilní s holou starou verzí:libnuke.so.1.3 [tj. stále kompatibilní s libnuke.so.1]

[UPRAVIT] pro dokončení:případ linux.

V reálném životě linuxu SONAME jako specifická forma :lib[NAME][API-VERSION].so.[major-version]major-version je pouze jedno celé číslo, které se zvyšuje při každé větší změně knihovny.API-VERSION je ve výchozím nastavení prázdná

ex libnuke.so.0

Pak skutečný název souboru zahrnuje menší verze a podverze, např.:libnuke.so.0.1.5

Myslím, že neposkytnutí soname je špatný postup, protože přejmenování souboru změní jeho chování.


Vytvořili jste dynamickou knihovnu s názvem libx.1.0.0 v tradici pojmenování libname.{a}.{b}.{c}

{a} stand for primary version, should changes when APIs changes(which making things incompatible).
{b} stand for sub version, should changes by adding APIs.
{c} stand for mirror version, should changes by bug fixing or optimizing

Nyní vydáváte libx.1.2.0 a musíte prohlásit, že libx.1.2.0 je kompatibilní s libx.1.0.0, protože pouhé přidání funkcí a spustitelného souboru lidí by nespadlo, stačí jej propojit jako za starých časů pomocí:

Nastavení libx.1.0.0 a libx.1.2.0 tak, aby měly stejné soname, například libx.1

To je to, co dělá soname.


Zde je příklad podporující odpověď Johanna Klaska.

Stručně řečeno, SONAME je potřeba za běhu. V době kompilace je potřeba pouze jméno linkeru nebo skutečné jméno (např. g++ main.cpp -L. -ladd nebo g++ main.cpp -L. -l:libadd.so.1.1 ). Definice názvu linkeru a skutečného jména se řídí HOWTO knihovny programů:3. Sdílené knihovny.

Zdrojový strom:

├── add.cpp
├── add.h
├── main.cpp
└── Makefile

Makefile:

SOURCE_FILE=add.cpp
# main.cpp includes `add.h`, whose implementation is `add.cpp`
MAIN_FILE=main.cpp
SONAME=libadd.so.1
REAL_NAME=libadd.so.1.1
LINKER_NAME=libadd.so
OUTPUT_FILE=a.out

all:
   g++ -shared -fPIC -Wl,-soname,${SONAME} -o ${REAL_NAME} ${SOURCE_FILE}
   ln -s ${REAL_NAME} ${LINKER_NAME}
   g++ main.cpp -I. -L. -ladd -o ${OUTPUT_FILE} 
   # Same as `ldconfig -n .`, creates a symbolic link
   ln -s ${REAL_NAME} ${SONAME}
   #./a.out: error while loading shared libraries: libadd.so.1: cannot open 
   # shared object file: No such file or directory
   LD_LIBRARY_PATH=. ./${OUTPUT_FILE}
clean:
   rm ${SONAME} ${REAL_NAME} ${LINKER_NAME} ${OUTPUT_FILE}

Linux
  1. Jaká je nejlepší distribuce Linuxu pro začátečníky?

  2. „který“ ekvivalent pro sdílené knihovny?

  3. Jak zkontrolovat, jaké sdílené knihovny jsou načteny za běhu pro daný proces?

  1. Jaký je ekvivalent C++ pro AutoResetEvent pod Linuxem?

  2. Jaké je výchozí kořenové heslo pro MySQL 5.7

  3. Jaký je důvod, proč rmdir(1) a rm(1) koexistují?

  1. Jaké je správné umístění proměnné PS1 Shell?

  2. Jaká je doporučená velikost pro Linux /boot oddíl?

  3. Co je nástroj syslog pro auditované protokoly?