Instructivo de Bazel: Compila un proyecto de C++

Informar un problema Ver fuente . Por la noche · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Introducción

¿Es la primera vez que usas Bazel? Estás en el lugar correcto. Sigue este tutorial de primera compilación para ver una introducción simplificada al uso de Bazel. En este tutorial, se definen los términos clave, ya que se usan en el contexto de Bazel y te guía a través de los conceptos básicos de Bazel en el flujo de trabajo. Comenzando con las herramientas que necesitas, compilarás y ejecutarás tres proyectos cada vez más complejos y aprenderás cómo y por qué se vuelven más complejos.

Por otro lado, Bazel es un sistema de compilación que admite compilaciones de varios lenguajes. En este instructivo, se usa un proyecto de C++ como ejemplo. y proporciona las pautas generales y el flujo que se aplican a la mayoría de los lenguajes.

Tiempo estimado de finalización: 30 minutos

Requisitos previos

Primero, instala Bazel si aún no lo has hecho. que ya existe. En este instructivo, se usa Git para controlar el código fuente, por lo que obtendrás mejores resultados Instalar Git como en la nube.

A continuación, recupera el proyecto de ejemplo del repositorio de GitHub de Bazel ejecutando el siguiente en tu herramienta de línea de comandos preferida:

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, te mostramos cómo está estructurada:

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 en este instructivo. En la primera etapa, compilarás un solo destino que resida en un solo paquete. En la segunda etapa, compilar un objeto binario y una biblioteca a partir de un solo paquete. En En la tercera y última etapa, crearás un proyecto con varios paquetes y compilarla con varios destinos.

Resumen: Introducción

Cuando instalas Bazel (y Git) y clonas el repositorio para este instructivo, puedes ya que sentaste las bases para tu primera compilación con Bazel. Continuar al siguiente para definir algunos términos y configurar tu lugar de trabajo.

Cómo comenzar

Configura el espacio de trabajo

Antes de compilar un proyecto, debes configurar su lugar de trabajo. Un espacio de trabajo es un directorio que contiene los archivos fuente de tu proyecto y los resultados de la compilación de Bazel. Integra también contiene estos archivos significativos:

  • El WORKSPACE file , que identifica el directorio y su contenido como un espacio de trabajo de Bazel se aloja en la raíz de la estructura del directorio del proyecto.
  • Uno o más BUILD files , que le indican a Bazel cómo compilar diferentes partes del proyecto. R dentro del espacio de trabajo que contenga un archivo BUILD package. (Más información sobre paquetes más adelante en este instructivo).

En proyectos futuros, para designar un directorio como lugar de trabajo de Bazel, crea un archivo vacío llamado WORKSPACE en ese directorio. A los efectos 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 se encuentran en diferentes espacios de trabajo son independientes de entre sí, a menos que se vinculen. Puedes encontrar información más detallada sobre las reglas consulta esta guía.

Comprende el archivo BUILD

Un archivo BUILD contiene varios tipos diferentes de instrucciones para Bazel. Cada El archivo BUILD requiere al menos una regla como un conjunto de instrucciones, que le indica a Bazel cómo compilar los resultados deseados. como objetos binarios o bibliotecas ejecutables. Cada instancia de una regla de compilación del El archivo BUILD se denomina destino y apunta a un conjunto específico de archivos de origen y dependencias. Un objetivo también puede dirigir a otros destinos.

Observa 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 la interfaz cc_binary rule La regla le indica a Bazel que compile un binario ejecutable independiente desde el Archivo de origen hello-world.cc sin dependencias.

Resumen: cómo empezar

Ya conoces algunos términos clave y lo que significan en el contexto este proyecto y Bazel en general. En la próxima sección, compilarás y probarás Etapa 1 del proyecto.

Etapa 1: destino único, paquete único

Es hora de construir la primera parte del proyecto. Para tener una referencia visual, el estructura de la sección de la Etapa 1 del proyecto es:

examples
└── cpp-tutorial
    └──stage1
       ├── main
       │   ├── BUILD
       │   └── hello-world.cc
       └── WORKSPACE

Ejecuta el siguiente comando para moverte 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. relativa a la raíz del lugar de trabajo, y hello-world es el nombre del destino en el archivo BUILD.

