Android.mk

Na tej stronie opisujemy składnię pliku kompilacji Android.mk używanego przez ndk-build.

Przegląd

Plik Android.mk znajduje się w podkatalogu katalogu jni/ projektu i opisuje źródła oraz biblioteki udostępnione w systemie kompilacji. Jest to tak naprawdę niewielki fragment pliku GNU, który system kompilacji co najmniej raz analizuje. Plik Android.mk przydaje się do określania ustawień w całym projekcie, które pozostawiają niezdefiniowane ustawienia Application.mk, systemu kompilacji i zmiennych środowiskowych. Możesz też zastąpić ustawienia obowiązujące w całym projekcie dla określonych modułów.

Składnia instrukcji Android.mk umożliwia grupowanie źródeł w moduły. Moduł może być biblioteką statyczną, biblioteką współdzieloną lub samodzielnym elementem wykonywalnym. W każdym pliku Android.mk możesz zdefiniować jeden lub więcej modułów. Tego samego pliku źródłowego możesz używać w wielu modułach. System kompilacji umieszcza w pakiecie aplikacji tylko biblioteki udostępnione. Biblioteki statyczne mogą też generować biblioteki udostępnione.

System kompilacji obsługuje nie tylko biblioteki pakietów, ale też wiele innych szczegółów. Nie musisz na przykład podawać plików nagłówka ani wyraźnych zależności między wygenerowanymi plikami w pliku Android.mk. System kompilacji NDK automatycznie oblicza te relacje za Ciebie. W związku z tym w kolejnych wersjach pakietu NDK obsługa łańcucha narzędzi i platformy powinna być dostępna bez konieczności wprowadzania zmian w pliku Android.mk.

Składnia tego pliku jest bardzo zbliżona do składni plików Android.mk rozpowszechnianych w ramach pełnego projektu Android Open Source Project. Choć implementacja systemu kompilacji, która z nich korzysta, jest inna, podobieństwo między nimi to zamierzona decyzja dotycząca projektowania, której celem jest ułatwienie deweloperom aplikacji ponownego używania kodu źródłowego w bibliotekach zewnętrznych.

Podstawy

Zanim bardziej szczegółowo poznasz składnię, warto zacząć od podstawowych informacji o zawartości pliku Android.mk. W tej sekcji używany jest plik Android.mk z przykładu Hello-JNI, wyjaśniający rolę, jaką odgrywa każdy wiersz w pliku.

Plik Android.mk musi zaczynać się od zdefiniowania zmiennej LOCAL_PATH:

LOCAL_PATH := $(call my-dir)

Ta zmienna wskazuje lokalizację plików źródłowych w drzewie programistycznym. W tym przypadku funkcja makra my-dir udostępniona przez system kompilacji zwraca ścieżkę bieżącego katalogu (katalogu zawierającego sam plik Android.mk).

Następny wiersz deklaruje zmienną CLEAR_VARS, której wartość dostarcza system kompilacji.

include $(CLEAR_VARS)

Zmienna CLEAR_VARS wskazuje specjalny plik GNU Makefile, który usuwa wiele zmiennych LOCAL_XXX, np. LOCAL_MODULE, LOCAL_SRC_FILES i LOCAL_STATIC_LIBRARIES. Pamiętaj, że nie czyści LOCAL_PATH. Ta zmienna musi utrzymywać swoją wartość, ponieważ system analizuje wszystkie pliki kontrolne kompilacji w jednym kontekście wykonania pliku GNU, w którym wszystkie zmienne są globalne. Przed opisaniem każdego modułu musisz zadeklarować tę zmienną ponownie.

Następnie zmienna LOCAL_MODULE przechowuje nazwę modułu, który chcesz utworzyć. Użyj tej zmiennej raz na moduł w aplikacji.

LOCAL_MODULE := hello-jni

Nazwa każdego modułu musi być unikalna i nie może zawierać spacji. Podczas generowania ostatecznego pliku biblioteki współdzielonej system kompilacji automatycznie dodaje odpowiedni prefiks i sufiks do nazwy przypisanej do LOCAL_MODULE. Na przykład przykład widoczny powyżej powoduje wygenerowanie biblioteki o nazwie libhello-jni.so.

W następnym wierszu znajdują się pliki źródłowe, rozdzielone spacjami:

LOCAL_SRC_FILES := hello-jni.c

Zmienna LOCAL_SRC_FILES musi zawierać listę plików źródłowych w języku C lub C++, aby można było wbudować ją w moduł.

