Das Build-System unterstützt das Generieren von Bindunggen-Bindungen über die rust_bindgen Modultyp. Bindgen stellt Rust-FFI-Bindungen für C-Bibliotheken bereit (mit einigen eingeschränkte C++-Unterstützung, was die Festlegung des Attributs cppstd erfordert).

Grundlegende Verwendung von rust_bindgen

Im Folgenden finden Sie ein Beispiel für die Definition eines Moduls, das Bindgen verwendet. dieses Modul als Kiste nutzen. Wenn Sie bindengen-Bindungen über include!()-Makro, z. B. für externen Code, erhalten Sie in der Quellgeneratoren Seite.

Beispiel für eine C-Bibliothek, die von Rust aufgerufen werden kann

Es folgt eine Beispiel-C-Bibliothek, die eine Struktur und eine Funktion zur Verwendung in Rust definiert.

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

rust_bindgen-Modul definieren

Definiere einen Wrapper-Header, external/rust/libbuzz/libbuzz_wrapper.h, der alle relevanten Header enthält:

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

Definieren Sie die Datei Android.bp als 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"],
}

Weitere Informationen zur Verwendung von Bindgen-Flags finden Sie im Abschnitt Generierte Bindungen anpassen der Bindgen-Anleitung.

Wenn Sie diesen Abschnitt verwendet haben, um ein rust_bindgen-Modul als Voraussetzung für mithilfe des Makros include!(), kehren Sie zu Voraussetzungen zurück auf der Seite "Source Generators" (Quellengeneratoren). Falls nicht, fahren Sie mit den nächsten Abschnitten fort.

Bindungen als Crate verwenden

Erstellen Sie external/rust/hello_bindgen/Android.bp mit folgendem Inhalt:

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

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

Erstellen Sie external/rust/hello_bindgen/src/main.rs mit folgendem Inhalt:

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

Rufen Sie abschließend m hello_bindgen auf, um das Binärprogramm zu erstellen.

Bindgen-Bindungen testen

Bindgen-Bindungen enthalten in der Regel eine Reihe von generierten Layouttests, um Abweichungen beim Speicherlayout zu vermeiden. AOSP empfiehlt, für diese Tests ein Testmodul zu definieren und die Tests im Rahmen der normalen Testsuite Ihres Projekts auszuführen.

Ein Test-Binary für diese kann ganz einfach erstellt werden, indem Sie ein rust_test-Modul in external/rust/hello_bindgen/Android.bp definieren:

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",
}

Sichtbarkeit und Verknüpfung

Generierte Bindungen sind in der Regel sehr klein, da sie aus Typdefinitionen, Funktionssignaturen und zugehörigen Konstanten. Daher ist es in der Regel diese Bibliotheken dynamisch zu verknüpfen. Die dynamische Verknüpfung wurde deaktiviert für diese Module, sodass bei ihrer Verwendung über rustlibs automatisch ein statische Variante.

Standardmäßig haben rust_bindgen-Module das Attribut visibility von [":__subpackages__"], wodurch nur Module im selben Android.bp zulässig sind oder darunter in der Verzeichnishierarchie befinden, um sie anzuzeigen. Das hat zwei Vorteile:

  • Damit wird von der Verwendung von C-Roh-Bindungen an anderer Stelle im Baum abgeraten.
  • Mit einer Mischung aus statischer und dynamischer Verknüpfung werden Probleme mit dem Diamant-Verknüpfungsmuster vermieden.

Normalerweise sollten Sie eine sichere Wrapper-Bibliothek um das generierte Modul herum bereitstellen, das Sie im selben Verzeichnisbaum wie die Bindungen hinzugefügt haben und das für andere Entwickler gedacht ist. Wenn dies bei Ihrem Anwendungsfall nicht funktioniert, können Sie zusätzliche Pakete zu visibility. Achten Sie beim Hinzufügen zusätzlicher Sichtbarkeitsbereiche darauf, dass Sie nicht zwei Bereiche hinzufügen, die in Zukunft möglicherweise mit demselben Prozess verknüpft werden, da die Verknüpfung sonst fehlschlagen kann.

Wichtige Eigenschaften von rust_bindgen

Die unten definierten Eigenschaften ergänzen die wichtigen allgemeinen Eigenschaften. die für alle Module gelten. Sie sind für Rust entweder besonders wichtig, bindengen oder ein spezielles Verhalten zeigen, das für den Modultyp rust_bindgen spezifisch ist.

stem, name, crate_name

rust_bindgen erstellt Bibliotheksvarianten, die die gleichen Anforderungen wie Die rust_library-Module für die Attribute stem, name und crate_name Weitere Informationen finden Sie unter Wichtige Objekte der Rust-Bibliothek als Referenz.

