Trình tạo nguồn

Trang này cung cấp thông tin tổng quan cấp cao về cách nguồn được tạo được hỗ trợ 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 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.

Các thùng từ nguồn được tạo

Mọi mô-đun Rust tạo mã nguồn có thể được sử dụng làm một thùng, chính xác như thể nó được xác định là rust_library. (Điều này có nghĩa là phần phụ thuộc có thể được định nghĩa là phần phụ thuộc vào 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ù được hỗ trợ cho nguồn được tạo, nhưng mục đích chính của macro include! là hỗ trợ mã của bên thứ ba nằm trong external/.

Có trường hợp mã nền tảng vẫn có thể sử dụng nguồn đã 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 riêng.

Sử dụng include!() để đưa vào nguồn đã 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!(). 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 là bạn đã xác định mô-đun rust_bindgen (libbuzz_bindgen) và có thể tiếp tục thực hiện Các bước để thêm nguồn được tạo để sử dụng macro include!(). Nếu bạn chưa có máy, vui lòng chuyển đến phần Xác định mô-đun liên kết gỉ sét, 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) }
}

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 đại diện cho điểm truy cập đến tệp nhị phân hoặc thư viện. Phương thức này dự kiến rằng cây nguồn có cấu trúc sao cho có thể tự động phát hiện tất cả các tệp nguồn bắt buộc. Đ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 một lệnh 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 xây dựng Cargo để xử lý sự khác biệt này. Khi tạo, lệnh cargo sẽ đặt một biến môi trường OUT_DIR vào đó các tập lệnh build.rs dự kiến sẽ đặt mã nguồn được tạo. Hãy sử dụng lệnh sau để thêm mã nguồn:

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

Điều này gây ra thách thức cho Soong vì đầu ra của mỗi mô-đun được đặt trong thư mục out/ riêng của mô-đun đó1. 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 tần suất đăng ký mã nguyên mẫu trên toàn bộ cây cần bảo trì. Mọi mã nguyên mẫu cần thiết để biên dịch nguồn được tạo thành một vùng chứa đều có thể được duy trì tập trung.
  • Tránh các hoạt động tương tác ngầm 2 giữa mã được tạo và vùng chứa 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 sẽ tạo ra mã có thể biên dịch và sử dụng làm 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 sẽ đặt biến môi trường OUT_DIR thành thư mục đó khi biên dịch mô-đun, nhờ đó 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 lớp này có thể tham chiếu các giá trị của không gian tên bao gồm, 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.