Introdução
Novo no Bazel? Você está no lugar certo. Siga este tutorial para ver uma introdução simplificada ao uso do Bazel. Neste tutorial, definimos os termos principais conforme usados no contexto do Bazel e mostramos as noções básicas do fluxo de trabalho do Bazel. Começando com as ferramentas necessárias, você criará e executará três projetos com maior complexidade e aprenderá como e por que eles ficam mais complexos.
Embora o Bazel seja um sistema de compilação compatível com compilações em várias linguagens, este tutorial usa um projeto C++ como exemplo e fornece as diretrizes e o fluxo gerais aplicáveis à 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 os melhores resultados, instale o Git também.
Em seguida, recupere o projeto de amostra do repositório do Bazel no GitHub executando o seguinte na ferramenta de linha de comando da sua preferência:
git clone https://github.com/bazelbuild/examples
O projeto de amostra deste tutorial está no diretório examples/cpp-tutorial
.
Veja abaixo como ela é estruturada:
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
Há três conjuntos de arquivos, cada um representando um cenário neste tutorial. Na primeira etapa, você criará um único destino residente em um único pacote. Na segunda etapa, você criará um binário e uma biblioteca a partir de um único pacote. Na terceira e última etapa, você vai criar um projeto com vários pacotes e vários destinos.
Resumo: Introdução
Ao instalar o Bazel (e o Git) e clonar o repositório para este tutorial, você estabeleceu 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.
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 projeto e as saídas de compilação do Bazel. Ele também contém estes arquivos significativos:
- O
, que identifica o diretório e seu conteúdo 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 partes diferentes do projeto. Um diretório no espaço de trabalho que contém um arquivoBUILD
filesBUILD
é um pacote. Veremos mais sobre os pacotes mais adiante neste tutorial.
Em projetos futuros, para designar um diretório como um espaço de trabalho do Bazel, crie um arquivo vazio chamado WORKSPACE
nesse diretório. Para este 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 residem em diferentes espaços de trabalho são independentes, a menos que estejam vinculados. Informações mais detalhadas sobre as regras de espaço de trabalho podem ser encontradas neste guia.
Entenda 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 compilação 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 autossuficiente a partir do arquivo de origem hello-world.cc
sem dependências.
Resumo: primeiros passos
Agora você conhece alguns termos importantes e o que eles significam no contexto deste projeto e no Bazel em geral. Na próxima seção, você criará e testará o Estágio 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 "Stage 1" do projeto é:
examples
└── cpp-tutorial
└──stage1
├── main
│ ├── BUILD
│ └── hello-world.cc
└── WORKSPACE
Execute o seguinte comando para mover para 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
relativo à raiz do espaço de trabalho, e hello-world
é o nome do 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 as saídas de compilação no diretório bazel-bin
na raiz do espaço de trabalho.
Agora, teste o binário recém-criado, que é:
bazel-bin/main/hello-world
Isso resultará em uma mensagem impressa de "Hello world
".
Este é o gráfico de dependência do Estágio 1:
Resumo: estágio 1
Agora que concluiu sua primeira compilação, você tem uma ideia básica de como uma versão é estruturada. Na próxima etapa, você adicionará complexidade ao adicionar outro destino.
Estágio 2: vários destinos de versão
Embora um único destino seja suficiente para projetos pequenos, convém dividir projetos maiores em vários destinos e pacotes. Isso permite builds incrementais rápidos, ou seja, o Bazel recria apenas o que foi alterado, e acelera as compilações criando várias partes de um projeto de uma só vez. Nesta etapa do tutorial, adicionamos um destino, e o próximo adiciona um pacote.
Este é o diretório no qual você está trabalhando para o Estágio 2:
├──stage2
│ ├── main
│ │ ├── BUILD
│ │ ├── hello-world.cc
│ │ ├── hello-greet.cc
│ │ └── hello-greet.h
│ └── WORKSPACE
Veja 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, é necessário alterar 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 conhecido:
bazel build //main:hello-world
Novamente, 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 recriar o projeto, o Bazel só recompilará esse arquivo.
Analisando o gráfico de dependência, é possível ver que hello-world
depende de uma entrada extra chamada hello-greet
:
Resumo: estágio 2
Você criou o projeto com dois destinos. O destino hello-world
cria um arquivo de origem e depende de outro destino (//main:hello-greet
), que cria dois arquivos de origem adicionais. Na próxima seção, avance um pouco mais e adicione outro pacote.
Estágio 3: vários pacotes
O próximo estágio adiciona outra camada de complicação e cria um projeto com
vários pacotes. Veja 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
Veja que 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
.
Confira o arquivo lib/BUILD
:
cc_library(
name = "hello-time",
srcs = ["hello-time.cc"],
hdrs = ["hello-time.h"],
visibility = ["//main:__pkg__"],
)
E 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
(portanto, o rótulo de destino //lib:hello-time
). O Bazel sabe disso por meio do atributo deps
. Isso é refletido no gráfico de dependência:
Para que a versão seja bem-sucedida, você torna o destino //lib:hello-time
em lib/BUILD
explicitamente visível para os destinos em main/BUILD
usando o atributo de visibilidade.
Isso ocorre porque, por padrão, os destinos só são visíveis para outros destinos no mesmo
arquivo BUILD
. O Bazel usa a visibilidade de destino para evitar problemas, como bibliotecas contendo 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 ver uma mensagem Hello world
final:
bazel-bin/main/hello-world
Resumo: estágio 3
Você criou o projeto como dois pacotes com três destinos e entende as dependências entre eles, o que permite a você avançar e criar projetos futuros com o Bazel. Na próxima seção, veja como continuar sua jornada no Bazel.
Próximas etapas
Você concluiu sua primeira compilação básica com o Bazel, mas isso é apenas o começo. Veja mais alguns recursos para continuar aprendendo com o Bazel:
- Para se concentrar em C++, leia sobre os casos de uso comuns de compilação em C++.
- Para começar a criar outros aplicativos com o Bazel, consulte os tutoriais do Java, do aplicativo para Android ou do aplicativo para 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.
Boa construção!