System kompilacji obsługuje generowanie powiązań powiązań za pomocą interfejsu rust_bindgen
typ modułu. Bindgen udostępnia powiązania FFI Rust w bibliotekach C (z niektórymi
ograniczona obsługa języka C++, co wymaga ustawienia właściwości cppstd
).
Podstawowe użycie rust_bindgen
Poniżej pokazujemy, jak zdefiniować moduł, który korzysta z powiązania.
jak wykorzystać go jako skrzynię. Jeśli chcesz używać bindgen za pomocą makra include!()
, np. w przypadku kodu zewnętrznego, zapoznaj się ze stroną Generatory źródeł.
Przykładowa biblioteka C do wywołania z systemu Rust
Poniżej znajduje się przykładowa biblioteka C, która definiuje strukturę i funkcję do wykorzystania w języku 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 ciąg
wszystkie istotne 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 „Generatory źródeł”. Jeśli nie, przejdź do kolejnych sekcji.
Używanie wiązań jako zbioru
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 testów oraz że są one uruchamiane w ramach standardowego zestawu testów w projekcie.
Testowy plik binarny dla tych można łatwo utworzyć, definiując moduł rust_test
w 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,
podpisy funkcji i powiązane stałe. W związku z tym zwykle
nie trzeba było ich dynamicznie łączyć. Wyłączyliśmy dynamiczne powiązanie
dla tych modułów, dzięki czemu użycie ich w usłudze rustlibs
spowoduje automatyczne wybranie
statycznego wariantu.
Domyślnie moduły rust_bindgen
mają właściwość visibility
o wartości
[":__subpackages__"]
, który zezwala wyłącznie na moduły w tej samej sekcji Android.bp
lub znajdujących się niżej w hierarchii katalogów. Ma to 2 cel:
- Nie zaleca się używania nieprzetworzonych połączeń C w innych miejscach w drzewie.
- Pozwala to uniknąć problemów z łączeniem diamentów w przypadku połączeń statycznych i dynamicznych.
Zwykle należy zapewnić bezpieczną bibliotekę owijającą wokół wygenerowanego modułu, który został dodany w tym samym drzewie katalogów co powiązania, które są przeznaczone 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.
Ważne 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 wersje biblioteki, więc ma te same wymagania co moduły rust_library
w przypadku właściwości stem
, name
i crate_name
. Zobacz
Ważne właściwości biblioteki Rust
w celach informacyjnych.
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 w C++ musi zawierać
z innego rozszerzenia, ustaw właściwość cpp_std
tak, aby zastępuje działanie domyślne
który zakładamy, że jest to plik C.
source_stem
To nazwa wygenerowanego pliku źródłowego. To pole musi
nawet jeśli używasz wiązań jako klatki, ponieważ stem
kontroluje tylko 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
, więc kolizje w source_stem
powodowałyby zastąpienie wygenerowanych plików źródłowych w katalogu OUT_DIR
.
c_std
Jest to ciąg znaków określający wersję C, która ma zostać użyta. Prawidłowe wartości są wymienione poniżej:
- Konkretna wersja, 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 ta zasada jest skonfigurowana, rozszerzenie pliku jest ignorowane, a nagłówek powinien
być nagłówkiem C. Nie można ustawić tej opcji równocześnie z wartością 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:
- Konkretna wersja, np.
"gnu++11"
"experimental"
, czyli wartość zdefiniowana przez system kompilacji wbuild/soong/cc/config/global.go
, może używać wersje robocze, np. C++1z gdy są dostępne.- Wartość nieskonfigurowana lub
""
, która wskazuje, że należy używać wartości domyślnej 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 ustawić tej opcji równocześnie z wartością c_std
.
kalosze
cflags
zawiera listę ciągów flag Clang wymaganych do prawidłowej interpretacji
nagłówki.
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 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 obsługiwana przez samą bibliotekę bindgen
. Aby zobaczyć przykład
użycie znajdziesz na stronie external/rust/crates/libsqlite3-sys/android/build.rs.
Dodatkowo możesz kontrolować pełen zestaw właściwości biblioteki. i kompilację biblioteki, choć rzadko trzeba je zdefiniować lub zmieniać.
handle_static_inline i static_inline_library
Te 2 usługi powinny być używane razem i umożliwiać tworzenie otoki statycznych funkcji wbudowanych, które można uwzględnić w wyeksportowanym powiązań.
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: ["."],
}