NDK, birden fazla C++ çalışma zamanı kitaplığını destekler. Bu dokümanda söz konusu kitaplıklar, ödün vermeniz ve kullanımları 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 | Başlık yok, sınırlı C++. |
libc++, hem statik hem de paylaşılan kitaplık olarak kullanılabilir.
libc++
LLVM'nin libc++'ı, Lollipop'tan itibaren Android OS tarafından kullanılan C++ standart kitaplığıdır ve NDK r18, NDK'da kullanılabilen tek HDS'dir.
CMake varsayılan olarak C++ clang sürümünün varsayılanını (şu anda C++14) kullanır. Bu nedenle, C++17 veya sonraki sürümleri kullanmak için standart CMAKE_CXX_STANDARD
öğesini CMakeLists.txt
dosyanızda uygun değere ayarlamanız gerekir. Daha fazla ayrıntı için
CMAKE_CXX_STANDARD
belgelerine bakın.
ndk-build ayrıca varsayılan olarak engelleme kararını da bırakır. Bu nedenle, ndk-build kullanıcıları -std=c++17
veya istedikleri her şeyi 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. Genelde derleme sistemi, bu kitaplıkları kullanıcı için gerektiği şekilde kullanma ve paketleme işlemlerini gerçekleştirir. Tipik olmayan durumlar için veya kendi derleme sisteminizi uygularken Derleme Sistemi Bakım Yönergeleri'ne ya da diğer derleme sistemlerini kullanma kılavuzuna bakın.
LLVM Projesi, LLVM İstisnaları ile Apache Lisansı 2.0 sürümü kapsamındadır. Daha fazla bilgi için lisans dosyasına bakın.
sistem
Sistemin çalışma zamanı, /system/lib/libstdc++.so
anlamına gelir. Bu kitaplık, GNU'nun tam özellikli libstdc++ ile karıştırılmamalıdır. Android'de libstdc++ yalnızca new
ve delete
'dır. Tam özellikli C++ standart kitaplığı için libc++ kullanın.
C++ çalışma zamanı sistemi, temel C++ Runtime ABI için destek sağlar.
Bu kitaplık, temel olarak new
ve delete
hizmetlerini sunar. NDK'da bulunan diğer seçeneklerin aksine, istisna işleme veya RTTI desteklenmez.
<cstdio>
gibi C kitaplığı başlıkları için C++ sarmalayıcılarının dışında standart kitaplık desteği yoktur. STL istiyorsanız bu sayfada sunulan diğer seçeneklerden birini kullanmanız gerekir.
yok
STL'nin olmaması da mümkündür. Bu durumda herhangi bir bağlantı veya lisanslama şartı yoktur. C++ standart üst bilgisi yok.
C++ Çalışma Zamanı Seçme
CMake
CMake varsayılan olarak c++_static
şeklindedir.
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'de ANDROID_STL dokümanlarını inceleyin.
-in-build
ndk-build varsayılan olarak none
değeridir.
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'da yapabilir.
Doğrudan Clang kullanma
Clang'ı doğrudan kendi derleme sisteminizde kullanıyorsanız clang++ varsayılan olarak c++_shared
yöntemini kullanır. Statik varyantı kullanmak için bağlayıcı işaretlerinize -static-libstdc++
ekleyin. Bu seçenek, geçmiş nedenlerle "libstdc++" adını kullansa da, bu durum libc++ için de geçerlidir.
Dikkat edilmesi gerekenler
Statik çalışma zamanları
Uygulamanızın tüm yerel kodu, paylaşılan tek bir kitaplıkta bulunuyorsa statik çalışma zamanını kullanmanızı öneririz. Bu sayede bağlayıcı, mümkün olan en iyi şekilde optimize edilmiş ve daha küçük boyutlu uygulamalar elde edilerek mümkün olan en az sayıda satır içi kodla buharı ayıklanır. Ayrıca, birden fazla paylaşılan kitaplığın işlenmesini zorlaştıran ve hataya açık hale getiren Android'in eski sürümlerindeki PackageManager ve dinamik bağlayıcı hatalarını da önler.
Bununla birlikte, C++ ürününde tek bir programda aynı işlevin veya nesnenin birden fazla kopyasını tanımlamak güvenli değildir. Bu, C++ standardında bulunan Bir Tanım Kuralı'nın bir parçasıdır.
Statik bir çalışma zamanı (ve genel olarak statik kitaplıklar) kullanırken bu kuralı yanlışlıkla aşabilirsiniz. Ö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 hem global veriler hem de statik oluşturucular dahil olmak üzere STL her iki kitaplıkta da yer alır. Bu uygulamanın çalışma zamanı davranışı tanımsız ve pratikte kilitlenmeler çok yaygındır. Diğer olası sorunlar şunlardır:
- Bir kitaplıkta ayrılan ve diğerinde boşaltılan bellek, bellek sızıntısına veya yığın bozulmasına neden olur.
libfoo.so
içinde karşılaşılan velibbar.so
içinde yakalanmayan istisnalar uygulamanızın kilitlenmesine neden olacaktır.std::cout
arabelleğe alma düzgün çalışmıyor.
Davranışsal sorunların yanı sıra statik çalışma zamanını birden fazla kütüphaneye bağlamak, paylaşılan her kitaplıktaki kodu çoğaltarak uygulamanızın boyutunu artırır.
Genel olarak, uygulamanızda +1 ve yalnızca bir paylaşılan kitaplığınız varsa C++ çalışma zamanının statik bir varyantını kullanabilirsiniz.
Paylaşılan çalışma zamanları
Uygulamanız birden fazla paylaşılan kitaplık içeriyorsa libc++_shared.so
kullanmanız gerekir.
Android'de, NDK tarafından kullanılan libc++, işletim sisteminin bir parçası olanla aynı değildir. Bu sayede, NDK kullanıcıları Android'in eski sürümlerini hedeflerken bile en son libc++ özelliklerine ve hata düzeltmelerine erişebilirler. Bunun karşılığında, libc++_shared.so
kullanıyorsanız bunu uygulamanıza eklemeniz gerekir. Uygulamanızı Gradle ile derlerseniz bu işlem otomatik olarak gerçekleştirilir.
Android'in eski sürümlerinde PackageManager'da ve dinamik bağlayıcıda yerel kitaplıkların yüklenmesi, güncellenmesi ve yüklenmesinin güvenilir olmamasına neden oluyordu. Özel olarak belirtmek gerekirse, uygulamanız Android 4.3'ten (Android API düzeyi 18) daha eski 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 çözümler sunar ve genellikle kendi çözümlerinizi yazmaktan daha iyi bir seçimdir.
Uygulama başına bir STL
Geçmişte NDK, libc++'ya ek olarak GNU libstdc++ ve STLport'u destekliyordu. Uygulamanız, NDK'ya karşı uygulamanızı oluştururken kullanılandan farklı bir şekilde oluşturulan libary'lere bağlıysa bunu uyumlu bir şekilde yaptığınızdan emin olmanız gerekir.
Uygulamalar birden fazla C++ çalışma zamanı kullanmamalıdır. Çeşitli HDS'ler birbirleriyle uyumlu değildir. Örneğin, libc++ öğesindeki std::string
düzeni gngsl ile aynı değildir. Bir STL'ye karşı yazılan kod, başka bir STL'ye karşı yazılan nesneleri kullanamaz. Bu yalnızca örneklerden biridir; uyumsuzluklar
çok sayıdadır.
Bu kural, kodunuzun ötesine geçer. Tüm bağımlılarınız, seçtiğiniz aynı HDS'yi kullanmalıdır. STL kullanan ve STL başına bir kitaplık sağlamayan kapalı kaynaklı bir üçüncü taraf bağımlılığına bağımlıysanız STL'de seçeneğiniz yoktur. Bağımlılığınızla aynı STL'yi kullanmanız gerekir.
Birbiriyle uyumlu olmayan iki kitaplığa bağımlı olabilirsiniz. Bu durumda tek çözüm bağımlılıklardan birini bırakmak veya ana makineden diğer STL'ye karşı oluşturulan bir kitaplık sağlamasını istemektir.
C++ İstisnaları
C++ istisnaları libc++ tarafından desteklenir ancak ndk-build içinde varsayılan olarak devre dışıdır. Bunun nedeni, geçmişte C++ istisnalarının NDK'da kullanılamamasıydı. CMake ve bağımsız araç zincirleri, varsayılan olarak C++ istisnalarına sahiptir.
ndk-build 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ü için istisnaları etkinleştirmek isterseniz Android.mk modülünde aşağıdaki modüle aşağıdaki satırı ekleyin:
LOCAL_CPP_FEATURES := exceptions
Alternatif olarak:
LOCAL_CPPFLAGS := -fexceptions
RTTI
İstisnalarda olduğu gibi RTTI, libc++ tarafından desteklenir ancak ndk-build içinde varsayılan olarak devre dışıdır. CMake ve bağımsız araç zincirleri, RTTI'yi varsayılan olarak etkinleştirir.
RTT'yi uygulamanızın tamamında ndk-build'de etkinleştirmek için Application.mk dosyanıza aşağıdaki satırı ekleyin:
APP_CPPFLAGS := -frtti
RTTI'yi tek bir nk-build modülü için etkinleştirmek isterseniz Android.mk modülünde aşağıdaki modüle aşağıdaki satırı ekleyin:
LOCAL_CPP_FEATURES := rtti
Alternatif olarak:
LOCAL_CPPFLAGS := -frtti