Ostatni wiersz pomaga systemowi powiązać wszystko ze sobą:

include $(BUILD_SHARED_LIBRARY)

Zmienna BUILD_SHARED_LIBRARY wskazuje skrypt GNU Makefile, który zbiera wszystkie informacje zdefiniowane w zmiennych LOCAL_XXX od momentu najnowszego include. Skrypt określa, co i jak należy utworzyć.

W katalogach z przykładami znajdują się bardziej złożone przykłady, w których możesz przejrzeć skomentowane pliki Android.mk. Dodatkowo w sekcji Przykład: natywny-aktywność znajdziesz szczegółowe objaśnienie pliku Android.mk tej próbki. Więcej informacji o zmiennych z tej sekcji znajdziesz też w sekcji Zmienne i makra.

Zmienne i makra

System kompilacji udostępnia wiele zmiennych, których można użyć w pliku Android.mk. Wiele z tych zmiennych ma przypisane wstępnie wartości. Inne, przypiszesz.

Oprócz tych zmiennych można też zdefiniować własne zmienne. Jeśli to zrobisz, pamiętaj, że system kompilacji NDK zastrzega sobie te nazwy zmiennych:

  • Nazwy zaczynające się od LOCAL_, np. LOCAL_MODULE.
  • Nazwy zaczynające się od liter PRIVATE_, NDK_ lub APP. System kompilacji korzysta z nich wewnętrznie.
  • Nazwy pisane małymi literami, np. my-dir. System kompilacji korzysta z nich również wewnętrznie.

Jeśli chcesz zdefiniować własne zmienne wygodne w pliku Android.mk, zalecamy dodanie do ich nazw ciągu MY_.

Zdefiniowane przez NDK, uwzględniaj zmienne

W tej sekcji omawiamy zmienne GNU Make zdefiniowane przez system kompilacji przed analizą pliku Android.mk. W pewnych okolicznościach NDK może wielokrotnie przeanalizować plik Android.mk, używając za każdym razem innej definicji niektórych zmiennych.

WYCZYŚĆ_WARIANCJE

Ta zmienna wskazuje skrypt kompilacji, który określa brak definicji prawie wszystkich zmiennych LOCAL_XXX wymienionych w sekcji „Zmienne zdefiniowane przez dewelopera” poniżej. Użyj tej zmiennej, by uwzględnić ten skrypt przed opisaniem nowego modułu. Składnia tego użycia:

include $(CLEAR_VARS)

KOMPILACJA_WYKONANIA

Ta zmienna wskazuje skrypt kompilacji, który zbiera wszystkie informacje o module podanych przez Ciebie w zmiennych LOCAL_XXX i określa sposób tworzenia docelowego pliku wykonywalnego na podstawie podanych przez Ciebie źródeł. Pamiętaj, że korzystanie z tego skryptu wymaga co najmniej przypisanych wartości do LOCAL_MODULE i LOCAL_SRC_FILES (więcej informacji o tych zmiennych znajdziesz w artykule Zmienne opisu modułu).

Składnia tej zmiennej:

include $(BUILD_EXECUTABLE)

BIILD_UDOSTĘPNIONA_BIBLIOTEKA

Ta zmienna wskazuje skrypt kompilacji, który zbiera wszystkie informacje o module podanych przez Ciebie w zmiennych LOCAL_XXX i określa sposób tworzenia docelowych zasobów wspólnych na podstawie wymienionych przez Ciebie źródeł. Pamiętaj, że korzystanie z tego skryptu wymaga co najmniej przypisanych wartości do LOCAL_MODULE i LOCAL_SRC_FILES (więcej informacji o tych zmiennych znajdziesz w artykule Zmienne opisu modułu).

Składnia tej zmiennej:

include $(BUILD_SHARED_LIBRARY)

Zmienna biblioteki współdzielonej powoduje, że system kompilacji generuje plik biblioteki z rozszerzeniem .so.

BIILD_STATYCZNA_BIBLIOTEKA

Wariant biblioteki BUILD_SHARED_LIBRARY służący do tworzenia biblioteki statycznej. System kompilacji nie kopiuje bibliotek statycznych do Twoich projektów lub pakietów, ale może ich używać do tworzenia bibliotek udostępnionych (patrz LOCAL_STATIC_LIBRARIES i LOCAL_WHOLE_STATIC_LIBRARIES poniżej). Składnia tej zmiennej:

include $(BUILD_STATIC_LIBRARY)

Zmienna biblioteki statycznej powoduje, że system kompilacji generuje bibliotekę z rozszerzeniem .a.

