site/en/docs/cc-toolchain-config-reference.md
Project: /_project.yaml Book: /_book.yaml
{% include "_buttons.html" %}
To invoke the compiler with the right options, Bazel needs some knowledge about the compiler internals, such as include directories and important flags. In other words, Bazel needs a simplified model of the compiler to understand its workings.
Bazel needs to know the following:
BUILD file.If the compiler has support for multiple architectures, Bazel needs to configure them separately.
CcToolchainConfigInfo is a provider that provides the necessary level of
granularity for configuring the behavior of Bazel's C++ rules. By default,
Bazel automatically configures CcToolchainConfigInfo for your build, but you
have the option to configure it manually. For that, you need a Starlark rule
that provides the CcToolchainConfigInfo and you need to point the
toolchain_config attribute of the
cc_toolchain to your rule.
You can create the CcToolchainConfigInfo by calling
cc_common.create_cc_toolchain_config_info().
You can find Starlark constructors for all structs you'll need in the process in
@rules_cc//cc:cc_toolchain_config_lib.bzl{: .external}.
When a C++ target enters the analysis phase, Bazel selects the appropriate
cc_toolchain target based on the BUILD file, and obtains the
CcToolchainConfigInfo provider from the target specified in the
cc_toolchain.toolchain_config attribute. The cc_toolchain target
passes this information to the C++ target through a CcToolchainProvider.
For example, a compile or link action, instantiated by a rule such as
cc_binary or cc_library, needs the following information:
--copt/--linkopt optionsAll of the above information except the artifacts required in the sandbox is
specified in the Starlark target that the cc_toolchain points to.
The artifacts to be shipped to the sandbox are declared in the cc_toolchain
target. For example, with the cc_toolchain.linker_files attribute you can
specify the linker binary and toolchain libraries to ship into the sandbox.
The toolchain selection logic operates as follows:
User specifies a cc_toolchain_suite target in the BUILD file and points
Bazel to the target using the
--crosstool_top option.
The cc_toolchain_suite target references multiple toolchains. The
values of the --cpu and --compiler flags determine which of those
toolchains is selected, either based only on the --cpu flag value, or
based on a joint --cpu | --compiler value. The selection process is as
follows:
If the --compiler option is specified, Bazel selects the
corresponding entry from the cc_toolchain_suite.toolchains
attribute with --cpu | --compiler. If Bazel does not find
a corresponding entry, it throws an error.
If the --compiler option is not specified, Bazel selects
the corresponding entry from the cc_toolchain_suite.toolchains
attribute with just --cpu.
If no flags are specified, Bazel inspects the host system and selects a
--cpu value based on its findings. See the
inspection mechanism code.
Once a toolchain has been selected, corresponding feature and action_config
objects in the Starlark rule govern the configuration of the build (that is,
items described later). These messages allow the implementation of
fully fledged C++ features in Bazel without modifying the
Bazel binary. C++ rules support multiple unique actions documented in detail
in the Bazel source code.
A feature is an entity that requires command-line flags, actions,
constraints on the execution environment, or dependency alterations. A feature
can be something as simple as allowing BUILD files to select configurations of
flags, such as treat_warnings_as_errors, or interact with the C++ rules and
include new compile actions and inputs to the compilation, such as
header_modules or thin_lto.
Ideally, CcToolchainConfigInfo contains a list of features, where each
feature consists of one or more flag groups, each defining a list of flags
that apply to specific Bazel actions.
A feature is specified by name, which allows full decoupling of the Starlark
rule configuration from Bazel releases. In other words, a Bazel release does not
affect the behavior of CcToolchainConfigInfo configurations as long as those
configurations do not require the use of new features.
A feature is enabled in one of the following ways:
enabled field is set to true.--feature Bazel option or features rule
attribute.Features can have interdependencies, depend on command line flags, BUILD file
settings, and other variables.
Dependencies are typically managed directly with Bazel, which simply enforces the requirements and manages conflicts intrinsic to the nature of the features defined in the build. The toolchain specification allows for more granular constraints for use directly within the Starlark rule that govern feature support and expansion. These are:
<table> <col width="300"> <col width="600"> <tr> <td><strong>Constraint</strong> </td> <td><strong>Description</strong> </td> </tr> <tr> <td><pre>requires = [ feature_set (features = [ 'feature-name-1', 'feature-name-2' ]), ]</pre> </td> <td>Feature-level. The feature is supported only if the specified required features are enabled. For example, when a feature is only supported in certain build modes (<code>opt</code>, <code>dbg</code>, or <code>fastbuild</code>). If `requires` contains multiple `feature_set`s the feature is supported if any of the `feature_set`s is satisfied (when all specified features are enabled). </td> </tr> <tr> <td><pre>implies = ['feature']</pre> </td> <td><p>Feature-level. This feature implies the specified feature(s). Enabling a feature also implicitly enables all features implied by it (that is, it functions recursively).</p> <p>Also provides the ability to factor common subsets of functionality out of a set of features, such as the common parts of sanitizers. Implied features cannot be disabled.</p> </td> </tr> <tr> <td><pre>provides = ['feature']</pre> </td> <td><p>Feature-level. Indicates that this feature is one of several mutually exclusive alternate features. For example, all of the sanitizers could specify <code>provides = ["sanitizer"]</code>.</p> <p>This improves error handling by listing the alternatives if the user asks for two or more mutually exclusive features at once.</p> </td> </tr> <tr> <td><pre>with_features = [ with_feature_set( features = ['feature-1'], not_features = ['feature-2'], ), ]</pre> </td> <td>Flag set-level. A feature can specify multiple flag sets with multiple. When <code>with_features</code> is specified, the flag set will only expand to the build command if there is at least one <code>with_feature_set</code> for which all of the features in the specified <code>features</code> set are enabled, and all the features specified in <code>not_features</code> set are disabled. If <code>with_features</code> is not specified, the flag set will be applied unconditionally for every action specified. </td> </tr> </table>Actions provide the flexibility to modify the circumstances under
which an action executes without assuming how the action will be run. An
action_config specifies the tool binary that an action invokes, while a
feature specifies the configuration (flags) that determine how that tool
behaves when the action is invoked.
Features reference actions to signal which Bazel actions
they affect since actions can modify the Bazel action graph. The
CcToolchainConfigInfo provider contains actions that have flags and tools
associated with them, such as c++-compile. Flags are assigned to each action
by associating them with a feature.
Each action name represents a single type of action performed by Bazel, such as
compiling or linking. There is, however, a many-to-one relationship between
actions and Bazel action types, where a Bazel action type refers to a Java class
that implements an action (such as CppCompileAction). In particular, the
"assembler actions" and "compiler actions" in the table below are
CppCompileAction, while the link actions are CppLinkAction.
AR actions assemble object files into archive libraries (.a files) via ar
and encode some semantics into the name.
The action_config is a Starlark struct that describes a Bazel
action by specifying the tool (binary) to invoke during the action and sets of
flags, defined by features. These flags apply constraints to the action's
execution.
The action_config() constructor has the following parameters:
An action_config can require and imply other features and
<code>action_config</code>s as dictated by the
feature relationships described earlier. This behavior
is similar to that of a feature.
The last two attributes are redundant against the corresponding attributes on
features and are included because some Bazel actions require certain flags or
environment variables and the goal is to avoid unnecessary action_config+feature
pairs. Typically, sharing a single feature across multiple action_configs is
preferred.
You can not define more than one action_config with the same action_name
within the same toolchain. This prevents ambiguity in tool paths
and enforces the intention behind action_config - that an action's properties
are clearly described in a single place in the toolchain.
Anaction_config can specify a set of tools via its tools parameter.
The tool() constructor takes in the following parameters:
For a given action_config, only a single tool applies
its tool path and execution requirements to the Bazel action. A tool is selected
by iterating through the tools attribute on an action_config until a tool
with a with_feature set matching the feature configuration is found
(see Feature relationships earlier on this page
for more information). You should end your tool lists with a default
tool that corresponds to an empty feature configuration.
Features and actions can be used together to implement Bazel actions
with diverse cross-platform semantics. For example, debug symbol generation on
macOS requires generating symbols in the compile action, then invoking a
specialized tool during the link action to create compressed dsym archive, and
then decompressing that archive to produce the application bundle and .plist
files consumable by Xcode.
With Bazel, this process can instead be implemented as follows, with
unbundle-debuginfo being a Bazel action:
load("@rules_cc//cc:defs.bzl", "ACTION_NAMES")
action_configs = [
action_config (
action_name = ACTION_NAMES.cpp_link_executable,
tools = [
tool(
with_features = [
with_feature(features=["generate-debug-symbols"]),
],
path = "toolchain/mac/ld-with-dsym-packaging",
),
tool (path = "toolchain/mac/ld"),
],
),
]
features = [
feature(
name = "generate-debug-symbols",
flag_sets = [
flag_set (
actions = [
ACTION_NAMES.c_compile,
ACTION_NAMES.cpp_compile
],
flag_groups = [
flag_group(
flags = ["-g"],
),
],
)
],
implies = ["unbundle-debuginfo"],
),
]
This same feature can be implemented entirely differently for Linux, which uses
fission, or for Windows, which produces .pdb files. For example, the
implementation for fission-based debug symbol generation might look as
follows:
load("@rules_cc//cc:defs.bzl", "ACTION_NAMES")
action_configs = [
action_config (
name = ACTION_NAMES.cpp_compile,
tools = [
tool(
path = "toolchain/bin/gcc",
),
],
),
]
features = [
feature (
name = "generate-debug-symbols",
requires = [with_feature_set(features = ["dbg"])],
flag_sets = [
flag_set(
actions = [ACTION_NAMES.cpp_compile],
flag_groups = [
flag_group(
flags = ["-gsplit-dwarf"],
),
],
),
flag_set(
actions = [ACTION_NAMES.cpp_link_executable],
flag_groups = [
flag_group(
flags = ["-Wl", "--gdb-index"],
),
],
),
],
),
]
CcToolchainConfigInfo allows you to bundle flags into groups that serve a
specific purpose. You can specify a flag within using pre-defined variables
within the flag value, which the compiler expands when adding the flag to the
build command. For example:
flag_group (
flags = ["%{output_execpath}"],
)
In this case, the contents of the flag will be replaced by the output file path of the action.
Flag groups are expanded to the build command in the order in which they appear in the list, top-to-bottom, left-to-right.
For flags that need to repeat with different values when added to the build
command, the flag group can iterate variables of type list. For example, the
variable include_path of type list:
flag_group (
iterate_over = "include_paths",
flags = ["-I%{include_paths}"],
)
expands to -I<path> for each path element in the include_paths list. All
flags (or flag_groups) in the body of a flag group declaration are expanded as
a unit. For example:
flag_group (
iterate_over = "include_paths",
flags = ["-I", "%{include_paths}"],
)
expands to -I <path> for each path element in the include_paths list.
A variable can repeat multiple times. For example:
flag_group (
iterate_over = "include_paths",
flags = ["-iprefix=%{include_paths}", "-isystem=%{include_paths}"],
)
expands to:
-iprefix=<inc0> -isystem=<inc0> -iprefix=<inc1> -isystem=<inc1>
Variables can correspond to structures accessible using dot-notation. For example:
flag_group (
flags = ["-l%{libraries_to_link.name}"],
)
Structures can be nested and may also contain sequences. To prevent name clashes and to be explicit, you must specify the full path through the fields. For example:
flag_group (
iterate_over = "libraries_to_link",
flag_groups = [
flag_group (
iterate_over = "libraries_to_link.shared_libraries",
flags = ["-l%{libraries_to_link.shared_libraries.name}"],
),
],
)
Flag groups support conditional expansion based on the presence of a particular
variable or its field using the expand_if_available, expand_if_not_available,
expand_if_true, expand_if_false, or expand_if_equal attributes. For example:
flag_group (
iterate_over = "libraries_to_link",
flag_groups = [
flag_group (
iterate_over = "libraries_to_link.shared_libraries",
flag_groups = [
flag_group (
expand_if_available = "libraries_to_link.shared_libraries.is_whole_archive",
flags = ["--whole_archive"],
),
flag_group (
flags = ["-l%{libraries_to_link.shared_libraries.name}"],
),
flag_group (
expand_if_available = "libraries_to_link.shared_libraries.is_whole_archive",
flags = ["--no_whole_archive"],
),
],
),
],
)
Note: The --whole_archive and --no_whole_archive options are added to
the build command only when a currently iterated library has an
is_whole_archive field.
This section provides a reference of build variables, features, and other information required to successfully configure C++ rules.
The following is a reference of CcToolchainConfigInfo build variables.
Note: The Action column indicates the relevant action type, if applicable.
<table> <tr> <td><strong>Variable</strong> </td> <td><strong>Action</strong> </td> <td><strong>Description</strong> </td> </tr> <tr> <td><strong><code>source_file</code></strong> </td> <td>compile</td> <td>Source file to compile. </td> </tr> <tr> <td><strong><code>input_file</code></strong> </td> <td>strip</td> <td>Artifact to strip. </td> </tr> <tr> <td><strong><code>output_file</code></strong> </td> <td>compile, strip</td> <td>Compilation output. </td> </tr> <tr> <td><strong><code>output_assembly_file</code></strong> </td> <td>compile</td> <td>Emitted assembly file. Applies only when the <code>compile</code> action emits assembly text, typically when using the <code>--save_temps</code> flag. The contents are the same as for <code>output_file</code>. </td> </tr> <tr> <td><strong><code>output_preprocess_file</code></strong> </td> <td>compile</td> <td>Preprocessed output. Applies only to compile actions that only preprocess the source files, typically when using the <code>--save_temps</code> flag. The contents are the same as for <code>output_file</code>. </td> </tr> <tr> <td><strong><code>includes</code></strong> </td> <td>compile</td> <td>Sequence of files the compiler must unconditionally include in the compiled source. </td> </tr> <tr> <td><strong><code>include_paths</code></strong> </td> <td>compile</td> <td>Sequence directories in which the compiler searches for headers included using <code>#include<foo.h></code> and <code>#include "foo.h"</code>. </td> </tr> <tr> <td><strong><code>quote_include_paths</code></strong> </td> <td>compile</td> <td>Sequence of <code>-iquote</code> includes - directories in which the compiler searches for headers included using <code>#include "foo.h"</code>. </td> </tr> <tr> <td><strong><code>system_include_paths</code></strong> </td> <td>compile</td> <td>Sequence of <code>-isystem</code> includes - directories in which the compiler searches for headers included using <code>#include <foo.h></code>. </td> </tr> <tr> <td><strong><code>dependency_file</code></strong> </td> <td>compile</td> <td>The <code>.d</code> dependency file generated by the compiler. </td> </tr> <tr> <td><strong><code>preprocessor_defines</code></strong> </td> <td>compile</td> <td>Sequence of <code>defines</code>, such as <code>--DDEBUG</code>. </td> </tr> <tr> <td><strong><code>pic</code></strong> </td> <td>compile</td> <td>Compiles the output as position-independent code. </td> </tr> <tr> <td><strong><code>gcov_gcno_file</code></strong> </td> <td>compile</td> <td>The <code>gcov</code> coverage file. </td> </tr> <tr> <td><strong><code>per_object_debug_info_file</code></strong> </td> <td>compile</td> <td>The per-object debug info (<code>.dwp</code>) file. </td> </tr> <tr> <td><strong><code>stripopts</code></strong> </td> <td>strip</td> <td>Sequence of <code>stripopts</code>. </td> </tr> <tr> <td><strong><code>legacy_compile_flags</code></strong> </td> <td>compile</td> <td>Sequence of flags from legacy <code>CROSSTOOL</code> fields such as <code>compiler_flag</code>, <code>optional_compiler_flag</code>, <code>cxx_flag</code>, and <code>optional_cxx_flag</code>. </td> </tr> <tr> <td><strong><code>user_compile_flags</code></strong> </td> <td>compile</td> <td>Sequence of flags from either the <code>copt</code> rule attribute or the <code>--copt</code>, <code>--cxxopt</code>, and <code>--conlyopt</code> flags. </td> </tr> <tr> <td><strong><code>unfiltered_compile_flags</code></strong> </td> <td>compile</td> <td>Sequence of flags from the <code>unfiltered_cxx_flag</code> legacy <code>CROSSTOOL</code> field or the <code>unfiltered_compile_flags</code> feature. These are not filtered by the <code>nocopts</code> rule attribute. </td> </tr> <tr> <td><strong><code>sysroot</code></strong> </td> <td></td> <td>The <code>sysroot</code>. </td> </tr> <tr> <td><strong><code>runtime_library_search_directories</code></strong> </td> <td>link</td> <td>Entries in the linker runtime search path (usually set with the <code>-rpath</code> flag). </td> </tr> <tr> <td><strong><code>library_search_directories</code></strong> </td> <td>link</td> <td>Entries in the linker search path (usually set with the <code>-L</code> flag). </td> </tr> <tr> <td><strong><code>libraries_to_link</code></strong> </td> <td>link</td> <td>Flags providing files to link as inputs in the linker invocation. </td> </tr> <tr> <td><strong><code>def_file_path</code></strong> </td> <td>link</td> <td>Location of def file used on Windows with MSVC. </td> </tr> <tr> <td><strong><code>linker_param_file</code></strong> </td> <td>link</td> <td>Location of linker param file created by bazel to overcome command line length limit. </td> </tr> <tr> <td><strong><code>output_execpath</code></strong> </td> <td>link</td> <td>Execpath of the output of the linker. </td> </tr> <tr> <td><strong><code>generate_interface_library</code></strong> </td> <td>link</td> <td><code>"yes"</code> or <code>"no"</code> depending on whether interface library should be generated. </td> </tr> <tr> <td><strong><code>interface_library_builder_path</code></strong> </td> <td>link</td> <td>Path to the interface library builder tool. </td> </tr> <tr> <td><strong><code>interface_library_input_path</code></strong> </td> <td>link</td> <td>Input for the interface library <code>ifso</code> builder tool. </td> </tr> <tr> <td><strong><code>interface_library_output_path</code></strong> </td> <td>link</td> <td>Path where to generate interface library using the <code>ifso</code> builder tool. </td> </tr> <tr> <td><strong><code>legacy_link_flags</code></strong> </td> <td>link</td> <td>Linker flags coming from the legacy <code>CROSSTOOL</code> fields. </td> </tr> <tr> <td><strong><code>user_link_flags</code></strong> </td> <td>link</td> <td>Linker flags coming from the <code>--linkopt</code> or <code>linkopts</code> attribute. </td> </tr> <tr> <td><strong><code>linkstamp_paths</code></strong> </td> <td>link</td> <td>A build variable giving linkstamp paths. </td> </tr> <tr> <td><strong><code>force_pic</code></strong> </td> <td>link</td> <td>Presence of this variable indicates that PIC/PIE code should be generated (Bazel option `--force_pic` was passed). </td> </tr> <tr> <td><strong><code>strip_debug_symbols</code></strong> </td> <td>link</td> <td>Presence of this variable indicates that the debug symbols should be stripped. </td> </tr> <tr> <td><strong><code>is_cc_test</code></strong> </td> <td>link</td> <td>Truthy when current action is a <code>cc_test</code> linking action, false otherwise. </td> </tr> <tr> <td><strong><code>is_using_fission</code></strong> </td> <td>compile, link</td> <td>Presence of this variable indicates that fission (per-object debug info) is activated. Debug info will be in <code>.dwo</code> files instead of <code>.o</code> files and the compiler and linker need to know this. </td> </tr> <tr> <td><strong><code>fdo_instrument_path</code></strong> </td> <td>compile, link</td> <td> Path to the directory that stores FDO instrumentation profile. </td> </tr> <tr> <td><strong><code>fdo_profile_path</code></strong> </td> <td>compile</td> <td> Path to FDO profile. </td> </tr> <tr> <td><strong><code>fdo_prefetch_hints_path</code></strong> </td> <td>compile</td> <td> Path to the cache prefetch profile. </td> </tr> <tr> <td><strong><code>cs_fdo_instrument_path</code></strong> </td> <td>compile, link</td> <td> Path to the directory that stores context sensitive FDO instrumentation profile. </td> </tr> </table>The following is a reference of features and their activation conditions.
<table> <col width="300"> <col width="600"> <tr> <td><strong>Feature</strong> </td> <td><strong>Documentation</strong> </td> </tr> <tr> <td><strong><code>opt | dbg | fastbuild</code></strong> </td> <td>Enabled by default based on compilation mode. </td> </tr> <tr> <td><strong><code>static_linking_mode | dynamic_linking_mode</code></strong> </td> <td>Enabled by default based on linking mode. </td> </tr> <tr> <td><strong><code>per_object_debug_info</code></strong> </td> <td>Enabled if the <code>supports_fission</code> feature is specified and enabled and the current compilation mode is specified in the <code>--fission</code> flag. </td> </tr> <tr> <td><strong><code>supports_start_end_lib</code></strong> </td> <td>If enabled (and the option <code>--start_end_lib</code> is set), Bazel will not link against static libraries but instead use the <code>--start-lib/--end-lib</code> linker options to link against objects directly. This speeds up the build since Bazel doesn't have to build static libraries. </td> </tr> <tr> <td><strong><code>supports_interface_shared_libraries</code></strong> </td> <td>If enabled (and the option <code>--interface_shared_objects</code> is set), Bazel will link targets that have <code>linkstatic</code> set to False (<code>cc_test</code>s by default) against interface shared libraries. This makes incremental relinking faster. </td> </tr> <tr> <td><strong><code>supports_dynamic_linker</code></strong> </td> <td>If enabled, C++ rules will know the toolchain can produce shared libraries. </td> </tr> <tr> <td><strong><code>static_link_cpp_runtimes</code></strong> </td> <td>If enabled, Bazel will link the C++ runtime statically in static linking mode and dynamically in dynamic linking mode. Artifacts specified in the <code>cc_toolchain.static_runtime_lib</code> or <code>cc_toolchain.dynamic_runtime_lib</code> attribute (depending on the linking mode) will be added to the linking actions. </td> </tr> <tr> <td><strong><code>supports_pic</code></strong> </td> <td>If enabled, toolchain will know to use PIC objects for dynamic libraries. The `pic` variable is present whenever PIC compilation is needed. If not enabled by default, and `--force_pic` is passed, Bazel will request `supports_pic` and validate that the feature is enabled. If the feature is missing, or couldn't be enabled, `--force_pic` cannot be used. </td> </tr> <tr> <td> <strong><code>static_linking_mode | dynamic_linking_mode</code></strong> </td> <td>Enabled by default based on linking mode.</td> </tr> <tr> <td><strong><code>no_legacy_features</code></strong> </td> <td> Prevents Bazel from adding legacy features to the C++ configuration when present. See the complete list of features below. </td> </tr> <tr> <td><strong><code>shorten_virtual_includes</code></strong> </td> <td> If enabled, virtual include header files are linked under <code>bin/_virtual_includes/<hash of target path></code> instead of <code>bin/<target package path>/_virtual_includes/<target name></code>. Useful on Windows to avoid long path issue with MSVC. </td> </tr> </table>This is a long list of features. The plan is to get rid of them once
Crosstool in Starlark{: .external} is
done. For the curious reader see the implementation in
CppActionConfigs,
and for production toolchains consider adding no_legacy_features to make
the toolchain more standalone.