Czy niezadowolone są biblioteki statyczne w języku C? [Zamknięte]

11

Istnieją 2 argumenty przemawiające za udostępnianiem bibliotek:

  1. Pomaga zmniejszyć miejsce na dysku.
  2. Gdy biblioteka współdzielona jest aktualizowana, wszystkie pliki binarne zależne od niej otrzymują aktualizację.

Główną wadą bibliotek współdzielonych jest:

  • Mogą (mogą) wprowadzić piekło zależności.

Na komputerach stacjonarnych pierwsza przewaga już nie istnieje. Marnowanie miejsca na dysku nie stanowi obecnie większego problemu.

Posiadanie statycznych plików binarnych pozwoliłoby nam uzyskać znacznie lepsze menedżery pakietów - to znaczy, że piekło zależności byłoby już przeszłością. Dodanie programu byłoby po prostu dodaniem pliku binarnego; ostatecznie folder, który pozwoli mu obsługiwać swoje pliki. Usunięcie programu byłoby po prostu usunięciem tego pliku. Zależności? Odszedł.

Druga zaleta wciąż pozostaje, ale myślę, że przewaga statycznych plików binarnych na komputerach stacjonarnych przeważa nad nią. Mam na myśli, że nawet nowe języki, takie jak Go, kompilują wszystkie swoje pliki binarne pomimo zalet bibliotek współdzielonych ze względu na wygodę.


Ponieważ jedna z głównych zalet bibliotek współdzielonych nie jest już niczym wielkim, czy biblioteki statyczne w C wciąż są niezadowolone? Jeśli tak, to dlaczego?

Florian Margaine
źródło
4
Głównym powodem, dla którego C jest już używany, jest szczególnie dlatego, że nie pracujesz na nowoczesnych komputerach stacjonarnych.
Telastyn
18
@Telastyn Przepraszam? Większość oprogramowania zainstalowanego na moich komputerach stacjonarnych jest napisana w C.
Florian Margaine
6
Bit boczny - przeczytany poza witryną temat - Dynamiczne linkowanie uważane za szkodliwe
6
Jedną z zalet dynamicznych bibliotek jest to, że ludzie mogą nadal aktualizować biblioteki, aby obejść błędy, dziury w zabezpieczeniach lub problemy sprzętowe w 15-letniej zamkniętej grze źródłowej, która już dawno przestała otrzymywać aktualizacje. Niby niszowy przypadek, ale ponieważ dobre gry nie są towarem, „po prostu użyj innego programu” naprawdę nie pomaga. Ma to również znaczenie dla zgodności z LGPL bez otwartego pozyskiwania własnego kodu.
Doval
4
Zapomniałeś o dwóch innych zaletach bibliotek współdzielonych: 1) one również są współużytkowane w pamięci, 2) wszystkie linkery źle się ssają, a łączenie ogromnego pliku binarnego jest bardzo nieprzyjemne. Podział pliku binarnego na kilka mniejszych jednostek sprawia, że ​​cały proces jest znacznie bardziej znośny.
SK-logic

Odpowiedzi:

9

Przesłanka twojego pytania jest błędna. To, co jest niezadowolone, to trzymanie się doktrynerów i absolutów bez zrozumienia podstaw, które się za nimi kryją (Cargo Cult Programming?).

Powiązana odpowiedź SO jest interesującym badaniem w tym właśnie temacie - pytanie dotyczyło tego, dlaczego kompilacja z opcją -static nie działa, a odpowiedź, z którą się łączyłeś, była niczym innym, jak rantem o niestosowaniu łączenia statycznego. Jeśli nie dyskutuje, dlaczego jest zły, i żąda OP używa dynamicznego linkowania. To niefortunne, że jest oznaczona jako poprawna odpowiedź (następująca odpowiedź ma dwa razy więcej głosów i jest prawidłową odpowiedzią na pytanie PO), ponieważ chociaż prawidłowa odpowiedź istnieje, jest głęboko ukryta w dogmatycznej opinii.

Prawdziwe pytanie brzmi: jakie są zalety i wady łączenia statycznego vs. dynamicznego i kiedy jeden z nich byłby preferowany.

