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 informasi selengkapnya, lihat file lisensi.

system

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

Runtime C++ sistem menyediakan dukungan untuk ABI Runtime C++ dasar. Pada intinya, 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 dari wrapper C++ untuk header library C seperti <cstdio>. Jika menginginkan STL, Anda harus menggunakan salah satu opsi lain yang ditampilkan di halaman ini.

none

Ada juga opsi untuk tidak memiliki STL. Dalam kasus tersebut, tidak ada persyaratan link atau lisensi. Tidak ada header C++ standar yang tersedia.

Memilih Runtime C++

Jika 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 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, secara default, toolchain tersebut akan menggunakan STL bersama. Untuk menggunakan varian statisnya, tambahkan -static-libstdc++ ke flag linker Anda.

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++, tidaklah aman untuk mendefinisikan 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 termasuk:

  • Memori dialokasikan di satu library, dan dibebaskan di library lainnya, sehingga terjadi kebocoran memori atau korupsi heap.
  • Pengecualian yang timbul di libfoo.so menjadi tidak tertangkap di libbar.so, sehingga aplikasi Anda mengalami error.
  • Buffering std::cout tidak berfungsi dengan baik.

Di luar masalah perilaku yang terkait, menautkan runtime statis ke banyak library akan menduplikasi kode di setiap library bersama, sehingga meningkatkan ukuran aplikasi Anda.

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

Runtime bersama

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

Pada Android, libc++ yang digunakan oleh NDK bukan merupakan bagian dari OS. Hal ini memberi pengguna NDK akses ke fitur libc++ dan perbaikan bug terbaru, bahkan saat mereka menargetkan Android versi lama. Konsekuensinya, jika menggunakan libc++_shared.so, Anda harus menyertakannya dalam APK. Jika Anda membuat aplikasi dengan Gradle, hal ini akan ditangani secara otomatis.

Android versi lama memiliki bug di PackageManager dan linker dinamis yang menyebabkan penginstalan, update, dan pemuatan library native menjadi tidak dapat diandalkan. Secara khusus, jika aplikasi Anda menargetkan versi Android sebelum 4.3 (Android API level 18), dan Anda menggunakan libc++_shared.so, maka Anda harus memuat library bersama sebelum library lain apa pun 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, NDK mendukung libstdc++ GNU dan STLport, selain libc++. Jika aplikasi Anda bergantung pada library bawaan yang dibuat berdasarkan NDK yang berbeda dengan yang digunakan untuk membuat aplikasi Anda, pastikan aplikasi tersebut melakukannya dengan 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 di libc++ tidak sama dengan di gnustl. Kode yang ditulis berdasarkan satu STL tidak akan dapat menggunakan objek yang ditulis berdasarkan STL lain. Ini hanyalah satu contoh; ketidakcocokan lainnya banyak.

Aturan ini melampaui kode Anda. Semua dependensi Anda harus menggunakan STL yang sama dengan yang Anda pilih. Jika Anda mengandalkan dependensi closed source pihak ketiga yang menggunakan STL dan tidak menyediakan satu library per STL, maka Anda tidak memiliki pilihan di STL selain 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 karena secara historis pengecualian C++ tidak tersedia di NDK. CMake dan toolchain mandiri memiliki pengecualian C++ yang diaktifkan secara default.

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

APP_CPPFLAGS := -fexceptions
    

Untuk mengaktifkan pengecualian untuk modul ndk-build tunggal, 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 untuk modul ndk-build tunggal, tambahkan baris berikut ke modul yang diberikan di Android.mk:

LOCAL_CPP_FEATURES := rtti
    

Atau Anda dapat menggunakan:

LOCAL_CPPFLAGS := -frtti