Il sistema di compilazione supporta la generazione di associazioni bindgen tramite rust_bindgen tipo di modulo. Bindgen fornisce associazioni Rust FFI alle librerie C (con alcune supporto limitato C++, 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 a usare quel modulo come cassa. Se devi utilizzare associazioni bindgen tramite una macro include!(), come il codice esterno, consulta Generatori di codice sorgente .

Libreria C di esempio da chiamare da Rust

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

Definire un modulo rust_bindgen

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

// 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 scoprire di più sull'utilizzo dei flag bindgen, consulta la sezione del manuale di bindgen su Personalizzazione delle 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 origine. In caso contrario, vai alle sezioni successive.

Utilizzare le associazioni come casse

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

Infine, chiama m hello_bindgen per compilare il file binario.

Testa le associazioni di Bindgen

Le associazioni Bindgen contengono in genere una serie di test di layout generati per evitare layout della memoria non corrispondenti. AOSP consiglia di definire un modulo di test per questi test e di eseguirli nell'ambito della normale suite di test del progetto.

È possibile produrre facilmente un file binario di test per questi moduli 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 molto piccole, in quanto costituite da definizioni di tipo, firme di funzioni e costanti correlate. Di conseguenza, in genere è un inutile spreco collegare queste librerie in modo dinamico. Il collegamento dinamico è stato disattivato per questi moduli in modo che il loro utilizzo tramite rustlibs selezioni automaticamente un una variante statica.

Per impostazione predefinita, rust_bindgen moduli hanno una proprietà visibility pari a [":__subpackages__"], che consentirà solo moduli nello stesso Android.bp o quelli sottostanti nella gerarchia di directory. Questo ha due scopi:

  • Scoraggia l'uso di associazioni C non elaborate altrove nell'albero.
  • Evita i problemi di collegamento a rombo con una combinazione di collegamenti statici e dinamici.

In genere, devi fornire una libreria wrapper sicura per il modulo generato che hai aggiunto nella stessa struttura di directory delle associazioni e che è destinata all'uso da parte di altri sviluppatori. Se non funziona per il tuo caso d'uso, puoi aggiungere pacchetti aggiuntivi alla visibility. Quando aggiungi ulteriori ambiti di visibilità, assicurati di non due ambiti che in futuro potrebbero essere collegati allo stesso processo, non riescono a collegarsi.

Proprietà rust_bindgen degne di nota

Le proprietà definite di seguito si aggiungono alle proprietà comuni importanti che si applicano a tutti i moduli. Questi sono particolarmente importanti per Rust moduli bindgen o presentare un comportamento univoco specifico del tipo di modulo rust_bindgen.

radice, nome, crate_name

rust_bindgen produce varianti di librerie, pertanto condividono gli stessi requisiti con i moduli rust_library per le proprietà stem, name e crate_name. Per riferimento, consulta Proprietà importanti delle librerie Rust.

wrapper_src

Si tratta del percorso relativo di un file di intestazione wrapper che include le intestazioni richieste per queste associazioni. L'estensione del file determina come interpretare l'intestazione e determina quale flag -std usare per impostazione predefinita. Si presume che sia una C intestazione a meno che l'estensione 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.

origine_origine

Si tratta del nome del file di origine generato. Questo campo deve anche se utilizzi le associazioni come cassa, dato che stem controlla solo il nome file di output per le varianti della libreria generate. Se un modulo dipende da più generatori di codice sorgente (ad esempio bindgen e protobuf) come sorgente anziché come casse tramite rustlibs, devi assicurarti che tutti i generatori di codice sorgente che sono dipendenze di quel modulo hanno valori source_stem univoci. Moduli dipendenti copia le origini da tutte le dipendenze SourceProvider definite in srcs a una directory OUT_DIR comune, quindi le collisioni in source_stem potrebbero comporta la sovrascrittura dei file di origine generati nella directory OUT_DIR.

c_std

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

  • Una versione specifica, ad esempio "gnu11".
  • "experimental", che è un valore definito dal sistema di compilazione build/soong/cc/config/global.go, può utilizzare versioni bozza come C++1z quando sono disponibili.
  • Non impostato o "", che indica che deve essere utilizzato il valore predefinito del sistema di build.

Se questo valore è impostato, l'estensione del file viene ignorata e si presume 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 standard di C da utilizzare. Valori validi:

  • Una versione specifica, ad esempio "gnu++11"
  • "experimental", che è un valore definito dal sistema di compilazione build/soong/cc/config/global.go, può utilizzare versioni bozza come C++1z quando sono disponibili.
  • Non impostato o "", che indica che deve essere utilizzato il valore predefinito del sistema di build.

Se questa opzione è impostata, l'estensione del file viene ignorata e si presume 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 il intestazioni.

associazione_personalizzata

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

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 queste operazioni viene gestita dalla libreria bindgen stessa. Per vedere un esempio visita external/rust/crates/libsqlite3-sys/android/build.rs.

Inoltre, è disponibile l'intero insieme 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à devono essere utilizzate insieme e consentono di produrre wrapper per funzioni inline statiche che possono essere incluse nelle associazioni di 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 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: ["."],
    }