Il sistema di compilazione supporta la generazione di collegamenti bindgen tramite il tipo di modulo rust_bindgen . Bindgen fornisce collegamenti FFI Rust alle librerie C (con un supporto C++ limitato, che richiede l'impostazione della proprietà cppstd ).

Utilizzo di base di ruggine_bindgen

Quello che segue è un esempio di come definire un modulo che utilizza bindgen e come utilizzare quel modulo come un crate. Se è necessario utilizzare i collegamenti bindgen tramite una macro include!() , ad esempio per il codice esterno, consultare la pagina Generatori di sorgenti .

Esempio di libreria C da chiamare da Rust

Segue un esempio di libreria C che definisce una struttura 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);
}

Definire un modulo ruggine_bindgen

Definisci un'intestazione wrapper, external/rust/libbuzz/libbuzz_wrapper.h , che include tutte le intestazioni rilevanti:

// Include headers that are required for generating bindings in a wrapper header.
#include "libbuzz.h"

Definisci il file Android.bp 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 ulteriori informazioni sull'utilizzo dei flag bindgen, consultare la sezione del manuale bindgen sulla personalizzazione delle associazioni generate .

Se hai utilizzato questa sezione per definire un modulo rust_bindgen come prerequisito per utilizzare la include!() , torna a Prerequisiti nella pagina Generatori di sorgenti. In caso contrario, procedere con le sezioni successive.

Usa gli attacchi come una cassa

Crea external/rust/hello_bindgen/Android.bp con il seguente contenuto:

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 il seguente contenuto:

//! 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) }
}

Infine, chiama m hello_bindgen per creare il file binario.

Prova gli attacchi Bindgen

I collegamenti Bindgen in genere contengono una serie di test di layout generati per prevenire mancate corrispondenze nel layout della memoria. AOSP consiglia di definire un modulo di test per questi test e di eseguirli come parte della normale suite di test del progetto.

Un binario di prova per questi può essere facilmente prodotto 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

I collegamenti generati sono in genere molto piccoli, poiché sono costituiti da definizioni di tipo, firme di funzione e costanti correlate. Di conseguenza, è generalmente uno spreco collegare queste librerie in modo dinamico. Abbiamo disabilitato il collegamento dinamico per questi moduli in modo che il loro utilizzo tramite rustlibs selezionerà automaticamente una variante statica.

Per impostazione predefinita, i moduli rust_bindgen hanno una proprietà visibility di [":__subpackages__"] , che consentirà solo ai moduli nello stesso file Android.bp o quelli sotto di esso nella gerarchia di directory di vederlo. Questo ha due scopi:

  • Scoraggia l'uso di attacchi C grezzi altrove nell'albero.
  • Evita problemi di collegamento del diamante con un mix di collegamento statico e dinamico.

Di solito, dovresti fornire una libreria wrapper sicura attorno al modulo generato che hai aggiunto nello stesso albero di directory dei collegamenti destinati all'utilizzo da parte di altri sviluppatori. Se questo non funziona per il tuo caso d'uso, puoi aggiungere pacchetti aggiuntivi a visibilità . Quando aggiungi ulteriori ambiti di visibilità, fai attenzione a non aggiungere due ambiti che potrebbero essere collegati allo stesso processo in futuro, poiché il collegamento potrebbe non riuscire.

Notevoli proprietà di ruggine_bindgen

Le proprietà definite di seguito sono in aggiunta alle proprietà comuni importanti che si applicano a tutti i moduli. Questi sono particolarmente importanti per i moduli Rust bindgen o mostrano un comportamento unico specifico per il tipo di modulo rust_bindgen .

radice, nome, nome_cassa

rust_bindgen produce varianti di libreria, quindi condividono gli stessi requisiti con i moduli rust_library per le proprietà stem , name e crate_name . Vedi Proprietà notevoli della libreria Rust come riferimento.

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 si tratti di 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 sovrascrivere il comportamento predefinito che presuppone che il file sia un file C.

radice_origine

Questo è il nome del file sorgente generato . Questo campo deve essere definito, anche se stai utilizzando i collegamenti come una cassa, poiché la proprietà stem controlla solo il nome del file di output per le varianti della libreria generate. Se un modulo dipende da più generatori di sorgenti (come bindgen e protobuf ) come sorgente piuttosto che come crate tramite rustlibs , è necessario assicurarsi che tutti i generatori di sorgenti che sono dipendenze di quel modulo abbiano valori source_stem univoci. I moduli dipendenti copiano i sorgenti 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 sorgente generati nella directory OUT_DIR .

c_std

Questa è una stringa che rappresenta quale versione dello standard C utilizzare. I valori validi sono elencati di seguito:

  • Una versione specifica, come "gnu11" .
  • "experimental" , che è un valore definito dal sistema di compilazione in build/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 è impostato, l'estensione del file viene ignorata e si presuppone che l'intestazione sia un'intestazione C. Questo non può essere impostato contemporaneamente a cpp_std .

cpp_std

cpp_std è una stringa che rappresenta quale versione standard C utilizzare. Valori validi:

  • Una versione specifica, come "gnu++11"
  • "experimental" , che è un valore definito dal sistema di compilazione in build/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 è impostato, l'estensione del file viene ignorata e si presuppone che l'intestazione sia un'intestazione C++. Questo non può essere impostato contemporaneamente a c_std .

cflag

cflags fornisce un elenco di stringhe di flag Clang necessari per interpretare correttamente le intestazioni.

custom_bindgen

Per casi d'uso avanzati, bindgen può essere utilizzato come libreria, fornendo un'API che può essere manipolata come parte di un binario Rust personalizzato. Il campo custom_bindgen prende il nome del modulo di un modulo rust_binary_host , che utilizza l'API bindgen invece del normale binario bindgen .

Questo 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 questo è gestita dalla stessa libreria bindgen . Per vedere un esempio di questo utilizzo, visitare external/rust/crates/libsqlite3-sys/android/build.rs .

Inoltre, è disponibile l'insieme completo delle proprietà della libreria per controllare la compilazione della libreria, sebbene raramente sia necessario definirle o modificarle.