Dukungan Library C++

NDK mendukung beberapa library runtime C++. Dokumen ini memberikan informasi tentang library ini, trade-off yang terkait, dan cara menggunakannya.

Library Runtime C++

Tabel 1. Runtime dan Fitur C++ NDK.

Nama Fitur
libc++ Dukungan C++17.
system new dan delete. (Tidak digunakan lagi pada r18.)
none Tanpa header, C++ terbatas.

libc++ tersedia sebagai library statis dan bersama.

libc++

libc++ dari LLVM adalah library standar C++ yang telah digunakan oleh Android OS sejak Lollipop, dan mulai NDK r18 adalah satu-satunya STL yang tersedia di NDK.

Library bersama untuk libc++ adalah libc++_shared.so, dan library statisnya adalah libc++_static.a.

libc++ memiliki dua lisensi di bawah lisensi "BSD-Like" University of Illinois dan lisensi MIT. Untuk mengetahui informasi selengkapnya, lihat file lisensi.

system

Runtime sistem mengacu pada /system/lib/libstdc++.so. Library ini tidak sama dengan libstdc++ GNU yang berfitur lengkap. Di Android, libstdc++ hanyalah new dan delete. Gunakan libc++ untuk library standar C++ berfitur lengkap.

Runtime C++ sistem memberikan dukungan untuk ABI Runtime C++ dasar. Pada dasarnya, library ini menyediakan new dan delete. Tidak seperti opsi lain yang tersedia di NDK, tidak ada dukungan untuk penanganan pengecualian atau RTTI.

Tidak ada dukungan library standar selain wrapper C++ untuk header library C seperti <cstdio>. Jika menginginkan STL, Anda harus menggunakan salah satu opsi lain yang ditampilkan di halaman ini.

none

Anda juga diperbolehkan untuk tidak memiliki STL. Tidak ada persyaratan penautan atau pemberian lisensi dalam situasi tersebut. Tidak ada header C++ standar yang tersedia.

Memilih Runtime C++

Jika Anda menggunakan CMake, Anda dapat menentukan runtime dari Tabel 1 dengan variabel ANDROID_STL dalam file build.gradle level modul. Untuk mempelajari lebih lanjut, lihat Menggunakan Variabel CMake.

Jika Anda menggunakan ndk-build, Anda dapat menentukan runtime dari Tabel 1 dengan variabel APP_STL dalam file Application.mk. Contoh:

APP_STL := c++_shared

Anda hanya dapat memilih satu runtime untuk aplikasi Anda, dan hanya dapat melakukannya di Application.mk.

Jika menggunakan Toolchain Mandiri, toolchain tersebut akan menggunakan STL bersama secara default. Untuk menggunakan varian statis, tambahkan -static-libstdc++ ke flag linker Anda. Perhatikan bahwa meskipun opsi tersebut menggunakan nama "libstdc++", ini juga berlaku untuk libc++.

Pertimbangan Penting

Runtime statis

Jika semua kode native aplikasi Anda termuat dalam satu library bersama, kami merekomendasikan penggunaan runtime statis. Hal ini memungkinkan linker untuk menyejajarkan dan memangkas sebanyak mungkin kode yang tidak terpakai, sehingga menghasilkan aplikasi yang paling optimal dan paling kecil. Hal ini juga menghindari bug PackageManager dan linker dinamis pada Android versi lama yang mengakibatkan penanganan beberapa library bersama menjadi sulit dan rentan error.

Meskipun demikian, dalam C++, sebaiknya jangan tentukan lebih dari satu salinan fungsi atau objek yang sama ke dalam satu program. Ini adalah salah satu aspek dari Satu Aturan Definisi yang ada dalam standar C++.

Saat menggunakan runtime statis (dan library statis secara umum), aturan ini rentan dilanggar secara tidak sengaja. Misalnya, aplikasi berikut melanggar aturan ini:

# 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)

Dalam situasi ini, data STL, include, dan global serta konstruktor statis, akan ada di kedua library. Perilaku runtime aplikasi ini tidak ditentukan dan, pada praktiknya, error sangat biasa terjadi. Masalah lain yang mungkin terjadi termasuk:

  • Memori dialokasikan di satu library dan dibebaskan di library lainnya sehingga mengakibatkan kebocoran memori atau kerusakan heap.
  • Pengecualian yang muncul di libfoo.so tidak terdeteksi di libbar.so sehingga akan menyebabkan aplikasi Anda berhenti bekerja.
  • Buffering std::cout tidak berfungsi sebagaimana mestinya.

