Система сборки поддерживает генерацию привязок Bindgen через модуль rust_bindgen
. Bindgen обеспечивает привязки Rust FFI к библиотекам C (с ограниченной поддержкой C++, требующей настройки свойства cppstd
).
Базовое использование rust_bindgen
Ниже представлен пример определения модуля, использующего 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"],
}
Дополнительную информацию об использовании флагов 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 где-либо еще в дереве.
- Он позволяет избежать проблем с ромбовидными связями за счет сочетания статического и динамического связывания.
Обычно следует предоставить безопасную библиотеку-обёртку вокруг добавленного вами сгенерированного модуля в том же дереве каталогов, что и привязки, предназначенную для использования другими разработчиками. Если это не подходит для вашего случая, вы можете добавить дополнительные пакеты в параметр «Visibility» . При добавлении дополнительных областей видимости будьте осторожны, чтобы не добавить две области, которые могут быть связаны с одним и тем же процессом в будущем, так как это может привести к сбою связи.
Известные свойства rust_bindgen
Свойства, определённые ниже, дополняют важные общие свойства , применимые ко всем модулям. Они либо особенно важны для модулей Rust Bindgen, либо демонстрируют уникальное поведение, характерное для модуля типа rust_bindgen
.
стебель, имя, имя_ящика
rust_bindgen
создаёт варианты библиотеки, поэтому они имеют те же требования к свойствам stem
, name
и crate_name
, что и модули rust_library
. См. раздел «Важнейшие свойства библиотеки Rust» .
wrapper_src
Это относительный путь к заголовочному файлу-обёртке, содержащему заголовочные файлы, необходимые для этих привязок. Расширение файла определяет, как интерпретировать заголовок и какой флаг -std
использовать по умолчанию. Предполагается, что это заголовок C, если только расширение не .hh
или .hpp
. Если ваш заголовочный файл C++ должен иметь другое расширение, установите свойство cpp_std
, чтобы переопределить поведение по умолчанию, предполагающее, что файл — это файл C.
source_stem
Это имя файла для сгенерированного исходного файла . Это поле необходимо определить, даже если вы используете привязки как контейнер, поскольку свойство 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: ["."],
}