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 đã tạo và cách sử dụng mã đó 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 xây dựng. Ba trường hợp sử dụng tạo nguồn được hệ thống xây dựng hỗ trợ là tạo liên kết C bằng cách sử dụng bindgen, giao diện AIDL và giao diện protobuf.

Thùng từ nguồn được tạo

Mọi mô-đun Rust tạo ra mã nguồn đều có thể được dùng làm một thùng, chính xác như nếu thuộc tính này được xác định là rust_library. (Điều này có nghĩa là chuyển đổi có thể được định nghĩa là phần phụ thuộc trong các thuộc tính rustlibs, rlibsdylibs.) Mẫu sử dụng tốt nhất cho mã nền tảng là sử dụng nguồn được tạo dưới dạng một vùng chứa. Mặc dù Macro include! được hỗ trợ cho nguồn đã tạo, 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à mã nền tảng có thể vẫn 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 cách độc đáo.

Sử dụng include!() để bao gồm nguồn được tạo

Các ví dụ trong mỗi trang mô-đun cụ thể (tương ứng) sẽ đề cập đến việc sử dụng nguồn được tạo làm một vùng chứa. Phần này cho biết cách tham chiếu nguồn đã tạo thông qua macro include!(). Lưu ý rằng quá trình này tương tự cho tất cả các nguồn một số trình tạo.

Đ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 mô-đun rust_bindgen (libbuzz_bindgen) và có thể chuyển sang Các bước để đưa nguồn đã tạo vào để sử dụng macro include!(). Nếu chưa, vui lòng chuyển đến phần Xác định mô-đun bindgen rust, tạo libbuzz_bindgen rồi quay lại đây.

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

Các bước để bao gồm nguồn đã tạo

Tạo external/rust/hello_bindgen/Android.bp với các 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 các 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) }
}

Lý do sử dụng vùng chứa 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 biểu thị một điểm truy cập đến một tệp nhị phân hoặc thư viện. Công cụ này dự kiến cây nguồn được cấu trúc sao cho tất cả các tệp nguồn bắt buộc đều 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 nguồn hoặc được cung cấp thông qua một lệnh include trong nguồn:

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

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

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

Việc này đặt ra một thách thức đối với Soong khi đầu ra cho mỗi mô-đun được đặt vào thư mục out/ riêng của chúng1. Không có OUT_DIR nào mà các phần phụ thuộc sẽ xuất 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 vùng chứa có thể nhập, vì một số lý do:

  • Ngăn tên tệp nguồn được tạo xung đột.
  • Giảm bớt mã nguyên mẫu xác nhận an toàn trong toàn bộ cây cần bảo trì. Bất kỳ mã nguyên mẫu nào cần thiết để biên dịch nguồn đã tạo vào một thùng có thể được duy trì tập trung.
  • Tránh các hoạt động tương tác2 ngầm ẩn giữa mã được tạo và kho dữ liệu xung quanh.
  • Giảm áp lực lên bộ nhớ và ổ đĩa bằng cách liên kết linh động các nguồn được tạo thường dùng.

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 như một thùng. Soong vẫn hỗ trợ các vùng chứa 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 đặt biến môi trường OUT_DIR vào thư mục đó khi biên dịch mô-đun, để có thể tìm thấy nguồn đã tạo. Tuy nhiên, vì những lý do đã mô tả, tốt nhất bạn chỉ nên 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 nó có thể tham chiếu các giá trị từ không gian tên bao bọc, sửa đổi không gian tên hoặc sử dụng các cấu trúc như #![foo]. Những hoạt động tương tác ngầm ẩn này có thể khó duy trì. Luôn ưu tiên sử dụng macro khi thực sự cần tương tác với phần còn lại của vùng chứa.