Neste tutorial, usamos um cenário de exemplo para descrever como configurar toolchains em C++ para um projeto.
O que você vai aprender
Neste tutorial, você vai aprender a:
- Configurar o ambiente de build
- Usar --toolchain_resolution_debugpara depurar a resolução do conjunto de ferramentas
- Configurar o conjunto de ferramentas C++
- Crie uma regra do Starlark que forneça configuração adicional para o
cc_toolchainpara que o Bazel possa criar o aplicativo comclang.
- Crie o binário C++ executando bazel build //main:hello-worldem uma máquina Linux.
- Faça a compilação cruzada do binário para Android executando bazel build //main:hello-world --platforms=//:android_x86_64
Antes de começar
Neste tutorial, presumimos que você está no Linux e criou aplicativos em C++
e instalou as ferramentas e bibliotecas adequadas. O tutorial usa clang version 19, que pode ser instalado no seu sistema.
Configurar o ambiente de build
Configure o ambiente de build da seguinte maneira:
- Se ainda não tiver feito isso, baixe e instale o Bazel 7.0.2 ou uma versão mais recente. 
- Adicione um arquivo - MODULE.bazelvazio na pasta raiz.
- Adicione o seguinte destino - cc_binaryao arquivo- main/BUILD:- cc_binary( name = "hello-world", srcs = ["hello-world.cc"], )- Como o Bazel usa muitas ferramentas internas escritas em C++ durante o build, como - process-wrapper, o conjunto de ferramentas padrão de C++ preexistente é especificado para a plataforma host. Isso permite que essas ferramentas internas criem usando a cadeia de ferramentas criada neste tutorial. Portanto, o destino- cc_binarytambém é criado com o conjunto de ferramentas padrão.
- Execute o build com o seguinte comando: - bazel build //main:hello-world- A build é bem-sucedida sem nenhuma cadeia de ferramentas registrada em - MODULE.bazel.- Para ver mais detalhes, execute: - bazel build //main:hello-world --toolchain_resolution_debug='@bazel_tools//tools/cpp:toolchain_type' INFO: ToolchainResolution: Target platform @@platforms//host:host: Selected execution platform @@platforms//host:host, type @@bazel_tools//tools/cpp:toolchain_type -> toolchain @@bazel_tools+cc_configure_extension+local_config_cc//:cc-compiler-k8- Sem especificar - --platforms, o Bazel cria o destino para- @platforms//hostusando- @bazel_tools+cc_configure_extension+local_config_cc//:cc-compiler-k8.
Configurar o conjunto de ferramentas C++
Para configurar o conjunto de ferramentas C++, crie o aplicativo repetidamente e elimine cada erro um por um, conforme descrito abaixo.
Ele também pressupõe clang version 9.0.1, embora os detalhes mudem apenas
um pouco entre diferentes versões do clang.
- Adicionar - toolchain/BUILDcom- filegroup(name = "empty") cc_toolchain( name = "linux_x86_64_toolchain", toolchain_identifier = "linux_x86_64-toolchain", toolchain_config = ":linux_x86_64_toolchain_config", all_files = ":empty", compiler_files = ":empty", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 0, ) toolchain( name = "cc_toolchain_for_linux_x86_64", toolchain = ":linux_x86_64_toolchain", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", exec_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:linux", ], target_compatible_with = [ "@platforms//cpu:x86_64", "@platforms//os:linux", ], )- Em seguida, adicione as dependências adequadas e registre a cadeia de ferramentas com - MODULE.bazelcom- bazel_dep(name = "platforms", version = "0.0.10") register_toolchains( "//toolchain:cc_toolchain_for_linux_x86_64" )- Esta etapa define um - cc_toolchaine o vincula a um destino- toolchainpara a configuração do host.
- Execute o build novamente. Como o pacote - toolchainainda não define o destino- linux_x86_64_toolchain_config, o Bazel gera o seguinte erro:- ERROR: toolchain/BUILD:4:13: in toolchain_config attribute of cc_toolchain rule //toolchain:linux_x86_64_toolchain: rule '//toolchain:linux_x86_64_toolchain_config' does not exist.
- No arquivo - toolchain/BUILD, defina um grupo de arquivos vazio da seguinte maneira:- package(default_visibility = ["//visibility:public"]) filegroup(name = "linux_x86_64_toolchain_config")
- Execute o build novamente. O Bazel gera o seguinte erro: - '//toolchain:linux_x86_64_toolchain_config' does not have mandatory providers: 'CcToolchainConfigInfo'.- CcToolchainConfigInfoé um provedor usado para configurar suas cadeias de ferramentas em C++. Para corrigir esse erro, crie uma regra do Starlark que forneça- CcToolchainConfigInfoao Bazel criando um arquivo- toolchain/cc_toolchain_config.bzlcom o seguinte conteúdo:- def _impl(ctx): return cc_common.create_cc_toolchain_config_info( ctx = ctx, toolchain_identifier = "k8-toolchain", host_system_name = "local", target_system_name = "local", target_cpu = "k8", target_libc = "unknown", compiler = "clang", abi_version = "unknown", abi_libc_version = "unknown", ) cc_toolchain_config = rule( implementation = _impl, attrs = {}, provides = [CcToolchainConfigInfo], )- cc_common.create_cc_toolchain_config_info()cria o provedor necessário- CcToolchainConfigInfo. Para usar a regra- cc_toolchain_config, adicione uma instrução de carregamento a- toolchain/BUILDlogo abaixo da instrução do pacote:- load(":cc_toolchain_config.bzl", "cc_toolchain_config")- E substitua o grupo de arquivos "linux_x86_64_toolchain_config" por uma declaração de uma regra - cc_toolchain_config:- cc_toolchain_config(name = "linux_x86_64_toolchain_config")
- Execute o build novamente. O Bazel gera o seguinte erro: - .../BUILD:1:1: C++ compilation of rule '//:hello-world' failed (Exit 1) src/main/tools/linux-sandbox-pid1.cc:421: "execvp(toolchain/DUMMY_GCC_TOOL, 0x11f20e0)": No such file or directory Target //:hello-world failed to build`- Neste ponto, o Bazel tem informações suficientes para tentar criar o código, mas ainda não sabe quais ferramentas usar para concluir as ações de build necessárias. Você vai modificar a implementação da regra do Starlark para informar ao Bazel quais ferramentas usar. Para isso, você precisa do construtor - tool_path()de- @bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl:- # toolchain/cc_toolchain_config.bzl: # NEW load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", "tool_path") def _impl(ctx): tool_paths = [ # NEW tool_path( name = "gcc", # Compiler is referenced by the name "gcc" for historic reasons. path = "/usr/bin/clang", ), tool_path( name = "ld", path = "/usr/bin/ld", ), tool_path( name = "ar", path = "/usr/bin/ar", ), tool_path( name = "cpp", path = "/bin/false", ), tool_path( name = "gcov", path = "/bin/false", ), tool_path( name = "nm", path = "/bin/false", ), tool_path( name = "objdump", path = "/bin/false", ), tool_path( name = "strip", path = "/bin/false", ), ] return cc_common.create_cc_toolchain_config_info( ctx = ctx, toolchain_identifier = "local", host_system_name = "local", target_system_name = "local", target_cpu = "k8", target_libc = "unknown", compiler = "clang", abi_version = "unknown", abi_libc_version = "unknown", tool_paths = tool_paths, # NEW )- Verifique se - /usr/bin/clange- /usr/bin/ldsão os caminhos corretos para seu sistema. Observe que o compilador é referenciado pelo nome "gcc" por motivos históricos.
- Execute o build novamente. O Bazel gera o seguinte erro: - ERROR: main/BUILD:3:10: Compiling main/hello-world.cc failed: absolute path inclusion(s) found in rule '//main:hello-world': the source file 'main/hello-world.cc' includes the following non-builtin files with absolute paths (if these are builtin files, make sure these paths are in your toolchain): '/usr/include/c++/13/ctime' '/usr/include/x86_64-linux-gnu/c++/13/bits/c++config.h' '/usr/include/x86_64-linux-gnu/c++/13/bits/os_defines.h' ...- O Bazel precisa saber onde pesquisar os cabeçalhos incluídos. Há várias maneiras de resolver isso, como usar o atributo - includesde- cc_binary, mas aqui o problema é resolvido no nível da cadeia de ferramentas com o parâmetro- cxx_builtin_include_directoriesde- cc_common.create_cc_toolchain_config_info. Se você estiver usando uma versão diferente do- clang, o caminho de inclusão será diferente. Esses caminhos também podem variar de acordo com a distribuição.- Modifique o valor de retorno em - toolchain/cc_toolchain_config.bzlpara que fique assim:- return cc_common.create_cc_toolchain_config_info( ctx = ctx, cxx_builtin_include_directories = [ # NEW "/usr/lib/llvm-19/lib/clang/19/include", "/usr/include", ], toolchain_identifier = "local", host_system_name = "local", target_system_name = "local", target_cpu = "k8", target_libc = "unknown", compiler = "clang", abi_version = "unknown", abi_libc_version = "unknown", tool_paths = tool_paths, )
- Execute o comando de build novamente. Você vai ver um erro como: - /usr/bin/ld: bazel-out/k8-fastbuild/bin/main/_objs/hello-world/hello-world.o: in function `print_localtime()': hello-world.cc:(.text+0x68): undefined reference to `std::cout'- Isso acontece porque o vinculador não tem a biblioteca padrão do C++ e não consegue encontrar os símbolos dela. Há muitas maneiras de resolver isso, como usar o atributo - linkoptsde- cc_binary. Aqui, o problema é resolvido garantindo que qualquer destino que use o conjunto de ferramentas não precise especificar essa flag.- Copie o seguinte código para - toolchain/cc_toolchain_config.bzl:- # NEW load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") # NEW load( "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", "feature", # NEW "flag_group", # NEW "flag_set", # NEW "tool_path", ) all_link_actions = [ # NEW ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ] def _impl(ctx): tool_paths = [ tool_path( name = "gcc", # Compiler is referenced by the name "gcc" for historic reasons. path = "/usr/bin/clang", ), tool_path( name = "ld", path = "/usr/bin/ld", ), tool_path( name = "ar", path = "/bin/false", ), tool_path( name = "cpp", path = "/bin/false", ), tool_path( name = "gcov", path = "/bin/false", ), tool_path( name = "nm", path = "/bin/false", ), tool_path( name = "objdump", path = "/bin/false", ), tool_path( name = "strip", path = "/bin/false", ), ] features = [ # NEW feature( name = "default_linker_flags", enabled = True, flag_sets = [ flag_set( actions = all_link_actions, flag_groups = ([ flag_group( flags = [ "-lstdc++", ], ), ]), ), ], ), ] return cc_common.create_cc_toolchain_config_info( ctx = ctx, features = features, # NEW cxx_builtin_include_directories = [ "/usr/lib/llvm-19/lib/clang/19/include", "/usr/include", ], toolchain_identifier = "local", host_system_name = "local", target_system_name = "local", target_cpu = "k8", target_libc = "unknown", compiler = "clang", abi_version = "unknown", abi_libc_version = "unknown", tool_paths = tool_paths, ) cc_toolchain_config = rule( implementation = _impl, attrs = {}, provides = [CcToolchainConfigInfo], )- Este código usa a biblioteca GNU C++ libstdc++. Se você quiser usar a biblioteca LLVM C++, use "-lc++" em vez de "-lstdc++". 
- Ao executar - bazel build //main:hello-world, ele vai criar o binário com sucesso para o host.
- Em - toolchain/BUILD, copie os destinos- cc_toolchain_config,- cc_toolchaine- toolchaine substitua- linux_x86_64por- android_x86_64nos nomes de destino.- Em - MODULE.bazel, registre a cadeia de ferramentas para Android.- register_toolchains( "//toolchain:cc_toolchain_for_linux_x86_64", "//toolchain:cc_toolchain_for_android_x86_64" )
- Execute - bazel build //main:hello-world --android_platforms=//toolchain:android_x86_64para criar o binário para Android.
Na prática, o Linux e o Android precisam ter configurações diferentes de toolchain do C++. Você pode modificar o cc_toolchain_config atual para as diferenças ou criar regras separadas (ou seja, um provedor CcToolchainConfigInfo) para plataformas separadas.
Revisar seu trabalho
Neste tutorial, você aprendeu a configurar uma cadeia de ferramentas básica em C++, mas elas são mais poderosas do que este exemplo.
Os principais tópicos são:
- É preciso especificar uma flag platformscorrespondente na linha de comando para que o Bazel resolva o conjunto de ferramentas com os mesmos valores de restrição na plataforma. A documentação tem mais informações sobre flags de configuração específicas da linguagem.
- Você precisa informar à cadeia de ferramentas onde elas estão. Neste tutorial, há uma versão simplificada em que você acessa as ferramentas do sistema. Se você quiser uma abordagem mais independente, leia sobre dependências externas. As ferramentas podem vir de um módulo diferente, e você precisaria disponibilizar os arquivos delas para o cc_toolchaincom dependências de destino em atributos, comocompiler_files. Otool_pathstambém precisaria ser alterado.
- Você pode criar recursos para personalizar quais flags devem ser transmitidas para diferentes ações, seja vinculação ou qualquer outro tipo de ação.
Leitura adicional
Para mais detalhes, consulte Configuração da cadeia de ferramentas C++.