Criar variáveis

Informar um problema Ver código-fonte

As variáveis "Make" são uma classe especial de variáveis de string expansíveis disponíveis para atributos marcados como "Subject to 'Make variables' REPLACE".

Elas podem ser usadas, por exemplo, para injetar caminhos específicos do conjunto de ferramentas em ações de compilação criadas pelo usuário.

Ele fornece variáveis predefinidas, disponíveis para todos os destinos, e variáveis personalizadas, que são definidas em destinos de dependência e só estão disponíveis para destinos que dependem deles.

O motivo do termo "Make" é histórico: a sintaxe e a semântica dessas variáveis foram originalmente destinadas a corresponder ao GNU Make (link em inglês).

Uso

Atributos marcados como "Subject to 'Make variables' Override" podem fazer referência à variável "Make" FOO da seguinte maneira:

my_attr = "prefix $(FOO) suffix"

Em outras palavras, qualquer substring correspondente a $(FOO) é expandida para o valor de FOO. Se esse valor for "bar", a string final será:

my_attr = "prefix bar suffix"

Se FOO não corresponder a uma variável conhecida pelo alvo consumidor, o Bazel falhará com um erro.

Variáveis "Make" com nomes que não são símbolos de letras, como @, também podem ser referenciadas usando apenas um cifrão, sem os parênteses. Exemplo:

my_attr = "prefix $@ suffix"

Para escrever $ como um literal de string (ou seja, para evitar a expansão de variáveis), escreva $$.

Variáveis predefinidas

As variáveis "Make" predefinidas podem ser referenciadas por qualquer atributo marcado como "Subject to 'Make variables' REPLACE" em qualquer destino.

Para ver a lista dessas variáveis e os respectivos valores para um determinado conjunto de opções de build, execute

bazel info --show_make_env [build options]

e observe as primeiras linhas da saída com letras maiúsculas.

Confira um exemplo de variáveis predefinidas.

Variáveis de opção do conjunto de ferramentas

Variáveis de caminho

  • BINDIR: a base da árvore binária gerada para a arquitetura de destino.

    Observe que uma árvore diferente pode ser usada para programas executados durante o build na arquitetura do host para oferecer suporte à compilação cruzada.

    Se você quiser executar uma ferramenta em um genrule, a maneira recomendada de encontrar o caminho é $(execpath toolname), em que toolname precisa estar listado no atributo tools do genrule.

  • GENDIR: a base da árvore de código gerada para a arquitetura de destino.

Variáveis de arquitetura de máquina

  • TARGET_CPU: a CPU da arquitetura de destino, por exemplo, k8.

Variáveis de regra geral predefinidas

Os elementos a seguir estão especialmente disponíveis para o atributo cmd do genrule e geralmente são importantes para que esse atributo funcione.

Confira um exemplo de variáveis predefinidas da regra geral.

  • OUTS: a lista outs do genrule. Se você tiver apenas um arquivo de saída, também poderá usar $@.
  • SRCS: a lista srcs do genrule (ou mais precisamente: os nomes dos caminhos dos arquivos correspondentes aos rótulos na lista srcs). Se você tiver apenas um arquivo de origem, também poderá usar $<.
  • <: SRCS, se for um único arquivo. Caso contrário, será gerado um erro de build.
  • @: OUTS, se for um único arquivo. Caso contrário, aciona um erro de build.
  • RULEDIR: o diretório de saída do destino, ou seja, o diretório correspondente ao nome do pacote que contém o destino na árvore genfiles ou bin. Para //my/pkg:my_genrule, isso sempre termina em my/pkg, mesmo que as saídas de //my/pkg:my_genrule estejam em subdiretórios.

  • @D: o diretório de saída. Se outs tiver uma entrada, ele se expandirá para o diretório que contém esse arquivo. Se tiver várias entradas, ele se expandirá para o diretório raiz do pacote na árvore genfiles, mesmo que todos os arquivos de saída estejam no mesmo subdiretório.

    Observação:use RULEDIR em vez de @D, porque RULEDIR tem uma semântica mais simples e se comporta da mesma maneira, independentemente do número de arquivos de saída.

    Se a regra geral precisar gerar arquivos intermediários temporários (talvez como resultado do uso de alguma outra ferramenta, como um compilador), ela precisará tentar gravá-los em @D (embora /tmp também seja gravável) e removê-los antes da conclusão.

    Evite especialmente gravar em diretórios que contenham entradas. Eles podem estar em sistemas de arquivos somente leitura. Mesmo que não, isso descarte a árvore de origem.

