Generator sumber

Halaman ini memberikan tampilan tingkat tinggi tentang cara sumber yang dihasilkan didukung dan cara sumber tersebut dapat digunakan dalam sistem build.

Semua generator sumber menyediakan fungsi sistem build yang serupa. Tiga kasus penggunaan pembuatan sumber yang didukung sistem build menghasilkan binding C menggunakan bindgen, antarmuka AIDL, dan antarmuka protobuf.

Crate dari sumber yang dihasilkan

Setiap modul Rust yang menghasilkan kode sumber dapat digunakan sebagai crate, persis seperti jika ditentukan sebagai rust_library. (Artinya, dependensi dapat ditentukan sebagai dependensi dalam properti rustlibs, rlibs, dan dylibs.) Pola penggunaan terbaik untuk kode platform adalah menggunakan sumber yang dihasilkan sebagai crate. Meskipun makro include! didukung untuk sumber yang dihasilkan, tujuan utamanya adalah untuk mendukung kode pihak ketiga yang berada di external/.

Ada kalanya kode platform mungkin masih menggunakan sumber yang dihasilkan melalui makro include!(), seperti saat Anda menggunakan modul genrule untuk membuat sumber dengan cara yang unik.

Menggunakan include!() untuk menyertakan sumber yang dihasilkan

Penggunaan sumber yang dihasilkan sebagai penampung dibahas oleh contoh di setiap halaman modul khusus (masing-masing). Bagian ini menunjukkan cara mereferensikan sumber yang dihasilkan melalui makro include!(). Perhatikan bahwa proses ini serupa untuk semua generator sumber.

Prasyarat

Contoh ini didasarkan pada asumsi bahwa Anda telah menentukan modul rust_bindgen (libbuzz_bindgen) dan dapat melanjutkan ke Langkah-langkah untuk menyertakan sumber yang dihasilkan untuk menggunakan makroinclude!(). Jika belum, buka Menentukan modul rust bindgen, buat libbuzz_bindgen, lalu kembali ke sini.

Perhatikan bahwa bagian file build ini berlaku untuk semua generator sumber.

Langkah-langkah untuk menyertakan sumber yang dihasilkan

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

rust_binary {
   name: "hello_bzip_bindgen_include",
   srcs: [
         // The primary rust source file must come first in this list.
         "src/lib.rs",

         // The module providing the bindgen bindings is
         // included in srcs prepended by ":".
         ":libbuzz_bindgen",
    ],

    // Dependencies need to be redeclared when generated source is used via srcs.
    shared_libs: [
        "libbuzz",
    ],
}

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

#![allow(clippy::all)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(unused)]
#![allow(missing_docs)]

// Note that "bzip_bindings.rs" here must match the source_stem property from
// the rust_bindgen module.
include!(concat!(env!("OUT_DIR"), "/bzip_bindings.rs"));

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

mod bindings;

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

Alasan membuat crate untuk sumber yang dihasilkan

Tidak seperti compiler C/C++, rustc hanya menerima satu file sumber yang mewakili titik entri ke biner atau library. Ini mengharapkan hierarki sumber disusun sedemikian rupa sehingga semua file sumber yang diperlukan dapat ditemukan secara otomatis. Artinya, sumber yang dihasilkan harus ditempatkan dalam hierarki sumber, atau disediakan melalui perintah include dalam sumber:

include!("/path/to/hello.rs");

Komunitas Rust bergantung pada skrip build.rs, dan asumsi tentang lingkungan build Cargo, untuk menangani perbedaan ini. Saat mem-build, perintah cargo menetapkan variabel lingkungan OUT_DIR tempat skrip build.rs diharapkan menempatkan kode sumber yang dihasilkan. Gunakan perintah berikut untuk menyertakan kode sumber:

include!(concat!(env!("OUT_DIR"), "/hello.rs"));

Hal ini menimbulkan tantangan bagi Soong karena output untuk setiap modul ditempatkan di direktori out/-nya sendiri1. Tidak ada satu OUT_DIR tempat dependensi menghasilkan sumber yang dihasilkannya.

Untuk kode platform, AOSP lebih memilih mengemas sumber yang dihasilkan ke dalam crate yang dapat diimpor, karena beberapa alasan:

  • Mencegah nama file sumber yang dihasilkan bentrok.
  • Kurangi kode boilerplate yang di-checkin di seluruh hierarki yang memerlukan pemeliharaan. Setiap boilerplate yang diperlukan untuk membuat sumber yang dihasilkan dikompilasi ke dalam crate dapat dikelola secara terpusat.
  • Hindari interaksi2 implisit antara kode yang dihasilkan dan crate di sekitarnya.
  • Mengurangi tekanan pada memori dan disk dengan menautkan sumber yang dihasilkan secara dinamis yang biasa digunakan.

Akibatnya, semua jenis modul pembuatan sumber Rust Android menghasilkan kode yang dapat dikompilasi dan digunakan sebagai crate. Soong masih mendukung container pihak ketiga tanpa modifikasi jika semua dependensi sumber yang dihasilkan untuk modul disalin ke dalam satu direktori per modul, mirip dengan Cargo. Dalam kasus tersebut, Soong menetapkan variabel lingkungan OUT_DIR ke direktori tersebut saat mengompilasi modul, sehingga sumber yang dihasilkan dapat ditemukan. Namun, karena alasan yang telah dijelaskan, praktik terbaiknya adalah hanya menggunakan mekanisme ini dalam kode platform jika benar-benar diperlukan.


  1. Hal ini tidak menimbulkan masalah untuk C/C++ dan bahasa serupa, karena jalur ke sumber yang dihasilkan disediakan langsung ke compiler. 

  2. Karena include! berfungsi dengan penyertaan tekstual, include! dapat mereferensikan nilai dari namespace yang melingkupi, mengubah namespace, atau menggunakan konstruksi seperti #![foo]. Interaksi implisit ini dapat sulit dikelola. Selalu pilih makro saat interaksi dengan kandang lainnya benar-benar diperlukan.