Система сборки поддерживает генерацию привязок 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-привязок в других частях дерева.
- Это позволяет избежать проблем с ромбовидным связыванием, возникающих при сочетании статического и динамического связывания.
Обычно следует предоставлять безопасную библиотеку-обертку вокруг сгенерированного модуля, добавленного в ту же директорию, что и привязки, предназначенную для использования другими разработчиками. Если это не подходит для вашего случая, вы можете добавить дополнительные пакеты в область видимости . При добавлении дополнительных областей видимости, пожалуйста, убедитесь, что вы не добавляете две области видимости, которые могут быть связаны с одним и тем же процессом в будущем, так как это может привести к ошибке связывания.
Примечательные свойства rust_bingen
Описанные ниже свойства дополняют важные общие свойства , применимые ко всем модулям. Они либо особенно важны для модулей Rust bindgen, либо демонстрируют уникальное поведение, специфичное для типа модуля rust_bindgen .
stem, name, crat_name
rust_bindgen создает варианты библиотек, поэтому они предъявляют те же требования к свойствам stem , name и crate_name , что и модули rust_library . См. раздел «Заметные свойства библиотек Rust» для получения дополнительной информации.
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 and 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: ["."],
}