Casos de uso comuns de build C++

Informar um problema Mostrar fonte Por noite · 7,4 do Google. 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Aqui você encontra alguns dos casos de uso mais comuns para criar projetos C++ com o Bazel. Comece a criar em C++, caso ainda não tenha feito isso. projetos com o Bazel concluindo o tutorial Introdução ao Bazel: criar um projeto C++.

Para obter informações sobre os arquivos de cabeçalho cc_library e hdrs, consulte cc_library.

Como incluir vários arquivos em um destino

Você pode incluir vários arquivos em um único destino com glob. Exemplo:

cc_library(
    name = "build-all-the-files",
    srcs = glob(["*.cc"]),
    hdrs = glob(["*.h"]),
)

Com esse destino, o Bazel vai criar todos os arquivos .cc e .h encontrados no mesmo diretório do arquivo BUILD que contém esse destino (excluindo subdiretórios).

Usar inclusões transitivas

Se um arquivo incluir um cabeçalho, todas as regras com esse arquivo como origem (ou seja, ter esse arquivo no atributo srcs, hdrs ou textual_hdrs) deve dependem da regra da biblioteca do cabeçalho incluído. Por outro lado, apenas dependências diretas precisam ser especificadas como dependências. Por exemplo, suponha sandwich.h inclui bread.h e bread.h inclui flour.h. sandwich.h não inclui flour.h (quem quer farinha no sanduíche?), então BUILD ficaria assim:

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

Aqui, a biblioteca sandwich depende da biblioteca bread, que depende da biblioteca flour.

Como adicionar caminhos de inclusão

Às vezes, não é possível (ou você não quer) incluir caminhos na raiz do espaço de trabalho. As bibliotecas existentes podem já ter um diretório de inclusão que não corresponder ao caminho dela no espaço de trabalho. Por exemplo, suponha que você tenha o seguinte do diretório atual:

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

O Bazel espera que some_lib.h seja incluído como legacy/some_lib/include/some_lib.h, mas suponha que some_lib.cc inclua "some_lib.h". Para tornar esse caminho de inclusão válido, O legacy/some_lib/BUILD vai precisar especificar que o some_lib/include é um diretório de inclusão:

cc_library(
    name = "some_lib",
    srcs = ["some_lib.cc"],
    hdrs = ["include/some_lib.h"],
    copts = ["-Ilegacy/some_lib/include"],
)

Isso é muito útil para dependências externas, já que os arquivos principais precisam ser incluídos com um prefixo /.

Como incluir bibliotecas externas

Suponha que você esteja usando o Google Test. Você pode usar uma das funções do repositório no arquivo WORKSPACE para fazer o download do Google Test e disponibilizá-lo no repositório:

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

Em seguida, crie gtest.BUILD, um arquivo BUILD usado para compilar o teste do Google. O Google Test tem vários requisitos "especiais" que tornam a regra cc_library mais complicada:

  • googletest-release-1.10.0/src/gtest-all.cc #include todos os outros arquivos em googletest-release-1.10.0/src/: exclua-o da compilação para evitar erros de vinculação de símbolos duplicados.

  • Ele usa arquivos de cabeçalho relativos à googletest-release-1.10.0/include/ ("gtest/gtest.h"), então é necessário adicionar esse diretório aos caminhos de inclusão.

  • É necessário vincular a conta em pthread. Portanto, adicione-a como linkopt.

A regra final fica assim:

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

Isso é um pouco confuso: tudo tem o prefixo googletest-release-1.10.0 como subproduto da estrutura do arquivo. Você pode fazer http_archive faixa esse prefixo adicionando o 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",
)

Então, gtest.BUILD ficaria assim:

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

Agora, as regras cc_ podem depender de @gtest//:main.

Como programar e executar testes em C++

Por exemplo, você pode criar um teste ./test/hello-test.cc, como:

#include "gtest/gtest.h"
#include "main/hello-greet.h"

TEST(HelloTest, GetGreet) {
  EXPECT_EQ(get_greet("Bazel"), "Hello Bazel");
}

Em seguida, crie o arquivo ./test/BUILD para seus testes:

cc_test(
    name = "hello-test",
    srcs = ["hello-test.cc"],
    copts = ["-Iexternal/gtest/include"],
    deps = [
        "@gtest//:main",
        "//main:hello-greet",
    ],
)

Para tornar o app hello-greet visível para o app hello-test, adicione "//test:__pkg__", para o atributo visibility em ./main/BUILD.

Agora você pode usar bazel test para executar o teste.

bazel test test:hello-test

Isso produz a seguinte saída:

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.

Como adicionar dependências em bibliotecas pré-compiladas

Se você quiser usar uma biblioteca da qual você só tem uma versão compilada (por exemplo, cabeçalhos e um arquivo .so) unem-o em uma regra cc_library:

cc_library(
    name = "mylib",
    srcs = ["mylib.so"],
    hdrs = ["mylib.h"],
)

Dessa forma, outros destinos C++ no seu espaço de trabalho podem depender dessa regra.