System kompilacji obsługuje generowanie powiązań bindgen poprzez typ modułu rust_bindgen . Bindgen zapewnia powiązania Rust FFI z bibliotekami C (z pewną ograniczoną obsługą C++, która wymaga ustawienia właściwości cppstd ).

Podstawowe użycie rust_bindgen

Poniżej znajduje się przykład definicji modułu korzystającego z bindgen oraz sposobu użycia tego modułu jako skrzynki. Jeśli chcesz użyć powiązań bindgen za pośrednictwem makra include!() , na przykład w przypadku kodu zewnętrznego, zobacz stronę Generatory źródeł .

Przykładowa biblioteka C do wywołania z Rusta

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 opakowania 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"],
}

Aby dowiedzieć się więcej na temat używania flag bindgen, zobacz sekcję podręcznika bindgen na temat Dostosowywanie wygenerowanych powiązań .

Jeśli użyłeś tej sekcji do zdefiniowania modułu rust_bindgen jako warunku wstępnego użycia include!() , wróć do Wymagania wstępne na stronie Generatory źródeł. Jeśli nie, przejdź do kolejnych sekcji.

Użyj wiązań jako skrzyni

Utwórz plik external/rust/hello_bindgen/Android.bp z następującą 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 external/rust/hello_bindgen/src/main.rs z następującą 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 zbudować plik binarny.

Przetestuj wiązania Bindgen

Powiązania Bindgen zazwyczaj zawierają szereg wygenerowanych testów układu, aby zapobiec niedopasowaniu układu pamięci. AOSP zaleca zdefiniowanie modułu testowego dla tych testów i uruchomienie testów w ramach normalnego zestawu testów projektu.

Testowy plik binarny dla nich 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 powiązania

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 zazwyczaj marnotrawstwem. Wyłączyliśmy dynamiczne połączenie dla tych modułów, aby użycie ich za pomocą rustlibs automatycznie wybrało wariant statyczny.

Domyślnie moduły rust_bindgen mają właściwość visibility [":__subpackages__"] , która pozwala zobaczyć je tylko modułom w tym samym pliku Android.bp lub znajdującym się pod nim w hierarchii katalogów. Służy to dwóm celom:

  • Zniechęca to do używania surowych powiązań C w innym miejscu drzewa.
  • Pozwala uniknąć problemów z łączeniem diamentowym dzięki połączeniu połączeń statycznych i dynamicznych.

Zwykle powinieneś udostępnić bezpieczną bibliotekę otaczającą wygenerowany moduł, który dodałeś 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 w Twoim przypadku użycia, możesz dodać dodatkowe pakiety do widoczności . Dodając dodatkowe zakresy widoczności, pamiętaj, aby nie dodać dwóch zakresów, które w przyszłości mogą zostać połączone w ten sam proces, ponieważ połączenie może nie zostać połączone.

Godne uwagi właściwości rust_bindgen

Właściwości zdefiniowane poniżej stanowią dodatek do ważnych wspólnych właściwości , które mają zastosowanie do wszystkich modułów. Są one albo szczególnie ważne dla modułów Rust bindgen, albo wykazują unikalne zachowanie specyficzne dla typu modułu rust_bindgen .

łodyga, nazwa, nazwa_skrzynki

rust_bindgen tworzy warianty bibliotek, więc mają one te same wymagania co moduły rust_library w zakresie właściwości stem , name i crate_name . Zobacz Godne uwagi właściwości biblioteki Rust w celach informacyjnych.

opakowanie_źródło

Jest to ścieżka względna do pliku nagłówkowego opakowania, który zawiera nagłówki wymagane dla tych powiązań. Rozszerzenie pliku określa sposób interpretacji nagłówka i określa, która flaga -std ma być używana domyślnie. Zakłada się, że jest to nagłówek C , chyba że ma rozszerzenie .hh lub .hpp . Jeśli nagłówek 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.

źródło_rdzeń

Jest to nazwa wygenerowanego pliku źródłowego . To pole musi zostać zdefiniowane, nawet jeśli używasz powiązań jako skrzynki, ponieważ właściwość stem kontroluje jedynie nazwę pliku wyjściowego dla wygenerowanych wariantów biblioteki. Jeśli moduł zależy od wielu generatorów źródeł (takich jak bindgen i protobuf ) jako źródła, a nie od skrzynek w rustlibs , musisz upewnić się, że wszystkie generatory źródeł będące zależnościami tego modułu mają unikalne wartości source_stem . Zależne moduły 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 spowodowałyby nadpisanie wygenerowanych plików źródłowych w katalogu OUT_DIR .

c_std

Jest to ciąg znaków reprezentujący wersję standardu C, której należy użyć. Prawidłowe wartości są wymienione poniżej:

  • Konkretna wersja, na przykład "gnu11" .
  • "experimental" , czyli wartość zdefiniowana przez system kompilacji w build/soong/cc/config/global.go , może używać wersji roboczych, takich jak C++ 1z, jeśli są dostępne.
  • Unset lub "" , co wskazuje, że należy użyć domyślnej wartości systemu kompilacji.

Jeśli ta opcja jest ustawiona, rozszerzenie pliku jest ignorowane i zakłada się, że nagłówek jest nagłówkiem C. Nie można tego ustawić w tym samym czasie co cpp_std .

cpp_std

cpp_std to ciąg znaków reprezentujący wersję standardu C, której należy użyć. Prawidłowe wartości:

  • Konkretna wersja, np. "gnu++11"
  • "experimental" , czyli wartość zdefiniowana przez system kompilacji w build/soong/cc/config/global.go , może używać wersji roboczych, takich jak C++ 1z, jeśli są dostępne.
  • Unset lub "" , co wskazuje, że należy użyć domyślnej wartości systemu kompilacji.

Jeśli ta opcja jest ustawiona, rozszerzenie pliku jest ignorowane i zakłada się, że nagłówek jest nagłówkiem C++. Nie można tego ustawić w tym samym czasie co c_std .

cflagi

cflags udostępnia listę ciągów flag Clang wymaganych do prawidłowej interpretacji nagłówków.

niestandardowe_wiązanie

W zaawansowanych przypadkach bindgen może być używany jako biblioteka, zapewniając interfejs API, którym można manipulować w ramach niestandardowego pliku binarnego Rusta. Pole custom_bindgen przyjmuje nazwę modułu rust_binary_host , który używa interfejsu API bindgen zamiast normalnego pliku binarnego bindgen .

Ten niestandardowy plik binarny musi oczekiwać argumentów w podobny sposób jak bindgen , na przykład

$ my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]

Większość z nich jest obsługiwana przez samą bibliotekę bindgen . Aby zobaczyć przykład takiego użycia, odwiedź external/rust/crates/libsqlite3-sys/android/build.rs .

Dodatkowo dostępny jest pełny zestaw właściwości biblioteki umożliwiający kontrolowanie kompilacji biblioteki, chociaż rzadko wymagają one definiowania lub zmiany.