Casos de uso comunes de compilación de C++

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

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, comienza a compilar C++. proyectos con Bazel completando el instructivo Introducción a Bazel: compila un proyecto de C++.

Para obtener más 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 (sin incluir subdirectorios).

Cómo usar inclusiones transitivas

Si un archivo incluye un encabezado, entonces, cualquier regla con ese archivo como fuente (es decir, tener ese archivo en el atributo srcs, hdrs o textual_hdrs) debe dependerá de la regla de biblioteca de encabezados incluidos. Por el contrario, solo los las dependencias deben especificarse como dependencias. Por ejemplo, supongamos sandwich.h incluye bread.h y bread.h incluye flour.h. sandwich.h no incluye flour.h (¿quién quiere harina en su sándwich?), por lo tanto, el BUILD archivo se vería así:

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 en la biblioteca flour.

Agrega rutas de inclusión

En ocasiones, no puedes (o no deseas) incluir rutas de acceso en el lugar de trabajo raíz. Puede que las bibliotecas existentes ya tengan un directorio de inclusión coincida con la ruta en tu lugar de trabajo. Por ejemplo, supongamos que tienes lo siguiente del directorio principal:

└── my-project
    ├── legacy
    │   └── some_lib
    │       ├── BUILD
    │       ├── include
    │       │   └── some_lib.h
    │       └── some_lib.cc
    └── WORKSPACE

Bazel esperará que se incluya some_lib.h como legacy/some_lib/include/some_lib.h, pero supongamos que some_lib.cc incluye "some_lib.h" Para que la ruta de inclusión sea válida, legacy/some_lib/BUILD deberá especificar que 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 especialmente útil para dependencias externas, ya que sus archivos de encabezado De lo contrario, debe incluirse con un prefijo /.

Incluye bibliotecas externas

Supongamos que usas Google Test. Puedes usar una de las funciones del repositorio del archivo WORKSPACE para descarga Google Test y haz 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 Google Test. Google Test tiene varias funciones requisitos que exigen la regla cc_library más complicados:

  • googletest-release-1.10.0/src/gtest-all.cc #includes el resto archivos en googletest-release-1.10.0/src/: exclúyelo de la compilar para evitar errores de vínculo debido a símbolos duplicados.

  • Utiliza archivos de encabezado relacionados con el googletest-release-1.10.0/include/ ("gtest/gtest.h"), por lo que debes y agregarás ese directorio a las rutas de inclusión.

  • Debe vincularse en pthread, así que agrégalo como linkopt.

Por lo tanto, la regla final se verá 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 subproducto de la estructura del archivo. Puedes crear una barra para http_archive este prefijo agregando 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",
)

Luego, 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 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:

#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",
    ],
)

Para que hello-test pueda ver hello-greet, debes agregar "//test:__pkg__", para el 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.

Cómo agregar dependencias en bibliotecas previamente compiladas

Si quieres usar una biblioteca de la cual solo tengas una versión compilada (para ejemplo, encabezados y un archivo .so) lo unen 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.