Di luar masalah perilaku yang terkait, menautkan runtime statis ke beberapa library akan menduplikatkan kode di setiap library bersama sehingga ukuran aplikasi akan bertambah.

Secara umum, Anda hanya dapat menggunakan varian statis runtime C++ jika Anda hanya memiliki satu library bersama di aplikasi Anda.

Runtime bersama

Jika aplikasi Anda menyertakan beberapa library bersama, Anda harus menggunakan libc++_shared.so.

Di Android, libc++ yang digunakan oleh NDK bukan merupakan bagian dari OS. Hal ini memungkinkan pengguna NDK mengakses fitur dan perbaikan bug libc++ terbaru, bahkan saat menargetkan versi lama Android. Konsekuensinya adalah, jika Anda menggunakan libc++_shared.so, Anda harus menyertakannya dalam APK Anda. Jika Anda mem-build aplikasi dengan Gradle, library ini akan ditangani secara otomatis.

Versi lama Android memiliki bug dalam PackageManager dan linker dinamis yang menyebabkan penginstalan, update, dan pemuatan library native menjadi tidak berfungsi sebagaimana mestinya. Secara khusus, jika aplikasi Anda menargetkan versi Android yang lebih lama dari Android 4.3 (Android API level 18), dan Anda menggunakan libc++_shared.so, Anda harus memuat library bersama terlebih dahulu sebelum library lain yang bergantung padanya.

Project ReLinker menawarkan solusi untuk semua masalah umum pemuatan library native, dan biasanya menjadi pilihan yang lebih baik daripada menulis solusi Anda sendiri.

Satu STL Per Aplikasi

Secara historis, selain mendukung libc++, NDK juga mendukung STLport dan libstdc++ GNU. Jika aplikasi Anda bergantung pada library siap pakai yang dibuat berdasarkan NDK yang berbeda dengan yang digunakan untuk mem-build aplikasi, Anda harus memastikan bahwa aplikasi dapat melakukannya dalam cara yang kompatibel.

Sebuah aplikasi tidak boleh menggunakan lebih dari satu runtime C++. Beberapa STL tidak kompatibel satu sama lain. Sebagai contoh, tata letak std::string dalam libc++ tidak sama dengan tata letak di gnustl. Kode yang ditulis berdasarkan satu STL tidak akan dapat menggunakan objek yang ditulis berdasarkan STL lain. Contoh ini hanyalah salah satu dari sekian ketidakcocokan lainnya.

Aturan ini melampaui kode Anda. Semua dependensi Anda harus menggunakan STL yang sama dengan yang Anda pilih. Jika bergantung pada dependensi closed source pihak ketiga yang menggunakan STL dan Anda tidak menyediakan satu library per STL, Anda tidak memiliki pilihan dalam STL. Anda harus menggunakan STL yang sama dengan dependensi Anda.

Anda mungkin akan bergantung pada dua library yang tidak kompatibel satu sama lain. Dalam situasi ini, satu-satunya solusi adalah dengan melepaskan salah satu dependensi atau meminta pengelola untuk menyediakan library yang dibuat berdasarkan STL lainnya.

Pengecualian C++

Pengecualian C++ didukung oleh libc++, tetapi dinonaktifkan secara default di ndk-build. Hal ini dikarenakan pengecualian C++ biasanya tidak tersedia di NDK. Pengecualian C++ diaktifkan secara default untuk CMake dan toolchain mandiri.

Untuk mengaktifkan pengecualian di seluruh aplikasi di ndk-build, tambahkan baris berikut ke file Application.mk Anda:

APP_CPPFLAGS := -fexceptions

Untuk mengaktifkan pengecualian bagi satu modul ndk-build, tambahkan baris berikut ke modul yang diberikan di Android.mk:

LOCAL_CPP_FEATURES := exceptions

Atau, Anda dapat menggunakan:

LOCAL_CPPFLAGS := -fexceptions

RTTI

Seperti halnya pengecualian, RTTI didukung oleh libc++, tetapi dinonaktifkan secara default di ndk-build. CMake dan toolchain mandiri mengaktifkan RTTI secara default.

Untuk mengaktifkan RTTI di seluruh aplikasi di ndk-build, tambahkan baris berikut ke file Application.mk Anda:

APP_CPPFLAGS := -frtti

Untuk mengaktifkan RTTI bagi satu modul ndk-build, tambahkan baris berikut ke modul yang diberikan di Android.mk:

LOCAL_CPP_FEATURES := rtti

Atau, Anda dapat menggunakan:

LOCAL_CPPFLAGS := -frtti