Be Book Kernel Kit Kernel Kit Indeks

Pojęcia obrazu

Obraz jest skompilowanym kodem. Są trzy typy obrazu:

Poniższe sekcje wyjaśniają jak ładować i uruchamiać obraz aplikacji, jak tworzyć biblioteki współdzielone i jak tworzyć i łądować obrazy wtyczek.

Ładowanie obrazu aplikacji

Ładowanie obrazu aplikacji jest jak uruchamianie "podprogramu". Obraz, który ładujesz jest odpalany w bardzo podobny sposób jak jest odpalany przez podwójne kliknięcie w Tracker'ze lub jak jest odpalany z wiersza poleceń. Działa on w swoim własnym zespole - nie współdzieli on przestrzeni adresowej z aplikacją z której był odpalony - i ogólnie, prowadzi własne życie.

Aplikacja może być ładowana jako obraz aplikacji; nie potrzebujesz specjalnuych instrukcji komplikacji lub inaczej manipulować binariami. Jedynym żądaniem obrazu aplikacji jest to, że musisz mieć funkcję main().

Aby załadować obraz aplikacji, wywołaj funkcję load_image():

thread_id load_image(int32 argc,
         const char **argv,
         const char **env)

Dwa pierwsze argumenty funkcji identyfikują obraz aplikacji (plik), który chcesz odpalić - wrócimy do tego za chwilę. Mając zlokalizowany plik, funkcja tworzy nowy zespó, zapoczątkowuje główny wątek i zwraca Ci identyfikator thread_id wątku. Wątek nie działą: aby dokonać jego uruchomienia przekazujesz thread_id do resume_thread() lub wait_for_thread() (jak wyjaśniono w rozdziale "Wątki i zespoły").

Para argumentów argc/argv jest kopiowana i posyłana do funkcji main() nowego wątku:

Poniższy przykład demonstruje typowe użycie funkcji load_image(). Najpierw dołączamy odpowiednie pliki i deklarujemy konieczne zmienne:

#include <image.h> /* load_executable() */
#include <OS.h> /* wait_for_thread() */
#include <stdlib.h> /* malloc() */

char **arg_v; /* wybierz nazwę która nie koliduje z argv */
int32 arg_c; /* taki sam jak argc */
thread_id exec_thread;
int32 return_value;

Zainstaluj (wprowadź - przyp. tłum.) w tablicy arg_v argumenty "wiersza poleceń". Symulejemy, że odpalamy program znaleziony w katalogu /boot/home/apps/adder, który pobiera dwie liczby całkowite, dodaje je do siebie i zwraca wynik jako kod wyjścia funkcji main(). Zatem są tutaj dwa argumenty: nazwa programu i wartości dwóch dodawanych liczb konwertowanych na łańcuchy znaków. Ponieważ są trzy argumenty, przyfdzielamy arg_v do przechowywania czterech wskaźników (aby pomieścić końcowy znak NULL). Następnie przydzielamy i kopiujemy argumenty.

arg_c = 3;
arg_v = (char **)malloc(sizeof(char *) * (arg_c + 1));

arg_v[0] = strdup("/boot/home/apps/adder");
arg_v[1] = strdup("5");
arg_v[2] = strdup("3");
arg_v[3] = NULL;

Teraz, gby wszystko jest właściwie ustawione, wywołujemy load_image(). Po zwróceniu wartości przez tą funkcję, bezpiecznie jest już zwalniana przydzielona tablica arg_v:

exec_thread = load_image(arg_c, arg_v, environ);

while (--arg_c >= 0)
   free(arg_v[arg_c]);

free(arg_v);

W tym miejscu, exec_thread jest zawieszany (naturalny stan nowo zapoczątkowanego wątku). Żeby uzyskać jego zwróconą wartość, używamy funkcji wait_for_thread() do powiadomienia wątku, żeby rozpoczął działanie:

wait_for_thread(exec_thread, &return_value);

Po zwróceniu wartości przez funkcję wait_for_thread(), wartość argumentu return_value powinna być równa 8 (t.j. 5 + 3).

Tworzenie biblioteki współdzielonej

Pierwotna dokumentacja o tworzeniu bibliotek współdzielonych jest dostarczana przez MetroWerks w ich podręczniku do programu CodeWarrior. Poza informacją, które tam znajdujesz, powinieneś być świadomym poprawek i zmian jakie zaszły:

$ echo $LIBRARY_PATH
%A/lib:/boot/home/config/lib:/boot/beos/system/lib

gdzie "%A" oznacza katalog, który zawiera aplikację, jaką odpala użytkownik.

Eksportowanie i importowanie symboli

Jeśli programujesz bibliotekę współdzieloną powinieneś jawnie wyeksportować każdy globalny symbol w Twojej bibliotece przez użycie makra __declspec(). Aby wyeksportować symbol, deklarujesz go w ten sposób...

__declspec(dllexport) typename

...gdzie "_declspec(dllexport)" jest literałem a type i name deklarują symbol. Kilka przykłladów:

__declspec(dllexport) char *some_name;
__declspec(dllexport) void some_func() {...}
class __declspec(dllexport) MyView {...}

Aby zaimportować te symbole, aplikacja, która chce użyć Twoją bibliotekę musi "odwrócić" deklarację przez zamianę dllexport na dllimport:

__declspec(dllimport) char *some_name;
__declspec(dllimport) void some_func();
class __declspec(dllimport) MyView;

Problem z tym systemem jest taki, że oznacza on dwa zestawy nagłówków, jeden do eksportowania (do budowania Twojej biblioteki) i kolejny do importowania (żeby klient Twojej biblioteki mógł ją użyć). Biblioteki Be używaja makr, zdefiniowanych w katalogu be/BeBuild.h, który przestawia przełącznik import/export więc pliki nagówkowe mogą być zunifikowane. Dla przykładu, podano tutaj takie makro dla libbe:

