En este instructivo, se usa una situación de ejemplo para describir cómo configurar C++ cadenas de herramientas para un proyecto.
Qué aprenderás
En este instructivo, aprenderás a hacer lo siguiente:
- Cómo configurar el entorno de compilación
- Usa
--toolchain_resolution_debug
para depurar la resolución de la cadena de herramientas. - Cómo configurar la cadena de herramientas de C++
- Cree una regla de Starlark que proporcione configuración adicional para el
cc_toolchain
para que Bazel pueda compilar la aplicación conclang
- Para compilar el objeto binario de C++, ejecuta
bazel build //main:hello-world
en un Máquina Linux - Ejecuta
bazel build //main:hello-world --platforms=//:android_x86_64
para compilar de forma cruzada el objeto binario para Android
Antes de comenzar
En este instructivo, se da por sentado que usas Linux y compilaste C++ correctamente
aplicaciones e instaló las herramientas y bibliotecas correspondientes. El instructivo
usa clang version 16
, que puedes instalar en tu sistema.
Cómo configurar el entorno de compilación
Configura tu entorno de compilación de la siguiente manera:
Si aún no lo has hecho, descarga e instala Bazel 7.0.2 o una versión posterior
Agrega un archivo
MODULE.bazel
vacío en la carpeta raíz.Agrega el siguiente destino
cc_binary
al archivomain/BUILD
:cc_binary( name = "hello-world", srcs = ["hello-world.cc"], )
Debido a que Bazel usa muchas herramientas internas escritas en C++ durante la compilación, como como
process-wrapper
, se especifica la cadena de herramientas predeterminada de C++ preexistente. para la plataforma host. Esto permite que estas herramientas internas compilen de la que se creó en este instructivo. Por lo tanto, el objetivocc_binary
también se compila con la cadena de herramientas predeterminada.Ejecuta la compilación con el siguiente comando:
bazel build //main:hello-world
La compilación se realiza de forma correcta sin ninguna cadena de herramientas registrada en
MODULE.bazel
.Para ver con más detalle el funcionamiento interno, ejecuta el siguiente comando:
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
Sin especificar
--platforms
, Bazel compila el destino para@platforms//host
usando@bazel_tools+cc_configure_extension+local_config_cc//:cc-compiler-k8
Cómo configurar la cadena de herramientas de C++
Para configurar la cadena de herramientas de C++, compila la aplicación de forma repetida y elimina cada error uno por uno, como se describe a continuación.
También se supone que es clang version 9.0.1
, aunque los detalles solo deben cambiar
un poco entre las diferentes versiones de Clang.
Agrega
toolchain/BUILD
confilegroup(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", ], )
Luego, agrega las dependencias apropiadas y registra la cadena de herramientas con
MODULE.bazel
conbazel_dep(name = "platforms", version = "0.0.10") register_toolchains( "//toolchain:cc_toolchain_for_linux_x86_64" )
En este paso, se define un
cc_toolchain
y se lo vincula a un destinotoolchain
para la configuración del host.Vuelve a ejecutar la compilación. Debido a que el paquete
toolchain
aún no define ellinux_x86_64_toolchain_config
, Bazel arroja el siguiente error: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.
En el archivo
toolchain/BUILD
, define un grupo de archivos vacío de la siguiente manera:package(default_visibility = ["//visibility:public"]) filegroup(name = "linux_x86_64_toolchain_config")
Vuelve a ejecutar la compilación. Bazel arroja el siguiente error:
'//toolchain:linux_x86_64_toolchain_config' does not have mandatory providers: 'CcToolchainConfigInfo'.
CcToolchainConfigInfo
es un proveedor que usas para configurar tu código C++. cadenas de herramientas. Para corregir este error, crea una regla de Starlark que proporcioneCcToolchainConfigInfo
a Bazel haciendo untoolchain/cc_toolchain_config.bzl
con el siguiente contenido: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()
crea el proveedor necesario.CcToolchainConfigInfo
Para usar la reglacc_toolchain_config
, agrega una carga atoolchain/BUILD
justo debajo de la declaración del paquete:load(":cc_toolchain_config.bzl", "cc_toolchain_config")
Y reemplacen "linux_x86_64_toolchain_config" grupo de archivos con una declaración de una regla
cc_toolchain_config
:cc_toolchain_config(name = "linux_x86_64_toolchain_config")
Vuelve a ejecutar la compilación. Bazel arroja el siguiente error:
.../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`
En este punto, Bazel tiene suficiente información para intentar compilar el código, pero todavía no sabe qué herramientas usar para completar la compilación necesaria acciones. Modificarás la implementación de la regla de Starlark para indicarle a Bazel qué. herramientas para usar. Para eso, necesitas el constructor
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", 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 )
Asegúrate de que
/usr/bin/clang
y/usr/bin/ld
sean las rutas correctas para en tu sistema.Vuelve a ejecutar la compilación. Bazel arroja el siguiente error:
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' ...
Bazel necesita saber dónde buscar los encabezados incluidos. Existen varias formas de solucionar esto, como usar el atributo
includes
decc_binary
pero aquí esto se resuelve a nivel de la cadena de herramientas con elcxx_builtin_include_directories
parámetro decc_common.create_cc_toolchain_config_info
. Ten en cuenta que si estás usando una versión diferente declang
, se agregará la ruta de acceso de inclusión es diferente. Estas rutas también pueden ser diferentes según la distribución.Modifica el valor que se muestra en
toolchain/cc_toolchain_config.bzl
para que se vea de la siguiente manera: esto:return cc_common.create_cc_toolchain_config_info( ctx = ctx, cxx_builtin_include_directories = [ # NEW "/usr/lib/llvm-16/lib/clang/16/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, )
Vuelve a ejecutar el comando de compilación. Verás un error como el siguiente:
/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'
Esto se debe a que al vinculador le falta el estándar C++ biblioteca y no encuentra sus símbolos. Hay muchas formas de resolver esto, como el uso del atributo
linkopts
decc_binary
. Aquí se resuelve con asegúrate de que ningún destino que use la cadena de herramientas deba especificarlo marca.Copia el siguiente código en
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", 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-9/lib/clang/9.0.1/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], )
Ejecuta
bazel build //main:hello-world
y, por último, debería compilar el objeto binario. correctamente para el host.En
toolchain/BUILD
, copiacc_toolchain_config
,cc_toolchain
ytoolchain
se orienta y reemplazalinux_x86_64
porandroid_x86_64
en los nombres de los destinos.En
MODULE.bazel
, registra la cadena de herramientas para Android.register_toolchains( "//toolchain:cc_toolchain_for_linux_x86_64", "//toolchain:cc_toolchain_for_android_x86_64" )
Ejecuta
bazel build //main:hello-world --android_platforms=//toolchain:android_x86_64
para compilar el objeto binario para Android
En la práctica, Linux y Android deberían tener diferentes configuraciones del conjunto de herramientas de C++. Tú
puedes modificar el cc_toolchain_config
existente para ver las diferencias
crea reglas independientes (es decir, el proveedor CcToolchainConfigInfo
) para diferentes
y plataformas de Google Cloud.
Revisa tu trabajo
En este instructivo, aprendiste a configurar una cadena de herramientas básica de C++, pero Las cadenas de herramientas son más potentes que este ejemplo.
Los conceptos principales son los siguientes:
- Debes especificar una marca
platforms
coincidente en la línea de comandos para para resolver los mismos valores de restricción en la cadena de herramientas. plataforma. La documentación incluye más información sobre lenguajes específicos de configuración. - Debes permitir que la cadena de herramientas sepa dónde se encuentran las herramientas. En este instructivo
hay una versión simplificada
en la que se accede a las herramientas del sistema. Si
estás interesado en un enfoque más autónomo, puedes leer acerca de
dependencias externas. Tus herramientas podrían provenir de un
en otro módulo y tendrías que hacer que sus archivos estén disponibles para el
cc_toolchain
con dependencias de destino en atributos, comocompiler_files
También se debería cambiartool_paths
. - Puedes crear funciones para personalizar a qué marcas se deben pasar diferentes acciones, ya sea la vinculación o cualquier otro tipo de acción.
Lecturas adicionales
Para obtener más información, consulta la cadena de herramientas de C++ configuración