BIBLIOTEKA_WSPÓŁPRACY

Wskazuje skrypt kompilacji służący do określenia gotowych zasobów wspólnych. W przeciwieństwie do BUILD_SHARED_LIBRARY i BUILD_STATIC_LIBRARY wartość LOCAL_SRC_FILES nie może być tutaj plikiem źródłowym. Musi to być pojedyncza ścieżka do gotowej biblioteki współdzielonej, takiej jak foo/libfoo.so. Składnia stosowania tej zmiennej:

include $(PREBUILT_SHARED_LIBRARY)

Możesz też odwoływać się do gotowej biblioteki w innym module, używając zmiennej LOCAL_PREBUILTS. Więcej informacji o używaniu gotowych bibliotek znajdziesz w artykule Korzystanie z gotowych bibliotek.

BIBLIOTEKA_STATYCZNA

Taka sama jak PREBUILT_SHARED_LIBRARY, ale dla gotowej biblioteki statycznej. Więcej informacji o używaniu gotowych bibliotek znajdziesz w artykule Korzystanie z gotowych bibliotek.

Docelowe zmienne informacyjne

System kompilacji analizuje Android.mk raz na każdy interfejs ABI określony przez zmienną APP_ABI, która jest zwykle definiowana w pliku Application.mk. Jeśli APP_ABI to all, system kompilacji analizuje Android.mk raz na każdy interfejs ABI obsługiwany przez NDK. W tej sekcji opisujemy zmienne definiowane przez system kompilacji przy każdej analizie Android.mk.

ARCH_DOCELOWY

Rodzina procesorów, na którą kierowany jest system kompilacji, gdy analizuje ten plik Android.mk. Będzie ona mieć jedną z tych wartości: arm, arm64, x86 lub x86_64.

TARGET_PLATFORM

Numer poziomu interfejsu Android API, na który kierowany jest system kompilacji, gdy analizuje ten plik Android.mk. Na przykład obrazy systemu Android 5.1 odpowiadają poziomowi 22 interfejsu API Androida: android-22. Pełną listę nazw platform i odpowiadających im obrazów systemu Android znajdziesz w artykule Natywne interfejsy API. Poniższy przykład przedstawia składnię tej zmiennej:

ifeq ($(TARGET_PLATFORM),android-22)
    # ... do something ...
endif

TARGET_ARCH_ABI

Interfejs ABI, na który kierowany jest system kompilacji, gdy analizuje ten plik Android.mk. Tabela 1 przedstawia ustawienia interfejsu ABI używane w przypadku każdego obsługiwanego procesora i architektury.

Tabela 1. Ustawienia interfejsu ABI dla różnych procesorów i architektur.

Procesor i architektura Ustawienie
ARMv7 armeabi-v7a
ARMv8 AArch64 arm64-v8a
I686 x86
x86–64 x86_64

Z przykładu poniżej dowiesz się, jak sprawdzić, czy docelową kombinację procesora i interfejsu ABI dla ARMv8 AArch64:

ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
  # ... do something ...
endif

Więcej informacji o interfejsach ABI architektury i powiązanych problemach ze zgodnością znajdziesz w artykule na temat interfejsów ABI Androida.

Nowe docelowe interfejsy ABI w przyszłości będą miały inne wartości.

TARGET_ABI

Połączenie docelowego poziomu interfejsu Android API i interfejsu ABI. Jest on szczególnie przydatny, gdy chcesz porównać konkretny obraz systemu z rzeczywistym urządzeniem. Aby na przykład sprawdzić, czy masz urządzenie z 64-bitową architekturą ARM i Androidem API na poziomie 22:

ifeq ($(TARGET_ABI),android-22-arm64-v8a)
  # ... do something ...
endif

Zmienne opisu modułu

Zmienne w tej sekcji opisują Twój moduł w systemie kompilacji. Opis każdego modułu powinien wyglądać tak:

  1. Zainicjuj zmienne powiązane z modułem lub cofnij ich definicję, używając zmiennej CLEAR_VARS.
  2. Przypisać wartości do zmiennych używanych do opisania modułu.
  3. Skonfiguruj system kompilacji NDK tak, aby używał odpowiedniego skryptu kompilacji dla modułu przy użyciu zmiennej BUILD_XXX.

LOCAL_PATH

Ta zmienna podaje ścieżkę bieżącego pliku. Musisz go zdefiniować na początku pliku Android.mk. Poniższy przykład pokazuje, jak to zrobić:

