NDK, birden fazla C++ çalışma zamanı kitaplığını destekler. Bu belgede söz konusu kitaplıklar, bunlar ve bunların nasıl kullanılacağı hakkında bilgi verilmektedir.
C++ çalışma zamanı kitaplıkları
Tablo 1. NDK C++ Çalışma Zamanları ve Özellikleri.
Ad | Özellikler |
---|---|
libc++ | Modern C++ desteği. |
sistem | new ve delete . (r18'de kullanımdan kaldırılmıştır.) |
yok | Üstbilgi yok, sınırlı C++. |
libc++ hem statik hem de paylaşılan bir kitaplık olarak kullanılabilir.
libc++
LLVM'nin libc++ ürünü, Lollipop'tan bu yana Android OS tarafından kullanılan C++ standart kitaplığıdır ve NDK r18 itibarıyla NDK'da kullanılabilen tek STL'dir.
CMake, varsayılan olarak C++ clang'ın varsayılan sürümüne (şu anda C++14) ayarlanır. Bu nedenle, C++17 veya sonraki özellikleri kullanmak için standart CMAKE_CXX_STANDARD
değerini CMakeLists.txt
dosyanızdaki uygun değere ayarlamanız gerekir. Daha ayrıntılı bilgi için CMAKE_CXX_STANDARD
ile ilgili CMake dokümanlarına bakın.
ndk-build, varsayılan olarak clang kararını da bırakır. Dolayısıyla, ndk-build kullanıcıları -std=c++17
veya istediklerini eklemek için APP_CPPFLAGS
kullanmalıdır.
libc++ için paylaşılan kitaplık libc++_shared.so
, statik kitaplık ise libc++_static.a
şeklindedir. Tipik durumlarda derleme sistemi, kullanıcı için gerektiğinde bu kitaplıkların kullanımını ve paketlenmesini gerçekleştirir. Normal olmayan durumlar için veya kendi derleme sisteminizi uygularken Sistem Bakımı Derleme Kılavuzu'na veya diğer derleme sistemlerini kullanma rehberine bakın.
LLVM Projesi, LLVM İstisnaları olan Apache Lisansı 2.0 sürümü kapsamındadır. Daha fazla bilgi edinmek için lisans dosyasına göz atın.
sistem
Sistem çalışma zamanının kaynağı: /system/lib/libstdc++.so
. Bu kitaplık, GNU'nun tam özellikli libstdc++ sürümüyle karıştırılmamalıdır. Android'de libstdc++ yalnızca new
ve delete
şeklindedir. Tam özellikli bir C++ standart kitaplığı için libc++ kullanın.
Sistem C++ çalışma zamanı, temel C++ Çalışma Zamanı ABI'si için destek sağlar.
Bu kitaplık temelde new
ve delete
sağlar. NDK'daki diğer seçeneklerin aksine, istisna işleme veya RTTI için destek yoktur.
<cstdio>
gibi C kitaplığı başlıkları için C++ sarmalayıcıları dışında standart bir kitaplık desteği yoktur. STL istiyorsanız bu sayfada sunulan diğer
seçeneklerden birini kullanmalısınız.
yok
STL'yi kullanmama seçeneği de mevcuttur. Böyle bir durumda bağlantı veya lisanslama gereksinimleri yoktur. C++ standart üstbilgisi yok.
C++ Çalışma Zamanı Seçme
Yapay Zeka
CMake için varsayılan değer c++_static
'dir.
Modül düzeyindeki build.gradle
dosyanızdaki ANDROID_STL
değişkenini kullanarak c++_shared
, c++_static
, none
veya system
belirtebilirsiniz. Daha fazla bilgi edinmek için CMake'deki ANDROID_STL dokümanlarına bakın.
NK-build
ndk-build için varsayılan değer none
'dir.
Application.mk dosyanızdaki APP_STL
değişkenini kullanarak c++_shared
, c++_static
, none
veya system
belirtebilirsiniz. Örneğin:
APP_STL := c++_shared
ndk-build, uygulamanız için yalnızca bir çalışma zamanı seçmenize izin verir ve bunu yalnızca Application.mk dosyasında yapabilir.
Doğrudan clang kullanma
clang'ı doğrudan kendi derleme sisteminizde kullanıyorsanız clang++ varsayılan olarak c++_shared
kullanır. Statik varyantı kullanmak için bağlayıcı flag'lerinize -static-libstdc++
ekleyin. Seçenek, geçmiş nedenlerle "libstdc++" adını kullansa da bunun libc++ için de doğru olduğunu unutmayın.
Dikkat edilmesi gerekenler
Statik çalışma zamanları
Uygulamanızın yerel kodunun tamamı tek bir paylaşılan kitaplıkta bulunuyorsa statik çalışma zamanını kullanmanızı öneririz. Bu, bağlayıcının mümkün olduğunca çok sayıda kullanılmayan kodu satır içi olarak ayıklamasına ve ayıklamasına olanak tanır. Böylece mümkün olan en optimize ve küçük uygulama ortaya çıkar. Ayrıca, Android'in eski sürümlerinde paylaşılan birden çok kitaplığın işlenmesini zorlaştıran ve hataya açık hale getiren PackageManager ve dinamik bağlayıcı hatalarından da kaçınır.
Bununla birlikte, C++'ta tek bir programda aynı işlevin veya nesnenin birden fazla kopyasını tanımlamak güvenli değildir. Bu, C++ standardında bulunan Tek Tanım Kuralı'nın bir yönüdür.
Statik çalışma zamanı (ve genel olarak statik kitaplıklar) kullanılırken bu kural yanlışlıkla bozulabilir. Örneğin, aşağıdaki uygulama bu kuralı bozar:
# 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)
Bu durumda, global veriler ve statik oluşturucular dahil STL her iki kitaplıkta da mevcuttur. Bu uygulamanın çalışma zamanı davranışı tanımlanmamıştır ve pratikte kilitlenmeler çok yaygındır. Diğer olası sorunlar şunlardır:
- Bir kitaplıkta ayrılıp diğerinde serbest bırakılan bellek sızıntısına veya yığın bozulmasına neden olur.
libfoo.so
hedefinde oluşturulan istisnalarlibbar.so
içinde yakalanmaz ve uygulamanızın kilitlenmesine neden olur.std::cout
dosyasının arabelleğe alınması düzgün çalışmıyor.
İlgili davranış sorunlarının ötesinde, statik çalışma zamanını birden fazla kitaplığa bağlamak, kodu her paylaşılan kitaplıkta çoğaltarak uygulamanızın boyutunu artırır.
Genel olarak, uygulamanızda yalnızca tek bir paylaşılan kitaplık varsa C++ çalışma zamanının statik varyantını kullanabilirsiniz.
Paylaşılan çalışma zamanları
Uygulamanızda birden fazla paylaşılan kitaplık varsa libc++_shared.so
kullanılmalıdır.
Android'de, NDK tarafından kullanılan libc++, işletim sisteminin parçası olanla aynı değildir. Bu, NDK kullanıcılarının Android'in eski sürümlerini hedeflerken bile en yeni libc++ özelliklerine ve hata düzeltmelerine erişebilmesini sağlıyor. Bunun karşılığında, libc++_shared.so
kullanırsanız bunu uygulamanıza eklemeniz gerekir. Uygulamanızı Gradle ile oluşturuyorsanız bu işlem otomatik olarak gerçekleştirilir.
Android'in eski sürümlerinde, PackageManager ve dinamik bağlayıcıda yerel kitaplıkların yüklenmesinin, güncellenmesinin ve yüklenmesinin güvenilmez olmasına neden olan hatalar vardı. Özellikle, uygulamanız Android 4.3'ten (Android API düzeyi 18) önceki bir Android sürümünü hedefliyorsa ve libc++_shared.so
kullanıyorsanız paylaşılan kitaplığı ona bağlı diğer kitaplıklardan önce yüklemeniz gerekir.
ReLinker projesi, bilinen tüm yerel kitaplık yükleme sorunları için geçici çözümler sunar ve genellikle kendi geçici çözümlerinizi yazmaktan daha iyi bir seçimdir.
Uygulama başına bir STL
Geçmişte NDK, libc++'a ek olarak GNU libstdc++ ve STLport'u destekliyordu. Uygulamanız, uygulamanızı derlemek için kullanılandan farklı bir NDK'ya göre oluşturulan önceden oluşturulmuş kitaplıklara bağlıysa bunu uyumlu bir şekilde yaptığından emin olmanız gerekir.
Bir uygulama birden fazla C++ çalışma zamanı kullanmamalıdır. Çeşitli STL'ler birbiriyle uyumlu değildir. Örneğin, std::string
öğesinin libc++ düzenindeki düzeni gnustl'dakiyle aynı değildir. Bir STL'ye karşı yazılan kod, diğerine karşı yazılan nesneleri kullanamaz. Bu sadece bir örnektir;
çok sayıda uyumsuzluk söz konusudur.
Bu kural, kodunuzun ötesine geçer. Tüm bağımlılıklarınız seçtiğiniz STL'yi kullanmalıdır. STL'yi kullanan ve STL başına kitaplık sağlamayan kapalı kaynaklı bir üçüncü taraf bağımlılığına bağlıysanız STL'de seçeneğiniz olmaz. Bağımlılığınızla aynı STL'yi kullanmanız gerekir.
Karşılıklı olarak uyumsuz iki kitaplığa bağlı olabilirsiniz. Bu durumda tek çözüm bağımlılıklardan birini bırakmak veya sorumlu kişiden diğer STL'ye dayalı bir kitaplık sunmasını istemektir.
C++ İstisnaları
C++ istisnaları libc++ tarafından desteklenir ancak ndk-build'de varsayılan olarak devre dışı bırakılır. Bunun nedeni, geçmişte NDK'da C++ istisnalarının bulunmamasıdır. CMake ve bağımsız araç zincirlerinde C++ istisnaları varsayılan olarak etkindir.
ndk-build'de uygulamanızın tamamında istisnaları etkinleştirmek için aşağıdaki satırı Application.mk dosyanıza ekleyin:
APP_CPPFLAGS := -fexceptions
Tek bir ndk-build modülünde istisnaları etkinleştirmek için Android.mk dosyasında belirtilen modüle aşağıdaki satırı ekleyin:
LOCAL_CPP_FEATURES := exceptions
Alternatif olarak şunları da kullanabilirsiniz:
LOCAL_CPPFLAGS := -fexceptions
GRTTI
İstisnalarda RTTI, libc++ tarafından desteklenir ancak ndk-build'de varsayılan olarak devre dışıdır. CMake ve bağımsız araç zincirlerinde RTTI varsayılan olarak etkindir.
RTTI'yı ndk-build'deki uygulamanızın tamamında etkinleştirmek için aşağıdaki satırı Application.mk dosyanıza ekleyin:
APP_CPPFLAGS := -frtti
Tek bir ndk-build modülünde RTTI'yı etkinleştirmek için Android.mk dosyasında belirtilen modüle aşağıdaki satırı ekleyin:
LOCAL_CPP_FEATURES := rtti
Alternatif olarak şunları da kullanabilirsiniz:
LOCAL_CPPFLAGS := -frtti