C++ kitaplığı desteği

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 istisnalar libbar.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