LOCAL_PATH := $(call my-dir)

Skrypt, do którego wskazuje CLEAR_VARS, nie usuwa tej zmiennej. Dlatego wystarczy zdefiniować go tylko raz, nawet jeśli plik Android.mk zawiera wiele modułów.

MODUŁ_LOKALNY

Ta zmienna przechowuje nazwę modułu. Musi być niepowtarzalna wśród wszystkich nazw modułów i nie może zawierać spacji. Musisz zdefiniować to przed dodaniem skryptów (innych niż ten dla CLEAR_VARS). Nie musisz dodawać prefiksu lib ani rozszerzenia pliku .so czy .a – system kompilacji wprowadza te zmiany automatycznie. W plikach Android.mk i Application.mk używaj niezmodyfikowanej nazwy modułu. Na przykład poniższy wiersz powoduje wygenerowanie modułu zasobów wspólnych o nazwie libfoo.so:

LOCAL_MODULE := "foo"

Jeśli chcesz, aby wygenerowany moduł miał inną nazwę niż lib + wartość LOCAL_MODULE, możesz użyć zmiennej LOCAL_MODULE_FILENAME, aby nadać mu własną nazwę.

LOCAL_MODULE_FILENAME

Ta opcjonalna zmienna pozwala zastąpić nazwy, których system kompilacji domyślnie używa w tworzonych przez siebie plikach. Jeśli na przykład nazwa Twojego LOCAL_MODULE to foo, możesz wymusić przez system wywołanie wygenerowanego przez siebie pliku libnewfoo. Poniższy przykład pokazuje, jak to zrobić:

LOCAL_MODULE := foo
LOCAL_MODULE_FILENAME := libnewfoo

W przypadku modułu zasobów wspólnych w tym przykładzie zostałby wygenerowany plik o nazwie libnewfoo.so.

LOCAL_SRC_FILES

Ta zmienna zawiera listę plików źródłowych używanych przez system kompilacji do generowania modułu. Wyświetlaj tylko te pliki, które system kompilacji faktycznie przekazuje do kompilatora, ponieważ system kompilacji automatycznie oblicza wszelkie powiązane zależności. Możesz używać zarówno ścieżek względnych (w odniesieniu do LOCAL_PATH), jak i bezwzględnych.

Zalecamy unikanie bezwzględnych ścieżek do plików. Ścieżki względne zwiększają możliwości przenoszenia pliku Android.mk.

LOCAL_CPP_EXTENSION

Tej opcjonalnej zmiennej możesz użyć, aby wskazać w plikach źródłowych C++ rozszerzenie pliku inne niż .cpp. Na przykład poniższy wiersz zmienia rozszerzenie na .cxx. (Ustawienie musi zawierać kropkę).

LOCAL_CPP_EXTENSION := .cxx

Za pomocą tej zmiennej możesz określić większą liczbę rozszerzeń. Przykład:

LOCAL_CPP_EXTENSION := .cxx .cpp .cc

LOCAL_CPP_FEATURES,

Możesz używać tej opcjonalnej zmiennej, aby wskazać, że Twój kod opiera się na określonych funkcjach C++. Włącza odpowiednie flagi kompilatora i łącznika podczas procesu kompilacji. W przypadku gotowych plików binarnych ta zmienna deklaruje również, od których funkcji zależy dany plik binarny, dzięki czemu ostateczne połączenie działa poprawnie. Zalecamy korzystanie z tej zmiennej zamiast włączania funkcji -frtti i -fexceptions bezpośrednio w definicji elementu LOCAL_CPPFLAGS.

Użycie tej zmiennej pozwala systemowi kompilacji używać odpowiednich flag każdego modułu. Użycie tagu LOCAL_CPPFLAGS powoduje, że kompilator używa wszystkich określonych flag w przypadku wszystkich modułów, niezależnie od rzeczywistej potrzeby.

Aby na przykład wskazać, że Twój kod korzysta z RTTI (informacje o typie środowiska wykonawczego), zapisz:

LOCAL_CPP_FEATURES := rtti

Aby wskazać, że w Twoim kodzie są wyjątki C++, napisz:

LOCAL_CPP_FEATURES := exceptions

Możesz też podać wiele wartości tej zmiennej. Na przykład:

LOCAL_CPP_FEATURES := rtti features

Kolejność, w jakiej opisujesz wartości, nie ma znaczenia.

LOCAL_C_INCLUDES

