Linux - piekło zależności - jakie są przyczyny

0

Witajcie

Wikipedia podaje:

Piekło zależności (ang. Dependency hell) – potoczny termin określający błędnie zdefiniowane lub trudne do spełnienia zależności, uniemożliwiające lub utrudniające instalację oprogramowania.

Trudne do spełnienia zależności występują na przykład w wypadku instalowania** dwóch aplikacji, z których każda wymaga innej wersji tego samego programu** (oba są od niego zależne).

1)Dlaczego biblioteka która jest niezbędna DANEJ aplikacji jest instalowana w systemie? Czy nie powinna być ona tak jakby z plikiem wykonywalnym - jak na Windows - gdy potrzebuje SFML to dołączam niezbędne *.dll'ki do folderu z *.exe i się nie martwię jakimiś zaleznościami.
Jeżeli aplikacja wymaga SFML 1.6 to ma ze sobą *.dll'ki SFML 1.6.

Albo gdy aplikacja wymaga starej wersji np glibc czy jakieś innej biblioteki - powinna ją zlinkować statycznie lub mieć ze sobą razem z plikiem wykonywalnym.

2)Jeżeli chodzi jeszcze o zależności - podkreśliłem ten fragment definicji z Wikipedii:

dwóch aplikacji, z których każda wymaga innej wersji tego samego programu

Czy to możliwe że aplikacja wymaga serwera X w wersji 123.45 a druga aplikacja potrzebuje do działania serwera X w wersji 234.56 ?
Jeżeli tak to jak ten problem został rozwiązany na Windowssie - mi się nigdy nie zdażyło by aplikacja mówiła Twój Windows ma zbyt nowoczesny menadzer okien ;)

0

Czy nie powinna być ona tak jakby z plikiem wykonywalnym

Pod Linuksem właściwie nie ma czegoś takiego jak "jakby z plikiem wykonywalnym". Wszystko, każda najmniejsza pierdoła, jest instalowane w /bin albo w /usr/local/bin.
Choć teoretycznie możliwe jest by każdy program miał osobny katalog jak pod Windows, to tak jednak się nie robi.

0
kacper546 napisał(a):

1)Dlaczego biblioteka która jest niezbędna DANEJ aplikacji jest instalowana w systemie?

Nieprawda, jak najbardziej można dystrybuować aplikację wraz z wymaganymi bibliotekami, oraz umieszczać biblioteki dynamiczne w dowolny katalogu (z wykorzystaniem zmiennej środowiskowej LD_LIBRARY_PATH)

kacper546 napisał(a):

Albo gdy aplikacja wymaga starej wersji np glibc czy jakieś innej biblioteki - powinna ją zlinkować statycznie lub mieć ze sobą razem z plikiem wykonywalnym.

Z glibc to akurat może być problem - jeśli masz za stary aplikacja może wymagać "update systemu". Większość innych bibliotek, albo można linkować statycznie, albo można dystrybuować z aplikacją.

kacper546 napisał(a):

Czy to możliwe że aplikacja wymaga serwera X w wersji 123.45 a druga aplikacja potrzebuje do działania serwera X w wersji 234.56 ?

Teoretycznie możliwe, ale do rozwiązania. Można np. postawić dwie instancje danego serwera.

Azarien napisał(a):

Czy nie powinna być ona tak jakby z plikiem wykonywalnym

Pod Linuksem właściwie nie ma czegoś takiego jak "jakby z plikiem wykonywalnym". Wszystko, każda najmniejsza pierdoła, jest instalowane w /bin albo w /usr/local/bin.
Choć teoretycznie możliwe jest by każdy program miał osobny katalog jak pod Windows, to tak jednak się nie robi.

