C++ kitaplığı desteği

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_STANDARDbelgelerine 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 ve libbar.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