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);
}
Definiowanie modułu 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 flagach bindgen znajdziesz w sekcji Dostosowywanie wygenerowanych bindowań w podręczniku bindgen.
Jeśli w tej sekcji zdefiniowałeś/zdefiniowałaś moduł rust_bindgen
jako warunek wstępny do korzystania z makra include!()
, wróć do sekcji Warunek wstępny na stronie Generatorów źródeł. Jeśli nie, przejdź do kolejnych sekcji.
Używanie wiązań jako skrzynki
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 zwykle zawierają kilka wygenerowanych testów układu, aby zapobiec niezgodności układu pamięci. AOSP zaleca zdefiniowanie modułu testowego dla tych testów i przeprowadzenie ich w ramach normalnego zestawu testów projektu.
Testowy plik binarny dla tych funkcji 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, sygnatur funkcji i powiązanych stałych. Dlatego łączenie tych bibliotek w sposób dynamiczny jest zwykle nieefektywne. 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 cel:
- Nie zaleca się używania nieprzetworzonych połączeń C w innych miejscach w drzewie.
- Zapobiega problemom z linkowaniem diamentów dzięki połączeniu linkowania statycznego i dynamicznego.
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 w przyszłości mogą zostać połączone z tym samym procesem, ponieważ może to spowodować niepowodzenie połączenia.
Ważniejsze właściwości rust_bindgen
Właściwości zdefiniowane poniżej są oprócz 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
.
stem, name, crate_name
rust_bindgen
generuje warianty 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
To jest ścieżka względna do pliku nagłówka opakowania, który zawiera nagłówki wymagane do tych powiązań. 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
To nazwa wygenerowanego pliku źródłowego. To pole musi zostać 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 crate 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
, więc kolizje w source_stem
powodowałyby 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.- Nieskonfigurowane 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.- Nieskonfigurowane 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, które są wymagane do prawidłowej interpretacji nagłówków.
custom_bindgen
W zaawansowanych zastosowaniach bindgen może być używany jako biblioteka, która udostępnia interfejs API, którym można manipulować w ramach niestandardowego binarnego Rusta. Pole custom_bindgen
przyjmuje nazwę modułu rust_binary_host
, który zamiast zwykłego binarnego pliku bindgen
używa interfejsu API bindgen.
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 użycia znajdziesz w pliku external/rust/crates/libsqlite3-sys/android/build.rs.
Dodatkowo dostępny jest pełny zestaw właściwości biblioteki, które umożliwiają 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 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: ["."],
}