Criar variáveis

As variáveis "Make" são uma classe especial de variáveis de string expansíveis disponíveis para atributos marcados como "Sujeito à substituição de variável Make".

Elas podem ser usadas, por exemplo, para injetar caminhos específicos da cadeia de ferramentas em ações de build construídas pelo usuário.

O Bazel oferece variáveis predefinidas, que estão 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 delas.

O motivo do termo "Make" é histórico: a sintaxe e a semântica de essas variáveis foram originalmente destinadas a corresponder ao GNU Make.

Usar

Os atributos marcados como "Sujeito à substituição de variável Make" podem referenciar a variável "Make" FOO da seguinte maneira:

my_attr = "prefix $(FOO) suffix"

Em outras palavras, qualquer substring correspondente a $(FOO) é expandida para FOO's valor. Se esse valor for "bar", a string final se tornará:

my_attr = "prefix bar suffix"

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

As variáveis "Make" cujos nomes são símbolos não alfabéticos, como @, também podem ser referenciadas usando apenas um cifrão, sem os parênteses. Por exemplo:

my_attr = "prefix $@ suffix"

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

Variáveis predefinidas

As variáveis "Make" predefinidas podem ser referenciadas por qualquer atributo marcado como "Sujeito à substituição de variável Make" em qualquer destino.

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

bazel info --show_make_env [build options]

e confira as linhas de saída principais com letras maiúsculas.

Confira um exemplo de variáveis predefinidas.

Variáveis de opção da cadeia de ferramentas

Variáveis de caminho

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

    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 acessar o caminho dela é $(execpath toolname), em que toolname precisa estar listado no atributo tools de genrule.

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

Variáveis de arquitetura da máquina

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

Variáveis de genrule predefinidas

As seguintes variáveis estão disponíveis especialmente para o atributo genrule's cmd e são geralmente importantes para que esse atributo funcione.

Confira um exemplo de variáveis de genrule predefinidas.

  • OUTS: a lista outs da genrule. Se você tiver apenas um arquivo de saída, também poderá usar $@.
  • SRCS: a lista srcs da genrule (ou, mais precisamente, os nomes de caminho 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, aciona 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, ela será expandida para o diretório que contém esse arquivo. Se tiver várias entradas, ela será expandida para o diretório raiz do pacote na genfiles árvore, 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 genrule precisar gerar arquivos intermediários temporários (talvez como resultado do uso de outra ferramenta, como um compilador), ela deverá tentar gravá-los em @D (embora /tmp também possa ser gravado) e removê-los antes de terminar.

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

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

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, esse é o caminho relativo à 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 do execroot em que o Bazel executa ações de build.

    No exemplo acima, o Bazel executa todas as ações de build no diretório vinculado por bazel-myproject na raiz do espaço de trabalho. O arquivo de origem empty.source está vinculado ao 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 maneira semelhante, mas também são prefixados com o subcaminho bazel-out/cpu-compilation_mode/bin (ou para as saídas de 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. Assim, o caminho de execução é bazel-out/cpu-opt-exec-hash/bin/testapp/app. Esse prefixo extra permite criar o mesmo destino para, digamos, duas CPUs diferentes no mesmo build sem que os resultados se sobreponham.

    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 isso for falso ou o rótulo estiver malformado, o build falhará com um erro.

  • rootpath: indica o caminho que um binário criado pode usar para encontrar uma dependência no ambiente de execução em relação ao subdiretório do diretório de runfiles 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. Use rlocationpath para oferecer suporte multiplataforma.

    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 relativos ao espaço de trabalho puro: testapp/empty.source e testapp/app.

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

    Isso tem os mesmos requisitos de "apenas uma saída" que execpath.

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

    Isso é semelhante a rootpath porque não contém prefixos de configuração, mas difere 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 vai começar com repo/, seguido pelo caminho relativo ao repositório.

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

    Isso tem os mesmos requisitos de "apenas uma saída" que execpath.

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

execpaths, rootpaths, rlocationpaths, e locations são as variações plurais de execpath, rootpath, rlocationpaths, elocation, respectivamente. Eles oferecem suporte a 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 em srcs, arquivos de saída ou deps do destino de consumo. Caso contrário, o build falhará. Os destinos do 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 são válidos.

Variáveis personalizadas

As variáveis "Make" personalizadas podem ser referenciadas por qualquer atributo marcado como "Sujeito à substituição de variável Make", mas apenas em 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 motivo muito bom para incorporá-las ao Bazel principal. Isso evita que o Bazel precise carregar dependências potencialmente caras para fornecer variáveis que os destinos de consumo talvez não se importem.

Variáveis da cadeia de ferramentas do C++

As seguintes variáveis são definidas nas regras da cadeia de ferramentas do C++ e estão disponíveis para qualquer regra que defina toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"] Algumas regras, como java_binary, incluem implicitamente a cadeia de ferramentas do C++ na definição da regra. Elas herdam essas variáveis automaticamente.

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

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

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

    Recomendamos sempre usar CC_FLAGS em combinação com CC. Se você não fizer isso, será por sua conta e risco.

  • CC_FLAGS: um conjunto mínimo de flags para que o compilador C/C++ possa ser usado por genrules. Em particular, ele contém flags para selecionar a arquitetura correta se CC oferecer suporte a várias arquiteturas.
  • NM: o comando "nm" do crosstool.
  • OBJCOPY: o comando objcopy do mesmo pacote que o compilador C/C++
  • STRIP: o comando strip do mesmo pacote que o compilador C/C++

Variáveis da cadeia de ferramentas Java

As seguintes variáveis são definidas nas regras da cadeia de ferramentas Java e estão 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 da cadeia de ferramentas do host).

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

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

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

Variáveis definidas pelo Starlark

Os autores de regras e cadeias de ferramentas podem definir variáveis totalmente personalizadas retornando um TemplateVariableInfo. Todas as regras que dependem delas pelo toolchains atributo podem ler os valores:

Confira um exemplo de variáveis definidas pelo Starlark.