Na tej stronie opisaliśmy składnię pliku kompilacji Android.mk
używanego przez ndk-build
.
Omówienie
Plik Android.mk
znajduje się w podkatalogu katalogu jni/
projektu i opisuje źródła oraz biblioteki udostępnione systemowi kompilacji.
Jest to bardzo mały fragment pliku make GNU, który system kompilacji analizuje raz lub więcej razy. Plik Android.mk
przydaje się do definiowania ustawień dla całego projektu, które powodują, że Application.mk
, system kompilacji i zmienne środowiskowe pozostają nieokreślone. Może też zastępować ustawienia całego projektu dla konkretnych modułów.
Dzięki składni Android.mk
możesz grupować źródła w moduły.
Moduł może być biblioteką statyczną, biblioteką współdzieloną lub samodzielnym plikiem wykonywalnym. W każdym pliku Android.mk
możesz zdefiniować co najmniej 1 moduł. Tego samego pliku źródłowego możesz używać w wielu modułach. System kompilacji umieszcza tylko biblioteki udostępnione w pakiecie aplikacji. Biblioteki statyczne mogą też generować biblioteki udostępnione.
Oprócz pakowania bibliotek system kompilacji obsługuje 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. W rezultacie w kolejnych wersjach NDK będziesz mieć możliwość korzystania z nowych funkcji łańcucha narzędzi/platformy bez konieczności kontaktu z plikiem Android.mk
.
Składnia tego pliku jest bardzo zbliżona do składni plików Android.mk
rozpowszechnianych w ramach pełnego Android Open Source Project. Chociaż system kompilacji, który ich używa, jest inny, ich podobieństwo jest celowym projektem, którego celem jest ułatwienie deweloperom aplikacji ponowne wykorzystanie kodu źródłowego zewnętrznych bibliotek.
Podstawy
Zanim zaczniesz szczegółowo analizować składnię, warto najpierw zapoznać się z podstawami zawartości pliku Android.mk
. W tej sekcji na przykładzie pliku Android.mk
w pliku Hello-JNI wyjaśniamy, jaką rolę odgrywa każdy wiersz w tym 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 programowania. Tutaj funkcja makro my-dir
udostępniana przez system kompilacji zwraca ścieżkę do bieżącego katalogu (katalogu zawierającego sam plik Android.mk
).
W następnym wierszu deklaruje się zmienną CLEAR_VARS
, której wartość dostarcza system kompilacji.
include $(CLEAR_VARS)
Zmienna CLEAR_VARS
wskazuje na specjalny plik Makefile GNU, który oczyszcza dla Ciebie wiele zmiennych LOCAL_XXX
, takich jak LOCAL_MODULE
, LOCAL_SRC_FILES
i LOCAL_STATIC_LIBRARIES
. Pamiętaj, że nie zostanie usunięte pole LOCAL_PATH
. Ta zmienna musi zachować swoją wartość, ponieważ system analizuje wszystkie pliki kontrolne kompilacji w jednym kontekście wykonywania GNU Make, w którym wszystkie zmienne są globalne. Przed opisaniem każdego modułu musisz ponownie zadeklarować tę zmienną.
Następnie zmienna LOCAL_MODULE
przechowuje nazwę modułu, który chcesz skompilować. Użyj tej zmiennej raz w każdym module w swojej aplikacji.
LOCAL_MODULE := hello-jni
Każda nazwa modułu musi być niepowtarzalna i nie może zawierać spacji. Gdy system kompilacji generuje ostateczny plik biblioteki współdzielonej, automatycznie dodaje odpowiedni prefiks i sufiks do nazwy przypisanej do LOCAL_MODULE
. Na przykład przykład podany powyżej powoduje wygenerowanie biblioteki o nazwie libhello-jni.so
.
Następny wiersz wymienia pliki źródłowe, a przerwy między nimi oznaczają spacje:
LOCAL_SRC_FILES := hello-jni.c
Zmienna LOCAL_SRC_FILES
musi zawierać listę plików źródłowych w języku C lub C++, które można umieścić w module.
Ostatni wiersz pomaga systemowi powiązać ze sobą wszystkie elementy:
include $(BUILD_SHARED_LIBRARY)
Zmienna BUILD_SHARED_LIBRARY
wskazuje skrypt GNU Makefile, który gromadzi wszystkie informacje zdefiniowane w zmiennych LOCAL_XXX
od ostatniego include
. Ten skrypt określa, co i jak budować.
W katalogach z przykładami znajdziesz bardziej złożone przykłady z komentarzami w plikach Android.mk
, które możesz przejrzeć. Dodatkowo Przykład: natywne-aktywność zawiera szczegółowe objaśnienie pliku Android.mk
przykładowego. Więcej informacji o zmiennych znajdziesz w sekcji Zmienne i makra.
Zmienne i makra
System kompilacji udostępnia wiele możliwych zmiennych do użycia w pliku Android.mk
.
Wiele z tych zmiennych ma wstępnie przypisane wartości. Pozostałe, które przypisujesz.
Oprócz tych zmiennych możesz także definiować własne dowolne. Pamiętaj, że system kompilacji NDK rezerwuje te nazwy zmiennych:
- Nazwy zaczynające się od
LOCAL_
, na przykładLOCAL_MODULE
. - nazwy zaczynające się od
PRIVATE_
,NDK_
lubAPP
; System kompilacji używa ich wewnętrznie. - Nazwy pisane małymi literami, np.
my-dir
. System kompilacji używa ich również wewnętrznie.
Jeśli musisz zdefiniować własne zmienne ułatwiające w pliku Android.mk
, zalecamy dodanie do ich nazw prefiksu MY_
.
Zmienne uwzględniania zdefiniowane przez NDK
W tej sekcji omawiamy zmienne GNU Make, które system kompilacji definiuje przed analizą pliku Android.mk
. W pewnych okolicznościach NDK może kilka razy przeanalizować plik Android.mk
, za każdym razem używając innej definicji niektórych zmiennych.
CLEAR_VARS
Ta zmienna wskazuje skrypt kompilacji, który niedefiniuje prawie wszystkich zmiennych LOCAL_XXX
wymienionych w sekcji „Zmienne zdefiniowane przez programistę” poniżej. Użyj tej zmiennej, aby uwzględnić ten skrypt przed opisem nowego modułu. Składnia używana:
include $(CLEAR_VARS)
BUILD_EXECUTABLE
Ta zmienna wskazuje skrypt kompilacji, który gromadzi wszystkie informacje o module podanym w zmiennych LOCAL_XXX
, i określa, jak skompilować plik wykonywalny docelowy na podstawie wymienionych źródeł. Pamiętaj, że użycie tego skryptu wymaga, aby wartości zmiennych LOCAL_MODULE
i LOCAL_SRC_FILES
były już przypisane (więcej informacji o tych zmiennych znajdziesz w sekcji Zmienna opisowa modułu).
Składnia używana do użycia tej zmiennej:
include $(BUILD_EXECUTABLE)
BUILD_SHARED_LIBRARY
Ta zmienna wskazuje skrypt kompilacji, który zbiera wszystkie informacje o module podany przez Ciebie w zmiennych LOCAL_XXX
i określa, jak na podstawie wymienionych źródeł utworzyć docelową bibliotekę udostępnioną. Pamiętaj, że ten skrypt wymaga wcześniejszego przypisania wartości do LOCAL_MODULE
i LOCAL_SRC_FILES
(więcej informacji o tych zmiennych znajdziesz w artykule Zmienne opisu modułu).
Składnia używana do użycia tej zmiennej:
include $(BUILD_SHARED_LIBRARY)
Zmienna biblioteki współdzielonej powoduje, że system kompilacji generuje plik biblioteki z rozszerzeniem .so
.
BUILD_STATIC_BIBLIOTEKA
Wariant języka BUILD_SHARED_LIBRARY
używany do tworzenia biblioteki statycznej. System kompilacji nie kopiuje bibliotek statycznych do projektu/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 użycia tej zmiennej:
include $(BUILD_STATIC_LIBRARY)
Zmienna biblioteki statycznej powoduje, że system kompilacji generuje bibliotekę z rozszerzeniem .a
.
PREBUILT_SHARED_LIBRARY
Wskazuje skrypt kompilacji używany do określenia gotowej biblioteki współdzielonej. W przeciwieństwie do sytuacji BUILD_SHARED_LIBRARY
i BUILD_STATIC_LIBRARY
wartość LOCAL_SRC_FILES
nie może być plikiem źródłowym. Musi to być pojedyncza ścieżka do
gotowej biblioteki współdzielonej, np. foo/libfoo.so
. Składnia użycia tej zmiennej:
include $(PREBUILT_SHARED_LIBRARY)
Możesz też odwołać się do gotowej biblioteki w innym module, używając zmiennej LOCAL_PREBUILTS
. Więcej informacji o korzystaniu z gotowych bibliotek znajdziesz w artykule Korzystanie z gotowych bibliotek.
PREBUILT_STATIC_BIBLIOTEKA
To samo co PREBUILT_SHARED_LIBRARY
, ale w przypadku wstępnie utworzonej biblioteki statycznej. Więcej informacji o korzystaniu z gotowych bibliotek znajdziesz w artykule Korzystanie z gotowych bibliotek.
Docelowe zmienne informacji
System kompilacji analizuje pole Android.mk
raz na interfejs ABI określony przez zmienną APP_ABI
, która jest zwykle definiowana w pliku Application.mk
. Jeśli APP_ABI
jest all
, system kompilacji analizuje Android.mk
raz na każdą wersję ABI obsługiwaną przez NDK. W tej sekcji opisujemy zmienne, które system kompilacji definiuje za każdym razem, gdy analizuje Android.mk
.
TARGET_ARCH
Rodzina procesorów, na którą system kompilacji kieruje się podczas analizowania tego pliku Android.mk
. Zmienna będzie jedną z tych zmiennych: arm
, arm64
, x86
lub x86_64
.
TARGET_PLATFORM
Numer poziomu interfejsu API Androida, na który system kompilacji kieruje podczas analizowania tego pliku Android.mk
. Na przykład obrazy systemu Androida 5.1 odpowiadają poziomowi API Androida 22: android-22
. Pełną listę nazw platform i odpowiadających im obrazów systemu Androida znajdziesz w artykule Natywne interfejsy API. Przykładowa składnia użycia tej zmiennej:
ifeq ($(TARGET_PLATFORM),android-22)
# ... do something ...
endif
TARGET_ARCH_ABI
Interfejs ABI, na który kierowany jest system kompilacji podczas analizowania tego pliku Android.mk
.
Tabela 1 przedstawia ustawienie interfejsu ABI używane w przypadku każdego obsługiwanego procesora i architektury.
Procesor i architektura | Ustawienie |
---|---|
ARM wersja 7 | armeabi-v7a |
ARMv8 AArch64 | arm64-v8a |
i686 | x86 |
x86-64 | x86_64 |
Ten przykład pokazuje, jak sprawdzić, czy ARMv8 AArch64 jest docelową kombinacją procesora i interfejsu ABI:
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
# ... do something ...
endif
Więcej informacji o interfejsach ABI i powiązanych z nimi problemach ze zgodnością znajdziesz w artykule Interfejsy ABI na Androida.
Nowe docelowe ABI będą miały w przyszłości inne wartości.
TARGET_ABI
Połączenie docelowego poziomu interfejsu API Androida i interfejsu ABI. Jest to szczególnie przydatne, gdy chcesz porównać z konkretnym docelowym obrazem systemu na rzeczywistym urządzeniu. Aby na przykład sprawdzić, czy urządzenie z procesorem ARM 64-bitowym działa na poziomie API 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 przebiegać w następujący sposób:
- za pomocą zmiennej
CLEAR_VARS
inicjować lub odznaczać zmienne powiązane z modulem; - Przypisanie wartości do zmiennych używanych do opisania modułu.
- Skonfiguruj system kompilacji NDK tak, aby używał odpowiedniego skryptu kompilacji dla danego modułu za pomocą zmiennej
BUILD_XXX
.
LOCAL_PATH
Ta zmienna służy do określenia ścieżki do bieżącego pliku. Musisz ją zdefiniować na początku pliku Android.mk
. Ten przykład pokazuje, jak to zrobić:
LOCAL_PATH := $(call my-dir)
Skrypt, na który wskazuje CLEAR_VARS
, nie odczytuje tej zmiennej. Dlatego wystarczy zdefiniować go tylko raz, nawet jeśli Twój plik Android.mk
opisuje wiele modułów.
LOCAL_MODULE
Ta zmienna przechowuje nazwę modułu. Musi być niepowtarzalna wśród wszystkich
nazw modułów i nie może zawierać spacji. Musisz go zdefiniować przed dodaniem skryptów (innych niż dla CLEAR_VARS
). Nie musisz dodawać przedrostka lib
ani rozszerzenia pliku .so
ani .a
. System kompilacji wprowadzi te zmiany automatycznie. W plikach Android.mk
i Application.mk
używaj niezmodyfikowanej nazwy modułu. Na przykład ten wiersz powoduje wygenerowanie modułu zasobów wspólnych o nazwie libfoo.so
:
LOCAL_MODULE := "foo"
Jeśli chcesz, aby wygenerowany moduł miał nazwę inną niż lib
+ wartość zmiennej LOCAL_MODULE
, możesz użyć zmiennej LOCAL_MODULE_FILENAME
, aby nadać wygenerowanemu modułowi nazwę według własnego uznania.
LOCAL_MODULE_FILENAME
Ta opcjonalna zmienna umożliwia zastąpienie nazw, których system kompilacji używa domyślnie w przypadku generowanych plików. Jeśli na przykład nazwa LOCAL_MODULE
to foo
, możesz zmusić system do wywołania wygenerowanego przez niego pliku libnewfoo
. Ten przykład ilustruje, jak to zrobić:
LOCAL_MODULE := foo
LOCAL_MODULE_FILENAME := libnewfoo
W przypadku modułu biblioteki udostępnionej ten przykład generuje plik o nazwie libnewfoo.so
.
LOCAL_SRC_FILES
Ta zmienna zawiera listę plików źródłowych, których system kompilacji używa do wygenerowania modułu. Wymień tylko pliki, które system kompilacji faktycznie przekazuje do kompilatora, ponieważ system kompilacji automatycznie oblicza wszystkie powiązane zależności. Pamiętaj, że możesz używać ścieżek względnych (względem LOCAL_PATH
) i bezwzględnych.
Zalecamy unikanie ścieżek bezwzględnych; ścieżki względne sprawiają, że plik Android.mk
jest bardziej przenośny.
LOCAL_CPP_EXTENSION
Za pomocą tej opcjonalnej zmiennej możesz wskazać w plikach źródłowych C++ rozszerzenie pliku inne niż .cpp
. Na przykład w tym wierszu rozszerzenie zmienia się na .cxx
. (ustawienie musi zawierać kropkę).
LOCAL_CPP_EXTENSION := .cxx
Za pomocą tej zmiennej możesz określać wiele rozszerzeń. Na przykład:
LOCAL_CPP_EXTENSION := .cxx .cpp .cc
LOCAL_CPP_FEATURES
Za pomocą tej opcjonalnej zmiennej możesz wskazać, że Twój kod korzysta z określonych funkcji C++. Umożliwia to włączenie odpowiednich flag kompilatora i linkera podczas procesu kompilacji. W przypadku gotowych plików binarnych ta zmienna deklaruje też, od których cech zależy element binarny, co pomaga zagwarantować prawidłowe działanie ostatecznego połączenia. Zalecamy używanie tej zmiennej zamiast włączania -frtti
i -fexceptions
bezpośrednio w definicji LOCAL_CPPFLAGS
.
Użycie tej zmiennej pozwala systemowi kompilacji używać odpowiednich flag dla każdego modułu. Użycie metody LOCAL_CPPFLAGS
powoduje, że kompilator używa wszystkich określonych flag w przypadku wszystkich modułów niezależnie od faktycznej potrzeby.
Aby na przykład wskazać, że kod używa informacji o typie w czasie wykonywania (RTTI), napisz:
LOCAL_CPP_FEATURES := rtti
Aby wskazać, że kod używa wyjątków 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
Za pomocą tej opcjonalnej zmiennej możesz podać listę ścieżek względnych do katalogu NDK root
, które mają zostać dodane do ścieżki wyszukiwania include podczas kompilowania wszystkich źródeł (C, C++ i Assembly). Na przykład:
LOCAL_C_INCLUDES := sources/foo
Możesz też:
LOCAL_C_INCLUDES := $(LOCAL_PATH)/<subdirectory>/foo
Zdefiniuj tę zmienną, zanim ustawisz odpowiednie flagi uwzględniania za pomocą LOCAL_CFLAGS
lub LOCAL_CPPFLAGS
.
System kompilacji automatycznie używa ścieżek LOCAL_C_INCLUDES
podczas uruchamiania debugowania natywnego za pomocą ndk-gdb.
LOCAL_ASFLAGS
Flagi, które zostaną przekazane do Clang podczas kompilowania plików .s
lub .S
.
LOCAL_ASMFLAGS
Flagi, które będą przekazywane do Ciebie podczas tworzenia plików .asm
.
LOCAL_CFLAGS
Flagi, które będą przekazywane do Clang podczas tworzenia plików źródłowych C, C++ i niektórych plików asemblera (.s
i .S
, ale nie .asm
). Ta funkcja może być przydatna do określania dodatkowych definicji makr lub opcji kompilacji. Użyj LOCAL_CPPFLAGS
, aby określić flagi tylko dla C++. Użyj LOCAL_CONLYFLAGS
, aby określić flagi tylko dla C.
Postaraj się nie zmieniać poziomu optymalizacji i debugowania w pliku Android.mk
.
System kompilacji może automatycznie obsłużyć to ustawienie za Ciebie, korzystając z odpowiednich informacji w pliku Application.mk
. Dzięki temu system kompilacji może generować przydatne pliki danych używane podczas debugowania.
Można określić dodatkowe ścieżki include, pisząc:
LOCAL_CFLAGS += -I<path>,
Lepiej jednak do tego celu jest użycie parametru LOCAL_C_INCLUDES
, ponieważ umożliwia to również korzystanie ze ścieżek dostępnych w przypadku debugowania natywnego z parametrem ndk-gdb.
LOCAL_CONLYFLAGS
Flagi, które będą przekazywane do Clang podczas kompilacji źródeł C. W przeciwieństwie do LOCAL_CFLAGS
kod LOCAL_CONLYFLAGS
nie będzie przekazywany do języka Clang podczas kompilowania źródeł w języku C++ lub źródeł asemblera.
LOCAL_CPPFLAGS
Opcjonalny zestaw flag kompilatora, który będzie przekazywany tylko podczas tworzenia plików źródłowych C++. Pojawiają się one po LOCAL_CFLAGS
w wierszu poleceń kompilatora. Użyj LOCAL_CFLAGS
, aby określić flagi zarówno w języku C, jak i C++.
LOCAL_STATIC_LIBRARIES
Ta zmienna przechowuje 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, ta zmienna wymusza połączenie tych bibliotek z wynikowym plikiem binarnym.
Jeśli bieżący moduł jest statyczną biblioteką, ta zmienna wskazuje, że inne moduły, które zależą od bieżącego, będą też zależeć od wymienionych bibliotek.
LOCAL_SHARED_LIBRARIES
Ta zmienna to lista modułów bibliotek wspólnych, od których zależy ten moduł w czasie wykonywania. Te informacje są potrzebne w momencie łączenia i wstawiania odpowiednich informacji do wygenerowanego pliku.
LOCAL_WHOLE_STATIC_LIBRARIES
Ta zmienna jest wariantem funkcji LOCAL_STATIC_LIBRARIES
i wskazuje, że tag łączący powinien traktować powiązane z nią moduły biblioteki jako całe archiwa. Więcej informacji na temat całych archiwów znajdziesz w dokumentacji GNU ld dotyczącej flagi --whole-archive
.
Ta zmienna jest przydatna, gdy występują zależności cykliczne między wieloma bibliotekami statycznymi. Gdy użyjesz tej zmiennej do skompilowania biblioteki współdzielonej, system kompilacji doda do końcowego pliku binarnego wszystkie pliki obiektowe z bibliotek statycznych. Nie dotyczy to jednak plików wykonywalnych.
LOCAL_LDLIBS
Ta zmienna zawiera listę dodatkowych flag tagu łączącego, które możesz wykorzystać podczas tworzenia biblioteki udostępnionej lub pliku wykonywalnego. Dzięki temu możesz przekazywać nazwy konkretnych bibliotek systemowych za pomocą prefiksu -l
. W tym przykładzie pokazujemy tagowi łączącemu wygenerowanie modułu łączącego się z adresem /system/lib/libz.so
w czasie wczytywania:
LOCAL_LDLIBS := -lz
Listę udostępnionych bibliotek systemowych, do których możesz się odwoływać w ramach tej wersji NDK, znajdziesz w artykule Natywne interfejsy API.
LOCAL_LDFLAGS
Lista innych flag linkera dla systemu kompilacji, których należy używać podczas kompilowania biblioteki współdzielonej lub pliku wykonywalnego. Aby np. użyć tagu łączącego ld.bfd
w architekturze ARM/X86:
LOCAL_LDFLAGS += -fuse-ld=bfd
LOCAL_ALLOW_UNDEFINED_SYMBOLS
Domyślnie, gdy system kompilacji natrafi na niezdefiniowane odwołanie podczas próby utworzenia udostępnionego, domyślnie wyświetli błąd niezdefiniowanego symbolu. Ten błąd może pomóc w wykrywaniu błędów w kodzie źródłowym.
Aby wyłączyć tę weryfikację, ustaw tę zmienną na true
. Pamiętaj, że to ustawienie może spowodować wczytywanie biblioteki udostępnionej w czasie wykonywania.
TRYB LOKALNY
Domyślnie system kompilacji generuje pliki binarne docelowego ARM w trybie thumb, w którym każda instrukcja ma 16 bitów i jest powiązana z bibliotekami STL w katalogu thumb/
. Zdefiniowanie tej zmiennej jako arm
wymusza przez system kompilacji generowanie plików obiektów modułu w 32-bitowym trybie arm
. Jak to zrobić:
LOCAL_ARM_MODE := arm
Możesz też polecić systemowi kompilacji, aby w trybie arm
kompilował tylko określone źródła. W tym celu do nazw plików źródłowych dodaj sufiks .arm
. Na przykład w tym przykładzie system kompilacji jest informowany, że bar.c
należy zawsze kompilować w trybie ARM, a foo.c
– zgodnie z wartością parametru 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 wbudowanych funkcji kompilatora ARM Advanced SIMD (NEON) w źródłach C i C++ oraz z instrukcji NEON w plikach asembly.
Pamiętaj, że nie wszystkie procesory ARMv7 obsługują rozszerzenia zestawu instrukcji NEON. Z tego powodu musisz przeprowadzić wykrywanie w czasie wykonywania, aby móc bezpiecznie używać tego kodu w czasie wykonywania. Więcej informacji znajdziesz w artykule o obsługi Neona i funkcjach procesora.
Możesz też użyć sufiksu .neon
, aby wskazać, że system kompilacji ma kompilować tylko określone pliki źródłowe z obsługą NEON. W tym przykładzie system kompilacji kompiluje foo.c
z obsługą funkcji thumb i neon, bar.c
z obsługą funkcji thumb oraz zoo.c
z obsługą architektury ARM i funkcji NEON:
LOCAL_SRC_FILES = foo.c.neon bar.c zoo.c.arm.neon
Jeśli używasz obu przyrostkó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 w stylu printf
używany jest ciąg znaków w formacie niestałym. Ta ochrona jest domyślnie włączona, ale możesz ją wyłączyć, ustawiając wartość tej zmiennej na true
. Nie zalecamy tego robić bez ważnego powodu.
LOCAL_EXPORT_CFLAGS
Ta zmienna rejestruje zestaw flag kompilatora C/C++, które należy dodać do definicji LOCAL_CFLAGS
każdego innego modułu, który korzysta z tego rodzaju za pomocą zmiennych LOCAL_STATIC_LIBRARIES
lub LOCAL_SHARED_LIBRARIES
.
Rozważmy na przykład parę modułów: foo
i bar
, która zależy od modułu 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)
Podczas kompilowania pliku bar.c
system kompilacji przekazuje do kompilatora flagi -DFOO=1
i -DBAR=2
. Dodaje też do LOCAL_CFLAGS
wyeksportowane flagi, dzięki czemu możesz je łatwo zastąpić.
Ponadto relacja między modułami jest przechodnia: jeśli zoo
zależy od bar
, który z kolei zależy od foo
, to zoo
dziedziczy również wszystkie flagi wyeksportowane z foo
.
Na koniec system kompilacji nie używa wyeksportowanych flag podczas kompilowania lokalnie (czyli kompilowania modułu, którego flagi są eksportowane). Dlatego w przykładzie powyżej podczas kompilowania funkcji foo/foo.c
nie jest przekazywana do kompilatora wartość -DFOO=1
. Aby kompilować lokalnie, użyj polecenia 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ędnij ścieżki. Jest to przydatne, gdy np. bar.c
musi zawierać nagłówki z modułu foo
.
LOCAL_EXPORT_LDFLAGS
Ta zmienna jest taka sama jak LOCAL_EXPORT_CFLAGS
, ale dotyczy flag linkera.
LOCAL_EXPORT_LDLIBS
Ta zmienna jest taka sama jak LOCAL_EXPORT_CFLAGS
i informuje system kompilacji, aby przekazywał nazwy konkretnych bibliotek systemowych do kompilatora. Do nazwy każdej biblioteki dodaj -l
.
Pamiętaj, że system kompilacji dołącza zaimportowane flagi linkera do wartości zmiennej LOCAL_LDLIBS
w module. Wynika to ze sposobu działania elementów łączących Unix.
Ta zmienna jest zwykle przydatna, gdy moduł foo
jest stałą biblioteką i zawiera kod, który zależy od biblioteki systemowej. Następnie możesz użyć polecenia LOCAL_EXPORT_LDLIBS
, aby wyeksportować zależność. 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 system kompilacji umieszcza -llog
na końcu polecenia łączącego, gdy tworzy libbar.so
. Dzięki temu tag łączący dane będzie wiedzieć, że wartość libbar.so
zależy od foo
, zależy także od biblioteki logów systemowych.
LOCAL_SHORT_POLECENIA
Jeśli moduł ma bardzo dużą liczbę źródeł lub zależnych bibliotek statycznych lub współdzielonych, ustaw tę zmienną na true
. Wymusza to w systemie kompilacji użycie składni @
w przypadku archiwów zawierających pośrednie pliki obiektów lub bibliotek z linkami.
Ta funkcja może być przydatna w systemie Windows, w którym wiersz poleceń może zawierać maksymalnie 8191 znaków, co może być za małe w przypadku złożonych projektów. Ma to również wpływ na kompilację poszczególnych plików źródłowych, umieszczając prawie wszystkie flagi kompilatora w plikach list.
Pamiętaj, że każda wartość inna niż true
spowoduje przywrócenie domyślnego działania. Możesz też zdefiniować parametr APP_SHORT_COMMANDS
w pliku Application.mk
, aby wymusić to 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
. W ten sposób wygenerujesz cienkie archiwum, czyli plik biblioteki, który nie zawiera plików obiektów, a tylko ścieżki do plików rzeczywistych obiektów, które normalnie zawierałyby ten plik.
To przydatne, aby zmniejszyć rozmiar danych wyjściowych kompilacji. Wadą jest to, że nie można przenieść takich bibliotek do innej lokalizacji (wszystkie ścieżki w ich obrębie są względne).
Prawidłowe wartości to true
, false
lub pusta wartość. Wartość domyślną możesz ustawić w pliku Application.mk
za pomocą zmiennej APP_THIN_ARCHIVE
.
LOCAL_FILTER_ASM
Zdefiniuj tę zmienną jako polecenie powłoki, których system kompilacji będzie używać do filtrowania plików zestawu wyodrębnionych lub wygenerowanych z plików określonych dla LOCAL_SRC_FILES
. Zdefiniowanie tej zmiennej powoduje następujące konsekwencje:
- System kompilacji generuje tymczasowy plik asemblera z dowolnego pliku źródłowego C lub C++, zamiast kompilować go do pliku obiektowego.
- System kompilacji wykonuje polecenie powłoki w pliku
LOCAL_FILTER_ASM
w przypadku każdego tymczasowego pliku assembly i każdego pliku assembly wymienionego w plikuLOCAL_SRC_FILES
, generując w ten sposób kolejny tymczasowy plik assembly. - System kompilacji kompiluje te przefiltrowane pliki zestawu 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
„1” odpowiada kompilatorowi, „2” filtrowi, a „3” – asemblerowi. Filtr musi być samodzielnym poleceniem powłoki, które przyjmuje jako pierwszy argument nazwę pliku wejściowego, a jako drugi – nazwę pliku wyjściowego. 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 opisano makrofunkcje GNU Make dostępne w NDK. Aby je ocenić, użyj funkcji $(call <function>)
, która zwraca informacje tekstowe.
my-dir
To makro zwraca ścieżkę ostatnio uwzględnionego pliku Makefile, którym jest zwykle bieżący katalog Android.mk
. my-dir
przydaje się do zdefiniowania LOCAL_PATH
na początku pliku Android.mk
. Na przykład:
LOCAL_PATH := $(call my-dir)
Ze względu na sposób działania GNU Make makro tak naprawdę zwraca ścieżkę ostatniego pliku Makefile zawartego przez system kompilacji przy analizie skryptów kompilacji. Z tego powodu nie należy wywoływać my-dir
po dołączeniu innego pliku.
Weź pod uwagę ten 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 drugi wywołanie funkcji my-dir
definiuje LOCAL_PATH
jako $PATH/foo
zamiast $PATH
, ponieważ wskazuje na najnowsze include.
Aby uniknąć tego problemu, umieść dodatkowe słowa „Zawiera” po wszystkich pozostałych elementach w pliku Android.mk
. 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 nie można uporządkować pliku w ten sposób, zapisz wartość pierwszego wywołania funkcji 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
all-subdir-makefiles
Zwraca listę plików Android.mk
znajdujących się we wszystkich podkatalogach bieżącej ścieżki my-dir
.
Za pomocą tej funkcji możesz przekazywać w systemie kompilacji głęboko zagnieżdżone hierarchie katalogów źródłowych. Domyślnie NDK szuka tylko plików w katalogu zawierającym plik Android.mk
.
this-makefile
Zwraca ścieżkę do bieżącego pliku makefile (z którego system kompilacji wywołał funkcję).
nadrzędny-makefile,
Zwraca ścieżkę nadrzędnego pliku Makefile w drzewie uwzględniania (ścieżki plikumakefile, który zawierał bieżący).
plik magistrali
Zwraca ścieżkę pliku Makefile nadrzędnego w drzewie uwzględniania (ścieżki pliku Makefile zawierającego bieżący).
import-module
Funkcja, która umożliwia znalezienie i uwzględnienie pliku Android.mk
modułu na podstawie jego nazwy. Typowy przykład:
$(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
.