Il sistema di compilazione supporta la generazione di associazioni bindgen tramite il tipo di modulo rust_bindgen. Bindgen fornisce associazioni FFI Rust alle librerie C (con un supporto C++ limitato, che richiede l'impostazione della proprietà cppstd).
Utilizzo di base di rust_bindgen
Di seguito è riportato un esempio di come definire un modulo che utilizza bindgen e di come utilizzare questo modulo come crate. Se devi utilizzare le associazioni bindgen tramite
una macro include!(), ad esempio per il codice esterno, consulta Generatori di codice sorgente.
Esempio di libreria C da chiamare da Rust
Di seguito è riportato un esempio di libreria C che definisce una struct e una funzione da utilizzare in 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);
}
Definisci un modulo rust_bindgen
Definisci un'intestazione wrapper, external/rust/libbuzz/libbuzz_wrapper.h, che includa tutte le intestazioni pertinenti:
// Include headers that are required for generating bindings in a wrapper header.
#include "libbuzz.h"
Definisci il Android.bp file come 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"],
}
Per scoprire di più sull'utilizzo dei flag bindgen, consulta la sezione del manuale di bindgen su Personalizzare le associazioni generate.
Se hai utilizzato questa sezione per definire un modulo rust_bindgen come prerequisito per
l'utilizzo della macro include!() torna a Prerequisito
nella pagina Generatori di codice sorgente. In caso contrario, procedi con le sezioni successive.
Utilizza le associazioni come crate
Crea external/rust/hello_bindgen/Android.bp con i seguenti contenuti:
rust_binary {
name: "hello_bindgen",
srcs: ["main.rs"],
// Add the rust_bindgen module as if it were a rust_library dependency.
rustlibs: ["libbuzz_bindgen"],
}
Crea external/rust/hello_bindgen/src/main.rs con i seguenti contenuti:
//! 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) }
}
Quindi, chiama m hello_bindgen per creare il file binario.
Testa le associazioni bindgen
Le associazioni bindgen in genere contengono una serie di test di layout generati per evitare mancate corrispondenze del layout di memoria. AOSP consiglia di definire un modulo di test per questi test e di eseguirli come parte della suite di test normale del progetto.
Puoi produrre un file binario di test per questi definendo un modulo rust_test in 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à e collegamento
Le associazioni generate sono in genere di piccole dimensioni, in quanto sono costituite da definizioni di tipo, firme di funzioni e costanti correlate. Di conseguenza, è uno spreco collegare dinamicamente queste librerie. Abbiamo disattivato il collegamento dinamico per questi moduli in modo che l'utilizzo con rustlibs selezioni automaticamente una variante statica.
Per impostazione predefinita, i moduli rust_bindgen hanno una proprietà visibility di
[":__subpackages__"], che consente ai moduli nello stesso file Android.bp
o a quelli sottostanti nella gerarchia delle directory di visualizzarlo. Questo ha due scopi:
- Scoraggia l'utilizzo di associazioni C non elaborate altrove nell'albero.
- Evita problemi di collegamento a diamante con una combinazione di collegamento statico e dinamico.
Devi fornire una libreria wrapper sicura intorno al modulo generato che hai aggiunto nella stessa struttura di directory delle associazioni, che è destinata all'utilizzo da parte di altri sviluppatori. Se questa soluzione non funziona per il tuo caso d'uso, puoi aggiungere
altri pacchetti a visibility.
Quando aggiungi altri ambiti di visibilità, non aggiungere due ambiti che potrebbero essere collegati allo stesso processo in futuro, perché il collegamento potrebbe non riuscire.
Proprietà rust_bindgen importanti
Le proprietà definite in questa sezione si aggiungono alle
proprietà comuni importanti che si applicano a tutti i moduli. Queste sono importanti per i moduli bindgen Rust o presentano un comportamento univoco specifico per il tipo di modulo rust_bindgen.
stem, name, crate_name
rust_bindgen produce varianti di libreria, quindi condividono gli stessi requisiti
con i moduli rust_library per le proprietà stem, name, e crate_name. Per riferimento, consulta Proprietà importanti della libreria Rust.
wrapper_src
Questo è il percorso relativo a un file di intestazione wrapper che include le intestazioni richieste per queste associazioni. L'estensione del file determina come interpretare l'intestazione e quale flag -std utilizzare per impostazione predefinita. Si presuppone che sia un'intestazione C, a meno che l'estensione non sia .hh o .hpp. Se l'intestazione C++ deve avere un'altra estensione, imposta la proprietà cpp_std per sostituire il comportamento predefinito che presuppone che il file sia un file C.
source_stem
Questo è il nome file del file di codice sorgente generato. Questo campo deve essere definito, anche se utilizzi le associazioni come crate, poiché la proprietà stem controlla solo il nome file di output per le varianti di libreria generate.
Se un modulo dipende da più generatori di codice sorgente (ad esempio bindgen e protobuf) come codice sorgente anziché come crate tramite rustlibs, assicurati che tutti i generatori di codice sorgente che sono dipendenze di quel modulo abbiano valori source_stem univoci. I moduli dipendenti copiano le origini da tutte le dipendenze SourceProvider definite in srcs in una directory OUT_DIR comune, quindi le collisioni in source_stem comporterebbero la sovrascrittura dei file di codice sorgente generati nella directory OUT_DIR.
c_std
Questa è una stringa che rappresenta la versione dello standard C da utilizzare. I valori validi sono elencati qui:
- Una versione specifica, ad esempio
gnu11 experimental, che è un valore definito dal sistema di compilazione inbuild/soong/cc/config/global.go, può utilizzare versioni bozza come C++1z quando sono disponibili- Non impostato o
"", che indica che deve essere utilizzata l'impostazione predefinita del sistema di compilazione
Se questa opzione è impostata, l'estensione del file viene ignorata e si presuppone che l'intestazione sia un'intestazione C. Non può essere impostato contemporaneamente a cpp_std.
cpp_std
cpp_std è una stringa che rappresenta la versione dello standard C da utilizzare. I valori validi sono elencati qui:
- Una versione specifica, ad esempio
gnu++11 experimental, che è un valore definito dal sistema di compilazione inbuild/soong/cc/config/global.go, può utilizzare versioni bozza come C++1z quando sono disponibili- Non impostato o
"", che indica che deve essere utilizzata l'impostazione predefinita del sistema di compilazione
Se questa opzione è impostata, l'estensione del file viene ignorata e si presuppone che l'intestazione sia un'intestazione C++. Non può essere impostato contemporaneamente a c_std.
cflags
cflags fornisce un elenco di stringhe di flag Clang necessari per interpretare correttamente le intestazioni.
custom_bindgen
Per i casi d'uso avanzati, bindgen può essere utilizzato come libreria, fornendo un'API che può essere manipolata come parte di un file binario Rust personalizzato. Il campo custom_bindgen
accetta il nome
del modulo di un modulo rust_binary_host, che utilizza l'API bindgen anziché il file binario bindgen normale.
Questo file binario personalizzato deve prevedere argomenti in modo simile a bindgen, ad esempio
$ my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]
La maggior parte di questa operazione viene gestita dalla libreria bindgen stessa. Per un esempio di
questo utilizzo, visita external/rust/crates/libsqlite3-sys/android/build.rs.
Inoltre, è disponibile l'insieme completo di proprietà della libreria per controllare la compilazione della libreria, anche se raramente è necessario definirle o modificarle.
handle_static_inline e static_inline_library
Queste due proprietà sono pensate per essere utilizzate insieme e consentono la produzione di wrapper per le funzioni statiche inline che possono essere incluse nelle associazioni bindgen esportate.
Per utilizzarli, imposta handle_static_inline: true e static_inline_library su un cc_library_static corrispondente che definisce il modulo rust_bindgen come input di origine.
Esempio di utilizzo:
rust_bindgen {
name: "libbindgen",
wrapper_src: "src/any.h",
crate_name: "bindgen",
stem: "libbindgen",
source_stem: "bindings",
// Produce bindings for static inline functions
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: ["."],
}