El sistema de compilación admite la generación de enlaces bindgen a través del tipo de módulo rust_bindgen . Bindgen proporciona enlaces Rust FFI a bibliotecas C (con cierta compatibilidad limitada con C++, lo que requiere configurar la propiedad cppstd ).

Uso básico de Rust_bindgen

Lo que sigue es un ejemplo de cómo definir un módulo que usa bindgen y cómo usar ese módulo como una caja. Si necesita utilizar enlaces bindgen a través de una macro include!() , como para código externo, consulte la página Generadores de código fuente .

Ejemplo de biblioteca C para llamar desde Rust

A continuación se muestra un ejemplo de biblioteca C que define una estructura y una función para usar en 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);
}

Definir un módulo Rust_bindgen

Defina un encabezado contenedor, external/rust/libbuzz/libbuzz_wrapper.h , que incluya todos los encabezados relevantes:

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

Defina el archivo Android.bp como 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"],
}

Para obtener más información sobre el uso de indicadores de bindgen, consulte la sección del manual de bindgen sobre Personalización de enlaces generados .

Si utilizó esta sección para definir un módulo rust_bindgen como requisito previo para usar la macro include!() , regrese a Requisito previo en la página Generadores de código fuente. Si no, continúe con las siguientes secciones.

Utilice fijaciones como caja

Cree external/rust/hello_bindgen/Android.bp con el siguiente contenido:

rust_binary {
   name: "hello_bindgen",
   srcs: ["main.rs"],

   // Add the rust_bindgen module as if it were a rust_library dependency.
   rustlibs: ["libbuzz_bindgen"],
}

Cree external/rust/hello_bindgen/src/main.rs con el siguiente contenido:

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

Finalmente, llame m hello_bindgen para compilar el binario.

Pruebe las fijaciones de Bindgen

Los enlaces de Bindgen normalmente contienen una serie de pruebas de diseño generadas para evitar discrepancias en el diseño de la memoria. AOSP recomienda tener un módulo de prueba definido para estas pruebas y que las pruebas se ejecuten como parte del conjunto de pruebas normal de su proyecto.

Se puede producir fácilmente un binario de prueba para estos definiendo un módulo rust_test en 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",
}

Visibilidad y vinculación

Los enlaces generados suelen ser muy pequeños, ya que constan de definiciones de tipos, firmas de funciones y constantes relacionadas. Como resultado, generalmente resulta un desperdicio vincular estas bibliotecas dinámicamente. Hemos deshabilitado el enlace dinámico para estos módulos para que al usarlos a través de rustlibs se seleccione automáticamente una variante estática.

De forma predeterminada, los módulos rust_bindgen tienen una propiedad visibility de [":__subpackages__"] , que solo permitirá que los módulos en el mismo archivo Android.bp o aquellos debajo de él en la jerarquía de directorios lo vean. Esto tiene dos propósitos:

  • Desalienta el uso de enlaces C sin procesar en otras partes del árbol.
  • Evita problemas de vinculación de diamantes con una combinación de vinculación estática y dinámica.

Por lo general, debe proporcionar una biblioteca contenedora segura alrededor del módulo generado que ha agregado en el mismo árbol de directorios que los enlaces destinados a que lo utilicen otros desarrolladores. Si esto no funciona para su caso de uso, puede agregar paquetes adicionales a la visibilidad . Al agregar ámbitos de visibilidad adicionales, tenga cuidado de no agregar dos ámbitos que puedan vincularse al mismo proceso en el futuro, ya que es posible que no se vinculen.

Propiedades notables de Rust_bindgen

Las propiedades definidas a continuación se suman a las propiedades comunes importantes que se aplican a todos los módulos. Estos son particularmente importantes para los módulos bindgen de Rust o exhiben un comportamiento único específico del tipo de módulo rust_bindgen .

tallo, nombre, nombre_caja

rust_bindgen produce variantes de biblioteca, por lo que comparten los mismos requisitos con los módulos rust_library para las propiedades stem , name y crate_name . Consulte Propiedades notables de la biblioteca Rust como referencia.

envoltura_src

Esta es la ruta relativa a un archivo de encabezado contenedor que incluye los encabezados necesarios para estos enlaces. La extensión del archivo determina cómo interpretar el encabezado y determina qué indicador -std usar de forma predeterminada. Se supone que es un encabezado C a menos que la extensión sea .hh o .hpp . Si su encabezado C++ debe tener alguna otra extensión, configure la propiedad cpp_std para anular el comportamiento predeterminado que supone que el archivo es un archivo C.

fuente_tallo

Este es el nombre del archivo fuente generado . Este campo debe definirse, incluso si está utilizando los enlaces como una caja, ya que la propiedad stem solo controla el nombre del archivo de salida para las variantes de biblioteca generadas. Si un módulo depende de múltiples generadores de fuente (como bindgen y protobuf ) como fuente en lugar de cajas a través de rustlibs , debe asegurarse de que todos los generadores de fuente que dependen de ese módulo tengan valores source_stem únicos. Los módulos dependientes copian fuentes de todas las dependencias SourceProvider que están definidas en srcs a un directorio OUT_DIR común, por lo que las colisiones en source_stem darían como resultado que los archivos fuente generados se sobrescriban en el directorio OUT_DIR .

c_std

Esta es una cadena que representa qué versión del estándar C usar. Los valores válidos se enumeran a continuación:

  • Una versión específica, como "gnu11" .
  • "experimental" , que es un valor definido por el sistema de compilación en build/soong/cc/config/global.go , puede usar versiones borrador como C++1z cuando estén disponibles.
  • Unset o "" , que indica que se debe utilizar el sistema de compilación predeterminado.

Si se establece esto, se ignora la extensión del archivo y se supone que el encabezado es un encabezado C. Esto no se puede configurar al mismo tiempo que cpp_std .

cpp_std

cpp_std es una cadena que representa qué versión estándar de C usar. Valores válidos:

  • Una versión específica, como "gnu++11"
  • "experimental" , que es un valor definido por el sistema de compilación en build/soong/cc/config/global.go , puede usar versiones borrador como C++1z cuando estén disponibles.
  • Unset o "" , que indica que se debe utilizar el sistema de compilación predeterminado.

Si se establece esto, se ignora la extensión del archivo y se supone que el encabezado es un encabezado C++. Esto no se puede configurar al mismo tiempo que c_std .

banderas

cflags proporciona una lista de cadenas de indicadores Clang necesarios para interpretar correctamente los encabezados.

enlace_personalizado

Para casos de uso avanzados, bindgen se puede utilizar como biblioteca, proporcionando una API que se puede manipular como parte de un binario Rust personalizado. El campo custom_bindgen toma el nombre del módulo de un módulo rust_binary_host , que utiliza la API de bindgen en lugar del binario bindgen normal.

Este binario personalizado debe contar con argumentos similares a bindgen , como por ejemplo

$ my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]

La mayor parte de esto lo maneja la propia biblioteca bindgen . Para ver un ejemplo de este uso, visite external/rust/crates/libsqlite3-sys/android/build.rs .

Además, el conjunto completo de propiedades de la biblioteca está disponible para controlar la compilación de la biblioteca, aunque rara vez es necesario definirlas o cambiarlas.