Система сборки поддерживает создание привязок связывания через тип 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: ["."],
}