W przeciwieństwie do tego co kolega mówi to w Linuxie są pliki wykonywalne. Mogą a często są umieszczane w innych katalogach niż wspomniane.
Proponuje katalogi /bin oraz /usr/local/bin potraktować analogicznie jak c:\Windows\ oraz c:\Program Files` na Windowsach - większość aplikacji jest tam instalowana, ale nic nie stoi na przeszkodzie aby instalować gdzie indziej.

0

Na dzień dzisiejszy jest to problem raczej teoretyczny, ponieważ:

mamy rozwinięte menadżery pakietów. Ja korzystam z Debiana w domu, a w pracy na serwerach z Red Hata. I w *.deb jest coś takiego, że wypisuje się po prostu wersję niezbędne do działania. Jest np. taki program debreate w którym można dosyć szybko się tego nauczyć i tworzyć własne *.deb: http://debreate.sourceforge.net .
Problem pojawia się gdy paczka A wymaga paczki B a ta wymaga paczek C,D,E,F. Generalnie im bardziej skomplikowany soft, tym trudniej spaczkować i dobrać czego brakuje.

W teorii wygląda to tak, że początkowy problem zależności (a także ich update) powinien być rozwiązany przez managery pakietów.
I są to dobre narzędzia, ale ludzie z nich różnie korzystają: czasami wypiszą złe wersje, czasami nie wypiszą wszystkiego, a czasami wypiszą coś czego nie ma w repozytoriach.
Jednak w świecie idealnym problem zależności powinien zostać rozwiązany przez menadżery pakietów z których idealnie korzystają ludzie.

W takim Debianie mamy porządek i raczej rzadko czegoś brakuje, ale oczywiście jak trzeba skompilować ze źródeł coś czego nie ma w repozytorium, to już muszę przeanalizować te zależności.
Dla osoby zwykłej: im lepiej ktoś chce zarządzać zależnościami, tym lepiej musi znać swój manadżer pakietów i repozytoria. Wraz z doświadczeniem problem ten znika.

Na serwerach prod. mają Red Haty i na poważnym serwerze bardzo rzadko coś się instaluje, co zagraża stabilności systemu (np. najpierw się sprawdza na testowych platformach). Sys-admini siedzą całymi dniami i analizują problemy update-ów. Więc są ludzie od tego.

0
Mały ludek napisał(a)

W przeciwieństwie do tego co kolega mówi to w Linuxie są pliki wykonywalne.

Nie napisałem że nie ma plików wykonywalnych, tylko że nie ma czegoś takiego jak "katalog aplikacji" w którym byłyby wszystkie pliki z nią związane, tak jak to jest pod Windowsem.

0

@mlyszczek to chyba ty używasz dziwacznej dystrybucji, skoro menedżer pakietów z oficjalnego repo ładuje ci pliki do /opt i to jeszcze do podkatalogów. Jak długo zyję, jeszcze takich cudów nie widziałem (debian, ubuntu, redhat, centos)

0

1)Dlaczego biblioteka która jest niezbędna DANEJ aplikacji jest instalowana w systemie? Czy nie powinna być ona tak jakby z plikiem wykonywalnym - jak na Windows - gdy potrzebuje SFML to dołączam niezbędne *.dll'ki do folderu z *.exe i się nie martwię jakimiś zaleznościami.
Jeżeli aplikacja wymaga SFML 1.6 to ma ze sobą *.dll'ki SFML 1.6.

Albo gdy aplikacja wymaga starej wersji np glibc czy jakieś innej biblioteki - powinna ją zlinkować statycznie lub mieć ze sobą razem z plikiem wykonywalnym.

Współdzielenie bibliotek pozwala nie tylko zmniejszyć wykorzystanie dysku, ale też RAMu. Producenci programów Windowsowych wybrali inny model dystrybucji, pewnie dlatego, że na Windowsie na ma żadnego menedżera pakietów.

Z drugiej strony, na Windowsie też jest problem z różnymi wersjami bibliotek naraz mimo, że producenci i tak zwykle wrzucają DLLki obok EXEków. Jest coś takiego jak "Microsoft Visual C++ Redistributable" i zwykle jest to zainstalowane w wielu kopiach na jednym komputerze: Why Are There So Many “Microsoft Visual C++ Redistributables” Installed on My PC?

Czy to możliwe że aplikacja wymaga serwera X w wersji 123.45 a druga aplikacja potrzebuje do działania serwera X w wersji 234.56 ?
Jeżeli tak to jak ten problem został rozwiązany na Windowssie - mi się nigdy nie zdażyło by aplikacja mówiła Twój Windows ma zbyt nowoczesny menadzer okien ;)

Nie zdarzyło ci się, że aplikacja się nie uruchomiła bo masz zbyt nowoczesnego Windowsa? No to chyba mało aplikacji odpalasz ;) Jest mnóstwo staroci, które chodzą na starych Windowsach, a na nowych ich nijak nie odpalisz.

0
Wibowit napisał(a):

Jest coś takiego jak "Microsoft Visual C++ Redistributable" i zwykle jest to zainstalowane w wielu kopiach na jednym komputerze

i bywa, że każda aplikacja wymaga innej wersji, a i wersji 32 lub 64 bit więc mamy podwójny bonus :)

2

oczywiście dodam, że to nie tylko problem "Linuxa", ale szerszy co do oprogramowania:

PHP i composer ?

Python i pip ?

NodeJS i npm ?

Ruby i gemy?

Perl i cpan ?

wszędzie w oprogramowaniu jest ten problem ;)
(według mnie najprzyjemniejszy i największy porządek jest w Ruby, później PHP composer, później Python, a na końcu NodeJS... zawsze Ruby najmniej problemów miał :D... ale to tylko subiektywna opinia)

generalnie nie da się pisać oprogramowania bez systemu zależności/bibliotek/paczek/dodatków/modułów/klas (jak zwał tak zwał).

0

No popatrz, a ja najwięcej problemów z zależnościami i pakietami miałem pod RoR i gem i tym rvm. Ciągle jakieś błędy pod Linuksem. Za to najlepiej działa mi pip, jak widzisz inna dystrybucja i inny problem. Z Node,js i npm też nie miałem problemów, używam dystrybucji Archo podobnych.

1

Trzy ciekawostki w tym temacie:

  1. dla Linuxa jest projekt, który naśladuje manager pakietów z OSX:
    https://github.com/Linuxbrew/brew

nazywa się to "Linuxbrew", jest odpowiednikiem homebrew ( http://brew.sh ) .
https://en.wikipedia.org/wiki/Homebrew_(package_management_software)

generalnie linuxbrew krytykowany jest za zmniejszenie bezpieczeństwa (kwestia uprawnień i wrzucanie wszystkiego do $HOME), ale wydaje mi się dosyć ciekawym rozwiązaniem:
"It can be installed in your home directory and does not require root access. The same package manager can be used on both your Linux server and your Mac laptop."
W wolnym czasie warto sobie posprawdzać jakie pakiety są w środku (adekwatne do homebrew) : http://braumeister.org

  1. największym problemem z utworzeniem "Linux From Scratch" (stawianie Linuxa od 0) jest właśnie zaaplikowanie jakiegoś sensownego managera pakietów.
    Generalnie dużo osób dochodziło do momentu, że stawiali swojego LFS, ale nie umieli zarządzać późniejszymi zależnościami. Pojawiał się koszmar przy update.
    Teoretycznie gdyby napisać swój manager pakietów (np. coś na Pythonie opartego), to dałoby się stworzyć oddzielną dystrybucję Linuxa, bo tak naprawdę system Linux to jest kernel + manager pakietów.

  2. Slackware ma na tyle ogólne pakiety : https://slackbuilds.org
    że można próbować to instalować na każdym Linuxie, w sensie, że korzystać z tego repozytorium, np taki fork:
    https://github.com/Ponce/slackbuilds
    Można to próbować instalować na dowolnej dystrybucji, bo jest dosyć spora kompatybilność tego repozytorium wobec całego Linuxa
    (oczywiście tutaj upraszczam, ale generalnie pakiety Slackware są bardzo kompatybilne wobec całego Linuxa)
    Swoją drogą - bardzo dobrym pomysłem byłoby utworzenie bezpośrednio repozytorium właśnie w całości opartego na GitHub + Git , według mnie rozwiązałoby to sprawę zależności (wszystko na GitHub).

0

No ale powstały takie narzędzia w Pythonie do zarządzania pakietami w różnych dystrybucjach, pod Slackware jest to slpkg, a pod Gentoo/Funtoo jest Emerge/Portage. Pod Lunar Linux jest manadżer pakietów a raczej programów do kompilacji i zarządzania nimi zwany lin.

1
Czarny Pomidor napisał(a):

No ale powstały takie narzędzia w Pythonie do zarządzania pakietami w różnych dystrybucjach, pod Slackware jest to slpkg, a pod Gentoo/Funtoo jest Emerge/Portage. Pod Lunar Linux jest manadżer pakietów a raczej programów do kompilacji i zarządzania nimi zwany lin.

Hmm , korzystam z Debiana, ale akurat Slackware ma świetne te SlackBuildy.
Są to zwykłe skrypty bash.
Np. biorę sobie grę flare i SlackBuild :
https://github.com/Ponce/slackbuilds/blob/current/games/flare/flare.SlackBuild

I teraz łatwo widać, że to zwykły skrypt bash, który ustawia uprawnienia i daje parametry dla make oraz make install.
Wszystko ładnie wypisane, prefix zawarty w zmiennych, np. $PKG. Można byłoby z 3-4 pakiety przeanalizować w ten sposób skompilowane i spokojnie to dostosować do swojej dystrybucji, np. dla Debiana.

To jest akurat fajne w Slackware, że trzyma się KISS i zwykłego basha.

Akurat wolę *.deb, bo większy wybór, ale to repozytorium SlackBuildów generalnie warto mieć na uwadzę, bo można łatwo to dostosować do swoich potrzeb.

1

To nie jest niedopatrzenie czy skeuomorf po czasach kiedy dyski miały po kilka GB a ram był liczony w MB.

To jest świadoma decyzja projektantów.
Dzięki temu, że liby są współdzielone pomiędzy programami dostajemy: mniejsze programy na dysku, mniejsze w ramie, ale przede wszystkim większe bezpieczeństwo, bo aktualizacja krytyka sprowadza się do aktualizacji jednej biblioteki, a nie wszystkich programów jej używających.

Przy okazji trzeba sobie jasno powiedzieć, że jeżeli aplikacja wymaga konkretnej wersji biblioteki, to jest to wynik błędów twórców bibliotek którzy zmieniają API pomiędzy wersjami(co jest za każdym razem porażką).
Twórcy aplikacji robiąc to, zwyczajnie się bronią, przy czym tego typu obrona też nie jest dobra.

Rozwiązaniem może być no Emerge.

0

Api bibliotek zawsze się zmienia, ale z reguły jakaś wielka zmiana niekompatybilna wstecz to nowa wersja, która może istnieć w systemie obok starej (dopóki stara nie zostanie wycofana gdy straci wsparcie). Lub istnieją i są wspierane 2 wersje, patrz np gtk2 i gtk3 i całe ich api.

To zresztą uniwersalna zasada.

0

Wiem ze temat dotyczy Linuxa ale nie chciałem zakładać nowego tematu.

Dzięki temu, że liby są współdzielone pomiędzy programami dostajemy: mniejsze programy na dysku, mniejsze w ramie, ale przede wszystkim** większe bezpieczeństwo, bo aktualizacja krytyka sprowadza się do aktualizacji jednej biblioteki**, a nie wszystkich programów jej używających.

Mamy systemy z rodziny Windows każda aplikacja chce czy nie korzysta na pewnym poziomie z WinAPI - funkcję te są dostępne ponieważ przy włączaniu aplikacji loader windowsa ładuje takie biblioteki jak kernel32.dll,ntdll.dll,gdi.dll,user32.dll
Czy Microsoft popełnił kiedyś błąd w jednej z tych bibliotek? Czy też biblioteki udostępnianie przez MS są tak dobrze testowane że to się nigdy nie zdarzyło?

Pytam z ciekawości

1

Wątpię, by były niezmienne. Sprawdź czy ich zawartość się nie zmienia po aktualizacjach systemu. Najprostszy sposób to liczenie hashy regularnie i zapisywanie wyników do pliku. Zobaczysz jak często są zmieniane.

Np tutaj jest coś co wygląda na aktualizację kernel32.dll: https://support.microsoft.com/en-us/kb/3063858

1

Aktualizacje bezpieczeństwa tak ważnych bibliotek w Windows właściwie nigdy nie zmieniają jej API, więc wszystkie inne aplikacje nadal będą z nią działać bez problemu.

Co więcej, istnieje w Windows mechanizm hotpatchowania, czyli modyfikacji takich bibliotek już w uruchomionych aplikacjach (najczęściej właśnie w celu zaaplikowanie poprawek bezpieczeństwa). W linuksowym ekosystemie np. Red Hat ma podobne rozwiązanie.

0

Czyli tak:

Z zewnątrz WinAPI się nie zmienia a ewentualne błędy są łatane w jądrze lub implementacji funkcji?
Na przykład

NTSTATUS importantFunction()
{
int * ptr = nullptr;
*ptr = 1616;
return ERROR_SUCCES;
} 

zostaje zmieniony na

NTSTATUS importantFunction()
{
//int * ptr = nullptr;
//*ptr = 1616;
return RANDOM_ERROR_OTHER_THAN_SUCCES;
} 

Jednak aplikacja jest wciąż zgodna gdyż zwracany typ, liczba, typ argumentów funkcji oraz jej nazwa pozostały nie zmienione?

Wiem też że te biblioteki się zmieniają, pisze o tym na swoim blogu @Gynvael Coldwind
Na przykład: http://gynvael.coldwind.pl/?id=124 - Windows 7 - lista zmian w exportach kernel32.dll
To zresztą wyjaśnia dlaczego nie powinno się używać starych funkcji do obłsugi rejestru.

Warto wiedzieć, że istnieje też funkcja RegOpenKey o znacznie prostszej składni, jednak pochodzi ona jeszcze z czasów Windows 3.1 (gdzie, jak wiemy, Rejestru w znanej nam formie właściwie nie było) i jej stosowanie nie jest zalecane.

http://cpp0x.pl/kursy/Kurs-WinAPI-C++/Podstawy/Rejestr/193

Byłem tylko ciekaw czy Microsoftowi zdarzyły się błędy bezpieczeństwa - nie znam, jakieś tam przepełnienie bufora czy stosu - i jak (oraz czy ;) ) je ewentualnie naprawiał.

Jeżeli wywołałbym funkcję z WinAPI z poziomu mojej aplikacji to czy błąd zabił by system czy tylko moją aplikację? Ja sadzę że aplikację ale nie jestem pewien.

#EDIT
Po pierwsze nienawidzę WinAPI a zwłaszcza rejestru ale ciekawi mnie jeszcze** dlaczego parametry niektórych funkcji są zarezerwowane?**
Microsoft przy projektowaniu API się pomylił czy to jakaś decyzja projektowa - na prawdę mnie to ciekawi.

Przykład
RegOpenKeyEx( hKey, lpSubKey, ulOptions, samDesired, phkResult )

Argument Znaczenie
hKey Uchwyt otwartego klucza
lpSubKey Nazwa podklucza, którey otwieramy/tworzymy
ulOptions ** Zarezerwowane - nie używać**
samDesired Maska bezpieczeństwa dostępu
phkResult Adres zmiennej na uchwyt klucza

1

Warto wiedzieć, że istnieje też funkcja RegOpenKey o znacznie prostszej składni, jednak pochodzi ona jeszcze z czasów Windows 3.1 (gdzie, jak wiemy, Rejestru w znanej nam formie właściwie nie było) i jej stosowanie nie jest zalecane.

Samo nieużycie funkcji niezalecanej to jeszcze mało. Trzeba zobaczyć, czym właściwie różni się to RegOpenKey od RegOpenKeyEx. Prawie na pewno funkcja z Ex ma jakiś dodatkowy parametr, bez którego zachowuje się tak jak funkcja bez Ex (a więc RegOpenKey po prostu wywołuje RegOpenKeyEx dodając domyślne wartości dodatkowych parametrów).

Jak wiem czym różni się Ex od nie Ex i wiem że nie potrzebuję dodatkowych parametrów, używam wersji bez Ex (np. RegisterClass, CreateWindow).

dlaczego parametry niektórych funkcji są zarezerwowane?

Może kiedyś coś znaczyły, ale w nowszej wersji systemu dany parametr jest bez znaczenia, albo Microsoft coś przewiduje dodać do funkcji w przyszłości.

Przykład
RegOpenKeyEx( hKey, lpSubKey, ulOptions, samDesired, phkResult )

Argument Znaczenie
hKey Uchwyt otwartego klucza
lpSubKey Nazwa podklucza, którey otwieramy/tworzymy
ulOptions ** Zarezerwowane - nie używać**
samDesired Maska bezpieczeństwa dostępu
phkResult Adres zmiennej na uchwyt klucza

MSDN podaje:

<quote>ulOptions [in]

Specifies the option to apply when opening the key. Set this parameter to zero or the following:
Value Meaning
REG_OPTION_OPEN_LINK The key is a symbolic link. Registry symbolic links should only be used when absolutely necessary.

1 użytkowników online, w tym zalogowanych: 0, gości: 1