Lista de discussão: bazel-go-discuss
Slack: #vá no Bazel Slack, #bazel no Go Slack
As regras estão em fase beta de desenvolvimento. Eles apoiam:
Atualmente, eles não oferecem suporte ou têm suporte limitado para:
As regras Go são testadas e suportadas nas seguintes plataformas host:
Os usuários relataram sucesso em diversas outras plataformas, mas as regras só são testadas nas listadas acima.
Nota: Desde a versão v0.38.0, regras_go requer Bazel ≥ 5.4.0 para funcionar.
O branch master
só funciona com a versão mais recente do Bazel.
Para construir código Go com Bazel, você precisará de:
patch
, cat
e algumas outras ferramentas Unix em PATH
.Normalmente você não precisará de um conjunto de ferramentas Go instalado. Bazel fará o download de um.
Consulte Usando regras_go no Windows para obter instruções de configuração específicas do Windows. Várias ferramentas adicionais precisam ser instaladas e configuradas.
Se você estiver usando o novo sistema de gerenciamento de dependências externas do Bazel, Bzlmod, consulte o guia Go with Bzlmod dedicado.
Crie um arquivo no topo do seu repositório chamado WORKSPACE
e adicione o snippet abaixo (ou adicione ao seu WORKSPACE
existente). Isso diz ao Bazel para buscar regras_go e suas dependências. O Bazel fará o download de um conjunto de ferramentas Go compatível recentemente e o registrará para uso.
load ( "@bazel_tools//tools/build_defs/repo:http.bzl" , "http_archive" )
http_archive (
name = "io_bazel_rules_go" ,
integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=" ,
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" ,
"https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" ,
],
)
load ( "@io_bazel_rules_go//go:deps.bzl" , "go_register_toolchains" , "go_rules_dependencies" )
go_rules_dependencies ()
go_register_toolchains ( version = "1.23.1" )
Você pode usar regras_go no master
usando git_repository em vez de http_archive e apontando para um commit recente.
Adicione um arquivo chamado BUILD.bazel
no diretório raiz do seu projeto. Você precisará de um arquivo de compilação em cada diretório com código Go, mas também precisará de um no diretório raiz, mesmo que seu projeto não tenha código Go lá. Para um binário "Hello, world", o arquivo deve ficar assim:
load ( "@io_bazel_rules_go//go:def.bzl" , "go_binary" )
go_binary (
name = "hello" ,
srcs = [ "hello.go" ],
)
Você pode construir este alvo com bazel build //:hello
.
Se o seu projeto puder ser compilado com go build
, você poderá gerar e atualizar seus arquivos de compilação automaticamente usando o gazelle.
Adicione o repositório bazel_gazelle
e suas dependências ao seu WORKSPACE
. Deveria ficar assim:
load ( "@bazel_tools//tools/build_defs/repo:http.bzl" , "http_archive" ) http_archive ( name = "io_bazel_rules_go" , integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=" , urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" , "https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" , ], ) http_archive ( name = "bazel_gazelle" , integrity = "sha256-12v3pg/YsFBEQJDfooN6Tq+YKeEWVhjuNdzspcvfWNU=" , urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz" , "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz" , ], ) load ( "@io_bazel_rules_go//go:deps.bzl" , "go_register_toolchains" , "go_rules_dependencies" ) load ( "@bazel_gazelle//:deps.bzl" , "gazelle_dependencies" ) go_rules_dependencies () go_register_toolchains ( version = "1.23.1" ) gazelle_dependencies ()
Adicione o código abaixo ao arquivo BUILD.bazel
no diretório raiz do seu projeto. Substitua a string após prefix
por um prefixo de caminho de importação que corresponda ao seu projeto. Deve ser igual ao caminho do seu módulo, se você tiver um arquivo go.mod
.
load ( "@bazel_gazelle//:def.bzl" , "gazelle" )
# gazelle:prefix github.com/example/project
gazelle ( name = "gazelle" )
Isso declara uma regra binária gazelle
, que você pode executar usando o comando abaixo:
bazel run //:gazelle
Isso irá gerar um arquivo BUILD.bazel
com destinos go_library, go_binary e go_test para cada pacote em seu projeto. Você pode executar o mesmo comando no futuro para atualizar arquivos de compilação existentes com novos arquivos de origem, dependências e opções.
Se o seu projeto não segue as convenções go build
ou você prefere não usar o gazelle, você pode escrever os arquivos de build manualmente.
Em cada diretório que contém o código Go, crie um arquivo chamado BUILD.bazel
Adicione uma instrução load
na parte superior do arquivo para as regras que você usa.
load ( "@io_bazel_rules_go//go:def.bzl" , "go_binary" , "go_library" , "go_test" )
Para cada biblioteca, adicione uma regra go_library como a mostrada abaixo. Os arquivos de origem estão listados no atributo srcs
. Os pacotes importados fora da biblioteca padrão são listados no atributo deps
usando rótulos Bazel que se referem às regras go_library correspondentes. O caminho de importação da biblioteca deve ser especificado com o atributo importpath
.
go_library (
name = "foo_library" ,
srcs = [
"a.go" ,
"b.go" ,
],
importpath = "github.com/example/project/foo" ,
deps = [
"//tools" ,
"@org_golang_x_utils//stuff" ,
],
visibility = [ "//visibility:public" ],
)
Para testes, adicione uma regra go_test como esta abaixo. A biblioteca que está sendo testada deve ser listada em um atributo embed
.
go_test (
name = "foo_test" ,
srcs = [
"a_test.go" ,
"b_test.go" ,
],
embed = [ ":foo_lib" ],
deps = [
"//testtools" ,
"@org_golang_x_utils//morestuff" ,
],
)
Para binários, adicione uma regra go_binary como a mostrada abaixo.
go_binary (
name = "foo" ,
srcs = [ "main.go" ],
)
Para cada repositório Go, adicione uma regra go_repository ao WORKSPACE
como a mostrada abaixo. Esta regra vem do repositório Gazelle, então você precisará carregá-la. gazelle update-repos pode gerar ou atualizar essas regras automaticamente a partir de um arquivo go.mod ou Gopkg.lock.
load ( "@bazel_tools//tools/build_defs/repo:http.bzl" , "http_archive" )
# Download the Go rules.
http_archive (
name = "io_bazel_rules_go" ,
integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=" ,
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" ,
"https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" ,
],
)
# Download Gazelle.
http_archive (
name = "bazel_gazelle" ,
integrity = "sha256-12v3pg/YsFBEQJDfooN6Tq+YKeEWVhjuNdzspcvfWNU=" ,
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz" ,
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz" ,
],
)
# Load macros and repository rules.
load ( "@io_bazel_rules_go//go:deps.bzl" , "go_register_toolchains" , "go_rules_dependencies" )
load ( "@bazel_gazelle//:deps.bzl" , "gazelle_dependencies" , "go_repository" )
# Declare Go direct dependencies.
go_repository (
name = "org_golang_x_net" ,
importpath = "golang.org/x/net" ,
sum = "h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=" ,
version = "v0.23.0" ,
)
# Declare indirect dependencies and register toolchains.
go_rules_dependencies ()
go_register_toolchains ( version = "1.23.1" )
gazelle_dependencies ()
Para gerar código a partir de buffers de protocolo, você precisará adicionar uma dependência de com_google_protobuf
ao seu WORKSPACE
.
load ( "@bazel_tools//tools/build_defs/repo:http.bzl" , "http_archive" )
http_archive (
name = "com_google_protobuf" ,
sha256 = "535fbf566d372ccf3a097c374b26896fa044bf4232aef9cab37bd1cc1ba4e850" ,
strip_prefix = "protobuf-3.15.0" ,
urls = [
"https://mirror.bazel.build/github.com/protocolbuffers/protobuf/archive/v3.15.0.tar.gz" ,
"https://github.com/protocolbuffers/protobuf/archive/v3.15.0.tar.gz" ,
],
)
load ( "@com_google_protobuf//:protobuf_deps.bzl" , "protobuf_deps" )
protobuf_deps ()
Você precisará de um conjunto de ferramentas C/C++ registrado para a plataforma de execução (a plataforma onde o Bazel executa ações) para criar o protoc.
A regra proto_library é fornecida pelo repositório rules_proto
. protoc-gen-go
, o plugin do compilador proto Go, é fornecido pelo repositório com_github_golang_protobuf
. Ambos são declarados por go_rules_dependencies. Você não precisará declarar uma dependência explícita, a menos que queira usar especificamente uma versão diferente. Consulte Substituindo dependências para obter instruções sobre como usar uma versão diferente.
As dependências gRPC não são declaradas por padrão (há muitas). Você pode declará-los no WORKSPACE usando go_repository. Você pode querer usar gazelle update-repos para importá-los de go.mod
.
Consulte Dependências proto, dependências gRPC para obter mais informações. Consulte também Evitando conflitos.
Depois que todas as dependências forem registradas, você poderá declarar as regras proto_library e go_proto_library para gerar e compilar código Go a partir de arquivos .proto.
load ( "@rules_proto//proto:defs.bzl" , "proto_library" )
load ( "@io_bazel_rules_go//proto:def.bzl" , "go_proto_library" )
proto_library (
name = "foo_proto" ,
srcs = [ "foo.proto" ],
deps = [ "//bar:bar_proto" ],
visibility = [ "//visibility:public" ],
)
go_proto_library (
name = "foo_go_proto" ,
importpath = "github.com/example/protos/foo_proto" ,
protos = [ ":foo_proto" ],
visibility = [ "//visibility:public" ],
)
Um destino go_proto_library
pode ser importado e dependente como um go_library
normal.
Observe que versões recentes de regras_go suportam APIv1 ( github.com/golang/protobuf
) e APIv2 ( google.golang.org/protobuf
). Por padrão, o código é gerado com github.com/golang/protobuf/cmd/protoc-gen-gen
para compatibilidade com ambas as interfaces. O código do cliente pode importar usando uma biblioteca de tempo de execução ou ambas.
Ir
Buffers de protocolo
Dependências e testes
Sim, mas não diretamente.
regras_go invoca o compilador e vinculador Go diretamente, com base nos destinos descritos com go_binary e outras regras. O Bazel e o regras_go juntos desempenham a mesma função do comando go
, portanto, não é necessário usar o comando go
em um espaço de trabalho do Bazel.
Dito isto, geralmente ainda é uma boa ideia seguir as convenções exigidas pelo comando go
(por exemplo, um pacote por diretório, os caminhos dos pacotes correspondem aos caminhos dos diretórios). Ferramentas que não são compatíveis com o Bazel ainda funcionarão, e seu projeto poderá depender de projetos que não sejam do Bazel.
Se precisar usar o comando go
para executar tarefas que o Bazel não cobre (como adicionar uma nova dependência a go.mod
), você pode usar a seguinte invocação do Bazel para executar o binário go
do Go SDK configurado pelo Bazel:
bazel run @io_bazel_rules_go//go -- < args >
Prefira isso a executar go
diretamente, pois garante que a versão do Go seja idêntica àquela usada por regras_go.
Sim, mas não diretamente. O Bazel ignora os arquivos go.mod
e todas as dependências do pacote devem ser expressas por meio de atributos deps
nos destinos descritos com go_library e outras regras.
Você pode baixar um módulo Go em uma versão específica como um repositório externo usando go_repository, uma regra de espaço de trabalho fornecida pelo gazelle. Isso também irá gerar arquivos de construção usando o gazelle.
Você pode importar regras go_repository de um arquivo go.mod
usando gazelle update-repos.
Isso foi usado para manter os caminhos de importação consistentes em bibliotecas que podem ser construídas com go build
antes que o atributo importpath
estivesse disponível.
Para compilar e vincular corretamente, regras_go deve conhecer o caminho de importação do Go (a string pela qual um pacote pode ser importado) para cada biblioteca. Agora isso está definido explicitamente com o atributo importpath
. Antes de esse atributo existir, o caminho de importação era inferido concatenando uma string de uma regra go_prefix
especial e o nome do pacote e do rótulo da biblioteca. Por exemplo, se go_prefix
fosse github.com/example/project
, para uma biblioteca //foo/bar:bar
, regras_go inferiria o caminho de importação como github.com/example/project/foo/bar/bar
. A falha no final é incompatível com go build
, portanto, se o nome do rótulo fosse go_default_library
, o caminho de importação não o incluiria. Portanto, para a biblioteca //foo/bar:go_default_library
, o caminho de importação seria github.com/example/project/foo/bar
.
Como go_prefix
foi removido e o atributo importpath
tornou-se obrigatório (veja #721), o nome go_default_library
não serve mais para nenhum propósito. Podemos decidir parar de usá-lo no futuro (ver #265).
Você pode fazer compilação cruzada definindo o sinalizador --platforms
na linha de comando. Por exemplo:
$ bazel build --platforms=@io_bazel_rules_go//go/toolchain:linux_amd64 //cmd
Por padrão, o cgo está desabilitado durante a compilação cruzada. Para compilação cruzada com cgo, adicione um sufixo _cgo
à plataforma de destino. Você deve registrar um conjunto de ferramentas C/C++ de compilação cruzada com o Bazel para que isso funcione.
$ bazel build --platforms=@io_bazel_rules_go//go/toolchain:linux_amd64_cgo //cmd
Fontes específicas da plataforma com tags de construção ou sufixos de nome de arquivo são filtradas automaticamente em tempo de compilação. Você pode incluir seletivamente dependências específicas da plataforma com expressões select
(o Gazelle faz isso automaticamente).
go_library (
name = "foo" ,
srcs = [
"foo_linux.go" ,
"foo_windows.go" ,
],
deps = select ({
"@io_bazel_rules_go//go/platform:linux_amd64" : [
"//bar_linux" ,
],
"@io_bazel_rules_go//go/platform:windows_amd64" : [
"//bar_windows" ,
],
"//conditions:default" : [],
}),
)
Para construir um destino go_binary específico para uma plataforma de destino ou usar uma versão específica do Golang SDK, use a regra go_cross_binary. Isso é útil para produzir vários binários para diferentes plataformas em uma única compilação.
Para construir um destino go_test específico para uma plataforma de destino, defina os atributos goos
e goarch
nessa regra.
Você pode depender de forma equivalente de uma regra go_binary ou go_test por meio de uma transição de configuração do Bazel em //command_line_option:platforms
(há problemas com essa abordagem antes de regras_go 0.23.0).
O Bazel executa testes em uma sandbox, o que significa que os testes não têm acesso automático aos arquivos. Você deve incluir arquivos de teste usando o atributo data
. Por exemplo, se você quiser incluir tudo no diretório testdata
:
go_test (
name = "foo_test" ,
srcs = [ "foo_test.go" ],
data = glob ([ "testdata/**" ]),
importpath = "github.com/example/project/foo" ,
)
Por padrão, os testes são executados no diretório do arquivo de construção que os definiu. Observe que isso segue a convenção de testes Go, não a convenção Bazel seguida por outras linguagens, que são executadas na raiz do repositório. Isso significa que você pode acessar arquivos de teste usando caminhos relativos. Você pode alterar o diretório de teste usando o atributo rundir
. Consulte go_test.
O Gazelle adicionará automaticamente um atributo data
como o acima se você tiver um diretório testdata
, a menos que contenha arquivos .go edificáveis ou arquivos de construção; nesse caso, testdata
é tratado como um pacote normal.
Observe que no Windows, os arquivos de dados não estão diretamente disponíveis para testes, pois os arquivos de dados de teste dependem de links simbólicos e, por padrão, o Windows não permite que usuários sem privilégios criem links simbólicos. Você pode usar a biblioteca github.com/bazelbuild/rules_go/go/tools/bazel para acessar arquivos de dados.
O local onde go_binary
grava seu arquivo executável não é estável nas versões de regras_go e não deve ser dependente dele. O diretório pai inclui alguns dados de configuração em seu nome. Isso evita que o cache do Bazel seja envenenado quando o mesmo binário é criado em configurações diferentes. O nome base binário também pode depender da plataforma: no Windows, adicionamos uma extensão .exe.
Para depender de um executável em uma regra go_test
, faça referência ao executável no atributo data
(para torná-lo visível) e expanda o local em args
. A localização real será passada para teste na linha de comando. Por exemplo:
go_binary (
name = "cmd" ,
srcs = [ "cmd.go" ],
)
go_test (
name = "cmd_test" ,
srcs = [ "cmd_test.go" ],
args = [ "$(location :cmd)" ],
data = [ ":cmd" ],
)
Veja //tests/core/cross para um exemplo completo de teste que acessa um binário.
Alternativamente, você pode definir o atributo out
de go_binary para um nome de arquivo específico. Observe que quando out
estiver definido, o binário não será armazenado em cache ao alterar as configurações.
go_binary (
name = "cmd" ,
srcs = [ "cmd.go" ],
out = "cmd" ,
)
go_test (
name = "cmd_test" ,
srcs = [ "cmd_test.go" ],
data = [ ":cmd" ],
)
Consulte Evitando conflitos na documentação do proto.
Isto não é suportado. Ao usar go_proto_library com o compilador @io_bazel_rules_go//proto:go_grpc
, uma dependência implícita é adicionada em @org_golang_google_grpc//:go_default_library
. Se você vincular outra cópia do mesmo pacote em //vendor/google.golang.org/grpc:go_default_library
ou em qualquer outro lugar, poderá enfrentar conflitos em tempo de compilação ou execução.
Se você estiver usando o Gazelle com a geração de regras proto ativada, as importações de google.golang.org/grpc
serão resolvidas automaticamente para @org_golang_google_grpc//:go_default_library
para evitar conflitos. O gRPC vendido deve ser ignorado neste caso.
Se você precisar usar especificamente um pacote gRPC de fornecedor, é melhor evitar usar go_proto_library
completamente. Você pode fazer check-in de arquivos .pb.go pré-gerados e construí-los com regras go_library
. O Gazelle irá gerar essas regras quando a geração de regras proto estiver desabilitada (adicione # gazelle:proto disable_global
ao seu arquivo de compilação raiz).
Consulte Substituindo dependências para obter instruções sobre como substituir repositórios declarados em go_rules_dependencies.
Referências:
Para executar testes do Bazel no Travis CI, você precisará instalar o Bazel no script before_install
. Veja nosso arquivo de configuração no link acima.
Você desejará executar o Bazel com vários sinalizadores para evitar que ele consuma uma grande quantidade de memória no ambiente de teste.
--host_jvm_args=-Xmx500m --host_jvm_args=-Xms500m
: Defina o tamanho de heap JVM máximo e inicial. Manter o mesmo significa que a JVM não perderá tempo aumentando o heap. A escolha do tamanho do heap é um tanto arbitrária; outros arquivos de configuração recomendam limites de até 2.500 m. Valores mais altos significam uma construção mais rápida, mas maior risco de eliminação de OOM.--bazelrc=.test-bazelrc
: Use um arquivo de configuração do Bazel específico para Travis CI. Você pode colocar a maioria das opções restantes aqui.build --spawn_strategy=standalone --genrule_strategy=standalone
: Desative o sandbox para a compilação. O sandboxing pode falhar dentro dos contêineres do Travis porque a chamada do sistema mount
não é permitida.test --test_strategy=standalone
: desative o sandbox para testes também.--local_resources=1536,1.5,0.5
: Defina os limites do Bazel para RAM disponível em MB, núcleos disponíveis para computação e núcleos disponíveis para E/S. Valores mais altos significam uma construção mais rápida, mas maior contenção e risco de eliminação de OOM.--noshow_progress
: Suprime mensagens de progresso na saída para logs mais limpos.--verbose_failures
: Obtenha mensagens de falha mais detalhadas.--test_output=errors
: Mostra o teste stderr no log do Travis. Normalmente, a saída do teste são arquivos de log gravados que o Travis não salva ou relata. Os downloads no Travis são relativamente lentos (a rede é muito disputada), então você vai querer minimizar a quantidade de E/S de rede em sua construção. Baixar o Bazel e um Go SDK é uma grande parte disso. Para evitar o download de um Go SDK, você pode solicitar um contêiner com uma versão pré-instalada do Go em seu arquivo .travis.yml
e, em seguida, chamar go_register_toolchains(go_version = "host")
em um arquivo WORKSPACE
específico do Travis.
Você pode ficar tentado a colocar o cache do Bazel no cache do Travis. Embora isso possa acelerar significativamente sua construção, Travis armazena seu cache na Amazon e leva muito tempo para transferi-lo. Construções limpas parecem mais rápidas na prática.
regras_go oferece suporte apenas a versões oficiais do Go SDK. No entanto, você ainda pode testar versões beta e RC passando uma version
como "1.16beta1"
para go_register_toolchains. Consulte também go_download_sdk.
load ( "@io_bazel_rules_go//go:deps.bzl" , "go_register_toolchains" , "go_rules_dependencies" )
go_rules_dependencies ()
go_register_toolchains ( version = "1.17beta1" )