System kompilacji obsługuje generowanie powiązań bindgen za pomocą typu modułu rust_bindgen
. Bindgen udostępnia powiązania Rust FFI z bibliotekami C (z ograniczoną obsługą C++, która wymaga ustawienia właściwości cppstd
).
Podstawowe użycie rust_bindgen
Poniżej znajdziesz przykład definiowania modułu, który korzysta z bindgen, oraz sposób używania tego modułu jako pakietu. Jeśli chcesz używać powiązań bindgen za pomocą makra include!()
, np. w przypadku kodu zewnętrznego, zapoznaj się ze stroną Generatory kodu źródłowego.
Przykład biblioteki C, z której można wywoływać funkcje w Rust
Poniżej znajdziesz przykład biblioteki C, która definiuje strukturę i funkcję do użycia w 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);
}
Zdefiniuj moduł rust_bindgen
Zdefiniuj nagłówek kodu, external/rust/libbuzz/libbuzz_wrapper.h
, który zawiera wszystkie odpowiednie nagłówki:
// Include headers that are required for generating bindings in a wrapper header.
#include "libbuzz.h"
Zdefiniuj plik Android.bp
jako 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"],
}
Więcej informacji o używaniu flag bindgen znajdziesz w sekcji podręcznika bindgen dotyczącej dostosowywania wygenerowanych powiązań.
Jeśli w tej sekcji zdefiniowano rust_bindgen
moduł jako warunek wstępny używania makra include!()
, wróć do sekcji Warunek wstępny na stronie Generatory źródeł. Jeśli nie, przejdź do następnych sekcji.
Używanie wiązań jako skrzyni
Utwórz plik external/rust/hello_bindgen/Android.bp
z tą zawartością:
rust_binary {
name: "hello_bindgen",
srcs: ["main.rs"],
// Add the rust_bindgen module as if it were a rust_library dependency.
rustlibs: ["libbuzz_bindgen"],
}
Utwórz plik external/rust/hello_bindgen/src/main.rs
z tą zawartością:
//! 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) }
}
Na koniec wywołaj m hello_bindgen
, aby utworzyć plik binarny.
Testowanie powiązań Bindgen
Wiązania bindgen zwykle zawierają wiele wygenerowanych testów układu, aby zapobiec niezgodnościom układu pamięci. AOSP zaleca zdefiniowanie modułu testowego dla tych testów i uruchamianie ich w ramach normalnego pakietu testów projektu.
Binarny plik testowy można łatwo utworzyć, definiując rust_test
moduł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",
}
Widoczność i połączenia
Wygenerowane powiązania są zwykle bardzo małe, ponieważ składają się z definicji typów, sygnatur funkcji i powiązanych stałych. W rezultacie dynamiczne łączenie tych bibliotek jest zwykle nieefektywne. Wyłączyliśmy linkowanie dynamiczne w przypadku tych modułów, aby korzystanie z nich za pomocą rustlibs
automatycznie wybierało wariant statyczny.
Domyślnie moduły rust_bindgen
mają właściwość visibility
ustawioną na [":__subpackages__"]
, co oznacza, że będą one widoczne tylko dla modułów w tym samym pliku Android.bp
lub w plikach znajdujących się niżej w hierarchii katalogów. Ma to 2 cele:
- Zniechęca to do używania w innych miejscach drzewa surowych powiązań C.
- Pozwala uniknąć problemów z łączeniem w kształcie rombu dzięki połączeniu statycznemu i dynamicznemu.
Zwykle należy udostępnić bezpieczną bibliotekę otoki wokół wygenerowanego modułu dodanego w tym samym drzewie katalogów co powiązania, która jest przeznaczona do użytku przez innych deweloperów. Jeśli to nie działa w Twoim przypadku, możesz dodać kolejne pakiety do widoczności. Dodając dodatkowe zakresy widoczności, uważaj, aby nie dodawać 2 zakresów, które w przyszłości mogą być połączone w tym samym procesie, ponieważ może to spowodować niepowodzenie połączenia.
Ważne właściwości rust_bindgen
Właściwości zdefiniowane poniżej są dodatkowe w stosunku do ważnych wspólnych właściwości, które mają zastosowanie do wszystkich modułów. Są one szczególnie ważne w przypadku modułów Rust bindgen lub wykazują unikalne zachowanie charakterystyczne dla typu modułu rust_bindgen
.
stem, name, crate_name
rust_bindgen
tworzy warianty biblioteki, więc mają one takie same wymagania jak moduły rust_library
w przypadku właściwości stem
, name
i crate_name
. Więcej informacji znajdziesz w sekcji Notable Rust library properties (Ważne właściwości biblioteki Rust).
wrapper_src
Jest to ścieżka względna do pliku nagłówkowego otoki, który zawiera nagłówki wymagane w przypadku tych powiązań. Rozszerzenie pliku określa sposób interpretacji nagłówka i domyślnie wskazuje, którego flagi -std
użyć. Zakłada się, że jest to nagłówek C
, chyba że rozszerzenie ma wartość .hh
lub .hpp
. Jeśli plik nagłówkowy C++ musi mieć inne rozszerzenie, ustaw właściwość cpp_std
, aby zastąpić domyślne zachowanie, które zakłada, że plik jest plikiem C.
source_stem
To nazwa pliku wygenerowanego pliku źródłowego. To pole musi
być zdefiniowane, nawet jeśli używasz powiązań jako pakietu, ponieważ właściwość stem
kontroluje tylko nazwę pliku wyjściowego dla wygenerowanych wariantów biblioteki.
Jeśli moduł zależy od wielu generatorów źródłowych (np. bindgen
i protobuf
) jako źródła, a nie jako pakietów za pomocą rustlibs
, musisz zadbać o to, aby wszystkie generatory źródłowe, które są zależnościami tego modułu, miały unikalne wartości source_stem
. Moduły zależne kopiują źródła ze wszystkich zależności SourceProvider
zdefiniowanych w srcs
do wspólnego katalogu OUT_DIR
, więc kolizje w source_stem
spowodują nadpisanie wygenerowanych plików źródłowych w katalogu OUT_DIR
.
c_std
To ciąg znaków wskazujący, której wersji standardu C należy użyć. Prawidłowe wartości są wymienione poniżej:
- konkretną wersję, np.
"gnu11"
; "experimental"
, czyli wartość zdefiniowana przez system kompilacji wbuild/soong/cc/config/global.go
, może używać wersji roboczych, takich jak C++1z, gdy są one dostępne.- Nieustawiona lub
""
, co oznacza, że należy użyć domyślnego ustawienia systemu kompilacji.
Jeśli to ustawienie jest skonfigurowane, rozszerzenie pliku jest ignorowane, a nagłówek jest traktowany jako nagłówek C. Nie można tego ustawić w tym samym czasie co cpp_std
.
cpp_std
cpp_std
to ciąg znaków określający, której wersji standardu C należy użyć. Prawidłowe wartości:
- konkretną wersję, np.
"gnu++11"
; "experimental"
, czyli wartość zdefiniowana przez system kompilacji wbuild/soong/cc/config/global.go
, może używać wersji roboczych, takich jak C++1z, gdy są one dostępne.- Nieustawiona lub
""
, co oznacza, że należy użyć domyślnego ustawienia systemu kompilacji.
Jeśli to ustawienie jest włączone, rozszerzenie pliku jest ignorowane, a nagłówek jest traktowany jako nagłówek C++. Nie można tego ustawić w tym samym czasie co c_std
.
cflags
cflags
zawiera listę ciągów znaków z flagami Clang, które są wymagane do prawidłowego interpretowania nagłówków.
custom_bindgen
W zaawansowanych przypadkach użycia narzędzie bindgen może być używane jako biblioteka udostępniająca interfejs API, którym można manipulować w ramach niestandardowego pliku binarnego Rust. Pole custom_bindgen
przyjmuje nazwę modułu rust_binary_host
, który korzysta z interfejsu API bindgen zamiast ze zwykłego pliku binarnego bindgen
.
Ten niestandardowy plik binarny musi oczekiwać argumentów w sposób podobny do bindgen
, np.
$ my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]
Większość tych czynności wykonuje sama biblioteka bindgen
. Przykład takiego użycia znajdziesz w pliku external/rust/crates/libsqlite3-sys/android/build.rs.
Dostępny jest też pełny zestaw właściwości biblioteki, który umożliwia kontrolowanie kompilacji biblioteki, choć rzadko trzeba je definiować lub zmieniać.
handle_static_inline i static_inline_library
Te 2 właściwości są przeznaczone do używania razem i umożliwiają tworzenie otoczek dla statycznych funkcji wbudowanych, które można uwzględnić w eksportowanych powiązaniach bindgen.
Aby ich użyć, ustaw handle_static_inline: true
i static_inline_library
na odpowiednią wartość cc_library_static
, która definiuje moduł rust_bindgen
jako źródło danych wejściowych.
Przykład użycia:
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: ["."],
}