Pakiet NDK obsługuje wiele bibliotek środowiska wykonawczego C++. Ten dokument zawiera na temat tych bibliotek, związanych z nimi kompromisów i sposobów korzystania z nich.
Biblioteki środowiska wykonawczego C++
Tabela 1. Środowiska wykonawcze i funkcje NDK C++.
Nazwa | Funkcje |
---|---|
libc + | Nowoczesna obsługa języka C++. |
system | new i delete . (Wycofane w wersji r18). |
brak | Bez nagłówków, ograniczony język C++. |
libc++ jest dostępna zarówno jako biblioteka statyczna, jak i współdzielona.
libc++
libc++ LLVM to standard w C++ biblioteka używana w systemie operacyjnym Android od wersji Lollipop, a od NDK r18 to jedyny STL dostępny w NDK.
Domyślna wersja clangu jest domyślnie ustawiona na C++ (obecnie C++14).
musisz więc ustawić standardową wartość CMAKE_CXX_STANDARD
na odpowiednią wartość
w pliku CMakeLists.txt
, aby używać funkcji C++17 lub nowszych. Poznaj CMake
dokumentacja usługi CMAKE_CXX_STANDARD
.
ndk-build również powoduje domyślne reagowanie na dźwięk, więc użytkownicy
powinni użyć elementu APP_CPPFLAGS
, aby dodać element -std=c++17
lub cokolwiek innego.
Zasoby wspólne biblioteki libc++ to libc++_shared.so
, a biblioteka statyczna
biblioteka jest libc++_static.a
. W typowych przypadkach system kompilacji
używanie i opakowanie tych bibliotek zgodnie z potrzebami użytkownika. W nietypowych przypadkach
lub gdy wdrażasz własny system kompilacji, przeczytaj artykuł Konserwacja do zarządzania systemem
Przewodnik lub przewodnik po korzystaniu z innych systemów kompilacji.
Projekt LLVM jest objęty licencją Apache w wersji 2.0 z wyjątkami LLVM. Więcej informacje znajdziesz w pliku licencji.
system
Środowisko wykonawcze systemu odnosi się do /system/lib/libstdc++.so
. Ta biblioteka nie powinna
z kompleksową domeną GNU libstdc++. W Androidzie libstdc++ to po prostu
new
i delete
. Aby utworzyć bibliotekę standardową C++, użyj biblioteki libc++.
Systemowe środowisko wykonawcze C++ zapewnia obsługę podstawowego interfejsu ABI środowiska wykonawczego C++.
Zasadniczo ta biblioteka zawiera new
i delete
. W przeciwieństwie do
dostępnych w NDK, nie jest obsługiwana obsługa wyjątków ani
RTTI.
Nie ma biblioteki standardowej poza kodami języka C++ dla języka C
takich jak <cstdio>
. Jeśli chcesz używać protokołu STL, użyj jednej z
inne opcje dostępne na tej stronie.
brak
Można też wybrać opcję bez STL. Nie ma żadnych połączeń ani licencji wymagania w tym przypadku. Brak dostępnych standardowych nagłówków w języku C++.
Wybieranie środowiska wykonawczego C++
CMake
Domyślna wartość w przypadku CMake to c++_static
.
Możesz określić c++_shared
, c++_static
, none
lub system
za pomocą
ANDROID_STL
w pliku build.gradle
na poziomie modułu. Aby dowiedzieć się więcej,
zapoznaj się z dokumentacją dla ANDROID_STL w
CMake.
ndk-build
Wartość domyślna dla ndk-build to none
.
Możesz określić c++_shared
, c++_static
, none
lub system
za pomocą
APP_STL
w pliku Application.mk. Na przykład:
APP_STL := c++_shared
Polecenie ndk-build pozwala wybrać tylko jedno środowisko wykonawcze aplikacji i można to zrobić Application.mk.
Używaj clang bezpośrednio
Jeśli używasz clang bezpośrednio we własnym systemie kompilacji, clang++ będzie używać
c++_shared
. Aby używać wariantu statycznego, dodaj atrybut -static-libstdc++
do
flagi tagu łączącego. Mimo że opcja ma nazwę „libstdc++”, w przypadku
z powodów historycznych, działa to również w przypadku libc++.
Ważne informacje
Statyczne środowiska wykonawcze
Jeśli cały kod natywny aplikacji znajduje się w jednym udostępnionym zalecamy używanie statycznego środowiska wykonawczego. Dzięki temu tag łączący i usuń jak najwięcej nieużywanego kodu. i przy użyciu jak najmniejszej możliwości. Unika także metody PackageManager i zarządzania błędy łączące w starszych wersjach Androida, które sprawiają, że obsługa wielu plików i biblioteki są trudne i podatne na błędy.
Jednak w C++ nie jest bezpieczne zdefiniowanie więcej niż jednej kopii tej samej funkcję lub obiekt w jednym programie. To jeden z aspektów programu, Jedna reguła definicji dostępna w standardzie C++.
W przypadku statycznego środowiska wykonawczego (i ogólnie bibliotek statycznych) łatwo jest przypadkowo złam tę regułę. Na przykład poniższa aplikacja powoduje przerwanie tego reguła:
# Application.mk
APP_STL := c++_static
# Android.mk
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo.cpp
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.cpp
LOCAL_SHARED_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)
W tej sytuacji STL, w tym dane globalne i konstruktory statyczne, będzie dostępna w obu bibliotekach. Działanie tej aplikacji w czasie działania to nieokreślonych, a w praktyce zdarzają się one bardzo często. Inne możliwe problemy uwzględnij:
- Pamięć jest przydzielona w jednej bibliotece, a zwolniona w drugiej, przez co pamięć jest przydzielona w jednej bibliotece wyciek lub uszkodzenie stosu.
- Wyjątki zgłoszone w regionie
libfoo.so
, które nie zostały wykryte w regionielibbar.so
, powodując do awarii. - Buforowanie pliku
std::cout
nie działa prawidłowo.
Oprócz problemów z działaniem połączenie statycznego środowiska wykonawczego w kilka zduplikują kod w każdej z bibliotek wspólnych, co zwiększy rozmiar Twojej aplikacji.
Ogólnie możesz używać statycznego wariantu środowiska wykonawczego C++ tylko wtedy, gdy go masz i tylko jedną bibliotekę współdzieloną.
Współdzielone środowiska wykonawcze
Jeśli Twoja aplikacja zawiera wiele bibliotek udostępnionych, użyj
libc++_shared.so
W Androidzie biblioteka libc++ używana w NDK różni się od biblioteki, która jest częścią
systemu operacyjnego. Daje to użytkownikom NDK dostęp do najnowszych funkcji libc++ i błędów
nawet w przypadku kierowania na starsze wersje Androida. A kompromis jest taki, że
używasz języka libc++_shared.so
, musisz uwzględnić go w swojej aplikacji. Jeśli tworzysz
z użyciem Gradle. Jest to obsługiwane automatycznie.
Starsze wersje Androida zawierały błędy w Menedżerze pakietów i dynamicznym narzędziu łączącym
które spowodowało instalację, aktualizację i wczytywanie bibliotek natywnych
zawodny. Zwłaszcza, jeśli Twoja aplikacja jest kierowana na starszą wersję Androida
niż w Androidzie 4.3 (poziom interfejsu API Androida 18) i używasz libc++_shared.so
,
musi wczytywać tę bibliotekę przed innymi bibliotekami, które jej wymagają.
Projekt ReLinker zapewnia obejścia wszystkich znanych problemów z ładowaniem biblioteki natywnej. Zazwyczaj jest to to lepsze rozwiązanie niż pisanie własnych rozwiązań.
Jeden STL na aplikację
Dawniej NDK obsługiwało pakiety GNU libstdc++ i STLport, a nie tylko libc++. Jeśli Twoja aplikacja zależy od gotowych bibliotek, które zostały skompilowane w oparciu o pakiet NDK różni się od tej użytej do skompilowania aplikacji, musisz upewnić się, że robi to w zgodny sposób.
Aplikacja nie powinna używać więcej niż jednego środowiska wykonawczego C++. Różne języki STL są
nie są zgodne. Przykład: układ strony std::string
w libc++ i w Ggnustl to nie to samo. Kod napisany przeciwko jednemu kodowi STL
nie można używać obiektów zapisanych przeciwko innym. To tylko jeden przykład.
występuje wiele niezgodności.
Ta reguła wykracza poza Twój kod. Wszystkie zależności muszą korzystać z tego samego wybrany język STL. Jeśli korzystasz z usług zewnętrznej firmy open source używająca języka STL i nie podaje biblioteki według tego języka, nie trzeba nie ma wyboru w STL. Musisz użyć tego samego protokołu STL co zależność.
Może się zdarzyć, że będziesz korzystać z 2 niekompatybilnych bibliotek. W w tej sytuacji jedynym rozwiązaniem jest porzucenie jednej z zależności lub poproszenie aby udostępnić bibliotekę stworzoną na tle innych STL.
Wyjątki C++
Wyjątki dla języka C++ są obsługiwane przez libc++, ale są domyślnie wyłączone w ndk-build. Dzieje się tak, ponieważ wyjątki dotyczące języka C++ nie były wcześniej dostępne w NDK. CMake i samodzielne łańcuchy narzędzi mają domyślnie włączone wyjątki w języku C++.
Aby włączyć wyjątki w całej aplikacji w narzędziu ndk-build, dodaj funkcję ten wiersz do pliku Application.mk:
APP_CPPFLAGS := -fexceptions
Aby włączyć wyjątki dla pojedynczego modułu ndk-build, dodaj następujący wiersz do danego modułu w pliku Android.mk:
LOCAL_CPP_FEATURES := exceptions
Możesz też użyć:
LOCAL_CPPFLAGS := -fexceptions
RTTI
Podobnie jak w przypadku wyjątków, protokół RTTI jest obsługiwany przez libc++, ale jest domyślnie wyłączony ndk-build. CMake i samodzielne łańcuchy narzędzi mają domyślnie włączoną funkcję RTTI.
Aby włączyć RTTI w całej aplikacji w narzędziu ndk-build, dodaj następujący tekst do pliku Application.mk:
APP_CPPFLAGS := -frtti
Aby włączyć RTTI dla pojedynczego modułu ndk-build, dodaj następujący wiersz do danego modułu w pliku Android.mk:
LOCAL_CPP_FEATURES := rtti
Możesz też użyć:
LOCAL_CPPFLAGS := -frtti