#if _BUILDING_be
#define _IMPEXP_BE   __declspec(dllexport)
#else
#define _IMPEXP_BE __declspec(dllimport)
#endif

Kiedy budowana jest biblioteka libbe, prywatna dyrektywa kompilatora definiuje _BUILDING_be aby była ona różna od zera a _IMPEXP_BE eksportuje symbole. Gdy programista dołącza BeBuild.h, zmienna _BUILDING_be jest ustawiona na zero, więc _IMPEXP_BE jest ustawiona na import symboli.

Możesz chcieć naśladować ten system przez zdefiniowanie makr dla Twoich własnych bibliotek. Powoduje to, że masz do zdefiniowania swój przełącznik kompilatora (analoggiczny do _BUILDING_be). Ustaw przełącznik na wartość różną od zera gdy bufdujesz swoją bibliotekę a następnie przestaw go na zero, kiedy publikujesz nagłówki do użycia przez klientów biblioteki.

Tworzenie i używanie obrazu wtyczki

Obraz wtyczki jest nie do odróżnienia od obrazu biblioteki współdzielonej. Tworzenie wtyczek jest dokładnie takie jak tworzenie biblioteki współdzielonej, temat który wieje powyższym ale z dołaczeniem kilku mniejszych zmian:

$ echo $ADDON_PATH
%A/add-ons:/boot/home/config/add-ons:/boot/beos/system/add-ons

Eksportowanie symboli wtyczki

Aby wyeksportować symbole wtyczki, zadeklaruj ich w ten sposób:

extern "C" __declspec(dllexport) void some_func();
extern "C" __declspec(dllexport) int32 some_global_data;

Oznaczania klasy C++ jako extern wymaga więcej pracy. Nie możesz bezpośrednio oznaczyć klasy jako extern; zwykle tym co robisz jest utworzenie (oznaczenie jako extern) funkcji C, która opakowuje konstruktor klasy:

extern "C" __declspec(dllexport) MyClass *instantiate_my_class();

instantiate_my_class() jest implementowane aby wywołać konstruktor MyClass:

MyClass *instantiate_my_class()
{
return new MyClass();
}

Ładowanie obrazu wtyczki

Aby załądować wtyczkę do Twojej aplikacji, wywołaj funkcję load_add_on(). Funkcja pobiera ścieżkę dostępu (absolutną lub względną w bieżącym katalogu roboczym) do pliku wtyczki i zwraca liczbę image_id, która jest unikalnym identyfikatorem obrazu w całym systemie.

Na przykład, powiedzmy, że utworzyłeś dodatkowy obraz, którym jest wprowadzony do pamięci plik /boot/home/add-ons/adder. Kod, który ładuje wtyczkę wygląda tak, jak ten:

/* Dla zwięzłości, nie sprawdzamy błędów. */
image_id addon_image;

/* Ładowanie wtyczki. */
addon_image = load_add_on("/boot/home/add-ons/adder");

W przeciwieństwie do ładowania pliku wykonywalnego, ładowanie wtyczki nie powoduje utworzenia oddzielnego zespołu ani nie powoduje zapoczątkowania kolejnego wątku. Całym sednem ładowania wtyczki jest wprowadzenie obrazu do przestrzeni adresowej Twojej aplikacji, więc możesz wywoływać funkcje i bawić się zmiennymi, które definiuje wtyczka.

Symbole

Po załadowaniu wtyczki do Twojej aplikacji, będziesz chciał sprawdzić symbole (zmienne i funkcje), które ona przynosi ze sobą. Aby uzyskać informacje o symbolu, wywołaj funkcję get_image_symbol():

status_t get_image_symbol(image_id image,
         char *symbol_name,
         int32 symbol_type,
         void **location)

Pierwsze trzy argumenty funkcji określają symbol, który chcesz uzyskać:

Stała Znaczenie
B_SYMBOL_TYPE_DATA Dane globalne (zmienne)
B_SYMBOL_TYPE_TEXT Funkcje
B_SYMBOL_TYPE_ANY Symbol istniejący gdziekolwiek

Te funkcje zwracają, przez referencję w końcowym argumencie, wskaźnik do adresu symbolu. Na przykład, powiedzmy, że kod wtyczki adder wygląda podobnie do tego:

extern "C" int32 a1 = 0;
extern "C" int32 a2 = 0;
extern "C" int32 adder(void);

int32 adder(void)
{
   return (a1 + a2);
}

Aby sprawdzić zmienne (a1 i a2), powinieneś wywołać get_image_symbol() w ten sposób:

int32 *var_a1, *var_a2;

get_image_symbol(addon_image, "a1", B_SYMBOL_TYPE_DATA, &var_a1);
get_image_symbol(addon_image, "a2", B_SYMBOL_TYPE_DATA, &var_a2);

Uzyskujemy tutaj symbol dla funkcji adder():

int32 (*func_add)();
get_image_symbol(addon_image, "adder", B_SYMBOL_TYPE_TEXT, &func_add);

Teraz, że uzyskaliśmy wszystkie symbole, możemy ustawić wartości dwóch dodawanych liczb i wywołać funkcję::

*var_a1 = 5;
*var_a2 = 3; int32 return_value = (*func_add)();


Be Book Kernel Kit Kernel Kit Indeks

Be Book,
...w ślicznym HTML...
dla BeOS wydanie 5

Copyright © 2000 Be, Inc. Wszelkie prawa zastrzeżone.