Możesz użyć tej opcjonalnej zmiennej, aby określić listę ścieżek względem katalogu NDK root, którą chcesz dodać do ścieżki wyszukiwania włączanego podczas kompilowania wszystkich źródeł (C, C++ i Asembly). Na przykład:

LOCAL_C_INCLUDES := sources/foo

Albo nawet:

LOCAL_C_INCLUDES := $(LOCAL_PATH)/<subdirectory>/foo

Zdefiniuj tę zmienną, zanim ustawisz odpowiednie flagi uwzględnienia za pomocą LOCAL_CFLAGS lub LOCAL_CPPFLAGS.

Gdy uruchamiasz natywne debugowanie z użyciem ndk-gdb, system kompilacji automatycznie używa też ścieżek LOCAL_C_INCLUDES.

LOCAL_CFLAGS

Ta opcjonalna zmienna ustawia flagi kompilatora, które system kompilacji przekazuje podczas kompilowania C oraz plików źródłowych C++. Dzięki temu można określić dodatkowe definicje makr lub opcje kompilowania. Użyj LOCAL_CPPFLAGS, aby określić flagi tylko dla C++.

Nie zmieniaj poziomu optymalizacji ani debugowania w pliku Android.mk. System kompilacji może obsłużyć to ustawienie automatycznie na podstawie odpowiednich informacji w pliku Application.mk. W ten sposób system kompilacji będzie mógł generować przydatne pliki danych używane podczas debugowania.

Dodatkowe ścieżki można określić, wpisując:

LOCAL_CFLAGS += -I<path>,

Lepszym rozwiązaniem jest jednak użycie w tym celu polecenia LOCAL_C_INCLUDES, bo dzięki temu można też korzystać ze ścieżek dostępnych do debugowania natywnego w ramach ndk-gdb.

LOKALNE_CPPFLAGS

Opcjonalny zestaw flag kompilatora, który będzie przekazywany tylko podczas tworzenia plików źródłowych C++. Pojawią się po elemencie LOCAL_CFLAGS w wierszu poleceń kompilatora. Użyj LOCAL_CFLAGS, aby określić flagi zarówno dla C, jak i C++.

BIBLIOTEKI_LOCAL_STATIC_LIBRARIES

Zawiera ona listę modułów bibliotek statycznych, od których zależy bieżący moduł.

Jeśli bieżący moduł jest biblioteką współdzieloną lub plikiem wykonywalnym, zmienna ta wymusza połączenie tych bibliotek w wynikowym pliku binarnym.

Jeśli bieżący moduł jest biblioteką statyczną, zmienna ta wskazuje po prostu, że inne moduły w zależności od bieżącego modułu również będą zależeć od bibliotek z listy.

BIBLIOTEKI_LOCAL_SHARED_SHARED

Ta zmienna to lista modułów bibliotek udostępnionych, od których ten moduł zależy w czasie działania. Te informacje są niezbędne w momencie tworzenia połączenia oraz do umieszczania odpowiednich informacji w wygenerowanym pliku.

LOCAL_WHOLE_STATIC_LIBRARIES

Ta zmienna jest wariantem funkcji LOCAL_STATIC_LIBRARIES i wskazuje, że tag łączący powinien traktować powiązane moduły biblioteki jako całe archiwa. Więcej informacji o całych archiwach znajdziesz w dokumentacji GNU ld dotyczącej flagi --whole-archive.

Ta zmienna jest przydatna w przypadku zależności cyklicznych między kilkoma bibliotekami statycznymi. Gdy użyjesz tej zmiennej do utworzenia biblioteki współdzielonej, system kompilacji doda do ostatecznego pliku binarnego wszystkie pliki obiektów z bibliotek statycznych. Nie dotyczy to jednak generowania plików wykonywalnych.

LOCAL_LDLIBS

Ta zmienna zawiera listę dodatkowych flag tagu łączącego do wykorzystania przy tworzeniu udostępnianych zasobów lub plików wykonywalnych. Umożliwia on użycie prefiksu -l do przekazywania nazw konkretnych bibliotek systemowych. Na przykład ten przykład informuje narzędzie łączące, że ma wygenerować moduł, który łączy się z elementem /system/lib/libz.so w czasie wczytywania:

LOCAL_LDLIBS := -lz

Listę ujawnionych bibliotek systemowych, z którymi można się połączyć w tej wersji NDK, znajdziesz w sekcji Natywne interfejsy API.

LOKALNE_LDFLAGS

Lista innych flag tagu łączącego dla systemu kompilacji, których należy używać podczas tworzenia biblioteki współdzielonej lub pliku wykonywalnego. Aby np. użyć tagu łączącego ld.bfd na architekturze ARM/X86:

