Das Build-System unterstützt das Generieren von Bindungen mit Bindgen über den Modultyp rust_bindgen
. Bindgen stellt Rust-FFI-Bindungen für C-Bibliotheken bereit (mit eingeschränkter C++-Unterstützung, für die das Attribut cppstd
festgelegt werden muss).
Grundlegende Verwendung von rust_bindgen
Im Folgenden finden Sie ein Beispiel dafür, wie Sie ein Modul mit bindgen definieren und dieses als Crate verwenden. Wenn Sie Bindungen von bindgen über ein include!()
-Makro verwenden müssen, z. B. für externen Code, lesen Sie den Artikel Quellcodegeneratoren.
Beispiel für eine C-Bibliothek, die von Rust aufgerufen werden kann
Im Folgenden finden Sie ein Beispiel für eine C-Bibliothek, die einen Datentyp und eine Funktion für die 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
Definieren Sie den 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 in diesem Abschnitt ein rust_bindgen
-Modul als Voraussetzung für die Verwendung des include!()
-Makros definiert haben, kehren Sie auf der Seite „Quellgeneratoren“ zu Voraussetzung zurück. 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 schließlich m hello_bindgen
auf, um die Binärdatei zu erstellen.
Bindungen von Bindgen 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 bestehen. Daher ist es in der Regel unnötig, diese Bibliotheken
dynamisch zu verknüpfen. Wir haben die dynamische Verknüpfung für diese Module deaktiviert. Wenn Sie sie über rustlibs
verwenden, wird automatisch eine statische Variante ausgewählt.
Standardmäßig haben rust_bindgen
-Module die visibility
-Eigenschaft [":__subpackages__"]
. Das bedeutet, dass sie nur von Modulen in derselben Android.bp
-Datei oder in der Verzeichnishierarchie darunter gesehen werden können. Das hat zwei Vorteile:
- Die Verwendung von C-Bindungen an anderer Stelle im Baum wird nicht empfohlen.
- 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 für Ihren Anwendungsfall nicht funktioniert, können Sie weitere Pakete zu visibility 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 sonst fehlschlagen kann.
Wichtige rust_bindgen-Eigenschaften
Die unten definierten Properties ergänzen die wichtigen allgemeinen Properties, die für alle Module gelten. Diese sind entweder besonders wichtig für Rust-Bindungsmodule oder weisen ein einzigartiges Verhalten auf, das für den rust_bindgen
-Modultyp spezifisch ist.
stem, name, crate_name
rust_bindgen
erzeugt Bibliotheksvarianten, die dieselben Anforderungen wie die rust_library
-Module für die Attribute stem
, name
und crate_name
haben. Weitere Informationen finden Sie unter Besondere Eigenschaften von Rust-Bibliotheken.
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 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 .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 der generierten Quelldatei. Dieses Feld muss definiert werden, auch wenn Sie die Bindungen als Crate verwenden, da die Eigenschaft 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 als Container über rustlibs
abhängig ist, müssen Sie dafür sorgen, dass alle Quellgeneratoren, die Abhängigkeiten dieses Moduls sind, eindeutige source_stem
-Werte haben. Abhängige Module kopieren Quellen aus allen in srcs
definierten SourceProvider
-Abhängigkeiten in ein gemeinsames OUT_DIR
-Verzeichnis. Kollisionen in source_stem
würden daher dazu führen, 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"
, ein vom Build-System inbuild/soong/cc/config/global.go
definierter Wert, kann Entwurfsversionen wie C++1z verwenden, sofern diese verfügbar sind.- Nicht festgelegt oder
""
, was bedeutet, dass der Build-Systemstandard 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 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"
ist ein vom Build-System inbuild/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 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, z. B.
$ my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]
Der Großteil 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.
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 Attribute sollen zusammen verwendet werden und ermöglichen die Erstellung von Wrappern für statische Inline-Funktionen, die in die exportierten bindgen-Bindungen aufgenommen werden können.
Wenn Sie sie verwenden möchten, legen Sie handle_static_inline: true
fest und setzen Sie static_inline_library
auf eine entsprechende cc_library_static
, die das Modul rust_bindgen
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: ["."],
}