Sistem build mendukung pembuatan binding bindgen melalui jenis modul rust_bindgen. Bindgen menyediakan binding FFI Rust ke library C (dengan beberapa dukungan C++ terbatas, yang memerlukan penetapan properti cppstd).

Penggunaan rust_bindgen dasar

Berikut adalah contoh cara menentukan modul yang menggunakan bindgen, dan cara menggunakan modul tersebut sebagai crate. Jika Anda perlu menggunakan binding bindgen melalui makro include!(), seperti untuk kode eksternal, lihat halaman Generator Sumber.

Contoh library C yang akan dipanggil dari Rust

Berikut adalah contoh library C yang menentukan struct dan fungsi untuk digunakan di Rust.

external/rust/libbuzz/libbuzz.h

typedef struct foo {
    int x;
} foo;

void fizz(int i, foo* cs);

external/rust/libbuzz/libbuzz.c

#include <stdio.h>
#include "libbuzz.h"

void fizz(int i, foo* my_foo){
    printf("hello from c! i = %i, my_foo->x = %i\n", i, my_foo->x);
}

Menentukan modul rust_bindgen

Tentukan header wrapper, external/rust/libbuzz/libbuzz_wrapper.h, yang menyertakan semua header yang relevan:

// Include headers that are required for generating bindings in a wrapper header.
#include "libbuzz.h"

Tentukan file Android.bp sebagai external/rust/libbuzz/Android.bp:

cc_library {
    name: "libbuzz",
    srcs: ["libbuzz.c"],
}

rust_bindgen {
     name: "libbuzz_bindgen",

     // Crate name that's used to generate the rust_library variants.
     crate_name: "buzz_bindgen",

     // Path to the wrapper source file.
     wrapper_src: "libbuzz_wrapper.h",

     // 'source_stem' controls the output filename.
     // This is the filename that's used in an include! macro.
     //
     // In this case, we just use "bindings", which produces
     // "bindings.rs".
     source_stem: "bindings",

     // Bindgen-specific flags and options to customize the bindings.
     // See the bindgen manual for more information.
     bindgen_flags: ["--verbose"],

     // Clang flags to be used when generating the bindings.
     cflags: ["-DSOME_FLAG"],

     // Shared, static, and header libraries which export the necessary
     // include directories must be specified.
     //
     // These libraries will also be included in the crate if static,
     // or propagated to dependents if shared.
     // static_libs: ["libbuzz"]
     // header_libs: ["libbuzz"]
     shared_libs: ["libbuzz"],
}

Untuk mempelajari lebih lanjut cara menggunakan flag bindgen, lihat bagian manual bindgen di Menyesuaikan Binding yang Dibuat.

Jika Anda menggunakan bagian ini untuk menentukan modul rust_bindgen sebagai prasyarat untuk menggunakan makro include!(), kembali ke Prasyarat di halaman Generator Sumber. Jika tidak, lanjutkan ke bagian berikutnya.

Menggunakan binding sebagai crate

Buat external/rust/hello_bindgen/Android.bp dengan konten berikut:

rust_binary {
   name: "hello_bindgen",
   srcs: ["main.rs"],

   // Add the rust_bindgen module as if it were a rust_library dependency.
   rustlibs: ["libbuzz_bindgen"],
}

Buat external/rust/hello_bindgen/src/main.rs dengan konten berikut:

//! Example crate for testing bindgen bindings

fn main() {
    let mut x = buzz_bindgen::foo { x: 2 };
    unsafe { buzz_bindgen::fizz(1, &mut x as *mut buzz_bindgen::foo) }
}

Terakhir, panggil m hello_bindgen untuk membangun biner.

Menguji binding Bindgen

Binding bindgen biasanya berisi sejumlah pengujian tata letak yang dihasilkan untuk mencegah ketidakcocokan tata letak memori. AOSP merekomendasikan agar Anda memiliki modul pengujian yang telah ditentukan untuk pengujian ini, dan bahwa pengujian tersebut berjalan sebagai bagian dari rangkaian pengujian normal project Anda.

Biner pengujian untuk ini dapat dengan mudah dibuat dengan menentukan modul rust_test di external/rust/hello_bindgen/Android.bp:

rust_test {
    name: "bindings_test",
    srcs: [
        ":libbuzz_bindgen",
    ],
    crate_name: "buzz_bindings_test",
    test_suites: ["general-tests"],
    auto_gen_config: true,

    // Be sure to disable lints as the generated source
    // is not guaranteed to be lint-free.
    clippy_lints: "none",
    lints: "none",
}

Visibilitas dan penautan

Binding yang dihasilkan biasanya sangat kecil, karena terdiri dari definisi jenis, tanda tangan fungsi, dan konstanta terkait. Akibatnya, menautkan library ini secara dinamis akan sia-sia. Kami telah menonaktifkan penautan dinamis untuk modul ini sehingga menggunakannya melalui rustlibs akan otomatis memilih varian statis.

Secara default, modul rust_bindgen memiliki properti visibility [":__subpackages__"], yang hanya akan mengizinkan modul dalam file Android.bp yang sama atau yang berada di bawahnya dalam hierarki direktori untuk melihatnya. Fungsi ini memiliki dua tujuan:

  • Hal ini tidak menganjurkan penggunaan binding C mentah di tempat lain dalam hierarki.
  • Hal ini menghindari masalah penautan berlian dengan campuran penautan statis dan dinamis.