LOCAL_LDFLAGS += -fuse-ld=bfd

LOCAL_ALLOW_UNDEFINED_SYMBOLS,

Domyślnie, gdy system kompilacji napotka niezdefiniowane odniesienie podczas próby skompilowania udostępnionego pliku, spowoduje to błąd niezdefiniowany symbol. Może on ułatwić wychwytywanie błędów w kodzie źródłowym.

Aby wyłączyć sprawdzanie, ustaw tę zmienną na wartość true. Pamiętaj, że to ustawienie może powodować wczytywanie zasobów wspólnych w czasie działania.

TRYB_LOCAL_ARM

Domyślnie system kompilacji generuje pliki binarne ARM w trybie kciuka, w którym każda instrukcja ma 16 bitów szerokości i jest połączona z bibliotekami STL w katalogu thumb/. Jeśli określisz tę zmienną jako arm, system kompilacji będzie generować pliki obiektów modułu w 32-bitowym trybie arm. Poniższy przykład pokazuje, jak to zrobić:

LOCAL_ARM_MODE := arm

Możesz też poinstruować system kompilacji, aby kompilował tylko określone źródła w trybie arm, dołączając do nazw plików źródłowych sufiks .arm. Na przykład ten przykład informuje system kompilacji, aby zawsze kompilował bar.c w trybie ARM, ale aby kompilował foo.c na podstawie wartości LOCAL_ARM_MODE.

LOCAL_SRC_FILES := foo.c bar.c.arm

LOCAL_ARM_NEON

Ta zmienna ma znaczenie tylko wtedy, gdy kierujesz reklamy na interfejs ABI armeabi-v7a. Umożliwia korzystanie z wbudowanego kompilatora ARM Advanced SIMD (NEON) w źródłach C i C++ oraz na korzystanie z instrukcji NEON w plikach Asembly.

Pamiętaj, że nie wszystkie procesory oparte na ARMv7 obsługują rozszerzenia zestawu instrukcji NEON. Aby bezpiecznie używać tego kodu w czasie działania, musisz je wykrywać w czasie działania. Więcej informacji znajdziesz w artykułach na temat obsługi marki Neon i funkcji procesora.

Możesz też użyć sufiksu .neon, aby wskazać, że system kompilacji będzie kompilować tylko określone pliki źródłowe z obsługą NEON. W poniższym przykładzie system kompilacji kompiluje foo.c z obsługą kciuków i neonów, bar.c z obsługą kciuka oraz zoo.c z obsługą architektur ARM i NEON:

LOCAL_SRC_FILES = foo.c.neon bar.c zoo.c.arm.neon

Jeśli używasz obu sufiksów, .arm musi poprzedzać .neon.

LOCAL_DISABLE_FORMAT_STRING_CHECKS

Domyślnie system kompilacji kompiluje kod z ochroną ciągu znaków formatu. Wymusza to błąd kompilatora, jeśli w funkcji stylu printf używany jest ciąg znaków o niestałym formacie. Ta ochrona jest domyślnie włączona, ale możesz ją wyłączyć, ustawiając tę zmienną na true. Nie zalecamy robić tego bez ważnego powodu.

LOCAL_EXPORT_CFLAGS

Ta zmienna rejestruje zestaw flag kompilatora C/C++, które można dodać do definicji każdego innego modułu, który korzysta z tego modułu LOCAL_CFLAGS, za pomocą zmiennych LOCAL_STATIC_LIBRARIES lub LOCAL_SHARED_LIBRARIES.

Przyjrzyj się na przykład tej parze modułów: foo i bar, która zależy od foo:

include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_CFLAGS := -DFOO=1
include $(BUILD_STATIC_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_CFLAGS := -DBAR=2
LOCAL_STATIC_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)

W tym przypadku system kompilacji przekazuje flagi -DFOO=1 i -DBAR=2 do kompilatora podczas kompilowania bar.c. Dołącza też wyeksportowane flagi do tagu LOCAL_CFLAGS modułu, dzięki czemu możesz je łatwo zastąpić.

Poza tym zależność między modułami jest przechodni: jeśli zoo zależy od wartości bar, która z kolei zależy od wartości foo, zoo odziedziczy też wszystkie flagi wyeksportowane z foo.

