O sistema de build possibilita gerar vinculações bindgen
usando o tipo de módulo rust_bindgen
. A bindgen fornece vinculações de FFI do Rust às bibliotecas C com suporte
para código C++ limitado, o que exige a definição da propriedade cppstd
.
Uso básico do rust_bindgen
Veja abaixo um exemplo de como definir um módulo que usa a bindgen e
aprenda a usar esse módulo como uma caixa. Se você precisar usar vinculações bindgen com
uma macro include!()
, como para código externo, consulte a
página
Geradores de origem.
Exemplo de uma biblioteca C para chamadas do Rust
Confira um exemplo de biblioteca C que define uma estrutura e uma função para uso com o Rust abaixo.
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);
}
Definir um módulo rust_bindgen
Defina um cabeçalho do wrapper external/rust/libbuzz/libbuzz_wrapper.h
, que inclui
todos os cabeçalhos relevantes:
// Include headers that are required for generating bindings in a wrapper header.
#include "libbuzz.h"
Defina o arquivo Android.bp
como 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"],
}
Para saber mais sobre o uso de sinalizações bindgen, consulte a seção do manual da bindgen em Como personalizar vinculações geradas (link em inglês).
Se você usou esta seção para definir um módulo rust_bindgen
como pré-requisito para
usar a macro include!()
, volte para a seção Pré-requisito
na página de Geradores de origem. Caso contrário, prossiga para as próximas seções.
Usar vinculações como uma caixa
Crie external/rust/hello_bindgen/Android.bp
com este conteúdo:
rust_binary {
name: "hello_bindgen",
srcs: ["main.rs"],
// Add the rust_bindgen module as if it were a rust_library dependency.
rustlibs: ["libbuzz_bindgen"],
}
Crie external/rust/hello_bindgen/src/main.rs
com este conteúdo:
//! 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) }
}
Por fim, chame m hello_bindgen
para criar o binário.
Testar vinculações bindgen
As vinculações bindgen geralmente contêm vários testes de layout gerados para evitar incompatibilidades de layout na memória. O AOSP recomenda que você defina um módulo para esses testes e que eles sejam executados como parte do pacote normal do projeto.
Um binário para esses testes pode ser facilmente produzido definindo um módulo rust_test
em 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",
}
Visibilidade e vinculação
As vinculações geradas tendem a ser muito pequenas, já que consistem em definições de tipo,
assinaturas de funções e constantes relacionadas. Como resultado, não vale a pena
vincular essas bibliotecas dinamicamente. Desativamos a vinculação dinâmica
para esses módulos. Assim, o uso com rustlibs
vai selecionar automaticamente uma
variante estática.
Por padrão, os módulos rust_bindgen
têm uma propriedade visibility
de
[":__subpackages__"]
, que só vai permitir módulos no mesmo arquivo Android.bp
ou abaixo dele na hierarquia do diretório. Isso tem dois
propósitos:
- Evitar o uso de vinculações C brutas em outros lugares da árvore.
- Evitar problemas de vinculação de diamantes com uma combinação de vinculações estáticas e dinâmicas.
Normalmente, você precisa fornecer uma biblioteca de wrapper segura em torno do módulo gerado que foi adicionado na mesma árvore de diretórios das vinculações, destinadas ao uso por outros desenvolvedores. Se isso não funcionar no seu caso de uso, adicione outros pacotes à visibilidade. Ao adicionar outros escopos de visibilidade, tome cuidado para não adicionar dois escopos que podem ser vinculados ao mesmo processo no futuro, porque isso pode causar uma falha.
Propriedades rust_bindgen importantes
As propriedades definidas abaixo são adicionadas a propriedades comuns importantes
que se aplicam a todos os módulos. Elas são particularmente importantes para os módulos bindgen
do Rust ou têm um comportamento único específico para o tipo de módulo rust_bindgen
.
stem, name, crate_name
A rust_bindgen
produz variantes de biblioteca. Portanto, elas compartilham os mesmos requisitos com
os módulos rust_library
para as propriedades stem
, name
e crate_name
. Consulte as
propriedades Rust importantes da biblioteca
para referência.
wrapper_src
Esse é o caminho relativo para um arquivo de cabeçalho do wrapper que inclui os cabeçalhos necessários
para essas vinculações. A extensão de arquivo determina como interpretar o cabeçalho
e qual sinalização -std
usar por padrão. Ela é considerada um cabeçalho
C, a menos que a extensão seja .hh
ou .hpp
. Se o cabeçalho C++ precisar
de outra extensão, defina a propriedade cpp_std
para substituir o comportamento padrão
que pressupõe que o arquivo é um arquivo C.
source_stem
Esse é o nome do arquivo de origem gerado. Esse campo precisa
ser definido, mesmo se você estiver usando as vinculações como uma caixa, já que a propriedade stem
controla apenas o nome do arquivo de saída das variantes de biblioteca geradas.
Se um módulo depende de vários geradores de origem (por exemplo, bindgen
e protobuf
)
como origem, e não como caixas usando rustlibs
, você precisa garantir que todos os geradores de origem
que são dependências desse módulo tenham valores source_stem
exclusivos. Módulos dependentes
copiam origens de todas as dependências SourceProvider
(definidas em
srcs
) para um diretório OUT_DIR
comum. Portanto, as colisões em source_stem
resultariam
nos arquivos da origem gerados sendo substituídos no diretório OUT_DIR
.
c_std
Essa é uma string que representa a versão padrão do C que será usada. Veja abaixo os valores válidos:
- Uma versão específica, como
"gnu11"
. "experimental"
, que é um valor definido pelo sistema de compilação embuild/soong/cc/config/global.go
, pode usar versões de rascunho, como C++1z, quando disponíveis.- Valor não definido ou
""
, o que indica que o padrão do sistema de compilação vai ser usado.
Se um valor não for definido, a extensão de arquivo vai ser ignorada e o cabeçalho será
considerado como C. Isso não pode ser definido ao mesmo tempo que cpp_std
.
cpp_std
cpp_std
é uma string que representa qual versão padrão do C será usada. Valores válidos:
- Uma versão específica, como
"gnu++11"
. "experimental"
, que é um valor definido pelo sistema de compilação embuild/soong/cc/config/global.go
, pode usar versões de rascunho, como C++1z, quando disponíveis.- Valor não definido ou
""
, o que indica que o padrão do sistema de compilação vai ser usado.
Se um desses valores for definido, a extensão de arquivo vai ser ignorada e o cabeçalho será
considerado como C++. Isso não pode ser definido ao mesmo tempo que c_std
.
cflags
cflags
fornece uma lista de strings de sinalizações do Clang necessárias para interpretar corretamente os
cabeçalhos.
custom_bindgen
Para casos de uso avançados, a bindgen pode ser usada como uma biblioteca, fornecendo uma API que
pode ser manipulada como parte de um binário personalizado do Rust. O campo custom_bindgen
recebe o nome
de um módulo rust_binary_host
, que usa a API bindgen em vez do
binário bindgen
normal.
Esse binário personalizado precisa esperar argumentos de forma parecida à bindgen
, como
$ my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]
A maior parte desse processo ocorre na própria biblioteca bindgen
. Para conferir um exemplo desse
uso, acesse external/rust/crates/libsqlite3-sys/android/build.rs.
Além disso, o conjunto completo de propriedades de biblioteca está disponível para controlar a compilação, embora elas raramente precisem ser definidas ou mudadas.
handle_static_inline e static_inline_library
Essas duas propriedades precisam ser usadas juntas e permitem a produção de wrappers para funções inline estáticas, que podem ser incluídas nas vinculações bindgen exportadas.
Configure handle_static_inline: true
para usar essas propriedades e static_inline_library
para
uma cc_library_static
correspondente, que define o módulo rust_bindgen
como
entrada de origem.
Exemplo de uso:
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"],
include_dirs: ["src/"],
}