Trình tạo nguồn

Trang này cung cấp thông tin tổng quan về cách hỗ trợ nguồn được tạo và cách sử dụng nguồn đó trong hệ thống xây dựng.

Tất cả trình tạo nguồn đều cung cấp chức năng tương tự cho hệ thống bản dựng. Ba trường hợp sử dụng tạo nguồn được hệ thống bản dựng hỗ trợ là tạo các liên kết C bằng bindgen, giao diện AIDL và giao diện protobuf.

Crates từ nguồn được tạo

Mọi mô-đun Rust tạo mã nguồn đều có thể được dùng làm crate, giống như khi được xác định là rust_library. (Tức là bạn có thể xác định mô-đun này là một phần phụ thuộc trong các thuộc tính rustlibs, rlibsdylibs.) Mô hình sử dụng tốt nhất cho mã nền tảng là sử dụng nguồn được tạo làm crate. Mặc dù macro include! được hỗ trợ cho nguồn được tạo, nhưng mục đích chính của macro này là hỗ trợ mã của bên thứ ba nằm trong external/.

Có những trường hợp mã nền tảng vẫn có thể sử dụng nguồn được tạo thông qua macro include!(), chẳng hạn như khi bạn sử dụng mô-đun genrule để tạo nguồn theo một cách riêng.

Sử dụng include!() để đưa nguồn được tạo vào

Việc sử dụng nguồn được tạo làm crate được đề cập trong các ví dụ trên trang của từng mô-đun cụ thể (tương ứng). Phần này cho biết cách tham chiếu nguồn được tạo thông qua macro include!(). Xin lưu ý rằng quy trình này tương tự đối với tất cả trình tạo nguồn.

Điều kiện tiên quyết

Ví dụ này dựa trên giả định rằng bạn đã xác định một rust_bindgen mô-đun (libbuzz_bindgen) và có thể chuyển sang Các bước đưa nguồn được tạo vào để sử dụng macroinclude!(). Nếu chưa, vui lòng chuyển đến phần Xác định mô-đun rust bindgen, tạo libbuzz_bindgen, sau đó quay lại đây.

Xin lưu ý rằng các phần tệp bản dựng của phần này áp dụng cho tất cả trình tạo nguồn.

Các bước đưa nguồn được tạo vào

Tạo external/rust/hello_bindgen/Android.bp với nội dung sau:

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",
    ],
}

Tạo external/rust/hello_bindgen/src/bindings.rs với nội dung sau:

#![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"));

Tạo external/rust/hello_bindgen/src/lib.rs với nội dung sau:

mod bindings;

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

Vì sao nên dùng crate cho nguồn được tạo

Không giống như trình biên dịch C/C++, rustc chỉ chấp nhận một tệp nguồn duy nhất đại diện cho điểm truy cập vào tệp nhị phân hoặc thư viện. Trình biên dịch này cho rằng cây nguồn được cấu trúc sao cho tất cả các tệp nguồn cần thiết có thể được tự động phát hiện. Điều này có nghĩa là nguồn được tạo phải được đặt trong cây nguồn hoặc được cung cấp thông qua chỉ thị include trong nguồn:

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

Cộng đồng Rust phụ thuộc vào các tập lệnh build.rs và các giả định về môi trường tạo bản dựng Cargo để xử lý sự khác biệt này. Khi tạo bản dựng, lệnh cargo sẽ đặt biến môi trường OUT_DIR mà các tập lệnh build.rs dự kiến sẽ đặt mã nguồn được tạo vào. Sử dụng lệnh sau để đưa mã nguồn vào:

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

Điều này gây ra thách thức cho Soong vì kết quả cho mỗi mô-đun được đặt trong thư mục out/ `out/`1 riêng. Không có OUT_DIR duy nhất nơi các phần phụ thuộc xuất ra nguồn được tạo.

Đối với mã nền tảng, AOSP ưu tiên đóng gói nguồn được tạo vào một crate có thể nhập được vì một số lý do:

Do đó, tất cả các loại mô-đun tạo nguồn Rust của Android đều tạo ra mã có thể được biên dịch và sử dụng làm crate. Soong vẫn hỗ trợ các crate của bên thứ ba mà không cần sửa đổi nếu tất cả các phần phụ thuộc nguồn được tạo cho một mô-đun được sao chép vào một thư mục duy nhất cho mỗi mô-đun, tương tự như Cargo. Trong những trường hợp như vậy, Soong sẽ đặt biến môi trường OUT_DIR thành thư mục đó khi biên dịch mô-đun, để có thể tìm thấy nguồn được tạo. Tuy nhiên, vì những lý do đã mô tả, bạn nên chỉ sử dụng cơ chế này trong mã nền tảng khi thực sự cần thiết.


  1. Điều này không gây ra vấn đề nào cho C/C++ và các ngôn ngữ tương tự, vì đường dẫn đến nguồn được tạo được cung cấp trực tiếp cho trình biên dịch.

  2. include! hoạt động bằng cách đưa văn bản vào, nên macro này có thể tham chiếu các giá trị từ không gian tên bao quanh, sửa đổi không gian tên hoặc sử dụng các cấu trúc như #![foo]. Bạn có thể khó duy trì các lượt tương tác ngầm ẩn này. Luôn ưu tiên macro khi thực sự cần tương tác với phần còn lại của crate.