System kompilacji nie używa wyeksportowanych flag podczas kompilowania lokalnego (np. podczas kompilowania modułu, którego flagi są eksportowane). Dlatego w powyższym przykładzie nie przekazuje ona do kompilatora -DFOO=1 podczas kompilowania dyrektywy foo/foo.c. Aby tworzyć kompilacje lokalnie, użyj LOCAL_CFLAGS.

LOCAL_EXPORT_CPPFLAGS

Ta zmienna jest taka sama jak LOCAL_EXPORT_CFLAGS, ale tylko w przypadku flag C++.

LOCAL_EXPORT_C_INCLUDES

Ta zmienna jest taka sama jak LOCAL_EXPORT_CFLAGS, ale w przypadku C uwzględnia ścieżki. Jest to przydatne w przypadkach, gdy na przykład bar.c musi dodać nagłówki z modułu foo.

LOCAL_EXPORT_LDFLAGS

Ta zmienna jest taka sama jak LOCAL_EXPORT_CFLAGS, ale występuje w przypadku flag tagu łączącego.

LOCAL_EXPORT_LDLIBS

Ta zmienna jest taka sama jak LOCAL_EXPORT_CFLAGS, ponieważ informuje system kompilacji o tym, że ma przekazywać do kompilatora nazwy konkretnych bibliotek systemowych. Dodaj przedrostek -l do nazwy każdej biblioteki.

Pamiętaj, że system kompilacji dołącza zaimportowane flagi łączące do wartości zmiennej LOCAL_LDLIBS modułu. Wynika to ze sposobu działania linków uniksowych.

Ta zmienna jest zwykle przydatna, gdy moduł foo jest biblioteką statyczną i zawiera kod, który zależy od biblioteki systemowej. Następnie możesz wyeksportować zależność za pomocą polecenia LOCAL_EXPORT_LDLIBS. Na przykład:

include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_LDLIBS := -llog
include $(BUILD_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_STATIC_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)

W tym przykładzie podczas tworzenia elementu libbar.so system kompilacji umieszcza -llog na końcu polecenia tagu łączącego. Informuje to usługę łączącą, że ponieważ libbar.so zależy od foo, zależy też od biblioteki logów systemowych.

LOCAL_SHORT_POLECENIA

Ustaw tę zmienną na true, gdy Twój moduł ma bardzo dużą liczbę źródeł bądź zależnych bibliotek statycznych lub udostępnionych. Wymusza to użycie przez system kompilacji składni @ na potrzeby archiwów zawierających obiekty pośrednie lub biblioteki łączące.

Ta funkcja może być przydatna w systemie Windows, gdzie wiersz poleceń akceptuje maksymalnie 8191 znaków, co jest zbyt małe w przypadku złożonych projektów. Wpływa też na kompilację poszczególnych plików źródłowych, ponieważ umieszcza prawie wszystkie flagi kompilatora w plikach list.

Pamiętaj, że każda wartość inna niż true zostanie przywrócona do działania domyślnego. Możesz też zdefiniować APP_SHORT_COMMANDS w pliku Application.mk, aby wymusić takie zachowanie we wszystkich modułach w projekcie.

Nie zalecamy domyślnego włączania tej funkcji, ponieważ spowalnia to kompilację.

LOCAL_THIN_ARCHIVE

Podczas tworzenia bibliotek statycznych ustaw tę zmienną na true. Spowoduje to wygenerowanie cienkiego archiwum, czyli pliku biblioteki, który nie będzie zawierać plików obiektów, ale tylko ścieżek do rzeczywistych obiektów, które normalnie zawiera.

Przydaje się to do zmniejszenia rozmiaru danych wyjściowych kompilacji. Wadą jest to, że takich bibliotek nie można przenosić w inne miejsce (wszystkie zawarte w nich ścieżki są względne).

Prawidłowe wartości to true, false lub puste. Wartość domyślną można ustawić w pliku Application.mk za pomocą zmiennej APP_THIN_ARCHIVE.

LOCAL_FILTER_ASM

Zdefiniuj tę zmienną jako polecenie powłoki, którego system kompilacji będzie używać do filtrowania plików zestawu wyodrębnionych lub wygenerowanych z plików określonych w zadaniu LOCAL_SRC_FILES. Zdefiniowanie tej zmiennej powoduje takie sytuacje:

  1. Zamiast kompilować do pliku obiektu, system kompilacji generuje tymczasowy plik montażowy z dowolnego pliku źródłowego w języku C lub C++.
  2. System kompilacji wykonuje polecenie powłoki w LOCAL_FILTER_ASM w dowolnym tymczasowym pliku asemblera i na dowolnym pliku asemblera wymienionym w LOCAL_SRC_FILES. W ten sposób generuje kolejny tymczasowy plik asemblera.
  3. System kompilacji kompiluje te odfiltrowane pliki asemblera do pliku obiektu.

