Introdução
Nunca usou o Bazel? Você está no lugar certo. Siga este tutorial de primeiro build para uma introdução simplificada ao uso do Bazel. Neste tutorial, definimos os termos-chave à medida que são usados no contexto do Bazel e mostramos os conceitos básicos do fluxo de trabalho do Bazel. Começando com as ferramentas necessárias, você criará e executará três projetos com complexidade crescente e aprenderá como e por que eles se tornam mais complexos.
Embora o Bazel seja um sistema de build compatível com builds em várias linguagens, este tutorial usa um projeto C++ como exemplo e fornece as diretrizes gerais e o fluxo que se aplicam à maioria das linguagens.
Tempo estimado de conclusão: 30 minutos.
Pré-requisitos
Comece instalando o Bazel, caso ainda não tenha feito isso. Neste tutorial, usamos o Git para controle de origem. Portanto, para ter melhores resultados, instale o Git.
Em seguida, recupere o projeto de amostra do repositório GitHub do Bazel executando o seguinte na ferramenta de linha de comando de sua escolha:
git clone https://github.com/bazelbuild/examples
O projeto de amostra deste tutorial está no diretório examples/cpp-tutorial
.
Veja abaixo como ele é estruturado:
examples
└── cpp-tutorial
├──stage1
│ ├── main
│ │ ├── BUILD
│ │ └── hello-world.cc
│ └── WORKSPACE
├──stage2
│ ├── main
│ │ ├── BUILD
│ │ ├── hello-world.cc
│ │ ├── hello-greet.cc
│ │ └── hello-greet.h
│ └── WORKSPACE
└──stage3
├── main
│ ├── BUILD
│ ├── hello-world.cc
│ ├── hello-greet.cc
│ └── hello-greet.h
├── lib
│ ├── BUILD
│ ├── hello-time.cc
│ └── hello-time.h
└── WORKSPACE
Existem três conjuntos de arquivos, e cada um deles representa um estágio neste tutorial. Na primeira etapa, você vai criar um único destino que reside em um único pacote. Na segunda etapa, você criará um binário e uma biblioteca com um único pacote. No terceiro e último estágio, você vai criar um projeto com vários pacotes e com vários destinos.
Resumo: introdução
Ao instalar o Bazel (e o Git) e clonar o repositório deste tutorial, você criou a base para sua primeira compilação com o Bazel. Continue na próxima seção para definir alguns termos e configurar seu espaço de trabalho.
Como começar
Configurar o espaço de trabalho
Antes de criar um projeto, você precisa configurar o espaço de trabalho dele. Um espaço de trabalho é um diretório que contém os arquivos de origem do seu projeto e as saídas de build do Bazel. Ele também contém estes arquivos importantes:
- O
, que identifica o diretório e o conteúdo dele como um espaço de trabalho do Bazel e reside na raiz da estrutura de diretórios do projeto.WORKSPACE
file - Um ou mais
, que informam ao Bazel como criar diferentes partes do projeto. Um diretório no espaço de trabalho que contém um arquivoBUILD
filesBUILD
é um pacote (link em inglês). Vamos falar mais sobre pacotes posteriormente neste tutorial.
Em projetos futuros, para designar um diretório como espaço de trabalho do Bazel, crie um
arquivo vazio chamado WORKSPACE
nesse diretório. Para os fins deste tutorial,
um arquivo WORKSPACE
já está presente em cada estágio.
OBSERVAÇÃO: quando o Bazel cria o projeto, todas as entradas precisam estar no mesmo espaço de trabalho. Os arquivos que estão em espaços de trabalho diferentes são independentes uns dos outros, a menos que estejam vinculados. Veja informações mais detalhadas sobre as regras do espaço de trabalho neste guia.
Noções básicas sobre o arquivo BUILD
Um arquivo BUILD
contém vários tipos diferentes de instruções para o Bazel. Cada arquivo BUILD
requer pelo menos uma regra como um conjunto de instruções, que informa ao Bazel como criar as saídas desejadas, como binários ou bibliotecas executáveis. Cada instância de uma regra de build no
arquivo BUILD
é chamada de destino
e aponta para um conjunto específico de arquivos de origem e dependências.
Um destino também pode apontar para outros destinos.
Observe o arquivo BUILD
no diretório cpp-tutorial/stage1/main
:
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
)
No nosso exemplo, o destino hello-world
instancia o cc_binary rule
integrado do Bazel.
A regra diz ao Bazel para criar um binário executável independente do
arquivo de origem hello-world.cc
sem dependências.
Resumo: como começar
Agora você está familiarizado com alguns termos-chave e o que eles significam no contexto deste projeto e no Bazel em geral. Na próxima seção, você vai criar e testar a fase 1 do projeto.
Estágio 1: destino único, pacote único
É hora de criar a primeira parte do projeto. Para uma referência visual, a estrutura da seção da Fase 1 do projeto é:
examples
└── cpp-tutorial
└──stage1
├── main
│ ├── BUILD
│ └── hello-world.cc
└── WORKSPACE
Execute o comando a seguir para acessar o diretório cpp-tutorial/stage1
:
cd cpp-tutorial/stage1
Depois execute:
bazel build //main:hello-world
No rótulo de destino, a parte //main:
é o local do arquivo BUILD
em relação à raiz do espaço de trabalho, e hello-world
é o nome de destino no arquivo BUILD
.
O Bazel produz algo parecido com isto:
INFO: Found 1 target...
Target //main:hello-world up-to-date:
bazel-bin/main/hello-world
INFO: Elapsed time: 2.267s, Critical Path: 0.25s
Você acabou de criar seu primeiro destino do Bazel. O Bazel coloca saídas de build no diretório
bazel-bin
na raiz do
espaço de trabalho.
Agora, teste seu binário recém-criado, que é:
bazel-bin/main/hello-world
O resultado é a mensagem "Hello world
" impressa.
Aqui está o gráfico de dependência do Estágio 1:
Resumo: etapa 1
Agora que você concluiu seu primeiro build, tem uma ideia básica de como ele é estruturado. Na próxima etapa, você aumentará a complexidade adicionando outro destino.
Estágio 2: vários destinos de build
Um único destino é suficiente para projetos pequenos, mas convém dividir projetos maiores em vários destinos e pacotes. Isso permite builds incrementais rápidos, ou seja, o Bazel apenas recria o que foi alterado e acelera os builds criando várias partes de um projeto de uma só vez. Esta etapa do tutorial adiciona um destino e o próximo, um pacote.
Este é o diretório com que você vai trabalhar para o Estágio 2:
├──stage2
│ ├── main
│ │ ├── BUILD
│ │ ├── hello-world.cc
│ │ ├── hello-greet.cc
│ │ └── hello-greet.h
│ └── WORKSPACE
Observe abaixo o arquivo BUILD
no diretório cpp-tutorial/stage2/main
:
cc_library(
name = "hello-greet",
srcs = ["hello-greet.cc"],
hdrs = ["hello-greet.h"],
)
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
deps = [
":hello-greet",
],
)
Com esse arquivo BUILD
, o Bazel primeiro cria a biblioteca hello-greet
(usando o cc_library rule
integrado do Bazel)
e, em seguida, o binário hello-world
. O atributo deps
no
destino hello-world
informa ao Bazel que a biblioteca hello-greet
é necessária para criar o binário hello-world
.
Antes de criar essa nova versão do projeto, você precisa mudar
os diretórios, alternando para o diretório cpp-tutorial/stage2
executando:
cd ../stage2
Agora você pode criar o novo binário usando o seguinte comando familiar:
bazel build //main:hello-world
Mais uma vez, o Bazel produz algo parecido com isto:
INFO: Found 1 target...
Target //main:hello-world up-to-date:
bazel-bin/main/hello-world
INFO: Elapsed time: 2.399s, Critical Path: 0.30s
Agora você pode testar o binário recém-criado, que retorna outro "Hello world
":
bazel-bin/main/hello-world
Se você modificar hello-greet.cc
e recompilar o projeto, o Bazel apenas vai recompilar
esse arquivo.
No gráfico de dependência, observe que hello-world
depende de uma entrada extra
chamada hello-greet
:
Resumo: etapa 2
Você acabou de criar o projeto com dois destinos. O destino hello-world
cria
um arquivo de origem e depende de outro destino (//main:hello-greet
), que
cria mais dois arquivos de origem. Na próxima seção, dê um passo adiante
e adicione outro pacote.
Estágio 3: vários pacotes
Essa próxima etapa vai adicionar outra camada de complicação e criar um projeto com
vários pacotes. Observe abaixo a estrutura e o conteúdo do diretório cpp-tutorial/stage3
:
└──stage3
├── main
│ ├── BUILD
│ ├── hello-world.cc
│ ├── hello-greet.cc
│ └── hello-greet.h
├── lib
│ ├── BUILD
│ ├── hello-time.cc
│ └── hello-time.h
└── WORKSPACE
Agora há dois subdiretórios e cada um contém um arquivo
BUILD
. Portanto, para o Bazel, o espaço de trabalho agora contém dois pacotes: lib
e
main
.
Dê uma olhada no arquivo lib/BUILD
:
cc_library(
name = "hello-time",
srcs = ["hello-time.cc"],
hdrs = ["hello-time.h"],
visibility = ["//main:__pkg__"],
)
No arquivo main/BUILD
:
cc_library(
name = "hello-greet",
srcs = ["hello-greet.cc"],
hdrs = ["hello-greet.h"],
)
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
deps = [
":hello-greet",
"//lib:hello-time",
],
)
O destino hello-world
no pacote principal depende do destino hello-time
no pacote lib
(por isso o rótulo de destino //lib:hello-time
). O Bazel sabe
isso pelo atributo deps
. Observe isso refletido no gráfico
de dependências:
Para que o build tenha sucesso, torne o destino //lib:hello-time
em lib/BUILD
explicitamente visível para destinos em main/BUILD
usando o atributo de visibilidade.
Isso ocorre porque, por padrão, os destinos ficam visíveis apenas para outros destinos no mesmo
arquivo BUILD
. Ele usa a visibilidade do destino para evitar problemas, como bibliotecas
com detalhes de implementação que vazam para APIs públicas.
Agora, crie esta versão final do projeto. Alterne para o diretório cpp-tutorial/stage3
executando:
cd ../stage3
Mais uma vez, execute o seguinte comando:
bazel build //main:hello-world
O Bazel produz algo parecido com isto:
INFO: Found 1 target...
Target //main:hello-world up-to-date:
bazel-bin/main/hello-world
INFO: Elapsed time: 0.167s, Critical Path: 0.00s
Agora teste o último binário deste tutorial para uma mensagem Hello world
final:
bazel-bin/main/hello-world
Resumo: etapa 3
Você criou o projeto como dois pacotes com três destinos e entendeu as dependências entre eles, o que permite criar projetos futuros com o Bazel. Na próxima seção, dê uma olhada em como continuar sua jornada do Bazel.
Próximas etapas
Você concluiu sua primeira compilação básica com o Bazel, mas este é apenas o início. Estes são mais alguns recursos para continuar aprendendo com o Bazel:
- Para continuar se concentrando no C++, leia sobre os casos de uso comuns de build do C++.
- Para começar a criar outros aplicativos com o Bazel, consulte os tutoriais para Java, app Android ou iOS.
- Para saber mais sobre como trabalhar com repositórios locais e remotos, leia sobre dependências externas.
- Para saber mais sobre as outras regras do Bazel, consulte este guia de referência.
Divirta-se!