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 forniscono funzionalità di sistema di compilazione simili. I tre casi d'uso di generazione di codice supportati dal sistema di compilazione sono la generazione di binding C utilizzando bindgen, interfacce AIDL e interfacce protobuf.
Casse dall'origine generata
Ogni modulo Rust che genera codice sorgente può essere utilizzato come crate, esattamente come se fosse 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 tramite la macro include!()
. Tieni presente che questa procedura è simile per tutti i generatori di codice.
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 Definire un modulo Rust bindgen,
crea libbuzz_bindgen
e poi torna qui.
Tieni presente che le parti del file di compilazione sono applicabili a tutti i generatori di origine.
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é le casse per il codice sorgente generato
A differenza dei compilatori C/C++, rustc
accetta un solo file di origine
che rappresentano un punto di ingresso di un file binario o di una libreria. Si presume che l'albero di origine sia strutturato in modo che tutti i file di origine richiesti possano essere rilevati automaticamente. Ciò significa che il codice sorgente generato deve essere inserito nell'albero di origine o fornito tramite una direttiva include nel codice sorgente:
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 compilazione, il comando cargo
imposta una variabile di ambiente OUT_DIR
in cui gli script build.rs
dovrebbero inserire il codice sorgente generato. Utilizza la
seguente comando per includere il codice sorgente:
include!(concat!(env!("OUT_DIR"), "/hello.rs"));
Questo rappresenta una sfida per Soong, in quanto gli output di ciascun modulo vengono posizionati nella rispettiva directory out/
1. Non esiste un solo OUT_DIR
in cui
delle dipendenze restituiscono l'origine generata.
Per il codice della piattaforma, AOSP preferisce impacchettare il codice sorgente generato in un crate che può essere importato, per diversi motivi:
- Evitare collisioni tra i nomi dei file di origine generati.
- Riduci il codice boilerplate checked-in nell'intera struttura ad albero che richiede manutenzione. Qualsiasi boilerplate necessario per compilare il codice sorgente generato in un crate può essere gestito centralmente.
- Evita interazioni implicite2 tra il codice generato e la cassa circostante.
- Riduci la pressione su memoria e disco collegando in modo dinamico le origini generate di uso comune.
Di conseguenza, tutti i tipi di moduli di generazione di codice sorgente Rust di Android producono codice che può essere compilato e utilizzato come crate.
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.
-
Questo non presenta alcun problema per C/C++ e linguaggi simili, poiché dell'origine generata viene fornito direttamente al compilatore.↩
-
Poiché
include!
funziona tramite inclusione di testo, potrebbe fare riferimento ai valori dello spazio dei nomi che lo racchiude, modificarlo o utilizzare costrutti come#![foo]
. Queste interazioni implicite possono essere difficili da gestire. Prediligi sempre le macro quando l'interazione con il resto della cassetta è davvero necessaria. ↩