Система сборки поддерживает создание привязок связывания через тип rust_bindgen . Bindgen предоставляет привязки Rust FFI к библиотекам C (с некоторой ограниченной поддержкой C++, которая требует установки свойства cppstd ).

Базовое использование ржавчины_bindgen

Далее следует пример того, как определить модуль, использующий привязку, и как использовать этот модуль в качестве крейта. Если вам нужно использовать привязкиbindgen через макрос include!() , например, для внешнего кода, см. страницу Генераторы исходного кода .

Пример библиотеки C для вызова из Rust

Ниже приведен пример библиотеки C, которая определяет структуру и функцию для использования в 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);
}

Определите модульrust_bindgen

Определите заголовок оболочки external/rust/libbuzz/libbuzz_wrapper.h , который включает все соответствующие заголовки:

// Include headers that are required for generating bindings in a wrapper header.
#include "libbuzz.h"

Определите файл Android.bp как 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"],
}

Чтобы узнать больше об использовании флагов привязки, обратитесь к разделу руководства по привязке, посвященному настройке сгенерированных привязок .

Если вы использовали этот раздел для определения rust_bindgen в качестве предварительного условия для использования макроса include!() , вернитесь к разделу «Предварительное условие» на странице «Генератор исходного кода». Если нет, переходите к следующим разделам.

Используйте крепления в качестве ящика

Создайте external/rust/hello_bindgen/Android.bp со следующим содержимым:

rust_binary {
   name: "hello_bindgen",
   srcs: ["main.rs"],

   // Add the rust_bindgen module as if it were a rust_library dependency.
   rustlibs: ["libbuzz_bindgen"],
}

Создайте external/rust/hello_bindgen/src/main.rs со следующим содержимым:

//! 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) }
}

Наконец, вызовите m hello_bindgen для сборки двоичного файла.

Тестирование привязок Bindgen

Привязки Bindgen обычно содержат ряд сгенерированных тестов макета, чтобы предотвратить несоответствие макета памяти. AOSP рекомендует определить тестовый модуль для этих тестов и запускать тесты как часть обычного набора тестов вашего проекта.

Тестовый двоичный файл для них можно легко создать, определив rust_test в 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",
}

Видимость и связь

Создаваемые привязки обычно очень малы, поскольку состоят из определений типов, сигнатур функций и связанных констант. В результате динамически связывать эти библиотеки обычно расточительно. Мы отключили динамическое связывание для этих модулей, чтобы при их использовании через rustlibs автоматически выбирался статический вариант.

По умолчанию модули rust_bindgen имеют свойство visibility [":__subpackages__"] , которое позволяет видеть его только модулям в том же файле Android.bp или модулям, находящимся ниже него в иерархии каталогов. Это служит двум целям:

  • Это препятствует использованию необработанных привязок C в других местах дерева.
  • Это позволяет избежать проблем с ромбовидными связями за счет сочетания статических и динамических связей.

Обычно вам следует предоставить безопасную библиотеку-оболочку для сгенерированного модуля, который вы добавили в то же дерево каталогов, что и привязки, предназначенные для использования другими разработчиками. Если это не подходит для вашего варианта использования, вы можете добавить в видимость дополнительные пакеты. При добавлении дополнительных областей видимости позаботьтесь о том, чтобы не добавить две области, которые в будущем могут быть связаны с одним и тем же процессом, поскольку это может не связать.

Примечательные свойства ржавчины_bindgen

Определенные ниже свойства дополняют важные общие свойства , применимые ко всем модулям. Они либо особенно важны для модулей Rustbindgen, либо демонстрируют уникальное поведение, специфичное для типа rust_bindgen .

стебель, имя, имя_ящика

rust_bindgen создает варианты библиотеки, поэтому они имеют те же требования, что и rust_library для свойств stem , name и crate_name . Дополнительную информацию см. в разделе «Примечательные свойства библиотеки Rust» .

обертка_src

Это относительный путь к файлу заголовка оболочки, который включает заголовки, необходимые для этих привязок. Расширение файла определяет, как интерпретировать заголовок, и определяет, какой флаг -std использовать по умолчанию. Предполагается, что это заголовок C, если только расширение не .hh или .hpp . Если ваш заголовок C++ должен иметь какое-то другое расширение, установите свойство cpp_std , чтобы переопределить поведение по умолчанию, которое предполагает, что файл является файлом C.

исходный_ствол

Это имя созданного исходного файла . Это поле должно быть определено, даже если вы используете привязки в качестве контейнера, поскольку свойство stem управляет только именем выходного файла для сгенерированных вариантов библиотеки. Если модуль зависит от нескольких генераторов исходного кода (таких bindgen и protobuf ) как источника, а не от ящиков через rustlibs , вы должны убедиться, что все генераторы исходного кода, которые являются зависимостями этого модуля, имеют уникальные значения source_stem . Зависимые модули копируют источники из всех зависимостей SourceProvider , которые определены в srcs , в общий каталог OUT_DIR , поэтому коллизии в source_stem приведут к перезаписи сгенерированных исходных файлов в каталоге OUT_DIR .

c_std

Это строка, показывающая, какую версию стандарта C следует использовать. Допустимые значения перечислены ниже:

  • Конкретная версия, например "gnu11" .
  • "experimental" (значение, определенное системой сборки в build/soong/cc/config/global.go ) может использовать черновые версии, такие как C++1z, когда они доступны.
  • Unset или "" , что указывает на то, что следует использовать систему сборки по умолчанию.

Если этот параметр установлен, расширение файла игнорируется и предполагается, что заголовок представляет собой заголовок C. Его нельзя установить одновременно с cpp_std .

cpp_std

cpp_std — это строка, показывающая, какую версию стандарта C следует использовать. Допустимые значения:

  • Конкретная версия, например "gnu++11"
  • "experimental" (значение, определенное системой сборки в build/soong/cc/config/global.go ) может использовать черновые версии, такие как C++1z, когда они доступны.
  • Unset или "" , что указывает на то, что следует использовать систему сборки по умолчанию.

Если этот параметр установлен, расширение файла игнорируется, а заголовок считается заголовком C++. Это не может быть установлено одновременно с c_std .

cфлаги

cflags предоставляет строковый список флагов Clang, необходимых для правильной интерпретации заголовков.

custom_bindgen

Для более сложных случаев использованияbingen можно использовать в качестве библиотеки, предоставляющей API, которым можно манипулировать как часть пользовательского двоичного файла Rust. Поле custom_bindgen принимает имя модуля rust_binary_host , который использует API привязки вместо обычного двоичного файла bindgen .

Этот пользовательский двоичный файл должен ожидать аргументов bindgen , например:

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

Большая часть этого обрабатывается самой bindgen . Чтобы увидеть пример такого использования, посетите external/rust/crates/libsqlite3-sys/android/build.rs .

Кроме того, доступен полный набор свойств библиотеки для управления компиляцией библиотеки, хотя их определение или изменение требуется редко.

handle_static_inline и static_inline_library

Эти два свойства предназначены для совместного использования и позволяют создавать оболочки для статических встроенных функций, которые можно включать в экспортированные привязки привязки.

Чтобы использовать их, установите handle_static_inline: true и установите static_inline_library в соответствующий cc_library_static , который определяет rust_bindgen в качестве входных данных источника.

Пример использования:

    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: ["."],
    }