Le système de compilation est compatible avec la génération de liaisons bindgen via le type de module rust_bindgen. Bindgen fournit des liaisons FFI Rust aux bibliothèques C (avec une prise en charge C++ limitée, qui nécessite la définition de la propriété cppstd).
Utilisation de base de rust_bindgen
Voici un exemple de définition d'un module qui utilise bindgen et de son utilisation en tant que crate. Si vous devez utiliser des liaisons bindgen via
une macro include!(), par exemple pour du code externe, consultez la
page Générateurs de sources.
Exemple de bibliothèque C à appeler depuis Rust
Voici un exemple de bibliothèque C qui définit une structure et une fonction à utiliser dans Rust.
external/rust/libbuzz/libbuzz.h
typedef struct foo {
int x;
} foo;
void fizz(int i, foo* cs);
external/rust/libbuzz/libbuzz.c
#include <stdio.h>
#include "libbuzz.h"
void fizz(int i, foo* my_foo){
printf("hello from c! i = %i, my_foo->x = %i\n", i, my_foo->x);
}
Définir un module rust_bindgen
Définissez un en-tête de wrapper, external/rust/libbuzz/libbuzz_wrapper.h, qui inclut tous les en-têtes pertinents :
// Include headers that are required for generating bindings in a wrapper header.
#include "libbuzz.h"
Définissez le fichier Android.bp comme external/rust/libbuzz/Android.bp :
cc_library {
name: "libbuzz",
srcs: ["libbuzz.c"],
}
rust_bindgen {
name: "libbuzz_bindgen",
// Crate name that's used to generate the rust_library variants.
crate_name: "buzz_bindgen",
// Path to the wrapper source file.
wrapper_src: "libbuzz_wrapper.h",
// 'source_stem' controls the output filename.
// This is the filename that's used in an include! macro.
//
// In this case, we just use "bindings", which produces
// "bindings.rs".
source_stem: "bindings",
// Bindgen-specific flags and options to customize the bindings.
// See the bindgen manual for more information.
bindgen_flags: ["--verbose"],
// Clang flags to be used when generating the bindings.
cflags: ["-DSOME_FLAG"],
// Shared, static, and header libraries which export the necessary
// include directories must be specified.
//
// These libraries will also be included in the crate if static,
// or propagated to dependents if shared.
// static_libs: ["libbuzz"]
// header_libs: ["libbuzz"]
shared_libs: ["libbuzz"],
}
Pour en savoir plus sur l'utilisation des indicateurs bindgen, consultez la section du manuel bindgen sur la personnalisation des liaisons générées.
Si vous avez utilisé cette section pour définir un module rust_bindgen comme condition préalable à
l'utilisation de la macro include!(), revenez à la section Conditions préalables
de la page Générateurs de sources. Sinon, passez aux sections suivantes.
Utiliser des liaisons en tant que crate
Créez external/rust/hello_bindgen/Android.bp avec le contenu suivant :
rust_binary {
name: "hello_bindgen",
srcs: ["main.rs"],
// Add the rust_bindgen module as if it were a rust_library dependency.
rustlibs: ["libbuzz_bindgen"],
}
Créez external/rust/hello_bindgen/src/main.rs avec le contenu suivant :
//! Example crate for testing bindgen bindings
fn main() {
let mut x = buzz_bindgen::foo { x: 2 };
unsafe { buzz_bindgen::fizz(1, &mut x as *mut buzz_bindgen::foo) }
}
Enfin, appelez m hello_bindgen pour compiler le binaire.
Tester les liaisons Bindgen
Les liaisons Bindgen contiennent généralement un certain nombre de tests de mise en page générés pour éviter les incompatibilités de mise en page de la mémoire. AOSP vous recommande de définir un module de test pour ces tests et de les exécuter dans le cadre de la suite de tests normale de votre projet.
Un binaire de test peut être facilement produit en définissant un module rust_test dans external/rust/hello_bindgen/Android.bp :
rust_test {
name: "bindings_test",
srcs: [
":libbuzz_bindgen",
],
crate_name: "buzz_bindings_test",
test_suites: ["general-tests"],
auto_gen_config: true,
// Be sure to disable lints as the generated source
// is not guaranteed to be lint-free.
clippy_lints: "none",
lints: "none",
}
Visibilité et liaison
Les liaisons générées sont généralement très petites, car elles se composent de définitions de types, de signatures de fonctions et de constantes associées. Par conséquent, il est généralement inutile de lier ces bibliothèques de manière dynamique. Nous avons désactivé la liaison dynamique pour ces modules afin que leur utilisation via rustlibs sélectionne automatiquement une variante statique.
Par défaut, les modules rust_bindgen ont une propriété visibility de
[":__subpackages__"], qui n'autorise que les modules du même fichier Android.bp
ou ceux situés en dessous dans la hiérarchie des répertoires à le voir. Cela sert deux objectifs :
- Cela décourage l'utilisation de liaisons C brutes ailleurs dans l'arborescence.
- Cela évite les problèmes de liaison en losange avec un mélange de liaisons statiques et dynamiques.
En règle générale, vous devez fournir une bibliothèque de wrapper sécurisée autour du module généré que vous avez ajouté dans la même arborescence de répertoires que les liaisons destinées à être utilisées par d'autres développeurs. Si cela ne fonctionne pas pour votre cas d'utilisation, vous pouvez ajouter des packages supplémentaires à la visibilité. Lorsque vous ajoutez des champs de visibilité supplémentaires, veillez à ne pas ajouter deux champs qui pourraient être liés au même processus à l'avenir, car cela pourrait entraîner un échec de la liaison.
Propriétés rust_bindgen notables
Les propriétés définies ci-dessous s'ajoutent aux propriétés communes importantes
qui s'appliquent à tous les modules. Elles sont particulièrement importantes pour les modules Rust bindgen ou présentent un comportement unique spécifique au type de module rust_bindgen.
stem, name, crate_name
rust_bindgen produit des variantes de bibliothèque. Elles partagent donc les mêmes exigences avec
les modules rust_library pour les propriétés stem, name et crate_name. Pour référence, consultez
Propriétés notables de la bibliothèque Rust.
wrapper_src
Il s'agit du chemin d'accès relatif à un fichier d'en-tête de wrapper qui inclut les en-têtes requis pour ces liaisons. L'extension de fichier détermine comment interpréter l'en-tête et quel indicateur -std utiliser par défaut. Il s'agit d'un en-tête C sauf si l'extension est .hh ou .hpp. Si votre en-tête C++ doit avoir une autre extension, définissez la propriété cpp_std pour remplacer le comportement par défaut qui suppose que le fichier est un fichier C.
source_stem
Il s'agit du nom de fichier du fichier source généré. Ce champ doit être défini, même si vous utilisez les liaisons en tant que crate, car la propriété stem ne contrôle que le nom de fichier de sortie pour les variantes de bibliothèque générées.
Si un module dépend de plusieurs générateurs de sources (tels que bindgen et protobuf) en tant que source plutôt qu'en tant que crates via rustlibs, vous devez vous assurer que tous les générateurs de sources qui sont des dépendances de ce module ont des valeurs source_stem uniques. Les modules dépendants copient les sources de toutes les dépendances SourceProvider définies dans srcs dans un répertoire OUT_DIR commun. Par conséquent, les conflits dans source_stem entraîneraient l'écrasement des fichiers sources générés dans le répertoire OUT_DIR.
c_std
Il s'agit d'une chaîne représentant la version standard C à utiliser. Les valeurs valides sont listées ci-dessous :
- Une version spécifique, telle que
"gnu11". "experimental", qui est une valeur définie par le système de compilation dansbuild/soong/cc/config/global.go, peut utiliser des versions préliminaires telles que C++1z lorsqu'elles sont disponibles.- Non défini ou
"", ce qui indique que la valeur par défaut du système de compilation doit être utilisée.
Si cette option est définie, l'extension de fichier est ignorée et l'en-tête est supposé être un en-tête C. Cette option ne peut pas être définie en même temps que cpp_std.
cpp_std
cpp_std est une chaîne représentant la version standard C à utiliser. Valeurs valides :
- Une version spécifique, telle que
"gnu++11" "experimental", qui est une valeur définie par le système de compilation dansbuild/soong/cc/config/global.go, peut utiliser des versions préliminaires telles que C++1z lorsqu'elles sont disponibles.- Non défini ou
"", ce qui indique que la valeur par défaut du système de compilation doit être utilisée.
Si cette option est définie, l'extension de fichier est ignorée et l'en-tête est supposé être un en-tête C++. Cette option ne peut pas être définie en même temps que c_std.
cflags
cflags fournit une liste de chaînes d'indicateurs Clang requis pour interpréter correctement les en-têtes.
custom_bindgen
Pour les cas d'utilisation avancés, bindgen peut être utilisé comme bibliothèque, fournissant une API qui peut être manipulée dans le cadre d'un binaire Rust personnalisé. Le champ custom_bindgen
prend le nom
de module d'un module rust_binary_host, qui utilise l'API bindgen au lieu
du binaire bindgen normal.
Ce binaire personnalisé doit s'attendre à des arguments semblables à bindgen, tels que
$ my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]
La plupart de ces éléments sont gérés par la bibliothèque bindgen elle-même. Pour voir un exemple de cette
utilisation, consultez external/rust/crates/libsqlite3-sys/android/build.rs.
De plus, l'ensemble complet des propriétés de la bibliothèque est disponible pour contrôler la compilation de la bibliothèque, bien qu'il soit rarement nécessaire de les définir ou de les modifier.
handle_static_inline et static_inline_library
Ces deux propriétés sont destinées à être utilisées ensemble et permettent de produire des wrappers pour les fonctions statiques intégrées qui peuvent être incluses dans les liaisons bindgen exportées.
Pour les utiliser, définissez handle_static_inline: true et static_inline_library sur un cc_library_static correspondant qui définit le module rust_bindgen comme entrée source.
Exemple d'utilisation :
rust_bindgen {
name: "libbindgen",
wrapper_src: "src/any.h",
crate_name: "bindgen",
stem: "libbindgen",
source_stem: "bindings",
// Produce bindings for static inline fucntions
handle_static_inline: true,
static_inline_library: "libbindgen_staticfns"
}
cc_library_static {
name: "libbindgen_staticfns",
// This is the rust_bindgen module defined above
srcs: [":libbindgen"],
// The include path to the header file in the generated c file is
// relative to build top.
include_dirs: ["."],
}