Das Build-System unterstützt die Generierung von Bindgen-Bindungen über den Modultyp rust_bindgen . Bindgen stellt Rust-FFI-Bindungen für C-Bibliotheken bereit (mit eingeschränkter C++-Unterstützung, die das Festlegen der cppstd Eigenschaft erfordert).

Grundlegende Verwendung von rust_bindgen

Im Folgenden finden Sie ein Beispiel dafür, wie Sie ein Modul definieren, das bindgen verwendet, und wie Sie dieses Modul als Kiste verwenden. Wenn Sie bindgen-Bindungen über ein include!() Makro verwenden müssen, beispielsweise für externen Code, lesen Sie die Seite „Quellgeneratoren“ .

Beispiel-C-Bibliothek zum Aufruf von Rust

Es folgt eine Beispiel-C-Bibliothek, die eine Struktur und 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);
}

Definieren Sie ein rust_bindgen-Modul

Definieren Sie 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 „Anpassen generierter Bindungen“ im Bindgen-Handbuch.

Wenn Sie diesen Abschnitt verwendet haben, um ein rust_bindgen Modul als Voraussetzung für die Verwendung des include!() zu definieren, kehren Sie auf der Seite „Quellgeneratoren“ zu „ Voraussetzung“ zurück. Wenn nicht, fahren Sie mit den nächsten Abschnitten fort.

Benutzen Sie Bindungen als Kiste

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 die Binärdatei zu erstellen.

Testen Sie Bindgen-Bindungen

Bindgen-Bindungen enthalten normalerweise eine Reihe generierter Layouttests, um Nichtübereinstimmungen im Speicherlayout zu verhindern. AOSP empfiehlt, für diese Tests ein Testmodul zu definieren und die Tests als Teil der normalen Testsuite Ihres Projekts auszuführen.

Eine Testbinärdatei für diese kann einfach erstellt werden, indem ein rust_test Modul in external/rust/hello_bindgen/Android.bp definiert wird:

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 normalerweise sehr klein, da sie aus Typdefinitionen, Funktionssignaturen und zugehörigen Konstanten bestehen. Daher ist es im Allgemeinen verschwenderisch, diese Bibliotheken dynamisch zu verknüpfen. Wir haben die dynamische Verknüpfung für diese Module deaktiviert, sodass bei der Verwendung über rustlibs automatisch eine statische Variante ausgewählt wird.

Standardmäßig verfügen rust_bindgen -Module über die visibility [":__subpackages__"] , die es nur Modulen in derselben Android.bp Datei oder den in der Verzeichnishierarchie darunter liegenden Modulen ermöglicht, sie zu sehen. Dies dient zwei Zwecken:

  • Es rät von der Verwendung roher C-Bindungen an anderer Stelle im Baum ab.
  • Durch eine Mischung aus statischer und dynamischer Verknüpfung werden Probleme mit der Rautenverknüpfung 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 die für die Verwendung durch andere Entwickler vorgesehen ist. Wenn dies für Ihren Anwendungsfall nicht funktioniert, können Sie zusätzliche Pakete zur Sichtbarkeit hinzufügen. 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 möglicherweise fehlschlägt.

Bemerkenswerte rust_bindgen-Eigenschaften

Die unten definierten Eigenschaften gelten zusätzlich zu den wichtigen allgemeinen Eigenschaften , die für alle Module gelten. Diese sind entweder besonders wichtig für Rust-Bindgen-Module oder weisen ein einzigartiges Verhalten auf, das für den Modultyp rust_bindgen spezifisch ist.

Stamm, Name, Crate_Name

rust_bindgen erzeugt Bibliotheksvarianten, daher haben sie dieselben Anforderungen wie die rust_library Module für die Eigenschaften stem , name und crate_name . Als Referenz finden Sie die bemerkenswerten Eigenschaften der Rust-Bibliothek .

wrapper_src

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

source_stem

Dies ist der Dateiname für die generierte Quelldatei . Dieses Feld muss auch dann definiert werden, wenn Sie die Bindungen als Crate verwenden, da die stem nur den Ausgabedateinamen für die generierten Bibliotheksvarianten steuert. Wenn ein Modul von mehreren Quellgeneratoren (z. B. bindgen und protobuf ) als Quelle und nicht von Crates über rustlibs abhängt, müssen Sie sicherstellen, dass alle Quellgeneratoren, die von diesem Modul abhängig sind, eindeutige source_stem -Werte haben. Abhängige Module kopieren Quellen aus allen SourceProvider Abhängigkeiten, die in srcs definiert sind, in ein gemeinsames OUT_DIR Verzeichnis, sodass Kollisionen in source_stem dazu führen würden, dass die generierten Quelldateien im OUT_DIR Verzeichnis überschrieben werden.

c_std

Dies ist eine Zeichenfolge, die angibt, welche C-Standardversion verwendet werden soll. Gültige Werte sind unten aufgeführt:

  • Eine bestimmte Version, z. B. "gnu11" .
  • "experimental" , ein vom Build-System in build/soong/cc/config/global.go definierter Wert, kann Entwurfsversionen wie C++1z verwenden, sofern diese verfügbar sind.
  • Unset oder "" , was angibt, dass die Build-System-Standardeinstellung verwendet werden soll.

Wenn dies festgelegt ist, wird die Dateierweiterung ignoriert und der Header wird als C-Header angenommen. Dies kann nicht gleichzeitig mit cpp_std festgelegt werden.

cpp_std

cpp_std ist eine Zeichenfolge, die angibt, welche C-Standardversion verwendet werden soll. Gültige Werte:

  • Eine bestimmte Version, z. B. "gnu++11"
  • "experimental" , ein vom Build-System in build/soong/cc/config/global.go definierter Wert, kann Entwurfsversionen wie C++1z verwenden, sofern diese verfügbar sind.
  • Unset oder "" , was angibt, dass die Build-System-Standardeinstellung verwendet werden soll.

Wenn dies festgelegt ist, wird die Dateierweiterung ignoriert und der Header wird als C++-Header angenommen. Dies kann nicht gleichzeitig mit c_std festgelegt werden.

cfflags

cflags stellt eine String-Liste von Clang-Flags bereit, die zur korrekten Interpretation der Header erforderlich sind.

custom_bindgen

Für fortgeschrittene Anwendungsfälle kann bindgen als Bibliothek verwendet werden und stellt eine API bereit, die als Teil einer benutzerdefinierten Rust-Binärdatei 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 auf ähnliche Weise wie bindgen erwarten, z

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

Das meiste davon wird von der bindgen Bibliothek selbst erledigt. Ein Beispiel für diese Verwendung finden Sie unter external/rust/crates/libsqlite3-sys/android/build.rs .

Darüber hinaus steht der gesamte Satz an Bibliothekseigenschaften zur Steuerung der Kompilierung der Bibliothek zur Verfügung, obwohl diese selten definiert oder geändert werden müssen.