Esta página se concentra na criação de regras compatíveis com o Windows, problemas comuns de criação de regras portáteis e algumas soluções.
Caminhos
Problemas:
Limite de comprimento: o comprimento máximo do caminho é de 259 caracteres.
Embora o Windows também ofereça suporte a caminhos mais longos (até 32.767 caracteres), muitos programas são criados com o limite inferior.
Tenha isso em mente sobre os programas executados nas ações.
Diretório de trabalho: também é limitado a 259 caracteres.
Os processos não podem
cd
em um diretório com mais de 259 caracteres.Diferenciação entre maiúsculas e minúsculas: os caminhos do Windows não diferenciam maiúsculas de minúsculas, enquanto os caminhos do Unix diferenciam.
Tenha isso em mente ao criar linhas de comando para ações.
Separadores de caminho: são o caractere de barra invertida (
\`), not forward slash (
/`).O Bazel armazena caminhos no estilo Unix com separadores
/
. Embora alguns programas do Windows ofereçam suporte a caminhos no estilo Unix, outros não. Alguns comandos integrados no cmd.exe oferecem suporte a eles, outros não.É melhor sempre usar
\` separators on Windows: replace
/with
ao criar linhas de comando e variáveis de ambiente para ações.Caminhos absolutos: não começam com barra (
/
).Os caminhos absolutos no Windows começam com uma letra de unidade, como
C:\foo\bar.txt
. Não há uma única raiz do sistema de arquivos.Tenha isso em mente se a regra verificar se um caminho é absoluto. Os caminhos absolutos devem ser evitados, já que muitas vezes não são portáveis.
Soluções:
Mantenha os caminhos curtos.
Evite nomes de diretório longos, estruturas de diretório profundamente aninhadas, nomes de arquivo longos, nomes de espaço de trabalho longos e nomes de destino longos.
Todos esses elementos podem se tornar componentes de caminho dos arquivos de entrada de ações e esgotar o limite de comprimento do caminho.
Use uma raiz de saída curta.
Use a flag
--output_user_root=<path>
para especificar um caminho curto para saídas do Bazel. Uma boa ideia é ter uma unidade (ou unidade virtual) apenas para saídas do Bazel (como o arquivoD:\`), and adding this line to your
.bazelrc):build --output_user_root=D:/
ou
build --output_user_root=C:/_bzl
Use cruzamentos.
As junções são, em termos gerais, links simbólicos de diretório[1]. As junções são fáceis de criar e podem apontar para diretórios (no mesmo computador) com caminhos longos. Se uma ação de build criar uma junção com um caminho curto, mas o destino for longo, as ferramentas com limite de caminho curto poderão acessar os arquivos no diretório de junção.
Em arquivos
.bat
ou em cmd.exe, é possível criar junções assim:mklink /J c:\path\to\junction c:\path\to\very\long\target\path
[1]: estritamente falando, as junções não são links simbólicos, mas, para as ações de build, você pode considerar as junções como links simbólicos de diretório.
Substitua
/
por "" em caminhos em actions / envvars.Ao criar a linha de comando ou as variáveis de ambiente para uma ação, faça os caminhos no estilo do Windows. Exemplo:
def as_path(p, is_windows): if is_windows: return p.replace("/", "\\") else: return p
Variáveis de ambiente
Problemas:
Diferenciação entre maiúsculas e minúsculas: os nomes de variáveis de ambiente do Windows não diferenciam maiúsculas de minúsculas.
Por exemplo, em Java,
System.getenv("SystemRoot")
eSystem.getenv("SYSTEMROOT")
produzem o mesmo resultado. Isso também se aplica a outros idiomas.Hermeticity: as ações precisam usar o mínimo possível de variáveis de ambiente personalizadas.
As variáveis de ambiente fazem parte da chave de cache da ação. Se uma ação usa variáveis de ambiente que mudam com frequência ou são personalizadas para os usuários, a regra fica menos armazenada em cache.
Soluções:
Use apenas nomes de variáveis de ambiente em maiúsculas.
Isso funciona no Windows, macOS e Linux.
Minimize os ambientes de ação.
Ao usar
ctx.actions.run
, defina o ambiente comoctx.configuration.default_shell_env
. Se a ação precisar de mais variáveis de ambiente, coloque todas em um dicionário e transmita-as para a ação. Exemplo:load("@bazel_skylib//lib:dicts.bzl", "dicts") def _make_env(ctx, output_file, is_windows): out_path = output_file.path if is_windows: out_path = out_path.replace("/", "\\") return dicts.add(ctx.configuration.default_shell_env, {"MY_OUTPUT": out_path})
Ações
Problemas:
Saídas executáveis: todos os arquivos executáveis precisam ter uma extensão executável.
As extensões mais comuns são
.exe
(arquivos binários) e.bat
(scripts em lote).Os scripts de shell (
.sh
) NÃO são executáveis no Windows. Não é possível especificá-los comoexecutable
dectx.actions.run
. Os arquivos também não têm permissão+x
, então não é possível executar arquivos arbitrários como no Linux.Comandos Bash: para fins de portabilidade, evite executar comandos Bash diretamente em ações.
O Bash é amplamente utilizado em sistemas semelhantes ao Unix, mas geralmente não está disponível no Windows. O Bazel está dependendo cada vez menos do Bash (MSYS2). Portanto, no futuro, os usuários terão menos probabilidade de ter o MSYS2 instalado com o Bazel. Para facilitar o uso de regras no Windows, evite executar comandos do Bash em ações.
Finais de linha: o Windows usa CRLF (
\r\n
), e os sistemas semelhantes ao Unix usam LF (\n
).Tenha isso em mente ao comparar arquivos de texto. Preste atenção nas suas configurações do Git, especialmente nas terminações de linha ao fazer check-out ou confirmar. Consulte a configuração
core.autocrlf
do Git.
Soluções:
Use uma regra específica sem Bash.
native.genrule()
é um wrapper para comandos do Bash e é usado com frequência para resolver problemas simples, como copiar um arquivo ou gravar um arquivo de texto. Você pode evitar depender do Bash (e reinventar a roda): confira se o bazel-skylib tem uma regra específica para suas necessidades. Nenhum deles depende do Bash quando criado/testado no Windows.Exemplos de regras de build:
copy_file()
(source, documentação): copia um arquivo para outro lugar, tornando-o opcionalmente executávelwrite_file()
(source, documentation): grava um arquivo de texto com os finais de linha desejados (auto
,unix
ouwindows
), opcionalmente tornando-o executável (se for um script)run_binary()
(source, documentation): executa um binário (ou regra*_binary
) com entradas e saídas esperadas como uma ação de build. É um wrapper de regra de build paractx.actions.run
.native_binary()
(source, documentation): encapsula um binário nativo em uma regra*_binary
, que pode serbazel run
ou usada no atributotool
dorun_binary()
ou no atributotools
donative.genrule()
.
Exemplos de regras de teste:
diff_test()
(source, documentation): teste que compara o conteúdo de dois arquivos.native_test()
(source, documentation): encapsula um binário nativo em uma regra*_test
, que pode serbazel test
.
No Windows, use scripts
.bat
para tarefas triviais.Em vez de usar scripts
.sh
, você pode resolver tarefas triviais com scripts.bat
.Por exemplo, se você precisar de um script que não faça nada, imprima uma mensagem ou saia com um código de erro fixo, um arquivo
.bat
simples será suficiente. Se a regra retornar um provedorDefaultInfo()
, o campoexecutable
poderá se referir a esse arquivo.bat
no Windows.Como as extensões de arquivo não importam no macOS e no Linux, você pode usar
.bat
como a extensão, mesmo para scripts de shell.Arquivos
.bat
vazios não podem ser executados. Se você precisar de um script vazio, escreva um espaço nele.Use o Bash de maneira adequada.
Nas regras de build e teste do Starlark, use
ctx.actions.run_shell
para executar scripts e comandos do Bash como ações.Em macros do Starlark, envolva scripts e comandos do Bash em um
native.sh_binary()
ounative.genrule()
. O Bazel vai verificar se o Bash está disponível e executar o script ou comando pelo Bash.Nas regras do repositório Starlark, evite o Bash. No momento, o Bazel não oferece uma maneira de executar comandos Bash de maneira simples nas regras do repositório.
Como excluir arquivos
Problemas:
Não é possível excluir arquivos enquanto eles estão abertos.
Arquivos abertos não podem ser excluídos (por padrão), as tentativas resultam em erros "Acesso negado". Se não for possível excluir um arquivo, talvez um processo em execução ainda esteja aberto.
O diretório de trabalho de um processo em execução não pode ser excluído.
Os processos têm um identificador aberto para o diretório de trabalho, e o diretório não pode ser excluído até que o processo seja encerrado.
Soluções:
No código, tente fechar os arquivos com rapidez.
Em Java, use
try-with-resources
. Em Python, usewith open(...) as f:
. Em princípio, tente fechar as alças assim que possível.