Biasanya, Anda harus menyediakan library wrapper yang aman di sekitar modul yang dihasilkan yang telah Anda tambahkan dalam hierarki direktori yang sama dengan binding yang ditujukan untuk digunakan developer lain. Jika hal ini tidak berfungsi untuk kasus penggunaan Anda, Anda dapat menambahkan paket tambahan ke visibilitas. Saat menambahkan cakupan visibilitas tambahan, pastikan Anda tidak menambahkan dua cakupan yang dapat ditautkan ke proses yang sama pada masa mendatang, karena hal tersebut dapat gagal ditautkan.

Properti rust_bindgen yang penting

Properti yang ditentukan di bawah ini adalah tambahan dari Properti umum yang penting yang berlaku untuk semua modul. Hal ini sangat penting untuk modul bindgen Rust, atau menunjukkan perilaku unik khusus untuk jenis modul rust_bindgen.

stem, name, crate_name

rust_bindgen menghasilkan varian library, sehingga memiliki persyaratan yang sama dengan modul rust_library untuk properti stem, name, dan crate_name. Lihat properti library Notable Rust untuk referensi.

wrapper_src

Ini adalah jalur relatif ke file header wrapper yang menyertakan header yang diperlukan untuk binding ini. Ekstensi file menentukan cara menafsirkan header dan menentukan flag -std yang akan digunakan secara default. File ini diasumsikan sebagai header C kecuali jika ekstensinya adalah .hh atau .hpp. Jika header C++ Anda harus memiliki beberapa ekstensi lain, tetapkan properti cpp_std untuk mengganti perilaku default yang menganggap file tersebut adalah file C.

stem_sumber

Ini adalah nama file untuk file sumber yang dihasilkan. Kolom ini harus ditentukan, meskipun Anda menggunakan binding sebagai crate, karena properti stem hanya mengontrol nama file output untuk varian library yang dihasilkan. Jika modul bergantung pada beberapa generator sumber (seperti bindgen dan protobuf) sebagai sumber, bukan sebagai crate melalui rustlibs, Anda harus memastikan bahwa semua generator sumber yang merupakan dependensi modul tersebut memiliki nilai source_stem yang unik. Modul dependen menyalin sumber dari semua dependensi SourceProvider yang ditentukan di srcs ke direktori OUT_DIR umum, sehingga konflik di source_stem akan mengakibatkan file sumber yang dihasilkan ditimpa di direktori OUT_DIR.

c_std

Ini adalah string yang mewakili versi standar C yang akan digunakan. Nilai yang valid tercantum di bawah ini:

  • Versi tertentu, seperti "gnu11".
  • "experimental", yang merupakan nilai yang ditentukan oleh sistem build di build/soong/cc/config/global.go, dapat menggunakan versi draf seperti C++1z jika tersedia.
  • Hapus penetapan atau "", yang menunjukkan bahwa default sistem build harus digunakan.

Jika disetel, ekstensi file akan diabaikan dan header dianggap sebagai header C. Nilai ini tidak dapat ditetapkan bersamaan dengan cpp_std.

cpp_std

cpp_std adalah string yang mewakili versi standar C yang akan digunakan. Nilai valid:

  • Versi tertentu, seperti "gnu++11"
  • "experimental", yang merupakan nilai yang ditentukan oleh sistem build di build/soong/cc/config/global.go, dapat menggunakan versi draf seperti C++1z jika tersedia.
  • Hapus penetapan atau "", yang menunjukkan bahwa default sistem build harus digunakan.

Jika ditetapkan, ekstensi file akan diabaikan dan header dianggap sebagai header C++. Nilai ini tidak dapat ditetapkan bersamaan dengan c_std.

cflags

cflags menyediakan daftar string flag Clang yang diperlukan untuk menafsirkan header dengan benar.

pengikatan_kustom

Untuk kasus penggunaan lanjutan, bindgen dapat digunakan sebagai library, yang menyediakan API yang dapat dimanipulasi sebagai bagian dari biner Rust kustom. Kolom custom_bindgen mengambil nama modul dari modul rust_binary_host, yang menggunakan API bindgen, bukan biner bindgen normal.

Biner kustom ini harus mengharapkan argumen dengan cara yang mirip dengan bindgen, seperti

$ my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]

Sebagian besar ditangani oleh library bindgen itu sendiri. Untuk melihat contoh penggunaan ini, buka external/rust/crates/libnoopener3-sys/android/build.rs.

Selain itu, kumpulan lengkap properti library tersedia untuk mengontrol kompilasi library, meskipun properti ini jarang perlu ditetapkan atau diubah.

handle_static_inline dan static_inline_library

Kedua properti ini dimaksudkan untuk digunakan bersama dan memungkinkan produksi wrapper untuk fungsi inline statis yang dapat disertakan dalam binding bindgen yang diekspor.

Untuk menggunakannya, tetapkan handle_static_inline: true dan tetapkan static_inline_library ke cc_library_static yang sesuai yang menentukan modul rust_bindgen sebagai input sumber.

Contoh penggunaan:

    rust_bindgen {
        name: "libbindgen",
        wrapper_src: "src/any.h",
        crate_name: "bindgen",
        stem: "libbindgen",
        source_stem: "bindings",

        // Produce bindings for static inline fucntions
        handle_static_inline: true,
        static_inline_library: "libbindgen_staticfns"
    }

    cc_library_static {
        name: "libbindgen_staticfns",

        // This is the rust_bindgen module defined above
        srcs: [":libbindgen"],

        // The include path to the header file in the generated c file is
        // relative to build top.
        include_dirs: ["."],
    }