Cette page offre une vue d'ensemble de la prise en charge de la source générée et de son utilisation dans le système de compilation.
Tous les générateurs de sources fournissent des fonctionnalités de système de compilation similaires. Les trois cas d'utilisation de la génération de sources compatibles avec le système de compilation consistent à générer des liaisons C à l'aide de bindgen, d'interfaces AIDL et d'interfaces protobuf.
Caisses issues de la source générée
Chaque module Rust qui génère du code source peut être utilisé comme crate, exactement comme s'il était défini comme un rust_library
. (Cela signifie qu'il peut être défini comme une dépendance dans les propriétés rustlibs
, rlibs
et dylibs
.) Utilisation optimale
le schéma du code de la plate-forme consiste à utiliser la source générée en tant que caisse. Bien que la macro include!
soit compatible avec le code source généré, son objectif principal est de prendre en charge le code tiers qui se trouve dans external/
.
Dans certains cas, le code de la plate-forme peut tout de même utiliser la source générée via la classe
include!()
, comme lorsque vous utilisez un module genrule
pour générer la source
d'une manière unique.
Utiliser include!() pour inclure la source générée
L'utilisation de la source générée en tant que crate est abordée dans les exemples de chaque page de module spécifique. Cette section explique comment référencer la source générée via la macro include!()
. Notez que ce processus est semblable pour tous les générateurs de sources.
Prérequis
Cet exemple suppose que vous avez défini un module rust_bindgen
(libbuzz_bindgen
) et que vous pouvez passer aux étapes d'inclusion de la source générée pour utiliser la macro include!()
. Si ce n'est pas le cas, consultez Définir un module rust bindgen, créez libbuzz_bindgen
, puis revenez ici.
Notez que les parties correspondant au fichier de compilation s'appliquent à tous les générateurs de sources.
Étapes pour inclure la source générée
Créez external/rust/hello_bindgen/Android.bp
avec le contenu suivant :
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",
],
}
Créez external/rust/hello_bindgen/src/bindings.rs
avec le contenu suivant :
#![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"));
Créez external/rust/hello_bindgen/src/lib.rs
avec le contenu suivant:
mod bindings;
fn main() {
let mut x = bindings::foo { x: 2 };
unsafe { bindings::fizz(1, &mut x as *mut bindings::foo) }
}
Pourquoi utiliser des crates pour les sources générées ?
Contrairement aux compilateurs C/C++, rustc
n'accepte qu'un seul fichier source
représentant un point d’entrée
dans un binaire ou une bibliothèque. Il s'attend à ce que l'arborescence source soit structurée de manière à ce que tous les fichiers sources requis puissent être découverts automatiquement. Cela signifie que la source générée doit être soit placée dans la source,
ou fournies par le biais d'une directive "include" dans la source:
include!("/path/to/hello.rs");
La communauté Rust dépend des scripts build.rs
et des hypothèses concernant l'environnement de compilation Cargo pour gérer cette différence.
Lors de la compilation, la commande cargo
définit une variable d'environnement OUT_DIR
dans laquelle les scripts build.rs
doivent placer le code source généré. Utilisez la commande suivante pour inclure le code source :
include!(concat!(env!("OUT_DIR"), "/hello.rs"));
Cela pose un problème pour Soong, car les sorties de chaque module sont placées dans leur propre répertoire out/
1. Il n'y a pas de OUT_DIR
où
les dépendances génèrent
leur source générée.
Pour le code de plate-forme, AOSP préfère empaqueter la source générée dans une caisse pour plusieurs raisons:
- Empêchez les conflits entre les noms des fichiers sources générés.
- Réduire le code récurrent enregistré dans l'arborescence qui nécessite une maintenance. Tout code récurrent nécessaire pour compiler la source générée dans une caisse peut être maintenue de manière centralisée.
- Évitez les interactions implicites2 entre le code généré et le crate environnant.
- Réduisez la pression sur la mémoire et le disque en associant de manière dynamique les sources générées couramment utilisées.
Par conséquent, tous les types de modules de génération de code source Rust d'Android produisent du code pouvant être compilé et utilisé en tant que crate.
Soong est toujours compatible avec les crates tierces sans modification si toutes les dépendances sources générées pour un module sont copiées dans un seul répertoire par module, comme Cargo. Dans ce cas, Soong définit la variable d'environnement OUT_DIR
dans ce répertoire lors de la compilation du module, afin que la source générée puisse être trouvée.
Toutefois, pour les raisons déjà décrites, il est recommandé de n'utiliser
ce mécanisme dans le code de la plateforme
quand c'est absolument nécessaire.
-
Cela ne pose aucun problème pour C/C++ et les langages similaires, car le chemin d'accès à la source générée est fourni directement au compilateur. ↩
-
Étant donné que
include!
fonctionne par inclusion textuelle, il peut faire référence à des valeurs de l'espace de noms englobant, modifier l'espace de noms ou utiliser des constructions telles que#![foo]
. Ces interactions implicites peuvent être difficiles à gérer. Toujours privilégier lorsqu'une interaction avec le reste de la caisse est vraiment nécessaire.⧖