Dukungan library C++

NDK mendukung beberapa library runtime C++. Dokumen ini memberikan informasi tentang library ini, konsekuensi yang terlibat, dan cara menggunakannya.

Library runtime C++

Tabel 1. Runtime dan Fitur C++ NDK.

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

libc++ tersedia sebagai library statis dan bersama.

libc++

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

CMake secara default disetel ke versi C++ apa pun yang menjadi default untuk clang (saat ini C++ 14), jadi Anda harus menyetel CMAKE_CXX_STANDARD standar ke nilai yang sesuai dalam file CMakeLists.txt untuk menggunakan fitur C++ 17 atau yang lebih baru. Lihat dokumentasi CMAKE_CXX_STANDARD CMake untuk melihat detail selengkapnya.

ndk-build juga menyerahkan keputusan kepada clang secara default, sehingga pengguna ndk-build harus menggunakan APP_CPPFLAGS untuk menambahkan -std=c++17 atau apa pun yang mereka inginkan.

Library bersama untuk libc++ adalah libc++_shared.so, dan library statisnya adalah libc++_static.a. Biasanya, sistem build akan menangani penggunaan dan pemaketan library ini sesuai kebutuhan pengguna. Untuk kasus yang tidak biasa atau saat mengimplementasikan sistem build Anda sendiri, lihat Panduan Pengelola Sistem Build atau panduan untuk menggunakan sistem build lainnya.

Project LLVM berada di bawah Lisensi Apache v2.0 dengan Pengecualian LLVM. Untuk mengetahui informasi selengkapnya, lihat file lisensi.

sistem

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++

CMake

Default untuk CMake adalah c++_static.

Anda dapat menentukan c++_shared, c++_static, none, atau system menggunakan variabel ANDROID_STL dalam file build.gradle level modul. Untuk mempelajari lebih lanjut, lihat dokumentasi ANDROID_STL di CMake.

ndk-build

Default untuk ndk-build adalah none.

Anda dapat menentukan c++_shared, c++_static, none, atau system menggunakan variabel APP_STL dalam file Application.mk. Contoh:

APP_STL := c++_shared

ndk-build hanya memungkinkan Anda memilih satu runtime untuk aplikasi, dan hanya dapat dilakukan di Application.mk.

Menggunakan clang secara langsung

Jika Anda menggunakan clang secara langsung di sistem build sendiri, clang++ akan menggunakan c++_shared secara default. Untuk menggunakan varian statis, tambahkan -static-libstdc++ ke flag linker. Perlu diketahui bahwa meskipun opsi tersebut menggunakan nama "libstdc++" untuk alasan historis, 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 linker dinamis dan PackageManager di 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 tidak sama dengan libc++ yang merupakan bagian dari OS. Hal ini memungkinkan pengguna NDK mengakses fitur dan perbaikan bug libc++ terbaru, meskipun menargetkan versi lama Android. Sebagai konsekuensinya, jika Anda menggunakan libc++_shared.so, Anda harus menyertakannya dalam aplikasi 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 menargetkan versi Android yang lebih lama dari Android 4.3 (Android API level 18), dan Anda menggunakan libc++_shared.so, library bersama harus dimuat terlebih dahulu sebelum library lain yang bergantung padanya.

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

Satu STL per aplikasi

Secara historis, selain mendukung libc++, NDK juga mendukung STLport dan Vertex Gate GNU. Jika aplikasi Anda bergantung pada library bawaan 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 satu dari banyak 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:

APP_CPPFLAGS := -fexceptions

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

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:

APP_CPPFLAGS := -frtti

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

LOCAL_CPP_FEATURES := rtti

Atau, Anda dapat menggunakan:

LOCAL_CPPFLAGS := -frtti