mattnz
źródło
2
Odpowiedź Basile nie powiedzieć dokładnie, dlaczego zaleca używanie biblioteki współdzielone: ?: „Dlaczego chcesz połączyć statycznie swoją aplikację . Jest to zazwyczaj błędem (bo nie zysk z aktualizacji do bibliotek dynamicznego systemu), w szczególności wyłącznik serwisowy nazwa obiekty z libc chcą bibliotek dynamicznych. To nie jest„ rant ”tylko dlatego, że się z tym nie zgadzasz.
Cody Gray
@Cody Odpowiedź na link została zredagowana, ponieważ nazwałem ją rantem. Jedyną opinią, którą mam na temat łączenia statycznego z dynamicznym, jest użycie tej, która jest odpowiednia dla twoich potrzeb, i zrozumienie mocnych i słabych stron wyboru, a następnie popadnięcie w doktrynę programowania kultowego ładunku, ponieważ „ktoś tak powiedział”.
mattnz
Tak, dodano część „W szczególności ...”. Nie jestem pewien, jak to wpływa na jego status rant. Oczywiście nie jestem zwolennikiem programowania kultowego ładunku. Po prostu zwolennicy statycznego linkowania (z mojego doświadczenia) często pomijają lub nie doceniają obaw związanych z bezpieczeństwem. Łączenie statyczne może być bardzo odpowiednie dla jednorazowych narzędzi, dzięki czemu aplikacja jest samodzielna, a tym samym znacznie łatwiejsza w dystrybucji. Ale każda aplikacja, która będzie szeroko wdrażana lub używana do produkcji, powinna naprawdę zawierać link do wspólnej biblioteki. Nie ma prawdziwych wad: na tym poziomie aplikacji potrzebujesz już procesu wdrażania.
Cody Gray
1
Dobrym przykładem tego, gdzie właściwe jest łączenie statyczne, jest miejsce pracy - duże, złożone systemy o krytycznym znaczeniu dla życia. Po przetestowaniu i zatwierdzeniu modułu krytycznego do działania jego zachowanie nie może ulec zmianie bez przejścia przez „proces”. Jednak żadne operacyjne i nieżywotne elementy systemu (rozliczanie i raportowanie) nie wymagają mniej niezawodnej kontroli i używają dynamicznego połączenia.
mattnz
7

Z punktu widzenia dewelopera dynamiczne linkowanie może często znacznie przyspieszyć twoją pętlę kompilacji / linku / testu.

Z punktu widzenia zarządzania pakietami, na przykład libGL. Mam około tuzina różnych jego implementacji dostępnych w moim menedżerze pakietów, niektóre ogólne i niektóre ukierunkowane na określone karty graficzne. Gdyby nie było dynamicznie powiązane, musiałoby istnieć kilkanaście wersji każdego programu, który łączy się z libGL, w przeciwnym razie musiałbyś opracować dodatkową warstwę abstrakcji, która nie byłaby tak skuteczna jak wywołanie funkcji.

Pomyśl o problemie bezpieczeństwa w popularnej bibliotece, takiej jak Qt. Dzięki dynamicznemu łączeniu mogę po prostu zaktualizować ten pakiet, zamiast identyfikować, rekompilować i wdrażać każdy pojedynczy pakiet, który łączy się w Qt.

Łączenie statyczne może mieć zalety w niezależnie wdrażanych aplikacjach zamkniętych źródeł, ale w zarządzaniu pakietami open source boli bardziej niż pomaga.

Karl Bielefeldt
źródło
2
To prawda (przyspieszenie rozwoju), ale naprawdę frustrujące jest to, że trafia do produkcji. Kanonicznym przykładem jest Firefox. Ilość wysiłku inżynieryjnego (w postaci ohydnych włamań), które przyspieszyły dynamiczne rozpoznawanie symboli linkowania, tak że Firefox ładuje się w rozsądnym czasie jest całkowicie szalony. Znacznie lepszą wydajność można by osiągnąć przy znacznie niższym koszcie inżynierii, gdyby tylko chcieli statycznie połączyć cały kod w projekcie (przy jednoczesnym dynamicznym łączeniu bibliotek systemowych i wtyczek, jeśli jest to pożądane).
R .. GitHub ZATRZYMAJ LÓD
5

