來源產生器

本頁面提供高階檢視畫面,說明如何支援產生的來源,以及如何在建構系統中使用來源。

所有來源產生器都提供類似的建構系統功能。系統支援三種建構系統的來源產生用途:使用 bindgen、AIDL 介面和 protobuf 介面產生 C 繫結。

從產生的來源建立 Crate

每個產生原始碼的 Rust 模組都可以做為 Crate 使用,就像定義為 rust_library 一樣。(也就是說,這可以定義為 rustlibsrlibsdylibs 屬性中的依附元件)。平台程式碼的最佳使用模式是將產生的來源做為 Crate。雖然產生的來源支援 include! 巨集,但主要用途是支援位於 external/ 中的第三方程式碼。

在某些情況下,平台程式碼可能仍會透過 include!() 巨集使用產生的來源,例如使用 genrule 模組以獨特方式產生來源時。

使用 include!() 納入產生的來源

如要瞭解如何將產生的來源當做 Crate 使用,請參閱各個特定 (相應) 模組頁面的範例。本節說明如何透過 include!() 巨集參照產生的來源。請注意,所有來源產生器的程序都類似。

先修規定

這個範例是以您已定義 rust_bindgen 模組 (libbuzz_bindgen) 為前提,並可繼續進行納入產生來源的步驟,以使用 include!() 巨集。如果還沒建立,請前往「定義 Rust bindgen 模組」一節,建立 libbuzz_bindgen,然後返回這裡。

請注意,這項建構檔案部分適用於所有來源產生器。

納入產生的來源的步驟

建立 external/rust/hello_bindgen/Android.bp,並加入以下內容:

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

建立 external/rust/hello_bindgen/src/bindings.rs,並加入以下內容:

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

建立 external/rust/hello_bindgen/src/lib.rs,並加入以下內容:

mod bindings;

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

為什麼要為產生的來源建立 Crate

與 C/C++ 編譯器不同,rustc 只接受代表二進位檔或程式庫進入點的單一來源檔案。它會預期來源樹狀結構的架構,可自動探索所有必要的來源檔案。也就是說,產生的來源必須放在來源樹狀結構中,或透過來源中的 include 指令提供:

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

Rust 社群依賴 build.rs 指令碼,以及對 Cargo 建構環境的假設,來因應這項差異。建構時,cargo 指令會設定 OUT_DIR 環境變數build.rs 指令碼應將產生的原始碼放入該變數。請使用以下指令加入原始碼:

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

這對 Soong 來說是一項挑戰,因為每個模組的輸出內容都會放在各自的 out/ 目錄 1 中。沒有單一 OUT_DIR,其中依附元件會輸出產生的來源。

就平台程式碼而言,Android 開放原始碼計畫偏好將產生的來源封裝到可匯入的 Crate 中,原因如下:

  • 避免產生的來源檔案名稱發生衝突。
  • 減少整個樹狀結構中需要維護的樣板程式碼。集中維護將生成的來源編譯到 Crate 中所需的任何樣板。
  • 避免在產生的程式碼和周圍 Crate 之間發生隱含的 2 互動。
  • 動態連結常用的產生來源,減輕記憶體和磁碟的負擔。

因此,所有 Android 的 Rust 來源產生模組類型都會產生可編譯及做為 Crate 使用的程式碼。如果模組的所有產生來源依附元件都複製到單一模組目錄中 (類似 Cargo),Soong 仍支援第三方 Crate,不必修改。在這種情況下,Soong 會在編譯模組時,將 OUT_DIR 環境變數設為該目錄,因此可以找到產生的來源。不過,基於上述原因,最佳做法是僅在絕對必要時,才在平台程式碼中使用這項機制。


  1. 這對 C/C++ 和類似語言不會造成任何問題,因為產生的來源路徑會直接提供給編譯器。 

  2. 由於 include! 是透過文字納入的方式運作,因此可能會參照封閉命名空間中的值、修改命名空間,或使用 #![foo] 等建構函式。這類隱含互動可能難以維護。如果確實需要與 Crate 的其餘部分互動,請一律優先使用巨集。