Na przykład:

LOCAL_SRC_FILES  := foo.c bar.S
LOCAL_FILTER_ASM :=

foo.c --1--> $OBJS_DIR/foo.S.original --2--> $OBJS_DIR/foo.S --3--> $OBJS_DIR/foo.o
bar.S                                 --2--> $OBJS_DIR/bar.S --3--> $OBJS_DIR/bar.o

Wartość „1” odpowiada kompilatorowi, „2” – filtrowi, a „3” – asematorowi. Filtr musi być samodzielnym poleceniem powłoki, którego pierwszym argumentem jest nazwa pliku wejściowego, a nazwa pliku wyjściowego – drugim. Na przykład:

myasmfilter $OBJS_DIR/foo.S.original $OBJS_DIR/foo.S
myasmfilter bar.S $OBJS_DIR/bar.S

Makra funkcji udostępniane przez NDK

W tej sekcji omówiono makra funkcji GNU Make dostępne w pakiecie NDK. Oceń je za pomocą $(call <function>). Zwracają informacje tekstowe.

mój dir

To makro zwraca ścieżkę ostatniego uwzględnionego pliku tworzenia, który zwykle jest bieżącym katalogiem Android.mk. Parametr my-dir przydaje się do definiowania parametru LOCAL_PATH na początku pliku Android.mk. Na przykład:

LOCAL_PATH := $(call my-dir)

Ze względu na sposób działania narzędzia GNU Make to makro tak naprawdę zwraca ścieżkę do ostatniego pliku tworzenia, który został uwzględniony przez system kompilacji podczas analizowania skryptów kompilacji. Z tego powodu nie należy wywoływać funkcji my-dir po dołączeniu innego pliku.

Przeanalizujmy następujący przykład:

LOCAL_PATH := $(call my-dir)

# ... declare one module

include $(LOCAL_PATH)/foo/`Android.mk`

LOCAL_PATH := $(call my-dir)

# ... declare another module

Problem polega na tym, że drugie wywołanie my-dir określa LOCAL_PATH jako $PATH/foo, a nie $PATH, ponieważ w tym miejscu wskazano ostatnie wywołanie elementu typu „include”.

Możesz uniknąć tego problemu, umieszczając w pliku Android.mk dodatkowe elementy z elementami innymi. Na przykład:

LOCAL_PATH := $(call my-dir)

# ... declare one module

LOCAL_PATH := $(call my-dir)

# ... declare another module

# extra includes at the end of the Android.mk file
include $(LOCAL_PATH)/foo/Android.mk

Jeśli struktura pliku w ten sposób nie jest możliwa, zapisz wartość pierwszego wywołania my-dir w innej zmiennej. Na przykład:

MY_LOCAL_PATH := $(call my-dir)

LOCAL_PATH := $(MY_LOCAL_PATH)

# ... declare one module

include $(LOCAL_PATH)/foo/`Android.mk`

LOCAL_PATH := $(MY_LOCAL_PATH)

# ... declare another module

wszystkie-pliki-subdir

Zwraca listę plików Android.mk znajdujących się we wszystkich podkatalogach bieżącej ścieżki my-dir.

Możesz użyć tej funkcji, aby udostępnić systemowi kompilacji głęboko zagnieżdżone hierarchie katalogów źródłowych. Domyślnie pakiet NDK szuka tylko plików w katalogu zawierającym plik Android.mk.

ten-plik-makefile

Zwraca ścieżkę bieżącego pliku tworzenia (z którego system kompilacji wywołał funkcję).

plik nadrzędny-makefile

Zwraca ścieżkę nadrzędnego pliku Makefile w drzewie uwzględniającym (ścieżkę plikumakefile, który zawiera bieżący).

plik-make-file-parent-parent

Zwraca ścieżkę pliku tworzenia wyższego poziomu w drzewie uwzględniającym (ścieżkę pliku tworzenia zawierającego bieżący plik).

Importuj moduł

Funkcja, która pozwala znaleźć i uwzględnić plik Android.mk modułu według nazwy modułu. Typowy przykład jest następujący:

$(call import-module,<name>)

W tym przykładzie system kompilacji szuka modułu oznaczonego tagiem <name> na liście katalogów, do których odwołuje się zmienna środowiskowa NDK_MODULE_PATH, i automatycznie dołącza plik Android.mk.