Biblioteki współdzielone są zdecydowanie preferowane przez opiekunów dystrybucji Linuksa z twojego powodu # 2. Jest to dla nich bardzo ważne, że na przykład, gdy ktoś znajdzie błąd bezpieczeństwa w Zlib , nie musi przekompilować każdego programu korzystającego z Zlib - nie tylko kosztowałoby to więcej cykli procesora rekompilując, każdy, kto użyje dystrybucji, będzie musiał ponownie pobrać wszystkie te programy. Tymczasem w zestawie pakietów dostarczanych przez dystrybucję piekło zależności nie jest problemem, ponieważ wszystko jest testowane pod kątem współpracy z tym zestawem bibliotek.

Jeśli budujesz oprogramowanie innej firmy, które potrzebuje bibliotek, których nie ma w Twojej dystrybucji, statyczne łączenie tych bibliotek może być mniej kłopotliwe niż alternatywa, i to w porządku.

Inną ważną rzeczą, o której należy wiedzieć, jest to, że GNU libci GCC libstdc++zawierają składniki, które nie działają niezawodnie, jeśli biblioteka jest statycznie połączona. Najczęstszym problemem jest dlopen, ponieważ z każdym ładowanym modułem dlopenjest on dynamicznie powiązany libc.so.6. Oznacza to, że teraz masz dwie kopie biblioteki C w swojej przestrzeni adresowej, a przezabawność pojawia się, gdy nie zgadzają się, która kopia wewnętrznej mallocstruktury danych (na przykład) jest autorytatywna. Jest coraz gorzej: cała masa funkcji, które wydają się nie mieć nic wspólnego z dlopen, jak gethostbynamei iconvużywaniedlopenwewnętrznie (aby ich zachowanie można było skonfigurować w środowisku wykonawczym). Na szczęście ABI dla libc i libstdc ++ jest bardzo stabilny, więc prawdopodobnie nie napotkasz problemów dynamicznie łączących je.

zwol
źródło
2

Zgadzam się z ostatnim punktem Mattnza: to pytanie jest pytaniem pełnym. Zakłada, że ​​statyczne łączenie jest złe. Mogę wymyślić dwa powody, dla których tak nie jest:

  • Łączenie statyczne jest bezpieczne: jeśli biblioteka współdzielona zostanie zaktualizowana w taki sposób, że aplikacja korzysta z nowej (być może nowa zastąpi starą lub stara zostanie usunięta), może to stwarzać ryzyko, że nowa wersja zepsuje aplikację. Jest to zmiana kodu poza zakresem oficjalnej aktualizacji aplikacji. Być może nie został przetestowany. Łączenie statyczne omija to, nie udostępniając bibliotek zewnętrznie. Uważam, że ze względu na to ryzyko jest to niekorzystne dla bibliotek współdzielonych. Co jeśli nowa wersja biblioteki współdzielonej wprowadza nowy błąd, który psuje niektóre starsze aplikacje?

  • Łączenie statyczne zapewnia, że ​​aplikacja jest bardziej samodzielna. Chociaż biblioteki współdzielone mogą być kolokowane przy użyciu głównego pliku wykonywalnego, często są one zdeponowane we wspólnych lokalizacjach. Statycznie połączone aplikacje są łatwiejsze do zapewnienia jako „przenośne” w znaczeniu „nie wymagającym zmian w plikach, katalogach lub ustawieniach należących do systemu operacyjnego” (pomyśl katalog Windows, rejestr itp.).


