Introducción
¿Es la primera vez que usas Bazel? Estás en el lugar correcto. Sigue este instructivo de First Build para obtener una introducción simplificada al uso de Bazel. En este instructivo, se definen los términos clave tal como se usan en el contexto de Bazel y se explican los conceptos básicos del flujo de trabajo de Bazel. Comenzarás con las herramientas que necesitas, y compilarás y ejecutarás tres proyectos con una complejidad cada vez mayor, y aprenderás cómo y por qué se vuelven más complejos.
Si bien Bazel es un sistema de compilación que admite compilaciones en varios lenguajes, en este instructivo, se usa un proyecto de C++ como ejemplo y se proporcionan los lineamientos generales y el flujo que se aplican a la mayoría de los lenguajes.
Tiempo estimado de finalización: 30 minutos.
Requisitos previos
Comienza por instalar Bazel, si aún no lo hiciste. En este instructivo, se usa Git para el control de código fuente, por lo que, para obtener mejores resultados, también instala Git.
A continuación, recupera el proyecto de ejemplo del repositorio de GitHub de Bazel ejecutando lo siguiente en la herramienta de línea de comandos que prefieras:
git clone https://github.com/bazelbuild/examples
El proyecto de muestra para este instructivo se encuentra en el directorio examples/cpp-tutorial
.
A continuación, puedes ver cómo se estructura:
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
Hay tres conjuntos de archivos, y cada uno representa una etapa de este instructivo. En la primera etapa, compilarás un solo destino que reside en un solo paquete. En la segunda etapa, compilarás un archivo binario y una biblioteca a partir de un solo paquete. En la tercera y última etapa, compilarás un proyecto con varios paquetes y lo compilarás con varios destinos.
Resumen: Introducción
Con la instalación de Bazel (y Git) y la clonación del repositorio para este instructivo, ya tienes la base para tu primera compilación con Bazel. Continúa con la siguiente sección para definir algunos términos y configurar tu espacio de trabajo.
Cómo comenzar
Configura el espacio de trabajo
Antes de compilar un proyecto, debes configurar su espacio de trabajo. Un lugar de trabajo es un directorio que contiene los archivos fuente de tu proyecto y los resultados de la compilación de Bazel. También contiene estos archivos importantes:
- El archivo
, que identifica el directorio y su contenido como un espacio de trabajo de Bazel y se encuentra en la raíz de la estructura de directorios del proyectoWORKSPACE
file - Uno o más archivos
, que le indican a Bazel cómo compilar diferentes partes del proyecto Un directorio dentro del espacio de trabajo que contiene un archivoBUILD
filesBUILD
es un paquete. (Más información sobre los paquetes más adelante en este instructivo).
En proyectos futuros, para designar un directorio como un espacio de trabajo de Bazel, crea un archivo vacío llamado WORKSPACE
en ese directorio. A los fines de este instructivo, ya hay un archivo WORKSPACE
en cada etapa.
NOTA: Cuando Bazel compila el proyecto, todas las entradas deben estar en el mismo espacio de trabajo. Los archivos que residen en diferentes espacios de trabajo son independientes entre sí, a menos que estén vinculados. En esta guía, encontrarás información más detallada sobre las reglas del espacio de trabajo.
Comprende el archivo BUILD
Un archivo BUILD
contiene varios tipos diferentes de instrucciones para Bazel. Cada archivo BUILD
requiere al menos una regla como un conjunto de instrucciones que le indica a Bazel cómo compilar los resultados deseados, como bibliotecas o archivos binarios ejecutables. Cada instancia de una regla de compilación en el archivo BUILD
se denomina destino y apunta a un conjunto específico de archivos fuente y dependencias.
Un destino también puede apuntar a otros destinos.
Consulta el archivo BUILD
en el directorio cpp-tutorial/stage1/main
:
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
)
En nuestro ejemplo, el destino hello-world
crea una instancia de cc_binary rule
integrado de Bazel.
La regla le indica a Bazel que compile un archivo binario ejecutable independiente a partir del archivo fuente hello-world.cc
sin dependencias.
Resumen: Introducción
Ahora ya conoces algunos términos clave y su significado en el contexto de este proyecto y de Bazel en general. En la siguiente sección, compilarás y probarás la etapa 1 del proyecto.
Etapa 1: Un solo objetivo, un solo paquete
Es hora de compilar la primera parte del proyecto. Para obtener una referencia visual, la estructura de la sección de la etapa 1 del proyecto es la siguiente:
examples
└── cpp-tutorial
└──stage1
├── main
│ ├── BUILD
│ └── hello-world.cc
└── WORKSPACE
Ejecuta el siguiente comando para ir al directorio cpp-tutorial/stage1
:
cd cpp-tutorial/stage1
Luego, ejecute el siguiente comando:
bazel build //main:hello-world
En la etiqueta de destino, la parte //main:
es la ubicación del archivo BUILD
en relación con la raíz del espacio de trabajo, y hello-world
es el nombre del destino en el archivo BUILD
.
Bazel produce algo similar a lo siguiente:
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
Acabas de compilar tu primer destino de Bazel. Bazel coloca los resultados de la compilación en el directorio bazel-bin
en la raíz del espacio de trabajo.
Ahora, prueba el objeto binario que acabas de compilar:
bazel-bin/main/hello-world
Esto genera un mensaje “Hello world
” impreso.
Este es el gráfico de dependencia de la etapa 1:
Resumen: Etapa 1
Ahora que completaste tu primera compilación, tienes una idea básica de cómo se estructura una compilación. En la siguiente etapa, agregarás complejidad con otro objetivo.
Etapa 2: Varios objetivos de compilación
Si bien un solo destino es suficiente para proyectos pequeños, es posible que desees dividir los proyectos más grandes en varios destinos y paquetes. Esto permite compilaciones incrementales rápidas, es decir, Bazel solo vuelve a compilar lo que cambió, y acelera tus compilaciones compilando varias partes de un proyecto a la vez. En esta etapa del instructivo, se agrega un destino, y en la siguiente, un paquete.
Este es el directorio con el que trabajarás en la etapa 2:
├──stage2
│ ├── main
│ │ ├── BUILD
│ │ ├── hello-world.cc
│ │ ├── hello-greet.cc
│ │ └── hello-greet.h
│ └── WORKSPACE
A continuación, observa el archivo BUILD
en el directorio 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",
],
)
Con este archivo BUILD
, Bazel primero compila la biblioteca hello-greet
(con el cc_library rule
integrado de Bazel) y, luego, el objeto binario hello-world
. El atributo deps
en el destino hello-world
le indica a Bazel que se requiere la biblioteca hello-greet
para compilar el objeto binario hello-world
.
Antes de compilar esta nueva versión del proyecto, debes cambiar los directorios y cambiar al directorio cpp-tutorial/stage2
ejecutando el siguiente comando:
cd ../stage2
Ahora puedes compilar el nuevo archivo binario con el siguiente comando conocido:
bazel build //main:hello-world
Una vez más, Bazel produce algo similar a lo siguiente:
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
Ahora puedes probar el objeto binario recién compilado, que devuelve otro “Hello world
”:
bazel-bin/main/hello-world
Si ahora modificas hello-greet.cc
y vuelves a compilar el proyecto, Bazel solo volverá a compilar ese archivo.
Si observas el gráfico de dependencias, puedes ver que hello-world
depende de una entrada adicional llamada hello-greet
:
Resumen: Etapa 2
Ahora compilaste el proyecto con dos destinos. El destino hello-world
compila un archivo fuente y depende de otro destino (//main:hello-greet
), que compila dos archivos fuente adicionales. En la siguiente sección, ve un paso más allá y agrega otro paquete.
Etapa 3: Varios paquetes
En esta siguiente etapa, se agrega otra capa de complicación y se compila un proyecto con varios paquetes. A continuación, observa la estructura y el contenido del directorio cpp-tutorial/stage3
:
└──stage3
├── main
│ ├── BUILD
│ ├── hello-world.cc
│ ├── hello-greet.cc
│ └── hello-greet.h
├── lib
│ ├── BUILD
│ ├── hello-time.cc
│ └── hello-time.h
└── WORKSPACE
Puedes ver que ahora hay dos subdirectorios y que cada uno contiene un archivo BUILD
. Por lo tanto, para Bazel, el espacio de trabajo ahora contiene dos paquetes: lib
y main
.
Echa un vistazo al archivo lib/BUILD
:
cc_library(
name = "hello-time",
srcs = ["hello-time.cc"],
hdrs = ["hello-time.h"],
visibility = ["//main:__pkg__"],
)
Y en el archivo 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",
],
)
El destino hello-world
en el paquete principal depende del destino hello-time
en el paquete lib
(por lo tanto, la etiqueta de destino es //lib:hello-time
). Bazel lo sabe a través del atributo deps
. Puedes ver esto reflejado en el gráfico de dependencias:
Para que la compilación se realice correctamente, haz que el destino //lib:hello-time
en lib/BUILD
sea explícitamente visible para los destinos en main/BUILD
con el atributo de visibilidad.
Esto se debe a que, de forma predeterminada, los destinos solo son visibles para otros destinos en el mismo archivo BUILD
. Bazel usa la visibilidad del destino para evitar problemas, como que las bibliotecas que contienen detalles de implementación se filtren en las APIs públicas.
Ahora, compila esta versión final del proyecto. Cambia al directorio cpp-tutorial/stage3
ejecutando el siguiente comando:
cd ../stage3
Ejecuta nuevamente el siguiente comando:
bazel build //main:hello-world
Bazel produce algo similar a lo siguiente:
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
Ahora, prueba el último objeto binario de este instructivo para obtener un mensaje Hello world
final:
bazel-bin/main/hello-world
Resumen: Etapa 3
Ahora, compilaste el proyecto como dos paquetes con tres destinos y comprendes las dependencias entre ellos, lo que te permite seguir adelante y compilar proyectos futuros con Bazel. En la siguiente sección, verás cómo continuar tu recorrido con Bazel.
Próximos pasos
Completaste tu primera compilación básica con Bazel, pero esto es solo el comienzo. Estos son algunos recursos más para seguir aprendiendo con Bazel:
- Para seguir enfocándote en C++, lee sobre los casos de uso de compilación de C++ comunes.
- Para comenzar a compilar otras aplicaciones con Bazel, consulta los instructivos para Java, aplicaciones para Android o aplicaciones para iOS.
- Para obtener más información sobre cómo trabajar con repositorios locales y remotos, consulta dependencias externas.
- Para obtener más información sobre otras reglas de Bazel, consulta esta guía de referencia.
¡Que disfrutes de la creación!