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

Базовое использование rust_bindgen

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

Пример библиотеки 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"],
}

Дополнительную информацию об использовании флагов bindgen см. в разделе руководства по bindgen «Настройка сгенерированных привязок» .

Если вы использовали этот раздел для определения модуля 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 в других местах дерева.
  • Он позволяет избежать проблем с ромбовидными связями за счет сочетания статического и динамического связывания.

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

Известные свойства rust_bindgen

Свойства, определенные ниже, являются дополнением к важным общим свойствам , которые применяются ко всем модулям. Они либо особенно важны для модулей Rust bindgen, либо демонстрируют уникальное поведение, характерное для типа модуля rust_bindgen .

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

rust_bindgen создает варианты библиотеки, поэтому они имеют те же требования, что и модули rust_library для свойств stem , name и crate_name . См. Notable Rust library properties для справки.

wrapper_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, когда они доступны.
  • Не установлено или "" , что указывает на то, что следует использовать систему сборки по умолчанию.

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

cpp_std

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

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

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

cflags

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

custom_bindgen

Для расширенных вариантов использования bindgen может использоваться как библиотека, предоставляющая API, которым можно манипулировать как частью пользовательского двоичного файла Rust. Поле custom_bindgen принимает имя модуля rust_binary_host , который использует API bindgen вместо обычного двоичного файла 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

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

Чтобы использовать их, установите 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: ["."],
    }