Aquí encontrarás algunos de los casos de uso más comunes para compilar proyectos de C++ con Bazel. Si aún no lo hiciste, completa el instructivo Introducción a Bazel: Compila un proyecto de C++ para comenzar a compilar proyectos de C++ con Bazel.
Para obtener información sobre los archivos de encabezado cc_library y hdrs, consulta cc_library.
Cómo incluir varios archivos en un destino
Puedes incluir varios archivos en un solo destino con glob. Por ejemplo:
cc_library(
name = "build-all-the-files",
srcs = glob(["*.cc"]),
hdrs = glob(["*.h"]),
)
Con este destino, Bazel compilará todos los archivos .cc
y .h
que encuentre en el
mismo directorio que el archivo BUILD
que contiene este destino (excepto
los subdirectorios).
Usa inclusiones transitivas
Si un archivo incluye un encabezado, cualquier regla con ese archivo como fuente (es decir, tener ese archivo en los atributos srcs
, hdrs
o textual_hdrs
) debe depender de la regla de la biblioteca del encabezado incluido. Por el contrario, solo las dependencias directas deben especificarse como dependencias. Por ejemplo, supongamos que sandwich.h
incluye bread.h
y que bread.h
incluye flour.h
. sandwich.h
no incluye flour.h
(¿quién quiere hacer un sándwich de harina?), por lo que el archivo BUILD
se vería de la siguiente manera:
cc_library(
name = "sandwich",
srcs = ["sandwich.cc"],
hdrs = ["sandwich.h"],
deps = [":bread"],
)
cc_library(
name = "bread",
srcs = ["bread.cc"],
hdrs = ["bread.h"],
deps = [":flour"],
)
cc_library(
name = "flour",
srcs = ["flour.cc"],
hdrs = ["flour.h"],
)
Aquí, la biblioteca sandwich
depende de la biblioteca bread
, que depende de la biblioteca flour
.
Cómo agregar rutas de inclusión
En ocasiones, no puedes (o no deseas) incluir rutas de acceso de inclusión en la raíz del lugar de trabajo. Es posible que las bibliotecas existentes ya tengan un directorio de inclusión que no coincide con la ruta de acceso en tu lugar de trabajo. Por ejemplo, supongamos que tienes la siguiente estructura de directorio:
└── my-project
├── legacy
│ └── some_lib
│ ├── BUILD
│ ├── include
│ │ └── some_lib.h
│ └── some_lib.cc
└── WORKSPACE
Bazel espera que some_lib.h
se incluya como legacy/some_lib/include/some_lib.h
, pero supongamos que some_lib.cc
incluye "some_lib.h"
. Para que esa ruta de acceso sea válida, legacy/some_lib/BUILD
deberá especificar que el directorio some_lib/include
es un directorio de inclusión:
cc_library(
name = "some_lib",
srcs = ["some_lib.cc"],
hdrs = ["include/some_lib.h"],
copts = ["-Ilegacy/some_lib/include"],
)
Esto es muy útil para las dependencias externas, ya que sus archivos de encabezado se deben incluir con un prefijo /
.
Incluye bibliotecas externas
Supongamos que usas Google Test.
Puedes usar una de las funciones del repositorio en el archivo WORKSPACE
para
descargar Google Test y hacer que esté disponible en tu repositorio:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "gtest",
url = "https://github.com/google/googletest/archive/release-1.10.0.zip",
sha256 = "94c634d499558a76fa649edb13721dce6e98fb1e7018dfaeba3cd7a083945e91",
build_file = "@//:gtest.BUILD",
)
Luego, crea gtest.BUILD
, un archivo BUILD
que se usa para compilar la prueba de Google.
Google Test tiene varios requisitos “especiales” que hacen que su regla cc_library
sea más complicada:
googletest-release-1.10.0/src/gtest-all.cc
establece#include
para todos los demás archivos engoogletest-release-1.10.0/src/
: exclúyelos de la compilación para evitar errores de vínculos por símbolos duplicados.Usa archivos de encabezado relacionados con el directorio
googletest-release-1.10.0/include/
("gtest/gtest.h"
), por lo que debes agregarlo a las rutas de inclusión.Debe vincularse a
pthread
, así que agrégalo comolinkopt
.
Por lo tanto, la regla final se ve de la siguiente manera:
cc_library(
name = "main",
srcs = glob(
["googletest-release-1.10.0/src/*.cc"],
exclude = ["googletest-release-1.10.0/src/gtest-all.cc"]
),
hdrs = glob([
"googletest-release-1.10.0/include/**/*.h",
"googletest-release-1.10.0/src/*.h"
]),
copts = [
"-Iexternal/gtest/googletest-release-1.10.0/include",
"-Iexternal/gtest/googletest-release-1.10.0"
],
linkopts = ["-pthread"],
visibility = ["//visibility:public"],
)
Esto es un poco desordenado: todo tiene el prefijo googletest-release-1.10.0
como un subproducto de la estructura del archivo. Para hacer que http_archive
quite este prefijo, agrega el atributo strip_prefix
:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "gtest",
url = "https://github.com/google/googletest/archive/release-1.10.0.zip",
sha256 = "94c634d499558a76fa649edb13721dce6e98fb1e7018dfaeba3cd7a083945e91",
build_file = "@//:gtest.BUILD",
strip_prefix = "googletest-release-1.10.0",
)
Entonces, gtest.BUILD
se vería de la siguiente manera:
cc_library(
name = "main",
srcs = glob(
["src/*.cc"],
exclude = ["src/gtest-all.cc"]
),
hdrs = glob([
"include/**/*.h",
"src/*.h"
]),
copts = ["-Iexternal/gtest/include"],
linkopts = ["-pthread"],
visibility = ["//visibility:public"],
)
Ahora las reglas de cc_
pueden depender de @gtest//:main
.
Cómo escribir y ejecutar pruebas de C++
Por ejemplo, puedes crear un ./test/hello-test.cc
de prueba como el siguiente:
#include "gtest/gtest.h"
#include "main/hello-greet.h"
TEST(HelloTest, GetGreet) {
EXPECT_EQ(get_greet("Bazel"), "Hello Bazel");
}
Luego, crea el archivo ./test/BUILD
para tus pruebas:
cc_test(
name = "hello-test",
srcs = ["hello-test.cc"],
copts = ["-Iexternal/gtest/include"],
deps = [
"@gtest//:main",
"//main:hello-greet",
],
)
A fin de que hello-greet
sea visible para hello-test
, debes agregar "//test:__pkg__",
al atributo visibility
en ./main/BUILD
.
Ahora puedes usar bazel test
para ejecutar la prueba.
bazel test test:hello-test
Esto produce el siguiente resultado:
INFO: Found 1 test target...
Target //test:hello-test up-to-date:
bazel-bin/test/hello-test
INFO: Elapsed time: 4.497s, Critical Path: 2.53s
//test:hello-test PASSED in 0.3s
Executed 1 out of 1 tests: 1 test passes.
Agrega dependencias a bibliotecas precompiladas
Si deseas usar una biblioteca de la que solo tienes una versión compilada (por ejemplo, encabezados y un archivo .so
), únela en una regla cc_library
:
cc_library(
name = "mylib",
srcs = ["mylib.so"],
hdrs = ["mylib.h"],
)
De esta manera, otros destinos de C++ en tu lugar de trabajo pueden depender de esta regla.