źródło
Dziękujemy za ulepszenie zalet, o których chciałem wspomnieć. Jeśli jednak widzisz większość pakietów dostarczanych na przykład przez dystrybucje Linuksa, nie są one kompilowane statycznie. To nie wydaje się, że kompilacja statyczny jest mile widziana, przynajmniej z punktu widzenia zewnętrznego.
Florian Margaine
1
Biblioteki dynamiczne w prawie każdym systemie operacyjnym są obecnie wyświetlane według zapotrzebowania. Tylko używane strony są w pamięci. Jeśli wiele aplikacji korzysta z tej samej funkcji, współużytkują pamięć i zużywają mniej niż obudowa biblioteki statycznej. Jeśli wiele aplikacji korzysta z różnych funkcji w tej samej bibliotece, oba zestawy funkcji będą stronicowane, co będzie miało taki sam wpływ jak podejście statyczne.
Alan Shutko
@AlanShutko Walczyłem i przepisałem tę część na kilka sposobów z powodu tego, o czym wspomniałeś. Tak czy inaczej, nie ma żadnych rzeczywistych gwarancji, nawet jeśli nowoczesne systemy operacyjne oferują w praktyce wydajność bibliotek współdzielonych z obciążeniem statycznym. Będę ponownie edytować.
@Snowman Myślę, że podstawową kwestią jest to, że w każdym realistycznym systemie operacyjnym, który zapewnia dynamiczne łączenie (nie znam żadnego systemu operacyjnego, który korzysta z dynamicznego łączenia, ale nie wymaga stronicowania), drugi punkt nie trzyma wody: pamięć nie jest faktycznie używana chyba że funkcja jest używana, a pamięć używana przez bibliotekę dynamiczną może być współużytkowana przez różne programy, które z niej korzystają, dzięki czemu użycie pamięci dla wersji dynamicznej jest bardziej wydajne niż mniejsze. Twój pierwszy i trzeci powód jest prawidłowy, ale po prostu usunę drugi: przy jakichkolwiek realistycznych założeniach jest to po prostu błędne.
Jules
@Jules Zgadzam się, jest to kwestia, która była problematyczna i wątpliwa pod względem ważności we współczesnych systemach operacyjnych. Usunąłem to.
1

Biblioteki statyczne i dynamiczne mają swoje własne zastosowania. Patrząc na zakres pojedynczej aplikacji, mamy inne wyobrażenie o tym, co jest konieczne, a co nie.

Łączenie statyczne znacznie upraszcza wdrażanie aplikacji. Nie trzeba wykrywać różnych wersji i radzić sobie z nimi. Po prostu upiecz i rozprowadź.

Oczywistą zaletą bibliotek dynamicznych jest możliwość niezależnego stosowania aktualizacji.

Jest to jeden z powodów, dla których nienawidzę maven i innych podobnych twórców dynamicznych linków do java. Oczekują, że jedna wersja biblioteki będzie dostępna pod danym adresem URL na zawsze. Nie rozumiem problemu, który pojawia się za 10 lat, kiedy nikt nie może skompilować aplikacji, ponieważ wszystkie źródła i słoiki zniknęły.

dużo chipsów
źródło
Czy jest jakiś szczególny powód, dla którego programy, które używają, nie FooLib1.8powinny mieć możliwości włączenia kodu dla tej biblioteki do swojego pakietu wykonywalnego w standardowy sposób, aby umożliwić narzędzie aktualizacji dostarczane z FooLib1.9aktualizacją lub wersją starszą? Sposób, w jaki kod był przechowywany w klasycznym komputerze Macintosh, byłby bardzo łatwy; czy jest jakiś powód, dla którego dzisiejsze systemy nie powinny być w stanie tego zrobić jeszcze lepiej?
supercat
@ supercat masz na myśli, że każda wersja danej biblioteki będzie dostępna w systemie? Nie jestem pewien, czy rozumiem pytanie. Pytanie OP było skierowane bardziej w stronę ogólnodostępnych bibliotek systemowych niż bibliotek statycznych, które zostaną spakowane razem.
dużo chipsów
Chodzi mi o to, że posiadanie pakietu wykonywalnego zawiera wszystkie biblioteki, których potrzebuje, nie powinno wykluczać możliwości aktualizacji bibliotek w nim zawartych. Dlatego nie wiem, czy uważam możliwość uaktualnienia rzeczy po wdrożeniu za zaletę niepowiązania aplikacji z jej bibliotekami.
supercat
Jeśli licencja danej biblioteki pozwala na rozpowszechnianie jej wraz z pakietem, jest to zawsze preferowany sposób. Zmniejsza liczbę zewnętrznych zależności. Ponieważ dystrybuowałbyś wszystko, mechanika aktualizacji lub łatania działałaby w taki sam sposób, jak statyczny lub dynamiczny. Patchowanie zwykle oparte na binarnych deltach. Nie byłoby różnicy.
dużo chipsów