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 system mengacu pada /system/lib/libstdc++.so. Jangan sampai keliru antara library ini 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 menggunakan CMake, Anda dapat menentukan runtime dari Tabel 1 dengan variabel ANDROID_STL dalam file build.gradle tingkat 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, toolchain tersebut akan menggunakan STL bersama secara default. Untuk menggunakan varian statis, tambahkan -static-libstdc++ ke tanda 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++, 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 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 memiliki satu-satunya 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 ketika menargetkan versi lama Android. Kesepakatannya adalah, jika Anda menggunakan libc++_shared.so, Anda harus menyertakannya dalam APK. 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 (API Android 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 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 pihak ketiga closed source 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 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. RTTI diaktifkan secara default untuk CMake dan toolchain mandiri.

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 Android.mk modul yang dimaksud:

LOCAL_CPP_FEATURES := rtti
    

Atau, Anda dapat menggunakan:

LOCAL_CPPFLAGS := -frtti