Jak przenieść projekt ze środowiska IAR Embedded Workbench do Atollic TrueSTUDIO – poradnik migracyjny

Zarządzanie bibliotekami

Biblioteki są zbiorami relokowalnych plików obiektowych, powszechnie używanymi w programach. Taki zbiór może zostać użyty przez konsolidator aby „rozwiązać” (resolve), czyli znaleźć odpowiednik dla funkcji lub danej, do której istnieją odniesienia w kodzie aplikacji.

Do każdego kompilatora dołączone jest wiele bibliotek, takich jak: standardowa biblioteka C, biblioteka matematyczna C, biblioteka uruchomieniowa C++ (runtime library) itd. Takie biblioteki „systemowe” zwykle zawierają domyślny kod startowy (startup code) i biblioteki istotne (intrinsic libraries), implementujące funkcje niskopoziomowe, konieczne do pracy aplikacji.

Kod startowy zapewnia, że mikrokontroler zostanie prawidłowo zainicjalizowany przy włączeniu lub resecie oraz, że środowisko wspomagania przetwarzania (runtime environment) jest ustawione prawidłowo (zmiennym globalnym przypisane są właściwe wartości, sterta jest zainicjalizowana itd.).

Biblioteki istotne implementują operacje niskopoziomowe, wymagane przez kompilator do obsługi tych cech wysokopoziomowych języka, które nie są implementowane za pomocą jednej lub kilku instrukcji asemblera. Przykładami funkcji istotnych mogą być: arytmetyka 64-bitowa na maszynach 32-bitowych, operacje zmiennoprzecinkowe na maszynach bez jednostki zmiennoprzecinkowej oraz kod rozpoczynający i kończący wywołanie funkcji (function prolog/epilog code) przy optymalizacji pod kątem rozmiaru kodu.

Każdy relokowalny moduł zawarty w bibliotece zostanie włączony do pliku wykonywalnego, jeśli przynajmniej jeden z symboli, które eksportuje (odpowiadających funkcjom lub danym) jest wykorzystywany, albo bezpośrednio w kodzie, albo pośrednio w którejś z bibliotek, używanych w aplikacji. Pozwala to na włączanie do plików wykonywalnych tylko potrzebnych funkcji i danych, zamiast włączania całej biblioteki standardowej C czy środowiska wspomagania C++.

Są dwa rodzaje bibliotek: statyczne i dynamiczne. Kod zawarty w bibliotece statycznej będzie częścią pliku wykonywalnego (o ile funkcje/dane biblioteczne są używane), czyli wszystkie odniesienia są „rozwiązywane” jednorazowo („statycznie”) w czasie budowania projektu. Jako że większość systemów wbudowanych to pojedyncze programy, jest to model najpopularniejszy. Biblioteki dynamiczne pozwalają na włączanie kodu bibliotecznego do aplikacji w czasie jej działania, co prowadzi do mniejszych plików wykonywalnych, ale wymaga dynamicznego konsolidatora, np. takiego, w jaki wyposażony jest Linux. Niniejszy tekst omawia tylko biblioteki statyczne, gdyż systemy przenoszone z IAR EmbeddedWorkbench nie działają pod kontrolą systemu operacyjnego.

Biblioteki standardowe

Standardy języków C i C++ definiują nie tylko języki jako takie, ale też określają zestaw bibliotek uruchomieniowych, które muszą być obsługiwane.

Biblioteki standardowe zapewniają narzędzia do manipulacji danymi na poziomie nie obsługiwanym bezpośrednio przez język (np. łańcuchy znakowe), dynamicznej alokacji pamięci (funkcje mallocfree w C oraz newdelete w C++) oraz do komunikacji z systemem, pod kontrolą którego działa program (czytanie z i zapis do plików, zarządzanie czasem itp.).

Oprócz bibliotek standardowych, kompilatory zwykle wyposażone są też w biblioteki istotne. Są one specyficzne dla kompilatora i zwykle zawierają niskopoziomowe funkcje, które kompilator wywołuje automatycznie w czasie procesu budowania. Funkcje istotne implementują zwykle funkcje i cechy języka, których dany sprzęt nie umie realizować wprost.

Przykłady to: arytmetyka 64-bitowa na jednostkach 16- i 32-bitowych czy operacje zmiennoprzecinkowe na CPU bez dedykowanej jednostki zmiennoprzecinkowej. Programiści nie wykorzystują bibliotek istotnych wprost (nie muszą) i nie ma gwarancji, że funkcje istotne będą zgodne z ABI.

Funkcje istotne są zwykle napisane w asemblerze, optymalizowane ręcznie i nieudokumentowane. Programista musi się tylko upewnić, że biblioteka istotna jest włączana w procesie budowania, aby poprawne funkcje niskopoziomowe były włączone w ostatecznej wersji programu.

Kolejny typ bibliotek, dostarczany zwykle z kompilatorem, jest wykorzystywany w systemach, w których obiekty lub zmienne wymagają inicjalizacji przy starcie. Wlicza się w to wywoływanie konstruktorów dla obiektów globalnych w C++; aplikacja powinna też zawsze kończyć działanie wywołując odpowiednie destruktory. Specjalne sekcje inicjalizacyjne i finalizacyjne, zawierające kod przebiegający po liście konstruktorów i destruktorów, są włączane w plikach wykonywalnych.

Poniższa tabela daje wgląd w biblioteki dołączane do kompilatora C/C++ GNU, których znajomość może być przydatna w czasie migracji.

 

Tab. 20. Biblioteki dołączane do kompilatora C/C++ GNU

Biblioteka Język Zastosowanie
Libc.a C Standardowa biblioteka uruchomieniowa C (bez biblioteki matematycznej).
Libg.a C Standardowa biblioteka uruchomieniowa C skompilowana dla potrzeb debugowania (debug build).
Libm.a C Standardowa biblioteka matematyczna C.
LibGCC.a C Biblioteka istotna, „wspierająca kompilator”, dla aplikacji w C.
Libiberty.a C Zbiór „podfunkcji” (subroutines) używanych przez różne programy GNU, włączając getopt, obstack, strerror, strtol i strtoul.
Libgcov.a C GCC pozwala na automatyczną poprawę kodu. Włączając gcov można analizować i optymalizować programy w celu poprawy wydajności i szybkości działania.
Libsupc++.a C++ Zapewnia obsługę języka C++ (zawiera m.in. funkcje obsługujące wyjątki). Można używać tej biblioteki, gdy nie jest konieczna cała biblioteka standardowa C++.
Libstdc++.a C++ Biblioteka standardowa C++. Wykorzystywana przez programy napisane w C++ zawiera często używane funkcje języka. Włączona jest w nią m.in. Standard Template Library (STL).
crtbegin.o i crtend.o C++ Pliki obsługujące konstruktory i destruktory.

 

Tworzenie bibliotek i zarządzanie nimi

Biblioteki statyczne są zbiorami skompilowanych modułów kodu i w przypadku kompilatora C/C++ GNU można je tworzyć i zarządzać nimi za pomocą standardowego narzędzia „archiwizującego”, nazwanego ar.

Aby stworzyć archiwum (*.a)  z jednego lub większej liczby relokowalnych plików obiektowych należy użyć poniższego polecenia, które tworzy z plików plik1.o i plik2.o nowe archiwum nazwane libmojepliki.a lub aktualizuje je, o ile takie już istnieje, zamieniając stare wersje plików plik1.o i plik2.o.

O autorze