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.
Crates à partir 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
.) Le meilleur modèle d'utilisation pour le code de plate-forme consiste à utiliser la source générée comme crate. 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 toujours utiliser le code source généré via la macro include!()
, par exemple lorsque vous utilisez un module genrule
pour générer du code source de 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.
Procédure d'inclusion de 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 la source générée
Contrairement aux compilateurs C/C++, rustc
n'accepte qu'un seul fichier source représentant un point d'entrée vers 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 placée dans l'arborescence source ou fournie via une directive d'inclusion 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'existe pas un seul OUT_DIR
où les dépendances génèrent leur source.
Pour le code de la plate-forme, AOSP préfère empaqueter la source générée dans un crate pouvant être importé, pour plusieurs raisons:
- Éviter les conflits de noms de fichiers sources générés.
- Réduire le code récurrent enregistré dans l'arborescence qui nécessite une maintenance. Tout code standard requis pour que la source générée soit compilée dans un crate peut être géré 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
sur 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 plate-forme que lorsque cela 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. Privilégiez toujours les macros lorsque l'interaction avec le reste de la crate est vraiment nécessaire. ↩