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}