Generatori di codice sorgente

Questa pagina fornisce una visione generale di come l'origine generata è supportata e e come può essere usata nel sistema di compilazione.

Tutti i generatori di codice sorgente offrono funzionalità di sistema di compilazione simili. I tre i casi d'uso di generazione di origini supportati dal sistema di build stanno generando associazioni C utilizzando bindgen, interfacce AIDL e interfacce Protobuf.

Casse da origine generata

Ogni modulo Rust che genera codice sorgente può essere usato come una cassa, esattamente come se è definito come rust_library. Ciò significa che può essere definito dipendenza nelle proprietà rustlibs, rlibs e dylibs. Utilizzo ottimale per il codice della piattaforma prevede l'utilizzo di un'origine generata come una cassa. Sebbene La macro include! è supportata per l'origine generata; il suo scopo principale è Supportano il codice di terze parti che risiede in external/.

In alcuni casi il codice della piattaforma potrebbe continuare a utilizzare il codice sorgente generato tramite Macro include!(), ad esempio quando utilizzi un modulo genrule per generare un'origine in modo peculiare.

Utilizza include!() per includere l'origine generata

L'utilizzo dell'origine generata come cassa è illustrato negli esempi di ogni specifica (rispettivamente) pagina del modulo. Questa sezione mostra come fare riferimento all'origine generata attraverso la macro include!(). Tieni presente che questa procedura è simile per tutte le origini generatori.

Prerequisito

Questo esempio si basa sul presupposto che tu abbia definito un valore rust_bindgen (libbuzz_bindgen) e può andare alla sezione Passaggi per includere l'origine generata per utilizzare la macro include!(). In caso contrario, vai a Definizione di un modulo Rust bindgen crea libbuzz_bindgen, quindi torna qui.

Tieni presente che le parti del file di build sono applicabili a tutti i generatori di codice sorgente.

Passaggi per includere l'origine generata

Crea external/rust/hello_bindgen/Android.bp con i seguenti contenuti:

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

Crea external/rust/hello_bindgen/src/bindings.rs con i seguenti contenuti:

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

Crea external/rust/hello_bindgen/src/lib.rs con i seguenti contenuti:

mod bindings;

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

Perché creare casse per l'origine generata

A differenza dei compilatori C/C++, rustc accetta un solo file di origine che rappresentano un punto di ingresso a un file binario o a una libreria. Si aspetta che l'origine è strutturato in modo che tutti i file di origine richiesti possano essere automaticamente sono state rilevate. Ciò significa che l'origine generata deve essere inserita nell'origine o fornita tramite una direttiva di inclusione nell'origine:

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

La community di Rust si basa su build.rs script e sulle ipotesi dell'ambiente di costruzione Cargo, per evitare questa differenza. Durante la creazione, il comando cargo imposta una variabile di ambiente OUT_DIR. in cui è previsto che build.rs script inseriscano il codice sorgente generato. Utilizza la seguente comando per includere il codice sorgente:

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

Questo presenta una sfida per Chooseg, poiché gli output per ogni modulo vengono inseriti la propria directory out/1. Non esiste un solo OUT_DIR in cui delle dipendenze restituiscono l'origine generata.

Per il codice della piattaforma, AOSP preferisce pacchettizzare l'origine generata in una cassa in grado di per diversi motivi:

  • Impedisci la collisione dei nomi dei file di origine generati.
  • Riduci il codice boilerplate. fare il check-in in tutto l'albero che richiede manutenzione. Qualsiasi boilerplate necessaria per effettuare la compilazione dell'origine generata in una cassa può essere sottoposta a manutenzione.
  • Evita interazioni implicite2 tra il codice generato e la cassa circostante.
  • Riduci la pressione sulla memoria e sul disco collegando dinamicamente le origini generate di uso comune.

Di conseguenza, tutti i tipi di moduli di generazione di origine Rust di Android producono codice che possono essere compilati e utilizzati come una cassa. Presto supporta ancora casse di terze parti senza modifiche se tutte le dipendenze dell'origine generate per un modulo vengono copiate in un simile a Cargo. In questi casi, Quickg imposta la variabile di ambiente OUT_DIR a quella directory durante la compilazione del modulo, in modo che sia possibile trovare l'origine generata. Tuttavia, per i motivi già descritti, conviene utilizzare solo questo meccanismo nel codice della piattaforma quando è assolutamente necessario.


  1. Questo non presenta alcun problema per C/C++ e linguaggi simili, poiché dell'origine generata viene fornito direttamente al compilatore.

  2. Poiché include! funziona tramite inclusione testuale, potrebbe fare riferimento ai valori di che lo contiene, modificare lo spazio dei nomi o utilizzare costrutti come #![foo]. Queste interazioni implicite possono essere difficili da gestire. Preferisco sempre quando è veramente richiesta l'interazione con il resto della cassa.