System kompilacji obsługuje generowanie bindgen za pomocą typu modułu rust_bindgen
. Bindgen zapewnia powiązania FFI Rust z bibliotekami C (z nieco 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 przykład użycia tego modułu jako crate. Jeśli chcesz używać bindgen za pomocą makra include!()
, np. w przypadku kodu zewnętrznego, zapoznaj się ze stroną Generatory źródeł.
Przykład biblioteki C do wywołania z Rust
Poniżej znajduje się przykładowa biblioteka 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 opakowujący 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 dotyczącej ręcznego tworzenia powiązań w artykule Dostosowywanie wygenerowanych powiązań.
Jeśli w tej sekcji zdefiniowano moduł rust_bindgen
jako warunek wstępny korzystania z makra include!()
, wróć do sekcji Wymagania wstępne na stronie Generatory źródeł. Jeśli nie, przejdź do następnych sekcji.
Używanie wiązań jako paczki
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 skompilować plik binarny.
Testowanie powiązań Bindgen
Powiązania Bindgen zawierają zwykle wiele wygenerowanych testów układu, aby zapobiegać niezgodności układu pamięci. AOSP zaleca, aby zdefiniowany moduł testów był zdefiniowany na potrzeby tych testów, a testy zostały uruchomione w ramach standardowego zestawu testów w projekcie.
Testowy binarny plik binarny dla tych urządzeń można łatwo wygenerować, definiując moduł rust_test
w pliku 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łączenie
Wygenerowane powiązania są zwykle bardzo małe, ponieważ składają się z definicji typów, podpisów funkcji i powiązanych stałych. Dlatego dynamiczne łączenie tych bibliotek
zwykle nie jest sensowne. Wyłączyliśmy dynamiczne linkowanie w przypadku tych modułów, aby ich używanie za pomocą rustlibs
automatycznie wybierało wariant statyczny.
Domyślnie moduły rust_bindgen
mają właściwość visibility
o wartości [":__subpackages__"]
, która pozwala widzieć je tylko modułom w tym samym pliku Android.bp
lub w katalogach podrzędnych w hierarchii katalogów. Ma to 2 cele:
- Nie zaleca się stosowania nieprzetworzonych połączeń C w innych miejscach w drzewie.
- Umożliwia unikanie problemów z połączeniami diamentowymi dzięki połączeniu łączenia statycznych i dynamicznych.
Zwykle należy udostępnić bezpieczną bibliotekę owijającą wygenerowany moduł w tym samym drzewie katalogów co powiązania, która jest przeznaczona do użytku przez innych programistów. Jeśli to nie zadziała, możesz dodać dodatkowe pakiety do widoczności. Podczas dodawania dodatkowych zakresów widoczności uważaj, aby nie dodawać zakresów, które mogą zostać połączone w ramach tego samego procesu w przyszłości, ponieważ może to spowodować niepowodzenie połączenia.
Właściwości rust_bindgen
Właściwości zdefiniowane poniżej są uzupełnieniem 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 Rustbindgen lub mają unikalne zachowanie specyficzne dla typu modułu rust_bindgen
.
łodyga, nazwa, nazwa_skrzynki
rust_bindgen
generuje wersje biblioteki, więc ma te same wymagania co moduły rust_library
w przypadku właściwości stem
, name
i crate_name
. Informacje o najważniejszych właściwościach biblioteki Rust znajdziesz w poniższej sekcji.
wrapper_src
Jest to ścieżka względna do pliku nagłówka kodu, który zawiera nagłówki wymagane przez te powiązania. Rozszerzenie pliku określa sposób interpretacji nagłówka oraz flagę -std
, która ma być używana domyślnie. Zakłada się, że jest to nagłówek C, chyba że rozszerzenie to .hh
lub .hpp
. Jeśli nagłówek C++ musi mieć inną rozszerzenie, ustaw właściwość cpp_std
, aby zastąpić domyślne działanie, które zakłada, że plik jest plikiem C.
source_stem
Jest to nazwa wygenerowanego pliku źródłowego. To pole musi być zdefiniowane, nawet jeśli używasz tych ograniczeń jako zbioru, ponieważ właściwość stem
wpływa tylko na nazwę pliku wyjściowego wygenerowanych wariantów biblioteki.
Jeśli moduł zależy od wielu generatorów źródłowych (takich jak bindgen
i protobuf
) jako źródła, a nie jako paczek za pomocą rustlibs
, musisz się upewnić, że wszystkie generatory źródłowe, które są zależnościami tego modułu, mają 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
, dlatego kolizje w source_stem
powodują zastąpienie 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:
- konkretnej wersji, np.
"gnu11"
; "experimental"
, która jest wartością zdefiniowaną przez system kompilacji wbuild/soong/cc/config/global.go
, może używać wersji roboczych, takich jak C++1z, gdy są dostępne.- Niezdefiniowane lub
""
, co oznacza, że należy użyć domyślnego systemu kompilacji.
Jeśli to ustawienie jest ustawione, rozszerzenie pliku jest ignorowane, a zakłada się, że nagłówek jest nagłówkiem C. Nie można go ustawić jednocześnie z opcją cpp_std
.
cpp_std
cpp_std
to ciąg znaków wskazujący, której wersji języka C należy użyć. Prawidłowe wartości:
- konkretnej wersji, np.
"gnu++11"
"experimental"
, która jest wartością zdefiniowaną przez system kompilacji wbuild/soong/cc/config/global.go
, może używać wersji roboczych, takich jak C++1z, gdy są dostępne.- Niezdefiniowane lub
""
, co oznacza, że należy użyć domyślnego systemu kompilacji.
Jeśli to ustawienie jest włączone, rozszerzenie pliku jest ignorowane, a zakłada się, że nagłówek jest nagłówkiem C++. Nie można go ustawić jednocześnie z opcją c_std
.
cflags
cflags
zawiera listę ciągów znaków z flagami Clang wymaganymi do prawidłowej interpretacji nagłówków.
niestandardowe_wiązanie
W zaawansowanych przypadkach użycia bindgen może służyć jako biblioteka, udostępniając interfejs API, na którym można manipulować jako część niestandardowego pliku binarnego Rust. Pole custom_bindgen
przyjmuje nazwę modułu rust_binary_host
, który zamiast zwykłego binarnego pliku bindgen
używa interfejsu bindgen API.
Ten niestandardowy plik binarny musi oczekiwać argumentów w sposób podobny do bindgen
, na przykład
$ my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]
Większość tych zadań jest wykonywana przez samą bibliotekę bindgen
. Przykład tego użycia znajdziesz na stronie external/rust/crates/libsqlite3-sys/android/build.rs.
Udostępniamy też pełny zestaw właściwości biblioteki, by kontrolować kompilację biblioteki. Rzadko trzeba je jednak zdefiniować lub zmienić.
handle_static_inline i static_inline_library
Te 2 właściwości są przeznaczone do używania razem i umożliwiają tworzenie obudów dla statycznych funkcji wbudowanych, które można uwzględnić w wyeksportowanych powiązaniach bindgen.
Aby ich użyć, ustaw handle_static_inline: true
i static_inline_library
na odpowiadający cc_library_static
, który 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: ["."],
}