Bazel produce algo que se ve de la siguiente manera:

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 las salidas de compilación en el bazel-bin en la raíz de la Workspace.

Ahora, prueba el objeto binario recién compilado, que es el siguiente:

bazel-bin/main/hello-world

Se mostrará un mensaje "Hello world" impreso.

Este es el gráfico de dependencias de la etapa 1:

El gráfico de dependencia de hello-world muestra un solo destino con un solo archivo de origen.

Resumen: etapa 1

Ahora que has completado tu primera construcción, tienes una idea básica de cómo está estructurado. En la siguiente etapa, agregarás complejidad agregando otra objetivo.

Etapa 2: múltiples destinos de compilación

Si bien un solo objetivo es suficiente para los proyectos pequeños, puede proyectos más grandes en múltiples objetivos y paquetes. Esto permite una rápida compilaciones incrementales (es decir, Bazel solo recompila lo que ha cambiado) y acelera tus construyen construyendo múltiples partes de un proyecto a la vez. Esta etapa del instructivo agrega un destino y el siguiente, un paquete.

Este es el directorio con el que estás trabajando para la etapa 2:

    ├──stage2
    │  ├── main
    │  │   ├── BUILD
    │  │   ├── hello-world.cc
    │  │   ├── hello-greet.cc
    │  │   └── hello-greet.h
    │  └── WORKSPACE

Observa el archivo BUILD en el directorio cpp-tutorial/stage2/main a continuación:

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 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 el hello-greet se requiere para compilar el objeto binario hello-world.

Antes de compilar esta nueva versión del proyecto, debes cambiar directorios y pasar al directorio cpp-tutorial/stage2 ejecutando lo siguiente:

cd ../stage2

Ahora puedes compilar el nuevo objeto binario con el siguiente comando que ya conoces:

bazel build //main:hello-world

Una vez más, Bazel produce algo que se ve de la siguiente manera:

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 muestra 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 dependencia, puedes ver que hello-world depende de una entrada adicional. llamado hello-greet:

El gráfico de dependencia de "hello-world" muestra los cambios de dependencia después de modificar el archivo.

Resumen: etapa 2

Ahora, compilaste el proyecto con dos destinos. Las compilaciones de destino hello-world un archivo fuente y depende de otro destino (//main:hello-greet), que compila dos archivos fuente adicionales. En la siguiente sección, ve más allá y agregar otro paquete.

Etapa 3: varios paquetes

En la siguiente etapa, se agrega otra capa de complicación y se compila un proyecto varios paquetes. Observa la estructura y el contenido de las 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 cada uno contiene un BUILD . Por lo tanto, para Bazel, el espacio de trabajo ahora contiene dos paquetes: lib y main

Observa el 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 objetivo hello-time en el paquete lib (de ahí la etiqueta de destino //lib:hello-time). Bazel sabe esto a través del atributo deps. Puedes ver esto reflejado en el modelo de dependencia gráfico:

El gráfico de dependencia de "hello-world" muestra cómo el destino en el paquete principal depende del objetivo en el paquete "lib".

Para que la compilación se realice correctamente, debes establecer el objetivo //lib:hello-time en lib/BUILD visibles de forma explícita para los destinos en main/BUILD mediante el atributo de visibilidad. Esto se debe a que, de forma predeterminada, los destinos solo son visibles para otros objetivos del mismo BUILD. Bazel usa la visibilidad de destino para evitar problemas, como las bibliotecas. que contienen detalles de implementación que se filtran en APIs públicas.

Ahora, compila esta versión final del proyecto. Cambiar a cpp-tutorial/stage3 con lo siguiente:

cd  ../stage3

Una vez más, ejecuta el siguiente comando:

bazel build //main:hello-world

Bazel produce algo que se ve de la siguiente manera:

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 ver un mensaje Hello world final:

bazel-bin/main/hello-world

Resumen: etapa 3

Ya compilaste el proyecto como dos paquetes con tres objetivos y comprendes las dependencias entre ellos, lo que te equipa para avanzar y construir proyectos con Bazel. En la siguiente sección, descubra cómo continuar con el viaje de Bazel.

Próximos pasos

Ya completaste tu primera compilación básica con Bazel, pero esta es solo la comenzar. Estos son algunos recursos más para seguir aprendiendo con Bazel:

¡Feliz compilación!