Dlaczego nie mogę zainstalować wielu wersji wspólnej biblioteki?

10

Często zdarza się, że określony program będzie zależał od wersji biblioteki xy, a inny na xz, ale, o ile mi wiadomo, żaden menedżer pakietów nie pozwoli mi zainstalować zarówno xy, jak i xz. Czasami pozwolą na obie główne wersje (takie jak qt4 i qt5, które można zainstalować w tym samym czasie), ale (pozornie) nigdy niewielkie wersje.

Dlaczego to? Jak jest czynnik ograniczający, który temu zapobiega? Zakładam, że musi istnieć dobry powód, aby nie zezwolić na tę pozornie przydatną funkcję. Np. Czy nie ma pola wskazującego, którą wersję załadować podczas ładowania obiektu współdzielonego, a zatem nie ma sposobu, aby Linux wiedział, jak zdecydować, który załadować? Czy naprawdę nie ma tego powodu? Czy wszystkie mniejsze wersje powinny być kompatybilne czy coś?

Tyler
źródło

Odpowiedzi:

13

W rzeczywistości można zainstalować wiele wersji biblioteki współużytkowanej, jeśli zostanie ona wykonana poprawnie.

Biblioteki współdzielone zwykle mają następujące nazwy:

lib<name>.so.<api-version>.<minor>

Następnie znajdują się dowiązania symboliczne do biblioteki pod następującymi nazwami:

lib<name>.so
lib<name>.so.<api-version>

Gdy programista łączy się z biblioteką, aby utworzyć plik binarny, to nazwa pliku kończy się na .sotym, który znajduje linker. W danym momencie może istnieć tylko jedna z nich, <name>ale oznacza to tylko, że programista nie może jednocześnie atakować wielu różnych wersji biblioteki. W przypadku menedżerów pakietów to .sodowiązanie symboliczne jest częścią osobnego -devpakietu, który tylko programiści muszą zainstalować.

Gdy linker znajdzie plik o nazwie kończącej się na .soi używa go, szuka w tej bibliotece pola o nazwie soname . Soname doradza linkerowi, jaką nazwę pliku umieścić w wynikowym pliku binarnym, a zatem jaka nazwa pliku będzie poszukiwana w czasie wykonywania. Soname ma być ustawiony lib<name>.so.<api-version>.

Dlatego w czasie wykonywania dynamiczny linker będzie tego szukał lib<name>.so.<api-version>i używał.

Chodzi o to, aby:

  • <minor>Uaktualnienia nie zmieniają interfejsu API biblioteki, a gdy zostaną one <minor>zderzone z wyższą wersją, można bezpiecznie zaktualizować wszystkie pliki binarne do nowej wersji. Ponieważ wszystkie pliki binarne szukają biblioteki pod lib<name>.so.<api-version>nazwą, która jest dowiązaniem symbolicznym do najnowszej zainstalowanej lib<name>.so.<api-version>.<minor>, otrzymują aktualizację.
  • <api-version>Uaktualnienia zmieniają interfejs API biblioteki i nie jest bezpieczne zezwalanie istniejącym aplikacjom binarnym na używanie nowej wersji. W przypadku <api-version>zmiany, ponieważ te aplikacje szukają nazwy, lib<name>.so.<api-version>ale mają inną wartość <api-version>, nie wybiorą nowej wersji.

Menedżerowie pakietów często nie pakują więcej niż jednej wersji tej samej biblioteki w tej samej wersji dystrybucji, ponieważ cała dystrybucja, w tym wszystkie pliki binarne korzystające z biblioteki, jest zwykle kompilowana w celu użycia spójnej wersji każdej biblioteki przed dystrybucją wydany. Zapewnienie, że wszystko jest spójne i że wszystko w dystrybucji jest kompatybilne ze wszystkim innym, stanowi dużą część obciążenia dla dystrybutorów.

Ale możesz łatwo skończyć z wieloma wersjami biblioteki, jeśli zaktualizowałeś system z jednej wersji swojej dystrybucji do innej i nadal masz kilka starszych pakietów wymagających starszych wersji bibliotek. Przykład:

  • libmysqlclient16 ze starszego Debiana, zawiera libmysqlclient.so.16.0.0i dowiązanie symboliczne libmysqlclient.so.16.
  • libmysqlclient18 z obecnego Debiana, zawiera libmysqlclient.so.18.0.0i dowiązanie symboliczne libmysqlclient.so.18.
Celada
źródło
4

Ta funkcja nie jest niedozwolona, ​​po prostu nie jest bardzo powszechna z powodu sposobu, w jaki działa większość numeracji bibliotek oraz z powodu niedogodności związanych ze zmianami nazw pakietów.

Jeśli używasz schematu z kropkowanymi numerami wersji XYZ Wersja „mikro” Z często zmienia się w przypadku poprawek błędów, „niewielka” liczba Y zmienia się w przypadku zmian zgodnych z poprzednimi wersjami, a „wersja główna” wersja X musi się zmieniać w przypadku zmian interfejsu API (a czasem główna dodatkowa funkcjonalność).

Nigdy nie powinien istnieć powód, dla którego nie chcesz naprawiać najnowszych błędów, a zmiany kompatybilne wstecz nie powinny również powodować uszkodzenia oprogramowania.

Jeśli biblioteka jest rozwijana w ten sposób, zawsze powinno być możliwe zastąpienie XYZ przez X. (Y + m). (Z + n). dla dowolnego danego m i n. Tzn. Zawsze powinieneś być w stanie zastąpić swoją bibliotekę najnowszą z tej samej serii numerów głównych. A jeśli programiści bibliotek są ostrożni, a następny numer główny jest zgodny (np. Przez ogłoszenie o wycofaniu rzeczy, ale jeszcze ich nie usuwa), możesz nawet użyć następnego numeru głównego.

Dla twórców pakietów oznacza to, że mogą używać nazwy tylko z jednym lub nawet bez numeru, aby uzyskać najnowszą wersję, po prostu aktualizując pakiet. Jeśli wysyłają bibliotekę w pakiecie abc2, muszą przejść przez obręcze, aby przenieść własne oprogramowanie, które polegało na abc2aktualizacji do użycia abc3, czasami z pakietami przejściowymi. Bardziej wygodne jest pominięcie głównego numeru wersji z biblioteki, jeśli działa to w przypadku większości zależnych pakietów. Więc nawet jeśli oba abc2i abc3powinny być dostępne w pewnym momencie dostępne w dystrybucji, abc3nazywany jest często abc(jak abc2nazywano kiedy nie było abc3jeszcze), i tak szybko, jak żadne pakiety zależą abc2w dystrybucji staje się możliwe do spadkuabc2 całkowicie.

Schemat numerowania nie jest jednolicie przestrzegany, ale mogę sobie tylko wyobrazić, że wraz z pojawieniem się Internetu rozpowszechniającego informacje na temat korzystania z takiego schematu oraz presji ze strony użytkowników bibliotek (w tym programistów dystrybucji), aby wyjaśnić ważne rzeczy, takie jak zgodność wsteczna bez czytając plik CHANGES zawarty w bibliotece, sprawili, że stało się to bardziej powszechne.

Przykładem licznika, ale nie biblioteki, jest interpreter Pythona, który nie jest kompatybilny z jego obiektami współdzielonymi i formatem wytrawiania przy niewielkiej zmianie liczby. Dlatego zobaczysz pakiety dla Pythona (najnowsze z serii 2.7) i python3 (najnowsze z obecnie serii Python3.4), a także jawne pakiety dla Pythona 2.6 (coraz mniej popularne), a także Python 3.3.

Anthon
źródło