Máy phát nguồn

Trang này cung cấp chế độ xem cấp cao 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ả các trình tạo nguồn đều cung cấp chức năng xây dựng hệ thống tương tự. Ba trường hợp sử dụng tạo nguồn được hệ thống xây dựng hỗ trợ đang tạo ra các liên kết C bằng cách sử dụng giao diện bindgen, AIDL và giao diện protobuf.

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

Mọi mô-đun Rust tạo mã nguồn đều có thể được sử dụng như một thùng, chính xác như thể nó được định nghĩa là một rust_library . (Điều này có nghĩa là nó có thể được định nghĩa là một 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 làm thùng. Mặc dù bao include! macro được hỗ trợ cho nguồn được tạo, mục đích chính của nó 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 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!() để bao gồm nguồn được tạo

Việc sử dụng nguồn được tạo làm thùng được đề cập trong các ví dụ trong từng trang mô-đun cụ thể (tương ứng). Phần này trình bày cách tham chiếu nguồn được tạo thông qua macro include!() . Lưu ý rằng quá trình này tương tự đối với tất cả cá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ô-đun rust_bindgen ( libbuzz_bindgen ) và có thể tiến hành các Bước để bao gồm nguồn được tạo để sử dụng macro include!() . Nếu chưa, vui lòng truy cập Xác định mô-đun bindgen rỉ sét , tạo libbuzz_bindgen , sau đó quay lại đây.

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

Các bước để bao gồm nguồn được tạ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) }
}

Tại sao lại có thùng 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ị điểm vào tệp nhị phân hoặc thư viện. Nó hy vọng 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 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 để giải quyết sự khác biệt này . Khi xây dựng, 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. Sử dụng lệnh sau để bao gồm mã nguồn:

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

Điều này đặt ra một thách thức đối với Soong vì đầu ra của mỗi mô-đun được đặt trong thư mục out/ 1 của riêng chúng. Không có một OUT_DIR nào mà các phần phụ thuộc xuất ra nguồn được tạo của chúng.

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

  • Ngăn chặn xung đột tên tệp nguồn được tạo.
  • Giảm việc đăng ký mã soạn sẵn trên toàn cây cần bảo trì. Bất kỳ bản soạn sẵn nào cần thiết để biên dịch nguồn được tạo vào thùng đều có thể được duy trì tập trung.
  • Tránh ẩn 2 tương tác giữa mã được tạo và thùng xung quanh.
  • Giảm áp lực lên bộ nhớ và đĩa bằng cách liên kết động các nguồn được tạo thường được sử dụng.

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

,

Trang này cung cấp chế độ xem cấp cao 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ả các trình tạo nguồn đều cung cấp chức năng xây dựng hệ thống tương tự. Ba trường hợp sử dụng tạo nguồn được hệ thống xây dựng hỗ trợ đang tạo ra các liên kết C bằng cách sử dụng giao diện bindgen, AIDL và giao diện protobuf.

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

Mọi mô-đun Rust tạo mã nguồn đều có thể được sử dụng như một thùng, chính xác như thể nó được định nghĩa là một rust_library . (Điều này có nghĩa là nó có thể được định nghĩa là một 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 làm thùng. Mặc dù bao include! macro được hỗ trợ cho nguồn được tạo, mục đích chính của nó 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 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!() để bao gồm nguồn được tạo

Việc sử dụng nguồn được tạo làm thùng được đề cập trong các ví dụ trong từng trang mô-đun cụ thể (tương ứng). Phần này trình bày cách tham chiếu nguồn được tạo thông qua macro include!() . Lưu ý rằng quá trình này tương tự đối với tất cả cá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ô-đun rust_bindgen ( libbuzz_bindgen ) và có thể tiến hành các Bước để bao gồm nguồn được tạo để sử dụng macro include!() . Nếu chưa, vui lòng truy cập Xác định mô-đun bindgen rỉ sét , tạo libbuzz_bindgen , sau đó quay lại đây.

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

Các bước để bao gồm nguồn được tạ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) }
}

Tại sao lại có thùng 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ị điểm vào tệp nhị phân hoặc thư viện. Nó hy vọng 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 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 để giải quyết sự khác biệt này . Khi xây dựng, 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. Sử dụng lệnh sau để bao gồm mã nguồn:

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

Điều này đặt ra một thách thức đối với Soong vì đầu ra của mỗi mô-đun được đặt trong thư mục out/ 1 của riêng chúng. Không có một OUT_DIR nào mà các phần phụ thuộc xuất ra nguồn được tạo của chúng.

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

  • Ngăn chặn xung đột tên tệp nguồn được tạo.
  • Giảm việc đăng ký mã soạn sẵn trên toàn cây cần bảo trì. Bất kỳ bản soạn sẵn nào cần thiết để biên dịch nguồn được tạo vào thùng đều có thể được duy trì tập trung.
  • Tránh ẩn 2 tương tác giữa mã được tạo và thùng xung quanh.
  • Giảm áp lực lên bộ nhớ và đĩa bằng cách liên kết động các nguồn được tạo thường được sử dụng.

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

,

Trang này cung cấp chế độ xem cấp cao 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ả các trình tạo nguồn đều cung cấp chức năng xây dựng hệ thống tương tự. Ba trường hợp sử dụng tạo nguồn được hệ thống xây dựng hỗ trợ đang tạo ra các liên kết C bằng cách sử dụng giao diện bindgen, AIDL và giao diện protobuf.

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

Mọi mô-đun Rust tạo mã nguồn đều có thể được sử dụng như một thùng, chính xác như thể nó được định nghĩa là một rust_library . (Điều này có nghĩa là nó có thể được định nghĩa là một 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 làm thùng. Mặc dù bao include! macro được hỗ trợ cho nguồn được tạo, mục đích chính của nó 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 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!() để bao gồm nguồn được tạo

Việc sử dụng nguồn được tạo làm thùng được đề cập trong các ví dụ trong từng trang mô-đun cụ thể (tương ứng). Phần này trình bày cách tham chiếu nguồn được tạo thông qua macro include!() . Lưu ý rằng quá trình này tương tự đối với tất cả cá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ô-đun rust_bindgen ( libbuzz_bindgen ) và có thể tiến hành các Bước để bao gồm nguồn được tạo để sử dụng macro include!() . Nếu chưa, vui lòng truy cập Xác định mô-đun bindgen rỉ sét , tạo libbuzz_bindgen , sau đó quay lại đây.

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

Các bước để bao gồm nguồn được tạ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) }
}

Tại sao lại có thùng 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ị điểm vào tệp nhị phân hoặc thư viện. Nó hy vọng 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 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 để giải quyết sự khác biệt này . Khi xây dựng, 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. Sử dụng lệnh sau để bao gồm mã nguồn:

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

Điều này đặt ra một thách thức đối với Soong vì đầu ra của mỗi mô-đun được đặt trong thư mục out/ 1 của riêng chúng. Không có một OUT_DIR nào mà các phần phụ thuộc xuất ra nguồn được tạo của chúng.

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

  • Ngăn chặn xung đột tên tệp nguồn được tạo.
  • Giảm việc đăng ký mã soạn sẵn trên toàn cây cần bảo trì. Bất kỳ bản soạn sẵn nào cần thiết để biên dịch nguồn được tạo vào thùng đều có thể được duy trì tập trung.
  • Tránh ẩn 2 tương tác giữa mã được tạo và thùng xung quanh.
  • Giảm áp lực lên bộ nhớ và đĩa bằng cách liên kết động các nguồn được tạo thường được sử dụng.

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