Biblioteki współdzielone
Transkrypt
Biblioteki współdzielone
Projektowanie oprogramowania systemów BIBLIOTEKI WSPÓŁDZIELONE plan biblioteki programistyczne statyczne współdzielone łączenie dynamiczne interfejs biblioteki wtyczki programowe kompatybilność wsteczna „DLL hell” przegląd użytecznych bibliotek biblioteki programistyczne biblioteka – kolekcja zasobów i procedur/funkcji używanych przez programy komputerowe, posiadająca ściśle zdefiniowany interfejs kod dostarczany przez bibliotekę może być wykorzystany przez wiele niepowiązanych programów – reużycie kodu program nie musi znać implementacji funkcji bibliotecznych – polega na ich interfejsie usługi dostarczane w ramach biblioteki zwykle dotyczą wspólnego zakresu zagadnień, dotyczą tego samego tematu (zestawu tematów) rodzaje bibliotek biblioteki możemy podzielić ze względu na rodzaj łączenia (linking) - na którym etapie tworzenia programu biblioteka jest łączona z programem wykonywalnym biblioteki statyczne (łączone statycznie) – stanowi kolekcję skompilowanych plików obiektowych, które są wprost łączone do pliku wykonywalnego podczas jego tworzenia, każdy plik wykonywalny otrzymuje prywatną kopię kodu zawartego w bibliotece biblioteki współdzielone (łączone dynamicznie) – kod biblioteki nie jest kopiowany do pliku wykonywalnego, tylko dodawane są „łącza” do biblioteki w osobnym pliku – ta sama biblioteka może być współdzielona równocześnie przez wiele programów porównanie bibliotek statyczne współdzielone kopiowanie kodu użycie współdzielonego kodu zmiana biblioteki wymaga rekompilacji/ponownego łączenia każdego programu, który z niej korzysta zmiana biblioteki możliwa poprzez zastąpienie pliku biblioteki, o ile jest zachowany spójny interfejs binarny i wsteczna kompatybilność otrzymany program wykonywalny składa się z pojedynczego pliku (łatwość dystrybucji) program wykonywalny do działania wymaga dodatkowych plików bibliotek program wykonywalny nie wymaga łączenia podczas uruchamiania programu następuje bibliotek w czasie wykonania – brak etap łączenia/relokacji bibliotek, który wiąże się opóźnień przy starcie z określonym kosztem czasu wykonania program jest samowystarczalny (selfcontained) poprawki w bibliotekach nie wymagają instalowania nowych wersji programów, które z nich korzystają niższe użycie pamięci dyskowej (tylko 1 plik biblioteki) i operacyjnej (obraz biblioteki jest współdzielony pomiędzy procesami) łączenie dynamiczne w programie wykonywalnym zapisywana jest nazwa używanej biblioteki współdzielonej oraz nazwy symboli eksportowanych przez bibliotekę lub indeksy do tablicy symboli biblioteki po uruchomieniu programu, używa on usługi linkera dynamicznego dostarczanej przez OS, do zlokalizowania biblioteki załadowania jej obrazu do przestrzeni adresowej wykonania niezbędnych relokacji symboli umieszczenia referencji do symboli z biblioteki w odpowiednich slotach tablicy symboli programu uruchomienia kodu startowego biblioteki (np. DllMain(), dlinit(), _declspec_(constructor)) ładowanie bibliotek w czasie wykonania łączenie dynamiczne nie musi odbywać się podczas startu programu – możliwe jest w dowolnym momencie jego wykonania ładowanie w czasie wykonania (run-time linking) niejawne – następuje automatycznie podczas pierwszego odwołania do jakiegokolwiek symbolu z biblioteki o opóźnionym czasie ładowania (lazy binding, delay loading) – przyspiesza czas uruchomienia programu jawne – kod programu w sposób jawny wywołuje funkcje służące do ładowania biblioteki i uzyskania dostępu do symboli o określonej nazwie – biblioteka nie musi być dostępna do uruchomienia programu – jej funkcjonalność może być wykorzystana opcjonalnie – „wtyczki” ładowanie bibliotek w czasie wykonania POSIX Windows ładowanie bibliotek w czasie wykonania typ symbolu (prototyp funkcji, jej sposób łączenia, typ parametrów i wyniku) musi być znany a’priori – błędny typ spowoduje zniszczenie stosu i crash programu nazwa symbolu musi być znana a’priori – w przypadku C++ nazwa dekorowana – nieprzenośne, dlatego stosujemy zwykle łączenie typu „extern C” symbol może odnosić się do eksportowanej funkcji lub zmiennej globalnej interfejs biblioteki interfejs biblioteki to lista wszystkich eksportowanych symboli oraz ich typ zwykle interfejs biblioteki jest dostarczany w postaci towarzyszących jej plików nagłówkowych (.h), zawierających prototypy eksportowanych funkcji/zmiennych globalnych eksport symbolu z biblioteki POSIX – domyślnie, wszystkie symbole zawarte w bibliotece są z niej eksportowane (udostępniane klientom biblioteki) – przy dużych bibliotekach powoduje to znaczący spadek wydajności kompilatory zgodne z GCC udostępniają atrybut visibility określający czy symbol jest eksportowany Windows - kompilator Visual C++ udostępnia dyrektywy dllexport i dllimport dla określenia symboli eksportowanych i importowanych z bibliotek eksportowanie symbolu na POSIX kompilujemy całą bibliotekę z visibility=hidden (opcja -fvisibility=hidden) używamy atrybutu visibility=„default” dla symboli, które chcemy eksportować na Windows dodajemy atrybut __declspec(dllexport) do symboli, które chcemy eksportować w programie korzystającym z biblioteki używamy dla tych samych symboli atrybutu __declspec(dllimport) patrz przykład -> eksportowanie symboli wtyczki programowe „wtyczka” to specjalny rodzaj biblioteki współdzielonej, która jest zaprojektowana, aby być ładowana w czasie działania programu wtyczki udostępniają zunifikowany interfejs oparty o symbolach o znanych nazwach i/lub klasach z „czysto wirtualnym” interfejsem wymagana zgodność interfejsu binarnego pomiędzy wtyczkami ukrywanie implementacji obiekty „nieprzezroczyste” (opaque) dostęp do stanu i zachowań obiektu tylko poprzez wywołania funkcji, enkapsulacja danych unikanie funkcji o dekorowanych nazwach (C++ name mangling) dla zapewnienia przenośności dostępu do symboli wtyczki programowe wtyczki programowe i kompatybilność wsteczna gdyby implementacja klasy plugin_interface była jawna i użylibyśmy funkcji nie-wirtualnych, wówczas jakakolwiek zmiana implementacji powodowałaby, że dostęp do danych tej klasy wymagałby innego kodu – zmiana interfejsu binarnego klasy dla zapewnienia kompatybilności wstecznej, kolejne wersje klasy plugin_interface muszą zachowywać dokładnie tą samą semantykę, składnię (prototypy) oraz kolejność funkcji wirtualnych zdefiniowanych w tablicy funkcji wirtualnych (vtable) poprzednich wersji klasy kolejne wersje interfejsu plugin_interface powinny więc powstawać poprzez dziedziczenie interfejsu z wersji wcześniejszej kompatybilność wsteczna typowe założenia wersjonowania bibliotek kod korzystający z wcześniejszej wersji biblioteki powinien działać z nowszą wersją biblioteki, o ile nie zmienił się główny numer wersji zmiany „łamiące” kompatybilność (breaking changes) powinny wiązać się ze zmianą głównego numeru wersji (major version number) typowy format numerów wersji: major_number.minor_number[.patch_number[.build_number]] major_number – numer wersji interfejsu binarnego biblioteki, znaczna zmiana funkcjonalności lub paradygmatu projektowania/użycia interfejsu zmiana minor_number – rozszerzenia funkcjonalności nie łamiące kompatybilności wstecznej zmiana patch_number – poprawki błędów nie rozszerzające interfejsu biblioteki build_number – numer kompilacji, używany np. do namierzenia, w którym dniu pojawił się błąd w kodzie „dll hell” termin dll hell (piekło bibliotek łączonych dynamicznie) odnosi się do sytuacji, w której w systemie istnieje kilka wersji tej samej biblioteki i nie jesteśmy w stanie określić, która z nich jest ładowana przez nasz program wykonywalny – również niekompatybilne wersje generalnie występuje to tylko na Windows ze względu na kiepską implementację mechanizmu linkera dynamicznego linker dynamiczny sprawdza również katalog roboczy programu i wszystkie lokalizacje na ścieżce systemowej (PATH) brak ścisłego mechanizmu wersjonowania bibliotek zdarzało się że program instalował wcześniejszą wersję biblioteki w katalogu systemowym nadpisując wersję późniejszą i powodując niedziałanie wszystkich innych programów z niej korzystających nikłe szanse na POSIX linker dynamiczny sprawdza tylko ściśle określone lokalizacje w poszukiwaniu bibliotek mechanizm wersjonowania bibliotek umożliwiający precyzyjne określenie, która wersja interfejsu jest niezbędna do działania (np. 2.X,1.3.X itp.) przegląd użytecznych bibliotek (C/C++) C++ - Boost zestaw bibliotek o bardzo szerokim zakresie tematycznym gwarantują przenośne działanie na wielu platformach zbudowane na bazie i rozszerzające bibliotekę standardową C++ jedne z najbardziej starannie zaprojektowanych i zaimplementowanych bibliotek dla C++ biblioteki należące do Boost często stają się podstawą nowych specyfikacji w rozwoju języka C++ ogółem kilkadziesiąt bibliotek dotyczących wszystkich możliwych aspektów programowania przystępując do rozwiązywania problemu zawsze warto sprawdzić, czy Boost już tego nie robi www.boost.org Boost Boost.Thread – przenośna implementacja wątków i obiektów synchronizacji (stała się podstawą nagłówka <thread> C++11) Boost.Atomic – implementacja atomowych zmiennych (podstawa dla C++11 <atomic>) Boost.Chrono, Boost.Date Time – pomiar czasu, formatowanie i parsowanie dat i interwałów Boost.Filesystem – przenośne operacje w systemie plików Boost.Format – formatowanie napisów Boost.Functional – programowanie funkcjonalne Boost.Interprocess – obiekty IPC Boost Boost.Asio – przenośna biblioteka nieblokującej komunikacji sieciowej i IPC Boost.Lexical Cast – konwersja typów Boost.Lockfree – kolejki nieblokujące Boost.Log – logowanie błędów i wykonania programu Boost.Math – funkcje matematyczne, m.in. interfejs C++ do biblioteki BLAS (basic linear algebra subsystems) Boost.Program Options – parsowanie plików konfiguracyjnych i wiersza poleceń Boost.Regex – wyrażenia regularne Boost.Smart Ptr – „sprytne” wskaźniki zapobiegające wyciekom pamięci C++ - OpenCV biblioteki algorytmów przetwarzania grafiki komputerowej, ale nie tylko przenośne działanie na wielu systemach m.in. operacje matematyczne na macierzach wielowymiarowych algorytmy mocno zoptymalizowane, korzystające z operacji wektorowych procesorów wsparcie dla obliczeń na GPU kilkanaście różnych bibliotek do różnych celów jedno z najpotężniejszych i najszerzej stosowanych narzędzi tego typu „wrappery” do m.in. Javy, Pythona www.opencv.org OpenCV core – operacje na macierzach, podstawowe typy graficzne, rysowanie imgproc – filtracja i transformacja obrazów, śledzenie obiektów highgui – podstawowe elementy GUI video – analiza ruchu, przepływ optyczny, usuwanie tła, filtracja Kalmana objdetect – wykrywanie obrazów ml – uczenie maszynowe portaudio przenośna biblioteka (C) służąca do obsługi interfejsów dźwiękowych wsparcie m.in. dla API ASIO2 – niskie opóźnienia zunifikowany interfejs na Windows, Mac OS X, Linux i wielu innych systemach www.portaudio.com dsp++ biblioteka służąca do tworzenia algorytmów CPS w języku C++ z wykorzystaniem programowania uogólnionego (szablonów) m.in. FFT (+ wrapper dla FFTW) filtry cyfrowe FIR i IIR (projektowanie i uruchamianie) korelacja OLA, splot przetwarzanie dźwięku – pomiar głośności (LUFS), procesory dynamiki buforowanie, partycjonowanie, zakładkowanie operacje stałopozycyjne działa również na platformach mobilnych (Android NDK, iOS) https://bitbucket.org/andrzejc/dsp fftw przenośna, zoptymalizowana biblioteka transformat FFT i innych „fastest FFT in the west” ciężki do ogarnięcia interfejs w C, ale olbrzymie możliwości transformaty o rozmiarach pierwszysch transformaty wielowymiarowe DCT, MDCT, FHT w C++ warto używać z wrapperem w dsp++ www.fftw.org libsndfile przenośna (C) biblioteka do odczytu i zapisu plików dźwiękowych w różnych formatach m.in. WAV, AIFF, FLAC… również format MAT pochodzący z Matlaba – łatwe przenoszenie danych podczas implementacji algorytmów prototypowanych w Matlabie w C++ warto używać wrappera w dsp++ http://www.mega-nerd.com/libsndfile/ Qt przenośna biblioteka (C++) służąca do tworzenia GUI na wielu platformach zawiera również wiele innych funkcji poza GUI – komunikacja sieciowa, multimedia oryginalnie rozwijana przez Trolltech AG, potem Nokia – jest również wersja OpenSource zawiera język opisu UI QML i wsparcie dla JavaScript prawdopodobnie najbardziej rozbudowane i najbardziej eleganckie UI z wszystkich tego typu bibliotek używa dodatkowego kompilatora metaobiektów – MOC – skomplikowane użycie wrapper dla Java www.qt.io