Co to jest

Biblioteka to taki bezgłowy program, czyli bez głównej funkcji, która jest używana przez system operacyjny jako punkt startu programu. Poza tym- wszystko wewnątrz biblioteki działa jak zwykły plik wykonywalny (upraszczając). Pisząc programy, nawet te małe, często można natrafić na sytuację, że jakaś część programu jest wspólna dla więcej niż jednego projektu. np. obsługa komunikacji za pomocą HTTP. Aby nie powielać kodu (bo powielanie kodu to szczyt bezczelności, w końcu programiści są leniwi) można uciec się do dwóch rozwiązań:

  1. Wyodrębnić część kodu, która jest wspólna, umieścić ją w katalogu dostępnym przez inne projekty i za pomocą konfiguracji projektu dołączać ją do kolejnych programów.
  2. Stworzyć bibliotekę.

Pierwsze rozwiązanie ma jedną zaleto-wadę: korzystając z tego wspólnego kodu źródłowego mamy dostęp do źródła i możemy przeczytać co ten kod dokładnie robi. Wadą jest tutaj możliwość ingerencji w ten kod. Takie niebezpieczeństwo powstaje, gdy projekt wymaga nieco innego podejścia niż pozostałe projekty i “fajnie by było, gdyby ten wspólny kod robił coś nieco inaczej”. W tym momencie, ulegając pokusie i modyfikując część wspólną, można spowodować błędy w projektach, które już korzystają z tego kodu. Poza tym to rozwiązanie ma słabe punkty takie jak:

  • dłuższy czas kompilacji: nawet jeżeli to są sekundy to przy setnej czy tysięcznej iteracji traci się na to godziny,
  • plik wynikowy jest większy,
  • kod źródłowy jest jawny i każdy może go przeczytać (to było ogromną wadą dawno temu, gdy ruch OpenSource nie był tak popularny).

Biblioteka powstała właśnie z tych względów. Po pierwsze, tworząc bibliotekę kompilujemy ją raz i oszczędzamy sporo czasu na kolejną kompilację. Po drugie, skompilowana biblioteka jest gotowa do użycia- nie trzeba tracić czasu na przygotowanie środowiska aby ją skompilować (tutaj uwaga- niektóre biblioteki, w szczególności te w systemach UNIXopodobnych są dostarczane tak samo często jako prekompilowane pliki jak i źródła tychże). Po trzecie, oszczędność miejsca- jedna biblioteka (plik czy ich zestaw) raz umieszczony w systemie jest dostępny dla wszystkich programów. Pierwszy i trzeci argument był w szczególności ważny w czasach, gdy komputery były wolne i nie posiadały tak dużo zasobów. Ostatnia rzecz- skompilowaną bibliotekę możemy udostępniać bez kodu źródłowego. Jest to w szczególności przydatne, gdy np. napisaliśmy jakiś algorytm, który ma bardzo wielką wartość i chcemy ten algorytm monetyzować.

Jak stworzyć bibliotekę

Bibliotekę tworzy się w bardzo podobny sposób jak każdy program, jedynie rezultat jest nieco inny. Biblioteka tworzona jest dla programów pisanych w tym samym języku programowania co ona. Składa się z dwóch elementów: skompilowanych źródeł (plik .dll albo .lib w windows, .so albo .a w unix) oraz nagłówków, które zawierają symbole dostępne w bibliotece. Tymi symbolami są nazwy funkcji, nazwy klas, etc., czyli jest to po prostu integralna część kodu tejże biblioteki (jedyny fragment kodu, który trzeba udostępnić wraz z biblioteką). Te udostępnione pliki nagłówka stanowią API tej biblioteki. Każdy kompilator ma wbudowane narzędzia zarówno do tworzenia bibliotek jak i używania już istniejących (w zasadzie to linker odpowiada za łączenie). Biblioteki można podzielić na dwie kategorie:

  1. Biblioteki dynamiczne, czyli takie, które wykorzystywane są w trakcie działania programu. Skompilowany program zawiera symbole i referencje do biblioteki z której korzysta. Podczas gdy system operacyjny uruchamia ten program, ładuje cały kod, do którego odnoszą się te symbole tak, jakby były one częścią uruchomionego programu. Biblioteki dynamiczne mają rozszerzenia .lib (Library) i .a (Archive Library) odpowiednio dla Windows i UNIX.
  2. Biblioteki statyczne, czyli takie, które są dołączane do programu (pliku wynikowego) w trakcie kompilacji. To znaczy, że kod biblioteki jest kopiowany do pliku wynikowego i wtedy system operacyjny nie musi niczego dodatkowo ładować. Biblioteki dynamiczne mają rozszerzenia .dll (Dynamic Link Library) i .so (Shared Object) odpowiednio dla Windows i UNIX.

W zależności od celu, można zbudować zarówno dynamiczną jak i statyczną bibliotekę i równie tak samo dobrze można załączać do swoich programów dynamicznie albo statycznie. Dynamiczne biblioteki znajdą zastosowanie przede wszystkim w sytuacjach, gdy są rozmiarowo duże albo są na tyle popularne, że użytkownik, dla którego tworzony jest program z pewnością będzie mieć je zainstalowane u siebie. Taki klasyczny przykład powyższego to WinAPI, czyli biblioteki dla programów okienkowych dla Windows. Biblioteki statyczne używane są przede wszystkim tam, gdzie nie można sobie pozwolić na zgadywanie, czy taka biblioteka będzie dostępna czy też nie.

Problemy związane z bibliotekami

Pomimo wielu zalet, biblioteki są obciążone wadami, a także złą sławą. Po pierwsze, w systemach UNIX, biblioteki zazwyczaj nie są udostępniane w wersji skompilowanej. Przyczyną tego jest fakt, że dystrybucji UNIX czy LINUX jest bardzo wiele, każda się czymś różni i dostarczanie skompilowanej biblioteki na każdą dystrybucję po prostu mija się z celem. Prekompilowane biblioteki dostarczane są głównie w znaczących dystrybucjach, jak np. Ubuntu. Może to nie zabrzmi jak wada, ale kompilacja biblioteki może nieść za sobą konieczność… kompilacji biblioteki, która jest używana w tej bibliotece. A ta druga biblioteka (będąca zależnością tej pierwszej) może mieć kolejną zależność. Mało tego! Każda z tych zależności może wymagać biblioteki w konkretnej jej wersji. I w ten sposób wpadamy w tzw. “dependency hell”. Sam wiele razy stawałem przed takimi problemami,które kończyły się wyrwaniem sobie garści włosów z głowy i zniszczeniem klawiatury. Tak, to jest jeden z powodów, dla którego ludzie nie lubią UNIX’a. Na szczęście to powoli się zmienia. Windows również może być podatny na problem opisany powyżej,ale występuje to zdecydowanie rzadziej. Niezależnie od systemu, powstaje jednak jeszcze jeden poziom skomplikowania. Otóż kompilując program, jest on budowany tak, aby działał na konkretnej architekturze procesora (32 albo 64-bitowej). Kompilując program 32-bitowy można go uruchomić na procesorze 64-bitowym. Problem jednak powstanie, gdy używamy dynamicznej biblioteki, a na komputerze, na którym program będzie uruchomiony nie ma jej 32-bitowego odpowiednika.

Dobry kontent!

Piotr Poźniak

Piotr Poźniak

Programuję od ponad 15 lat. Prowadzę software house. Angażuję i zachęcam wszystkich do programowania w ramach inicjatywy Programowanie jest łatwe.

Bądź pierwszy, podziel się swoją opinią!