O sistema de compilação suporta a geração de ligações bindgen por meio do tipo de módulo rust_bindgen
. Bindgen fornece ligações Rust FFI para bibliotecas C (com algum suporte limitado a C++, que requer a configuração da propriedade cppstd
).
Uso básico de Rust_bindgen
O que se segue é um exemplo de como definir um módulo que usa bindgen e como usar esse módulo como uma caixa. Se você precisar usar vinculações bindgen por meio de uma macro include!()
, como para código externo, consulte a página Geradores de código-fonte .
Exemplo de biblioteca C para chamar de Rust
Segue um exemplo de biblioteca C que define uma estrutura e uma função para uso em 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);
}
Defina um módulo Rust_bindgen
Defina um cabeçalho de 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 como usar sinalizadores bindgen, consulte a seção do manual bindgen em Personalizando ligações geradas .
Se você usou esta seção para definir um módulo rust_bindgen
como um pré-requisito para usar a macro include!()
, retorne para Pré-requisito na página Geradores de Origem. Caso contrário, prossiga para as próximas seções.
Use encadernações como caixa
Crie external/rust/hello_bindgen/Android.bp
com o seguinte 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 o seguinte 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) }
}
Finalmente, chame m hello_bindgen
para construir o binário.
Testar ligações do Bindgen
As ligações Bindgen normalmente contêm vários testes de layout gerados para evitar incompatibilidades de layout de memória. AOSP recomenda que você tenha um módulo de teste definido para esses testes e que os testes sejam executados como parte do conjunto de testes normal do seu projeto.
Um binário de teste para estes 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 ligação
As ligações geradas são geralmente muito pequenas, pois consistem em definições de tipo, assinaturas de função e constantes relacionadas. Como resultado, geralmente é um desperdício vincular essas bibliotecas de forma dinâmica. Desativamos a ligação dinâmica para esses módulos para que usá-los por meio de rustlibs
selecione automaticamente uma variante estática.
Por padrão, os módulos rust_bindgen
têm uma propriedade visibility
de [":__subpackages__"]
, que permitirá apenas que módulos no mesmo arquivo Android.bp
ou aqueles abaixo dele na hierarquia de diretórios o vejam. Isso serve a dois propósitos:
- Isso desencoraja o uso de ligações C brutas em outras partes da árvore.
- Evita problemas de ligação em diamante com uma mistura de ligação estática e dinâmica.
Normalmente, você deve fornecer uma biblioteca wrapper segura em torno do módulo gerado que você adicionou na mesma árvore de diretórios que as ligações que devem ser usadas por outros desenvolvedores. Se isso não funcionar para o seu caso de uso, você pode adicionar pacotes adicionais aoibility . Ao adicionar escopos de visibilidade adicionais, tome cuidado para não adicionar dois escopos que possam ser vinculados ao mesmo processo no futuro, pois isso pode falhar na vinculação.
Propriedades notáveis de ferrugem_bindgen
As propriedades definidas abaixo são adicionais às propriedades comuns importantes que se aplicam a todos os módulos. Eles são particularmente importantes para os módulos Rust bindgen ou exibem um comportamento exclusivo específico para o tipo de módulo rust_bindgen
.
caule, nome, crate_name
rust_bindgen
produz variantes de biblioteca, então elas compartilham os mesmos requisitos com os módulos rust_library
para as propriedades stem
, name
e crate_name
. Consulte Propriedades notáveis da biblioteca Rust para referência.
wrapper_src
Este é o caminho relativo para um arquivo de cabeçalho wrapper que inclui os cabeçalhos necessários para essas ligações. A extensão do arquivo determina como interpretar o cabeçalho e qual sinalizador -std
usar por padrão. Presume-se que seja um cabeçalho C , a menos que a extensão seja .hh
ou .hpp
. Se o seu cabeçalho C++ precisar ter alguma outra extensão, defina a propriedade cpp_std
para substituir o comportamento padrão que assume que o arquivo é um arquivo C.
origem_stem
Este é o nome do arquivo de origem gerado . Este campo deve ser definido, mesmo se você estiver usando as ligações como uma caixa, pois a propriedade stem
controla apenas o nome do arquivo de saída para as variantes da biblioteca geradas. Se um módulo depender de vários geradores de origem (como bindgen
e protobuf
) como fonte em vez de como caixas por meio de rustlibs
, você deverá garantir que todos os geradores de origem que são dependências desse módulo tenham valores source_stem
exclusivos. Módulos dependentes copiam fontes de todas as dependências SourceProvider
que são definidas em srcs
para um diretório OUT_DIR
comum, portanto, colisões em source_stem
resultariam na substituição dos arquivos de origem gerados no diretório OUT_DIR
.
c_std
Esta é uma string que representa qual versão do padrão C usar. Os valores válidos estão listados abaixo:
- 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 estiverem disponíveis. - Unset ou
""
, que indica que o padrão do sistema de compilação deve ser usado.
Se isto for definido, a extensão do arquivo será ignorada e o cabeçalho será considerado um cabeçalho 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 C usar. 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 estiverem disponíveis. - Unset ou
""
, que indica que o padrão do sistema de compilação deve ser usado.
Se estiver definido, a extensão do arquivo será ignorada e o cabeçalho será considerado um cabeçalho C++. Isso não pode ser definido ao mesmo tempo que c_std
.
flags
cflags
fornece uma lista de strings de sinalizadores Clang necessários para interpretar corretamente os cabeçalhos.
custom_bindgen
Para casos de uso avançados, bindgen pode ser usado como uma biblioteca, fornecendo uma API que pode ser manipulada como parte de um binário Rust personalizado. O campo custom_bindgen
leva o nome do módulo de um módulo rust_binary_host
, que usa a API bindgen em vez do binário bindgen
normal.
Este binário personalizado deve esperar argumentos de maneira semelhante a bindgen
, como
$ my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]
A maior parte disso é tratada pela própria biblioteca bindgen
. Para ver um exemplo desse uso, visite external/rust/crates/libsqlite3-sys/android/build.rs .
Além disso, o conjunto completo de propriedades da biblioteca está disponível para controlar a compilação da biblioteca, embora raramente precisem ser definidas ou alteradas.