Geradores de origem

Esta página fornece uma visão de alto nível de como a fonte gerada é suportada e como ela pode ser usada no sistema de compilação.

Todos os geradores de código-fonte fornecem funcionalidade de sistema de compilação semelhante. Os três casos de uso de geração de origem suportados pelo sistema de compilação estão gerando ligações C usando bindgen, interfaces AIDL e interfaces protobuf.

Caixas da fonte gerada

Todo módulo Rust que gera código fonte pode ser usado como uma caixa, exatamente como se fosse definido como uma rust_library . (Isso significa que pode ser definido como uma dependência nas rustlibs , rlibs e dylibs .) O melhor padrão de uso para o código da plataforma é empregar o código-fonte gerado como um engradado. Embora a include! macro é compatível com a fonte gerada, seu objetivo principal é dar suporte ao código de terceiros que reside em external/ .

Há casos em que o código da plataforma ainda pode usar o código-fonte gerado por meio da macro include!() , como quando você usa um módulo genrule para gerar o código-fonte de maneira exclusiva.

Usando include!() para incluir a fonte gerada

O uso da fonte gerada como uma caixa é coberto pelos exemplos em cada página de módulo específica (respectiva). Esta seção mostra como fazer referência à fonte gerada por meio da macro include!() . Observe que esse processo é semelhante para todos os geradores de origem.

Pré-requisito

Este exemplo é baseado na suposição de que você definiu um módulo rust_bindgen ( libbuzz_bindgen ) e pode prosseguir para as Etapas para incluir a fonte gerada para usar a macro include!() . Se você não tiver, vá para Definindo um módulo rust bindgen , crie libbuzz_bindgen e volte aqui.

Observe que as partes do arquivo de compilação são aplicáveis ​​a todos os geradores de origem.

Etapas para incluir a fonte gerada

Crie external/rust/hello_bindgen/Android.bp com o seguinte conteúdo:

rust_binary {
   name: "hello_bzip_bindgen_include",
   srcs: [
         // The primary rust source file must come first in this list.
         "src/lib.rs",

         // The module providing the bindgen bindings is
         // included in srcs prepended by ":".
         ":libbuzz_bindgen",
    ],

    // Dependencies need to be redeclared when generated source is used via srcs.
    shared_libs: [
        "libbuzz",
    ],
}

Crie external/rust/hello_bindgen/src/bindings.rs com o seguinte conteúdo:

#![allow(clippy::all)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(unused)]
#![allow(missing_docs)]

// Note that "bzip_bindings.rs" here must match the source_stem property from
// the rust_bindgen module.
include!(concat!(env!("OUT_DIR"), "/bzip_bindings.rs"));

Crie external/rust/hello_bindgen/src/lib.rs com o seguinte conteúdo:

mod bindings;

fn main() {
    let mut x = bindings::foo { x: 2 };
    unsafe { bindings::fizz(1, &mut x as *mut bindings::foo) }
}

Por que caixas para fonte gerada

Ao contrário dos compiladores C/C++, rustc aceita apenas um único arquivo de origem que representa um ponto de entrada para um binário ou biblioteca. Ele espera que a árvore de origem seja estruturada de forma que todos os arquivos de origem necessários possam ser descobertos automaticamente. Isso significa que o código-fonte gerado deve ser colocado na árvore de código-fonte ou fornecido por meio de uma diretiva include no código-fonte:

include!("/path/to/hello.rs");

A comunidade Rust depende de scripts build.rs e suposições sobre o ambiente de construção Cargo, para trabalhar com essa diferença . Quando é compilado, o comando cargo define uma variável de ambiente OUT_DIR na qual os scripts build.rs devem colocar o código-fonte gerado. Use o seguinte comando para incluir o código-fonte:

include!(concat!(env!("OUT_DIR"), "/hello.rs"));

Isso representa um desafio para Soong, pois as saídas de cada módulo são colocadas em seu próprio diretório out/ 1 . Não há um único OUT_DIR onde as dependências geram sua fonte gerada.

Para o código da plataforma, o AOSP prefere empacotar a fonte gerada em um engradado que pode ser importado, por vários motivos:

  • Impeça a colisão de nomes de arquivos de origem gerados.
  • Reduza o check-in de código clichê em toda a árvore que requer manutenção. Qualquer clichê necessário para compilar a fonte gerada em um engradado pode ser mantido centralmente.
  • Evite 2 interações implícitas entre o código gerado e o engradado ao redor.
  • Reduza a pressão na memória e no disco vinculando dinamicamente as fontes geradas comumente usadas.

Como resultado, todos os tipos de módulos de geração de fonte Rust do Android produzem código que pode ser compilado e usado como uma grade . Soong ainda suporta caixas de terceiros sem modificação se todas as dependências de origem geradas para um módulo forem copiadas em um único diretório por módulo, semelhante ao Cargo. Nesses casos, Soong define a variável de ambiente OUT_DIR para esse diretório ao compilar o módulo, para que a fonte gerada possa ser encontrada. No entanto, pelos motivos já descritos, é uma prática recomendada usar esse mecanismo apenas no código da plataforma quando for absolutamente necessário.


  1. Isso não apresenta problemas para C/C++ e linguagens similares, pois o caminho para a fonte gerada é fornecido diretamente ao compilador.

  2. Desde include! funciona por inclusão textual, pode referenciar valores do namespace delimitador, modificar o namespace ou usar construções como #![foo] . Essas interações implícitas podem ser difíceis de manter. Sempre prefira macros quando a interação com o resto da caixa for realmente necessária.