Wrapper_src

Dies ist der relative Pfad zu einer Wrapper-Headerdatei, die die für diese Bindungen erforderlichen Header enthält. Die Dateiendung bestimmt, wie der Header interpretiert wird, und welches -std-Flag standardmäßig verwendet wird. Es wird davon ausgegangen, dass es sich um einen C-Header handelt, es sei denn, die Erweiterung ist .hh oder .hpp. Wenn Ihr C++-Header eine andere Erweiterung haben muss, legen Sie die Property cpp_std fest, um das Standardverhalten zu überschreiben, bei dem davon ausgegangen wird, dass es sich um eine C-Datei handelt.

source_stem

Dies ist der Dateiname für die generierte Quelldatei. Dieses Feld muss definiert werden, auch wenn Sie die Bindungen als Kiste verwenden, da die stem steuert nur den Ausgabedateinamen für die generierten Bibliotheksvarianten. Wenn ein Modul von mehreren Quellgeneratoren (z. B. bindgen und protobuf) als Quelle anstatt als Crates über rustlibs abhängt, müssen alle Quellgeneratoren, die zu den Abhängigkeiten dieses Moduls gehören, eindeutige source_stem-Werte haben. Abhängige Module kopiert Quellen aus allen SourceProvider Abhängigkeiten, die definiert sind in srcs mit einem gemeinsamen OUT_DIR-Verzeichnis, sodass Kollisionen in source_stem führt dazu, dass die generierten Quelldateien im Verzeichnis OUT_DIR überschrieben werden.

c_std

Dies ist ein String, der angibt, welche C-Standardversion verwendet werden soll. Gültige Werte sind unten aufgeführt:

  • Eine bestimmte Version, z. B. "gnu11".
  • "experimental" ist ein vom Build-System in build/soong/cc/config/global.go definierter Wert. Es können Entwurfsversionen wie C++1z verwendet werden, sofern verfügbar.
  • Nicht festgelegt oder "", was bedeutet, dass die Standardeinstellung des Build-Systems verwendet werden soll.

Ist dieser festgelegt, wird die Dateiendung ignoriert und es wird angenommen, dass der Header ein C-Header sein. Dies kann nicht gleichzeitig mit cpp_std festgelegt werden.

cpp_std

cpp_std ist ein String, der angibt, welche C-Standardversion verwendet werden soll. Gültige Werte:

  • Eine bestimmte Version, z. B. "gnu++11"
  • "experimental", ein Wert, der vom Build-System in build/soong/cc/config/global.go, darf verwendet werden Entwürfe wie C++1z sobald sie verfügbar sind.
  • Nicht festgelegt oder "", was bedeutet, dass der Standardwert des Build-Systems verwendet werden soll.

Wenn diese Option festgelegt ist, wird die Dateiendung ignoriert und davon ausgegangen, dass es sich um einen C++-Header handelt. Dieser Wert kann nicht gleichzeitig mit c_std festgelegt werden.

cflags

cflags enthält eine Stringliste mit Clang-Flags, die für die korrekte Interpretation der Header erforderlich sind.

custom_bindgen.

Für erweiterte Anwendungsfälle kann bindgen als Bibliothek verwendet werden und bietet eine API, die als Teil eines benutzerdefinierten Rust-Binärprogramms manipuliert werden kann. Das Feld custom_bindgen nimmt den Modulnamen eines rust_binary_host-Moduls an, das die bindgen API anstelle der normalen bindgen-Binärdatei verwendet.

Diese benutzerdefinierte Binärdatei muss Argumente ähnlich wie bindgen erwarten, wie als

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

Das meiste davon wird von der bindgen-Bibliothek selbst erledigt. Um ein Beispiel dafür zu sehen, finden Sie unter external/rust/crates/libsqlite3-sys/android/build.rs.

Außerdem stehen alle Bibliothekseigenschaften zur Verfügung, um die Kompilierung der Bibliothek zu steuern. Diese müssen jedoch selten definiert oder geändert werden.

handle_static_inline und static_inline_library

Diese beiden Eigenschaften sind für die gemeinsame Verwendung vorgesehen und ermöglichen die Erstellung von Wrappern für statische Inline-Funktionen, die in die exportierten Bindungen aufgenommen werden können.

Wenn Sie sie verwenden möchten, legen Sie handle_static_inline: true und static_inline_library auf eine entsprechende cc_library_static fest, die das rust_bindgen-Modul als Quelleingabe definiert.

Verwendungsbeispiele:

    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: ["."],
    }