ソースジェネレータ

このページでは、生成されたソースがどのようにサポートされ、ビルドシステムでどのように使用できるかについての概要を説明します。

すべてのソースジェネレータは、同様のビルドシステム機能を提供します。ビルドシステムでサポートされる3つのソース生成のユースケースは、bindgen、AIDLインターフェイス、およびprotobufインターフェイスを使用してCバインディングを生成することです。

生成されたソースからのクレート

ソースコードを生成するすべてのRustモジュールは、 rust_libraryとして定義されているかのように、クレートとして使用できます。 (これは、 rustlibsrlibs 、およびdylibsプロパティの依存関係として定義できることを意味します。)プラットフォームコードの最適な使用パターンは、生成されたソースをクレートとして使用することです。 include!マクロは生成されたソースでサポートされており、その主な目的は、 external/に存在するサードパーティのコードをサポートすることです。

genruleモジュールを使用して独自の方法でソースを生成する場合など、プラットフォームコードがinclude!()マクロを介して生成されたソースを引き続き使用する場合があります。

include!()を使用して生成されたソースを含める

生成されたソースをクレートとして使用する方法については、特定の(それぞれの)モジュールページの例で説明しています。このセクションでは、 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) }
}

生成されたソースのクレートを選ぶ理由

C / C ++コンパイラとは異なり、 rustcはバイナリまたはライブラリへのエントリポイントを表す単一のソースファイルのみを受け入れます。ソースツリーは、必要なすべてのソースファイルが自動的に検出されるように構成されている必要があります。つまり、生成されたソースは、ソースツリーに配置するか、sourceのincludeディレクティブを介して提供する必要があります。

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

Rustコミュニティは、この違いを処理するために、 build.rsスクリプトとCargoビルド環境に関する仮定に依存しています。ビルド時に、 cargoコマンドは、 build.rsスクリプトが生成されたソースコードを配置することが期待されるOUT_DIR環境変数を設定します。次のコマンドを使用して、ソースコードを含めます。

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

各モジュールの出力は独自のout/ディレクトリ1に配置されるため、これはSoongにとって課題となります。依存関係が生成されたソースを出力する単一のOUT_DIRはありません。

プラットフォームコードの場合、AOSPは、いくつかの理由から、生成されたソースをインポート可能なクレートにパッケージ化することを好みます。

  • 生成されたソースファイル名が衝突しないようにします。
  • メンテナンスが必要なツリー全体でチェックインされるボイラープレートコードを減らします。生成されたソースをクレートにコンパイルするために必要なボイラープレートは、一元的に管理できます。
  • 生成されたコードと周囲のクレートの間の暗黙的な2つの相互作用は避けてください。
  • 一般的に使用される生成されたソースを動的にリンクすることにより、メモリとディスクへの負担を軽減します。

その結果、AndroidのすべてのRustソース生成モジュールタイプは、コンパイルしてクレートとして使用できるコードを生成します。 Soongは、Cargoと同様に、モジュールに対して生成されたすべてのソース依存関係が単一のモジュールごとのディレクトリにコピーされた場合でも、変更なしでサードパーティのクレートをサポートします。このような場合、Soongは、モジュールのコンパイル時にOUT_DIR環境変数をそのディレクトリに設定するため、生成されたソースを見つけることができます。ただし、すでに説明した理由により、このメカニズムは、絶対に必要な場合にのみプラットフォームコードで使用することをお勧めします。


  1. 生成されたソースへのパスはコンパイラに直接提供されるため、これはC / C ++および同様の言語では問題になりません。

  2. include!テキストを含めることで機能し、囲んでいる名前空間の値を参照したり、名前空間を変更したり、 #![foo]のような構造を使用したりする場合があります。これらの暗黙の相互作用は、維持するのが難しい場合があります。クレートの残りの部分との相互作用が本当に必要な場合は、常にマクロを優先します。