Variáveis predefinidas de caminho de origem/saída

As variáveis predefinidas execpath, execpaths, rootpath, rootpaths, location e locations usam parâmetros de rótulo (por exemplo, $(execpath //foo:bar)) e substituem os caminhos de arquivo indicados por esse rótulo.

Para arquivos de origem, é o caminho relativo para a raiz do espaço de trabalho. Para arquivos que são saídas de regras, esse é o caminho de saída do arquivo. Consulte a explicação dos arquivos de saída abaixo.

Confira um exemplo de variáveis de caminho predefinidas.

  • execpath: indica o caminho abaixo da execroot (em inglês), em que o Bazel executa ações de compilação.

    No exemplo acima, o Bazel executa todas as ações de compilação no diretório vinculado pelo link simbólico bazel-myproject na raiz do espaço de trabalho. O arquivo de origem empty.source está vinculado no caminho bazel-myproject/testapp/empty.source. Portanto, o caminho de execução (que é o subcaminho abaixo da raiz) é testapp/empty.source. Esse é o caminho que as ações de build podem usar para encontrar o arquivo.

    Os arquivos de saída são preparados de forma semelhante, mas também são prefixados com o subcaminho bazel-out/cpu-compilation_mode/bin (ou para as saídas das ferramentas: bazel-out/cpu-opt-exec-hash/bin). No exemplo acima, //testapp:app é uma ferramenta porque aparece no atributo tools de show_app_output. Portanto, o arquivo de saída app é gravado em bazel-myproject/bazel-out/cpu-opt-exec-hash/bin/testapp/app. O caminho de execução é, portanto, bazel-out/cpu-opt-exec-hash/bin/testapp/app. Esse prefixo extra permite criar o mesmo destino para, por exemplo, duas CPUs diferentes no mesmo build sem que os resultados atrapalhem uma à outra.

    O rótulo transmitido a essa variável precisa representar exatamente um arquivo. Para rótulos que representam arquivos de origem, isso é verdadeiro automaticamente. Para rótulos que representam regras, a regra precisa gerar exatamente uma saída. Se for falso ou o rótulo estiver incorreto, o build falhará com um erro.

  • rootpath: indica o caminho que um binário criado pode usar para encontrar uma dependência no momento da execução em relação ao subdiretório do diretório de arquivos de execução correspondente ao repositório principal. Observação:isso só funciona se --enable_runfiles estiver ativado, o que não acontece no Windows por padrão. Em vez disso, use rlocationpath para compatibilidade com várias plataformas.

    Isso é semelhante a execpath, mas remove os prefixos de configuração descritos acima. No exemplo acima, isso significa que empty.source e app usam caminhos puros relativos ao espaço de trabalho: testapp/empty.source e testapp/app.

    O rootpath de um arquivo em um repositório externo repo começa com ../repo/, seguido pelo caminho relativo ao repositório.

    Esse código tem os mesmos requisitos de "apenas uma saída" que execpath.

  • rlocationpath: o caminho que um binário compilado pode passar para a função Rlocation de uma biblioteca de arquivos de execução para encontrar uma dependência no ambiente de execução, seja no diretório de arquivos de execução (se disponível) ou usando o manifesto de arquivos de execução.

    Isso é semelhante a rootpath, porque não contém prefixos de configuração, mas é diferente porque sempre começa com o nome do repositório. No exemplo acima, isso significa que empty.source e app resultam nos seguintes caminhos: myproject/testapp/empty.source e myproject/testapp/app.

    O rlocationpath de um arquivo em um repositório externo repo começa com repo/, seguido pelo caminho relativo ao repositório.

    Transmitir esse caminho para um binário e resolvê-lo em um caminho de sistema de arquivos usando as bibliotecas de arquivos de execução é a abordagem recomendada para encontrar dependências no ambiente de execução. Comparado ao rootpath, ele tem a vantagem de funcionar em todas as plataformas e mesmo que o diretório de arquivos de execução não esteja disponível.

    Esse código tem os mesmos requisitos de "apenas uma saída" que execpath.

  • location: um sinônimo para execpath ou rootpath, dependendo do atributo que está sendo expandido. Esse é um comportamento legado pré-Starlark e não é recomendado, a menos que você realmente saiba o que ele faz para uma regra específica. Consulte o documento #2475 para saber mais detalhes.

execpaths, rootpaths, rlocationpaths e locations são as variações plurais de execpath, rootpath, rlocationpaths e location, respectivamente. Eles são compatíveis com rótulos que produzem várias saídas. Nesse caso, cada saída é listada separada por um espaço. Regras de saída zero e rótulos malformados produzem erros de build.

Todos os rótulos referenciados precisam aparecer no srcs do destino de consumo, nos arquivos de saída ou no deps. Caso contrário, o build falhará. Os destinos C++ também podem referenciar rótulos em data.

Os rótulos não precisam estar no formato canônico: foo, :foo e //somepkg:foo estão corretos.

Variáveis personalizadas

Variáveis "Make" personalizadas podem ser referenciadas por qualquer atributo marcado como "Subject to 'Make variables' REPLACE", mas somente nos destinos que dependem de outros destinos que definem essas variáveis.

Como prática recomendada, todas as variáveis precisam ser personalizadas, a menos que haja um bom motivo para integrá-las ao Bazel principal. Isso evita que o Bazel tenha que carregar dependências potencialmente caras para fornecer variáveis que consomem taretas.

Variáveis do conjunto de ferramentas C++

Os itens a seguir são definidos nas regras do conjunto de ferramentas do C++ e ficam disponíveis para qualquer regra que defina toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"]. Algumas regras, como java_binary, incluem implicitamente o conjunto de ferramentas C++ na definição das regras. Eles herdam essas variáveis automaticamente.

As regras integradas do C++ são muito mais sofisticadas do que "executar o compilador nele". Para oferecer suporte a modos de compilação tão diversos como *SAN, ThinLTO, com/sem módulos e binários cuidadosamente otimizados ao mesmo tempo que testes de execução rápida em várias plataformas, as regras integradas fazem o necessário para garantir que as entradas, saídas e sinalizações de linha de comando corretas sejam definidas em cada uma das ações possivelmente geradas internamente.

Essas variáveis são um mecanismo substituto a ser usado por especialistas em linguagem em casos raros. Se você quiser usá-los, entre em contato com os desenvolvedores do Bazel primeiro.

  • ABI: a versão da ABI C++.
  • AR: o comando "ar" do crosstool.
  • C_COMPILER: identificador do compilador C/C++, por exemplo, llvm.
  • CC: o comando do compilador C e C++.

    É altamente recomendável usar sempre CC_FLAGS em combinação com CC. Não fazê-lo por sua conta e risco.

  • CC_FLAGS: um conjunto mínimo de sinalizações para que o compilador C/C++ possa ser usado pelas regras gerais. Em particular, ele contém sinalizações para selecionar a arquitetura correta se CC for compatível com várias arquiteturas.
  • NM: o comando "nm" do crosstool.
  • OBJCOPY: o comando objcopy do mesmo pacote que o compilador C/C++.
  • STRIP: o comando de remoção do mesmo pacote que o compilador C/C++.

Variáveis do conjunto de ferramentas Java

Os itens a seguir são definidos nas regras do conjunto de ferramentas Java e ficam disponíveis para qualquer regra que defina toolchains = ["@bazel_tools//tools/jdk:current_java_runtime"] (ou "@bazel_tools//tools/jdk:current_host_java_runtime" para o equivalente do conjunto de ferramentas de host).

a maioria das ferramentas no JDK não deve ser usada diretamente. As regras integradas do Java usam abordagens muito mais sofisticadas de compilação e empacotamento Java do que as ferramentas upstream podem expressar, como jars de interface, jars de interface de cabeçalho e empacotamento Jar altamente otimizado e implementações de mesclagem.

Essas variáveis são um mecanismo substituto a ser usado por especialistas em linguagem em casos raros. Se você quiser usá-los, entre em contato com os desenvolvedores do Bazel primeiro.

  • JAVA: o comando "java" (uma máquina virtual Java). Evite isso e use uma regra java_binary sempre que possível. Pode ser um caminho relativo. Se você precisar mudar de diretório antes de invocar java, será necessário capturar o diretório de trabalho antes de mudá-lo.
  • JAVABASE: o diretório base que contém os utilitários do Java. Pode ser um caminho relativo. Ele terá um subdiretório "bin".

Variáveis definidas pelo Starlark

Os gravadores de regras e conjuntos de ferramentas podem definir variáveis completamente personalizadas retornando um provedor TemplateVariableInfo. Todas as regras que dependem delas por meio do atributo toolchains podem ler os valores:

Veja um exemplo de variáveis definidas pelo Starlark.