Merge branch 'main' into rules-based-toolchain-example
diff --git a/MODULE.bazel b/MODULE.bazel index 51a00b2..91092b0 100644 --- a/MODULE.bazel +++ b/MODULE.bazel
@@ -1,11 +1,11 @@ module( name = "rules_cc", - version = "0.0.4", + version = "0.0.10", compatibility_level = 1, ) bazel_dep(name = "bazel_skylib", version = "1.7.1") -bazel_dep(name = "platforms", version = "0.0.7") +bazel_dep(name = "platforms", version = "0.0.10") bazel_dep(name = "stardoc", version = "0.7.0") cc_configure = use_extension("@bazel_tools//tools/cpp:cc_configure.bzl", "cc_configure_extension")
diff --git a/WORKSPACE b/WORKSPACE index 875888e..a4587d5 100644 --- a/WORKSPACE +++ b/WORKSPACE
@@ -41,10 +41,10 @@ http_archive( name = "platforms", - sha256 = "3a561c99e7bdbe9173aa653fd579fe849f1d8d67395780ab4770b1f381431d51", + sha256 = "218efe8ee736d26a3572663b374a253c012b716d8af0c07e842e82f238a0a7ee", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.7/platforms-0.0.7.tar.gz", - "https://github.com/bazelbuild/platforms/releases/download/0.0.7/platforms-0.0.7.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.10/platforms-0.0.10.tar.gz", + "https://github.com/bazelbuild/platforms/releases/download/0.0.10/platforms-0.0.10.tar.gz", ], )
diff --git a/cc/action_names.bzl b/cc/action_names.bzl index 3df7cfa..6735d82 100644 --- a/cc/action_names.bzl +++ b/cc/action_names.bzl
@@ -88,6 +88,9 @@ # A string constant for the clif action. CLIF_MATCH_ACTION_NAME = "clif-match" +# A string constant for the obj copy actions. +OBJ_COPY_ACTION_NAME = "objcopy_embed_data" + ACTION_NAMES = struct( c_compile = C_COMPILE_ACTION_NAME, cpp_compile = CPP_COMPILE_ACTION_NAME, @@ -113,6 +116,7 @@ objc_fully_link = OBJC_FULLY_LINK_ACTION_NAME, objcpp_compile = OBJCPP_COMPILE_ACTION_NAME, clif_match = CLIF_MATCH_ACTION_NAME, + objcopy_embed_data = OBJ_COPY_ACTION_NAME, ) # Names of actions that parse or compile C++ code.
diff --git a/cc/cc_binary.bzl b/cc/cc_binary.bzl index 70810a2..f36e431 100644 --- a/cc/cc_binary.bzl +++ b/cc/cc_binary.bzl
@@ -19,7 +19,7 @@ # added as a dependency to @rules_cc//:link_extra_lib. The intermediate library # @bazel_tools@bazel_tools//tools/cpp:link_extra_lib should either be added as a dependency # to @rules_cc//:link_extra_lib, or removed entirely (if possible). -_LINK_EXTRA_LIB = "@rules_cc//:link_extra_lib" # copybara-use-repo-external-label +_LINK_EXTRA_LIB = Label("//:link_extra_lib") def cc_binary(**attrs): """Bazel cc_binary rule.
diff --git a/cc/cc_test.bzl b/cc/cc_test.bzl index d3ba601..387fd18 100644 --- a/cc/cc_test.bzl +++ b/cc/cc_test.bzl
@@ -20,7 +20,7 @@ # added as a dependency to @rules_cc//:link_extra_lib. The intermediate library # @bazel_tools@bazel_tools//tools/cpp:link_extra_lib should either be added as a dependency # to @rules_cc//:link_extra_lib, or removed entirely (if possible). -_LINK_EXTRA_LIB = "@rules_cc//:link_extra_lib" # copybara-use-repo-external-label +_LINK_EXTRA_LIB = Label("//:link_extra_lib") def cc_test(**attrs): """Bazel cc_test rule.
diff --git a/cc/common/visibility.bzl b/cc/common/visibility.bzl index dfbc8ce..981ce86 100644 --- a/cc/common/visibility.bzl +++ b/cc/common/visibility.bzl
@@ -1,3 +1,3 @@ """Bzl load visibility package specs""" -INTERNAL_VISIBILITY = ["//cc/..."] +INTERNAL_VISIBILITY = ["public"]
diff --git a/cc/find_cc_toolchain.bzl b/cc/find_cc_toolchain.bzl index 4129680..c3e9ed4 100644 --- a/cc/find_cc_toolchain.bzl +++ b/cc/find_cc_toolchain.bzl
@@ -29,7 +29,7 @@ attrs = { "_cc_toolchain": attr.label( default = Label( - "@rules_cc//cc:current_cc_toolchain", # copybara-use-repo-external-label + "@rules_cc//cc:current_cc_toolchain", ), ), }, @@ -53,7 +53,7 @@ Bazel version is not needed), it's enough to only keep the toolchain type. """ -CC_TOOLCHAIN_TYPE = "@bazel_tools//tools/cpp:toolchain_type" # copybara-use-repo-external-label +CC_TOOLCHAIN_TYPE = Label("@bazel_tools//tools/cpp:toolchain_type") def find_cc_toolchain(ctx, *, mandatory = True): """
diff --git a/cc/toolchains/BUILD b/cc/toolchains/BUILD index 8ae4d97..98fe2cf 100644 --- a/cc/toolchains/BUILD +++ b/cc/toolchains/BUILD
@@ -13,15 +13,11 @@ # limitations under the License. load("@bazel_skylib//:bzl_library.bzl", "bzl_library") -load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") load("@bazel_skylib//rules:diff_test.bzl", "diff_test") +load("@bazel_skylib//rules:expand_template.bzl", "expand_template") load("@stardoc//stardoc:stardoc.bzl", "stardoc") - -bool_flag( - name = "experimental_enable_rule_based_toolchains", - build_setting_default = False, - visibility = ["//visibility:public"], -) +load("//cc/toolchains/impl:documented_api.bzl", "DOCUMENTED_TOOLCHAIN_RULES") +load("//cc/toolchains/impl:markdown_helpers.bzl", "xref_substitutions") bzl_library( name = "toolchain_rules", @@ -49,11 +45,30 @@ stardoc( name = "toolchain_api", - out = "generated_toolchain_api.md", + out = "raw_generated_toolchain_api.md", input = "//cc/toolchains/impl:documented_api.bzl", deps = [":toolchain_rules"], ) +expand_template( + name = "toolchain_api_md", + out = "generated_toolchain_api.md", + # Dictionary order 100% matters here! + # buildifier: disable=unsorted-dict-items + substitutions = { + # Strip @rules_cc to prevent instances of @rules_cc@rules_cc//cc. + "@rules_cc//cc": "//cc", + # In GitHub, we prefer to clarify all the labels that come from + # rules_cc. + "//cc": "@rules_cc//cc", + } | xref_substitutions({ + "`{}`".format(rule_name): "#{}".format(rule_name) + for rule_name in DOCUMENTED_TOOLCHAIN_RULES + }), + # buildifier: enable=unsorted-dict-items + template = ":raw_generated_toolchain_api.md", +) + diff_test( name = "toolchain_api_diff_test", file1 = ":generated_toolchain_api.md",
diff --git a/cc/toolchains/actions.bzl b/cc/toolchains/actions.bzl index fc91787..78c1fc6 100644 --- a/cc/toolchains/actions.bzl +++ b/cc/toolchains/actions.bzl
@@ -37,14 +37,26 @@ }, doc = """A type of action (eg. c_compile, assemble, strip). -Example: +`cc_action_type` rules are used to associate arguments and tools together to +perform a specific action. Bazel prescribes a set of known action types that are used to drive +typical C/C++/ObjC actions like compiling, linking, and archiving. The set of well-known action +types can be found in [//cc/toolchains/actions:BUILD](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/actions/BUILD). -load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") +It's possible to create project-specific action types for use in toolchains. Be careful when +doing this, because every toolchain that encounters the action will need to be configured to +support the custom action type. If your project is a library, avoid creating new action types as +it will reduce compatibility with existing toolchains and increase setup complexity for users. + +Example: +``` +load("//cc:action_names.bzl", "ACTION_NAMES") +load("//cc/toolchains:actions.bzl", "cc_action_type") cc_action_type( - name = "cpp_compile", - action_name = = ACTION_NAMES.cpp_compile, + name = "cpp_compile", + action_name = = ACTION_NAMES.cpp_compile, ) +``` """, provides = [ActionTypeInfo, ActionTypeSetInfo], ) @@ -60,15 +72,21 @@ cc_action_type_set = rule( doc = """Represents a set of actions. +This is a convenience rule to allow for more compact representation of a group of action types. +Use this anywhere a `cc_action_type` is accepted. + Example: +``` +load("//cc/toolchains:actions.bzl", "cc_action_type_set") cc_action_type_set( name = "link_executable_actions", actions = [ - ":cpp_link_executable", - ":lto_index_for_executable", + "//cc/toolchains/actions:cpp_link_executable", + "//cc/toolchains/actions:lto_index_for_executable", ], ) +``` """, implementation = _cc_action_type_set_impl, attrs = {
diff --git a/cc/toolchains/actions/BUILD b/cc/toolchains/actions/BUILD index e122f5c..164a336 100644 --- a/cc/toolchains/actions/BUILD +++ b/cc/toolchains/actions/BUILD
@@ -185,6 +185,13 @@ ) cc_action_type_set( + name = "c_compile_actions", + actions = [ + ":c_compile", + ], +) + +cc_action_type_set( name = "cpp_compile_actions", actions = [ ":linkstamp_compile", @@ -201,7 +208,7 @@ name = "compile_actions", actions = [ ":cpp_compile_actions", - ":c_compile", + ":c_compile_actions", ":assembly_actions", ], )
diff --git a/cc/toolchains/args.bzl b/cc/toolchains/args.bzl index 4f71986..bdcf7ce 100644 --- a/cc/toolchains/args.bzl +++ b/cc/toolchains/args.bzl
@@ -86,30 +86,18 @@ "actions": attr.label_list( providers = [ActionTypeSetInfo], mandatory = True, - doc = """A list of action types that this flag set applies to. - -See @rules_cc//cc/toolchains/actions:all for valid options. -""", + doc = """See documentation for cc_args macro wrapper.""", ), "allowlist_include_directories": attr.label_list( providers = [DirectoryInfo], - doc = """Include paths implied by using this rule. - -Some flags (e.g. --sysroot) imply certain include paths are available despite -not explicitly specifying a normal include path flag (`-I`, `-isystem`, etc.). -Bazel checks that all included headers are properly provided by a dependency or -allowlisted through this mechanism. -""", + doc = """See documentation for cc_args macro wrapper.""", ), "env": attr.string_dict( - doc = "Environment variables to be added to the command-line.", + doc = """See documentation for cc_args macro wrapper.""", ), "requires_any_of": attr.label_list( providers = [FeatureConstraintInfo], - doc = """This will be enabled when any of the constraints are met. - -If omitted, this flag set will be enabled unconditionally. -""", + doc = """See documentation for cc_args macro wrapper.""", ), "_variables": attr.label( default = "//cc/toolchains/variables:variables", @@ -128,9 +116,175 @@ """, ) -def cc_args(name, format = {}, **kwargs): +def cc_args( + *, + name, + actions = None, + allowlist_include_directories = None, + args = None, + data = None, + env = None, + format = {}, + iterate_over = None, + nested = None, + requires_not_none = None, + requires_none = None, + requires_true = None, + requires_false = None, + requires_equal = None, + requires_equal_value = None, + requires_any_of = None, + **kwargs): + """Action-specific arguments for use with a cc_toolchain. + + This rule is the fundamental building building block for every toolchain tool invocation. Each + argument expressed in a toolchain tool invocation (e.g. `gcc`, `llvm-ar`) is declared in a + `cc_args` rule that applies an ordered list of arguments to a set of toolchain + actions. `cc_args` rules can be added unconditionally to a + `cc_toolchain`, conditionally via `select()` statements, or dynamically via an + intermediate `cc_feature`. + + Conceptually, this is similar to the old `CFLAGS`, `CPPFLAGS`, etc. environment variables that + many build systems use to determine which flags to use for a given action. The significant + difference is that `cc_args` rules are declared in a structured way that allows for + significantly more powerful and sharable toolchain configurations. Also, due to Bazel's more + granular action types, it's possible to bind flags to very specific actions (e.g. LTO indexing + for an executable vs a dynamic library) multiple different actions (e.g. C++ compile and link + simultaneously). + + Example usage: + ``` + load("//cc/toolchains:args.bzl", "cc_args") + + # Basic usage: a trivial flag. + # + # An example of expressing `-Werror` as a `cc_args` rule. + cc_args( + name = "warnings_as_errors", + actions = [ + # Applies to all C/C++ compile actions. + "//cc/toolchains/actions:compile_actions", + ], + args = ["-Werror"], + ) + + # Basic usage: ordered flags. + # + # An example of linking against libc++, which uses two flags that must be applied in order. + cc_args( + name = "link_libcxx", + actions = [ + # Applies to all link actions. + "//cc/toolchains/actions:link_actions", + ], + # On tool invocation, this appears as `-Xlinker -lc++`. Nothing will ever end up between + # the two flags. + args = [ + "-Xlinker", + "-lc++", + ], + ) + + # Advanced usage: built-in variable expansions. + # + # Expands to `-L/path/to/search_dir` for each directory in the built-in variable + # `library_search_directories`. This variable is managed internally by Bazel through inherent + # behaviors of Bazel and the interactions between various C/C++ build rules. + cc_args( + name = "library_search_directories", + actions = [ + "//cc/toolchains/actions:link_actions", + ], + args = ["-L{search_dir}"], + iterate_over = "//cc/toolchains/variables:library_search_directories", + requires_not_none = "//cc/toolchains/variables:library_search_directories", + format = { + "search_dir": "//cc/toolchains/variables:library_search_directories", + }, + ) + ``` + + For more extensive examples, see the usages here: + https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args + + Args: + name: (str) The name of the target. + actions: (List[Label]) A list of labels of `cc_action_type` or + `cc_action_type_set` rules that dictate which actions these + arguments should be applied to. + allowlist_include_directories: (List[Label]) A list of include paths that are implied by + using this rule. These must point to a skylib + [directory](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/directory_doc.md#directory) + or [subdirectory](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/directory_subdirectory_doc.md#subdirectory) rule. + Some flags (e.g. --sysroot) imply certain include paths are available despite + not explicitly specifying a normal include path flag (`-I`, `-isystem`, etc.). + Bazel checks that all included headers are properly provided by a dependency or + allowlisted through this mechanism. + + As a rule of thumb, only use this if Bazel is complaining about absolute paths in + your toolchain and you've ensured that the toolchain is compiling with the + `-no-canonical-prefixes` and/or `-fno-canonical-system-headers` arguments. + + This can help work around errors like: + `the source file 'main.c' includes the following non-builtin files with absolute paths + (if these are builtin files, make sure these paths are in your toolchain)`. + args: (List[str]) The command-line arguments that are applied by using this rule. This is + mutually exclusive with [nested](#cc_args-nested). + data: (List[Label]) A list of runtime data dependencies that are required for these + arguments to work as intended. + env: (Dict[str, str]) Environment variables that should be set when the tool is invoked. + format: (Dict[str, Label]) A mapping of format strings to the label of the corresponding + `cc_variable` that the value should be pulled from. All instances of + `{variable_name}` will be replaced with the expanded value of `variable_name` in this + dictionary. The complete list of possible variables can be found in + https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD. + It is not possible to declare custom variables--these are inherent to Bazel itself. + iterate_over: (Label) The label of a `cc_variable` that should be iterated over. This is + intended for use with built-in variables that are lists. + nested: (List[Label]) A list of `cc_nested_args` rules that should be + expanded to command-line arguments when this rule is used. This is mutually exclusive + with [args](#cc_args-args). + requires_not_none: (Label) The label of a `cc_variable` that should be checked + for existence before expanding this rule. If the variable is None, this rule will be + ignored. + requires_none: (Label) The label of a `cc_variable` that should be checked for + non-existence before expanding this rule. If the variable is not None, this rule will be + ignored. + requires_true: (Label) The label of a `cc_variable` that should be checked for + truthiness before expanding this rule. If the variable is false, this rule will be + ignored. + requires_false: (Label) The label of a `cc_variable` that should be checked + for falsiness before expanding this rule. If the variable is true, this rule will be + ignored. + requires_equal: (Label) The label of a `cc_variable` that should be checked + for equality before expanding this rule. If the variable is not equal to + (requires_equal_value)[#cc_args-requires_equal_value], this rule will be ignored. + requires_equal_value: (str) The value to compare (requires_equal)[#cc_args-requires_equal] + against. + requires_any_of: (List[Label]) These arguments will be used + in a tool invocation when at least one of the [cc_feature_constraint](#cc_feature_constraint) + entries in this list are satisfied. If omitted, this flag set will be enabled + unconditionally. + **kwargs: [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. + """ return _cc_args( name = name, + actions = actions, + allowlist_include_directories = allowlist_include_directories, + args = args, + data = data, + env = env, + # We flip the key/value pairs in the dictionary here because Bazel doesn't have a + # string-keyed label dict attribute type. format = {k: v for v, k in format.items()}, + iterate_over = iterate_over, + nested = nested, + requires_not_none = requires_not_none, + requires_none = requires_none, + requires_true = requires_true, + requires_false = requires_false, + requires_equal = requires_equal, + requires_equal_value = requires_equal_value, + requires_any_of = requires_any_of, **kwargs )
diff --git a/cc/toolchains/args/archiver_flags/BUILD b/cc/toolchains/args/archiver_flags/BUILD index d293ed9..4e3c97f 100644 --- a/cc/toolchains/args/archiver_flags/BUILD +++ b/cc/toolchains/args/archiver_flags/BUILD
@@ -16,7 +16,7 @@ cc_args( name = "create_static_archive", - actions = ["//cc/toolchains/actions:cpp_link_static_library"], + actions = ["//cc/toolchains/actions:ar_actions"], args = select({ "@platforms//os:macos": ["-static"], "//conditions:default": ["rcsD"], @@ -25,7 +25,7 @@ cc_args( name = "output_execpath", - actions = ["//cc/toolchains/actions:cpp_link_static_library"], + actions = ["//cc/toolchains/actions:ar_actions"], args = select({ "@platforms//os:macos": ["-o"], "//conditions:default": [], @@ -36,7 +36,7 @@ cc_args( name = "libraries_to_link", - actions = ["//cc/toolchains/actions:cpp_link_static_library"], + actions = ["//cc/toolchains/actions:ar_actions"], nested = ["libraries_to_link_expansion"], requires_not_none = "//cc/toolchains/variables:libraries_to_link", )
diff --git a/cc/toolchains/args/force_pic_flags/BUILD b/cc/toolchains/args/force_pic_flags/BUILD index 63bc341..3eaae56 100644 --- a/cc/toolchains/args/force_pic_flags/BUILD +++ b/cc/toolchains/args/force_pic_flags/BUILD
@@ -4,10 +4,7 @@ cc_args( name = "force_pic_flags", - actions = [ - "//cc/toolchains/actions:cpp_link_executable", - "//cc/toolchains/actions:lto_index_for_executable", - ], + actions = ["//cc/toolchains/actions:link_executable_actions"], args = select({ "@platforms//os:macos": ["-Wl,-pie"], "//conditions:default": ["-pie"],
diff --git a/cc/toolchains/args/libraries_to_link/BUILD b/cc/toolchains/args/libraries_to_link/BUILD index 4bd1331..c338c1c 100644 --- a/cc/toolchains/args/libraries_to_link/BUILD +++ b/cc/toolchains/args/libraries_to_link/BUILD
@@ -6,14 +6,7 @@ cc_args( name = "libraries_to_link", - actions = [ - "//cc/toolchains/actions:cpp_link_executable", - "//cc/toolchains/actions:cpp_link_dynamic_library", - "//cc/toolchains/actions:cpp_link_nodeps_dynamic_library", - "//cc/toolchains/actions:lto_index_for_executable", - "//cc/toolchains/actions:lto_index_for_dynamic_library", - "//cc/toolchains/actions:lto_index_for_nodeps_dynamic_library", - ], + actions = ["//cc/toolchains/actions:link_actions"], nested = [ ":thinlto_param_file", ":libraries_to_link_args",
diff --git a/cc/toolchains/args/linker_param_file/BUILD b/cc/toolchains/args/linker_param_file/BUILD index 64471dc..6d1b4b2 100644 --- a/cc/toolchains/args/linker_param_file/BUILD +++ b/cc/toolchains/args/linker_param_file/BUILD
@@ -12,13 +12,8 @@ cc_args( name = "use_param_file", actions = [ - "//cc/toolchains/actions:cpp_link_executable", - "//cc/toolchains/actions:cpp_link_dynamic_library", - "//cc/toolchains/actions:cpp_link_nodeps_dynamic_library", - "//cc/toolchains/actions:lto_index_for_executable", - "//cc/toolchains/actions:lto_index_for_dynamic_library", - "//cc/toolchains/actions:lto_index_for_nodeps_dynamic_library", - "//cc/toolchains/actions:cpp_link_static_library", + "//cc/toolchains/actions:link_actions", + "//cc/toolchains/actions:ar_actions", ], args = ["@{param_file}"], format = {"param_file": "//cc/toolchains/variables:linker_param_file"},
diff --git a/cc/toolchains/args/runtime_library_search_directories/BUILD b/cc/toolchains/args/runtime_library_search_directories/BUILD index 2b980bc..50bdb43 100644 --- a/cc/toolchains/args/runtime_library_search_directories/BUILD +++ b/cc/toolchains/args/runtime_library_search_directories/BUILD
@@ -32,14 +32,7 @@ cc_args( name = "runtime_library_search_directories_static_runtimes_args", - actions = [ - "//cc/toolchains/actions:cpp_link_executable", - "//cc/toolchains/actions:cpp_link_dynamic_library", - "//cc/toolchains/actions:cpp_link_nodeps_dynamic_library", - "//cc/toolchains/actions:lto_index_for_executable", - "//cc/toolchains/actions:lto_index_for_dynamic_library", - "//cc/toolchains/actions:lto_index_for_nodeps_dynamic_library", - ], + actions = ["//cc/toolchains/actions:link_actions"], nested = [":iterate_over_search_dirs"], requires_any_of = [":static_link_cpp_runtimes_enabled"], requires_not_none = "//cc/toolchains/variables:runtime_library_search_directories", @@ -90,14 +83,7 @@ # longer required. cc_args( name = "runtime_library_search_directories_args", - actions = [ - "//cc/toolchains/actions:cpp_link_executable", - "//cc/toolchains/actions:cpp_link_dynamic_library", - "//cc/toolchains/actions:cpp_link_nodeps_dynamic_library", - "//cc/toolchains/actions:lto_index_for_executable", - "//cc/toolchains/actions:lto_index_for_dynamic_library", - "//cc/toolchains/actions:lto_index_for_nodeps_dynamic_library", - ], + actions = ["//cc/toolchains/actions:link_actions"], nested = [":search_dir_args"], # Remove the requires_any_of here if the workaround for b/27153401 is no # longer required.
diff --git a/cc/toolchains/args/shared_flag/BUILD b/cc/toolchains/args/shared_flag/BUILD index 6a8401a..0c4f1e9 100644 --- a/cc/toolchains/args/shared_flag/BUILD +++ b/cc/toolchains/args/shared_flag/BUILD
@@ -4,12 +4,7 @@ cc_args( name = "shared_flag", - actions = [ - "//cc/toolchains/actions:cpp_link_dynamic_library", - "//cc/toolchains/actions:cpp_link_nodeps_dynamic_library", - "//cc/toolchains/actions:lto_index_for_dynamic_library", - "//cc/toolchains/actions:lto_index_for_nodeps_dynamic_library", - ], + actions = ["//cc/toolchains/actions:dynamic_library_link_actions"], args = ["-shared"], visibility = ["//visibility:public"], )
diff --git a/cc/toolchains/args_list.bzl b/cc/toolchains/args_list.bzl index fbbaad5..0747acb 100644 --- a/cc/toolchains/args_list.bzl +++ b/cc/toolchains/args_list.bzl
@@ -24,11 +24,49 @@ cc_args_list = rule( implementation = _cc_args_list_impl, - doc = "A list of cc_args", + doc = """An ordered list of cc_args. + + This is a convenience rule to allow you to group a set of multiple `cc_args` into a + single list. This particularly useful for toolchain behaviors that require different flags for + different actions. + + Note: The order of the arguments in `args` is preserved to support order-sensitive flags. + + Example usage: + ``` + load("//cc/toolchains:cc_args.bzl", "cc_args") + load("//cc/toolchains:args_list.bzl", "cc_args_list") + + cc_args( + name = "gc_sections", + actions = [ + "//cc/toolchains/actions:link_actions", + ], + args = ["-Wl,--gc-sections"], + ) + + cc_args( + name = "function_sections", + actions = [ + "//cc/toolchains/actions:compile_actions", + "//cc/toolchains/actions:link_actions", + ], + args = ["-ffunction-sections"], + ) + + cc_args_list( + name = "gc_functions", + args = [ + ":function_sections", + ":gc_sections", + ], + ) + ``` + """, attrs = { "args": attr.label_list( providers = [ArgsListInfo], - doc = "The cc_args to include", + doc = "(ordered) cc_args to include in this list.", ), }, provides = [ArgsListInfo],
diff --git a/cc/toolchains/feature.bzl b/cc/toolchains/feature.bzl index a282762..f0acbfe 100644 --- a/cc/toolchains/feature.bzl +++ b/cc/toolchains/feature.bzl
@@ -110,22 +110,23 @@ toolchain, they can happily live alongside each other in the same BUILD file. Example: +``` +cc_feature( + name = "sysroot_macos", + feature_name = "sysroot", + ... +) - cc_feature( - name = "sysroot_macos", - feature_name = "sysroot", - ... - ) - - cc_feature( - name = "sysroot_linux", - feature_name = "sysroot", - ... - ) +cc_feature( + name = "sysroot_linux", + feature_name = "sysroot", + ... +) +``` """, ), "args": attr.label_list( - doc = """Args that, when expanded, implement this feature.""", + doc = """A list of `cc_args` or `cc_args_list` labels that are expanded when this feature is enabled.""", providers = [ArgsListInfo], ), "requires_any_of": attr.label_list( @@ -152,7 +153,7 @@ ), "mutually_exclusive": attr.label_list( providers = [MutuallyExclusiveCategoryInfo], - doc = """A list of things that this is mutually exclusive with. + doc = """A list of things that this feature is mutually exclusive with. It can be either: * A feature, in which case the two features are mutually exclusive. @@ -171,14 +172,16 @@ that the feature "opt" was defined twice. Example: +``` +load("//cc/toolchains:feature.bzl", "cc_feature") - cc_feature( - name = "opt", - feature_name = "opt", - ... - overrides = "@toolchain//features/well_known:opt", - ) - +cc_feature( + name = "opt", + feature_name = "opt", + args = [":size_optimized"], + overrides = "//cc/toolchains/features:opt", +) +``` """, ), }, @@ -188,53 +191,58 @@ FeatureConstraintInfo, MutuallyExclusiveCategoryInfo, ], - doc = """Defines the implemented behavior of a C/C++ toolchain feature. + doc = """A dynamic set of toolchain flags that create a singular [feature](https://bazel.build/docs/cc-toolchain-config-reference#features) definition. -A feature is basically a toggleable list of args. There are a variety of -dependencies and compatibility requirements that must be satisfied for the -listed args to be applied. +A feature is basically a dynamically toggleable `cc_args_list`. There are a variety of +dependencies and compatibility requirements that must be satisfied to enable a +`cc_feature`. Once those conditions are met, the arguments in [`cc_feature.args`](#cc_feature-args) +are expanded and added to the command-line. A feature may be enabled or disabled through the following mechanisms: -* Via command-line flags, or a `.bazelrc`. -* Through inter-feature relationships (enabling one feature may implicitly - enable another). -* Individual rules may elect to manually enable or disable features through the - builtin `features` attribute. +* Via command-line flags, or a `.bazelrc` file via the + [`--features` flag](https://bazel.build/reference/command-line-reference#flag--features) +* Through inter-feature relationships (via [`cc_feature.implies`](#cc_feature-implies)) where one + feature may implicitly enable another. +* Individual rules (e.g. `cc_library`) or `package` definitions may elect to manually enable or + disable features through the + [`features` attribute](https://bazel.build/reference/be/common-definitions#common.features). -Because of the toggleable nature of toolchain features, it's generally best to -avoid defining features as part of your toolchain with the following exceptions: -* You want build files to be able to configure compiler flags. For example, a +Note that a feature may alternate between enabled and disabled dynamically over the course of a +build. Because of their toggleable nature, it's generally best to avoid adding arguments to a +`cc_toolchain` as a `cc_feature` unless strictly necessary. Instead, prefer to express arguments +via [`cc_toolchain.args`](#cc_toolchain-args) whenever possible. + +You should use a `cc_feature` when any of the following apply: +* You need the flags to be dynamically toggled over the course of a build. +* You want build files to be able to configure the flags in question. For example, a binary might specify `features = ["optimize_for_size"]` to create a small binary instead of optimizing for performance. * You need to carry forward Starlark toolchain behaviors. If you're migrating a complex Starlark-based toolchain definition to these rules, many of the - workflows and flags were likely based on features. This rule exists to support - those existing structures. + workflows and flags were likely based on features. -If you want to be able to configure flags via the bazel command-line, instead -consider making a bool_flag, and then making your `cc_args` `select` on those -flags. +If you only need to configure flags via the Bazel command-line, instead +consider adding a +[`bool_flag`](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/common_settings_doc.md#bool_flag) +paired with a [`config_setting`](https://bazel.build/reference/be/general#config_setting) +and then make your `cc_args` rule `select` on the `config_setting`. For more details about how Bazel handles features, see the official Bazel documentation at https://bazel.build/docs/cc-toolchain-config-reference#features. -Examples: +Example: +``` +load("//cc/toolchains:feature.bzl", "cc_feature") - # A feature that can be easily toggled to optimize for size - cc_feature( - name = "optimize_for_size", - feature_name = "optimize_for_size", - args = [":optimize_for_size_args"], - ) - - # This feature signals a capability, and doesn't have associated flags. - # - # For a list of well-known features, see: - # https://bazel.build/docs/cc-toolchain-config-reference#wellknown-features - cc_feature( - name = "supports_pic", - overrides = "//cc/toolchains/features:supports_pic - ) +# A feature that enables LTO, which may be incompatible when doing interop with various +# languages (e.g. rust, go), or may need to be disabled for particular `cc_binary` rules +# for various reasons. +cc_feature( + name = "lto", + feature_name = "lto", + args = [":lto_args"], +) +``` """, )
diff --git a/cc/toolchains/feature_constraint.bzl b/cc/toolchains/feature_constraint.bzl index c6ae44a..8a3d60f 100644 --- a/cc/toolchains/feature_constraint.bzl +++ b/cc/toolchains/feature_constraint.bzl
@@ -47,8 +47,26 @@ ), }, provides = [FeatureConstraintInfo], - doc = """Defines a constraint on features. + doc = """Defines a compound relationship between features. -Can be used with require_any_of to specify that something is only enabled when -a constraint is met.""", +This rule can be used with [`cc_args.require_any_of`](#cc_args-require_any_of) to specify that a set +of arguments are only enabled when a constraint is met. Both `all_of` and `none_of` must be +satisfied simultaneously. + +This is basically a `cc_feature_set` that supports `none_of` expressions. This extra flexibility +is why this rule may only be used by [`cc_args.require_any_of`](#cc_args-require_any_of). + +Example: +``` +load("//cc/toolchains:feature_constraint.bzl", "cc_feature_constraint") + +# A constraint that requires a `linker_supports_thinlto` feature to be enabled, +# AND a `no_optimization` to be disabled. +cc_feature_constraint( + name = "thinlto_constraint", + all_of = [":linker_supports_thinlto"], + none_of = [":no_optimization"], +) +``` +""", )
diff --git a/cc/toolchains/feature_set.bzl b/cc/toolchains/feature_set.bzl index 07af6d1..5fcdae4 100644 --- a/cc/toolchains/feature_set.bzl +++ b/cc/toolchains/feature_set.bzl
@@ -44,14 +44,20 @@ provides = [FeatureSetInfo], doc = """Defines a set of features. -Example: +This may be used by both `cc_feature` and `cc_args` rules, and is effectively a way to express +a logical `AND` operation across multiple requred features. - cc_feature_set( - name = "thin_lto_requirements", - all_of = [ - ":thin_lto", - ":opt", - ], - ) +Example: +``` +load("//cc/toolchains:feature_set.bzl", "cc_feature_set") + +cc_feature_set( + name = "thin_lto_requirements", + all_of = [ + ":thin_lto", + ":opt", + ], +) +``` """, )
diff --git a/cc/toolchains/impl/documented_api.bzl b/cc/toolchains/impl/documented_api.bzl index d840b7e..a863290 100644 --- a/cc/toolchains/impl/documented_api.bzl +++ b/cc/toolchains/impl/documented_api.bzl
@@ -13,6 +13,48 @@ # limitations under the License. """This is a list of rules/macros that should be exported as documentation.""" +load("//cc/toolchains:actions.bzl", _cc_action_type = "cc_action_type", _cc_action_type_set = "cc_action_type_set") +load("//cc/toolchains:args.bzl", _cc_args = "cc_args") +load("//cc/toolchains:args_list.bzl", _cc_args_list = "cc_args_list") +load("//cc/toolchains:feature.bzl", _cc_feature = "cc_feature") +load("//cc/toolchains:feature_constraint.bzl", _cc_feature_constraint = "cc_feature_constraint") +load("//cc/toolchains:feature_set.bzl", _cc_feature_set = "cc_feature_set") +load("//cc/toolchains:mutually_exclusive_category.bzl", _cc_mutually_exclusive_category = "cc_mutually_exclusive_category") +load("//cc/toolchains:nested_args.bzl", _cc_nested_args = "cc_nested_args") +load("//cc/toolchains:tool.bzl", _cc_tool = "cc_tool") load("//cc/toolchains:tool_map.bzl", _cc_tool_map = "cc_tool_map") +load("//cc/toolchains/impl:external_feature.bzl", _cc_external_feature = "cc_external_feature") +load("//cc/toolchains/impl:variables.bzl", _cc_variable = "cc_variable") cc_tool_map = _cc_tool_map +cc_tool = _cc_tool +cc_args = _cc_args +cc_nested_args = _cc_nested_args +cc_args_list = _cc_args_list +cc_action_type = _cc_action_type +cc_action_type_set = _cc_action_type_set +cc_variable = _cc_variable +cc_feature = _cc_feature +cc_feature_constraint = _cc_feature_constraint +cc_feature_set = _cc_feature_set +cc_mutually_exclusive_category = _cc_mutually_exclusive_category +cc_external_feature = _cc_external_feature + +# This list is used to automatically remap instances of `foo` to [`foo`](#foo) +# links in the generated documentation so that maintainers don't need to manually +# ensure every reference to a rule is properly linked. +DOCUMENTED_TOOLCHAIN_RULES = [ + "cc_tool_map", + "cc_tool", + "cc_args", + "cc_nested_args", + "cc_args_list", + "cc_action_type", + "cc_action_type_set", + "cc_variable", + "cc_feature", + "cc_feature_constraint", + "cc_feature_set", + "cc_mutually_exclusive_category", + "cc_external_feature", +]
diff --git a/cc/toolchains/impl/external_feature.bzl b/cc/toolchains/impl/external_feature.bzl index 1e11bc9..027738f 100644 --- a/cc/toolchains/impl/external_feature.bzl +++ b/cc/toolchains/impl/external_feature.bzl
@@ -69,5 +69,26 @@ ), }, provides = [FeatureInfo, FeatureSetInfo, FeatureConstraintInfo], - doc = "A declaration that a feature with this name is defined elsewhere.", + doc = """A declaration that a [feature](https://bazel.build/docs/cc-toolchain-config-reference#features) with this name is defined elsewhere. + +This rule communicates that a feature has been defined externally to make it possible to reference +features that live outside the rule-based cc toolchain ecosystem. This allows various toolchain +rules to reference the external feature without accidentally re-defining said feature. + +This rule is currently considered a private API of the toolchain rules to encourage the Bazel +ecosystem to migrate to properly defining their features as rules. + +Example: +``` +load("//cc/toolchains:external_feature.bzl", "cc_external_feature") + +# rules_rust defines a feature that is disabled whenever rust artifacts are being linked using +# the cc toolchain to signal that incompatible flags should be disabled as well. +cc_external_feature( + name = "rules_rust_unsupported_feature", + feature_name = "rules_rust_unsupported_feature", + overridable = False, +) +``` +""", )
diff --git a/cc/toolchains/impl/markdown_helpers.bzl b/cc/toolchains/impl/markdown_helpers.bzl new file mode 100644 index 0000000..1ae401f --- /dev/null +++ b/cc/toolchains/impl/markdown_helpers.bzl
@@ -0,0 +1,53 @@ +# Copyright 2024 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""A few small helpers for working with Markdown.""" + +def markdown_link(link_text, href): + """Creates a markdown link. + + Args: + link_text: The text to display for the link. + href: The href for the link. + + Returns: + A markdown link. + """ + return "[" + link_text + "](" + href + ")" + +def xref_substitutions(match_text_patterns): + """Creates a dictionary of substitutions for use for linkification of text. + + Example: + ``` + # Produces a dictionary containing: + # { + # "foo": "[foo](http://foo.com)" + # "bar": "[bar](http://bar.com)" + # } + substitutions = xref_substitutions({ + "foo": "http://foo.com", + "bar": "http://bar.com", + }) + ``` + + Args: + match_text_patterns: A dictionary mapping string literals to the links they should point to. + + Returns: + A dictionary of string literals mapped to their linkified substitutions. + """ + return { + match_text: markdown_link(match_text, href) + for match_text, href in match_text_patterns.items() + }
diff --git a/cc/toolchains/impl/toolchain_config.bzl b/cc/toolchains/impl/toolchain_config.bzl index 5c8d69c..da2a873 100644 --- a/cc/toolchains/impl/toolchain_config.bzl +++ b/cc/toolchains/impl/toolchain_config.bzl
@@ -13,7 +13,6 @@ # limitations under the License. """Implementation of the cc_toolchain rule.""" -load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") load( "//cc/toolchains:cc_toolchain_info.bzl", "ActionTypeSetInfo", @@ -52,9 +51,6 @@ if ctx.attr.features: fail("Features is a reserved attribute in bazel. Did you mean 'known_features' or 'enabled_features'?") - if not ctx.attr._enabled[BuildSettingInfo].value and not ctx.attr.skip_experimental_flag_validation_for_test: - fail("Rule based toolchains are experimental. To use it, please add --@rules_cc//cc/toolchains:experimental_enable_rule_based_toolchains to your bazelrc") - toolchain_config = toolchain_config_info( label = ctx.label, known_features = ctx.attr.known_features + [ctx.attr._builtin_features], @@ -86,7 +82,7 @@ ), # This allows us to support all_files. # If all_files was simply an alias to - # ///cc/toolchains/actions:all_actions, + # //cc/toolchains/actions:all_actions, # then if a toolchain introduced a new type of action, it wouldn't get # put in all_files. DefaultInfo(files = depset(transitive = toolchain_config.files.values())), @@ -101,9 +97,7 @@ "args": attr.label_list(providers = [ArgsListInfo]), "known_features": attr.label_list(providers = [FeatureSetInfo]), "enabled_features": attr.label_list(providers = [FeatureSetInfo]), - "skip_experimental_flag_validation_for_test": attr.bool(default = False), "_builtin_features": attr.label(default = "//cc/toolchains/features:all_builtin_features"), - "_enabled": attr.label(default = "//cc/toolchains:experimental_enable_rule_based_toolchains"), }, provides = [ToolchainConfigInfo], )
diff --git a/cc/toolchains/impl/variables.bzl b/cc/toolchains/impl/variables.bzl index c2820f3..aac945e 100644 --- a/cc/toolchains/impl/variables.bzl +++ b/cc/toolchains/impl/variables.bzl
@@ -67,19 +67,32 @@ ) def cc_variable(name, type, **kwargs): - """Defines a variable for both the specified variable, and all nested ones. + """Exposes a toolchain variable to use in toolchain argument expansions. - Eg. cc_variable( - name = "foo", - type = types.list(types.struct(bar = types.string)) + This internal rule exposes [toolchain variables](https://bazel.build/docs/cc-toolchain-config-reference#cctoolchainconfiginfo-build-variables) + that may be expanded in `cc_args` or `cc_nested_args` + rules. Because these varaibles merely expose variables inherrent to Bazel, + it's not possible to declare custom variables. + + For a full list of available variables, see + [//cc/toolchains/varaibles:BUILD](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD). + + Example: + ``` + load("//cc/toolchains/impl:variables.bzl", "cc_variable") + + # Defines two targets, ":foo" and ":foo.bar" + cc_variable( + name = "foo", + type = types.list(types.struct(bar = types.string)), ) - - would define two targets, ":foo" and ":foo.bar" + ``` Args: name: (str) The name of the outer variable, and the rule. - type: The type of the variable, constructed using types above. - **kwargs: kwargs to pass to _cc_variable. + type: The type of the variable, constructed using `types` factory in + [//cc/toolchains/impl:variables.bzl](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/impl/variables.bzl). + **kwargs: [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. """ _cc_variable(name = name, type = json.encode(type), **kwargs)
diff --git a/cc/toolchains/mutually_exclusive_category.bzl b/cc/toolchains/mutually_exclusive_category.bzl index 9920290..f83b554 100644 --- a/cc/toolchains/mutually_exclusive_category.bzl +++ b/cc/toolchains/mutually_exclusive_category.bzl
@@ -23,7 +23,40 @@ cc_mutually_exclusive_category = rule( implementation = _cc_mutually_exclusive_category_impl, - doc = "A category of features, for which only one can be enabled", + doc = """A rule used to categorize `cc_feature` definitions for which only one can be enabled. + +This is used by [`cc_feature.mutually_exclusive`](#cc_feature-mutually_exclusive) to express groups +of `cc_feature` definitions that are inherently incompatible with each other and must be treated as +mutually exclusive. + +Warning: These groups are keyed by name, so two `cc_mutually_exclusive_category` definitions of the +same name in different packages will resolve to the same logical group. + +Example: +``` +load("//cc/toolchains:feature.bzl", "cc_feature") +load("//cc/toolchains:mutually_exclusive_category.bzl", "cc_mutually_exclusive_category") + +cc_mutually_exclusive_category( + name = "opt_level", +) + +cc_feature( + name = "speed_optimized", + mutually_exclusive = [":opt_level"], +) + +cc_feature( + name = "size_optimized", + mutually_exclusive = [":opt_level"], +) + +cc_feature( + name = "unoptimized", + mutually_exclusive = [":opt_level"], +) +``` +""", attrs = {}, provides = [MutuallyExclusiveCategoryInfo], )
diff --git a/cc/toolchains/nested_args.bzl b/cc/toolchains/nested_args.bzl index 1d31275..d81dd99 100644 --- a/cc/toolchains/nested_args.bzl +++ b/cc/toolchains/nested_args.bzl
@@ -41,9 +41,88 @@ """, ) -def cc_nested_args(name, format = {}, **kwargs): +def cc_nested_args( + *, + name, + args = None, + data = None, + format = {}, + iterate_over = None, + nested = None, + requires_not_none = None, + requires_none = None, + requires_true = None, + requires_false = None, + requires_equal = None, + requires_equal_value = None, + **kwargs): + """Nested arguments for use in more complex `cc_args` expansions. + + While this rule is very similar in shape to `cc_args`, it is intended to be used as a + dependency of `cc_args` to provide additional arguments that should be applied to the + same actions as defined by the parent `cc_args` rule. The key motivation for this rule + is to allow for more complex variable-based argument expensions. + + Prefer expressing collections of arguments as `cc_args` and + `cc_args_list` rules when possible. + + For living examples of how this rule is used, see the usages here: + https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/runtime_library_search_directories/BUILD + https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/libraries_to_link/BUILD + + Note: These examples are non-trivial, but they illustrate when it is absolutely necessary to + use this rule. + + Args: + name: (str) The name of the target. + args: (List[str]) The command-line arguments that are applied by using this rule. This is + mutually exclusive with [nested](#cc_nested_args-nested). + data: (List[Label]) A list of runtime data dependencies that are required for these + arguments to work as intended. + format: (Dict[str, Label]) A mapping of format strings to the label of the corresponding + `cc_variable` that the value should be pulled from. All instances of + `{variable_name}` will be replaced with the expanded value of `variable_name` in this + dictionary. The complete list of possible variables can be found in + https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD. + It is not possible to declare custom variables--these are inherent to Bazel itself. + iterate_over: (Label) The label of a `cc_variable` that should be iterated + over. This is intended for use with built-in variables that are lists. + nested: (List[Label]) A list of `cc_nested_args` rules that should be + expanded to command-line arguments when this rule is used. This is mutually exclusive + with [args](#cc_nested_args-args). + requires_not_none: (Label) The label of a `cc_variable` that should be checked + for existence before expanding this rule. If the variable is None, this rule will be + ignored. + requires_none: (Label) The label of a `cc_variable` that should be checked for + non-existence before expanding this rule. If the variable is not None, this rule will be + ignored. + requires_true: (Label) The label of a `cc_variable` that should be checked for + truthiness before expanding this rule. If the variable is false, this rule will be + ignored. + requires_false: (Label) The label of a `cc_variable` that should be checked + for falsiness before expanding this rule. If the variable is true, this rule will be + ignored. + requires_equal: (Label) The label of a `cc_variable` that should be checked + for equality before expanding this rule. If the variable is not equal to + (requires_equal_value)[#cc_nested_args-requires_equal_value], this rule will be ignored. + requires_equal_value: (str) The value to compare + (requires_equal)[#cc_nested_args-requires_equal] against. + **kwargs: [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. + """ return _cc_nested_args( name = name, + args = args, + data = data, + # We flip the key/value pairs in the dictionary here because Bazel doesn't have a + # string-keyed label dict attribute type. format = {k: v for v, k in format.items()}, + iterate_over = iterate_over, + nested = nested, + requires_not_none = requires_not_none, + requires_none = requires_none, + requires_true = requires_true, + requires_false = requires_false, + requires_equal = requires_equal, + requires_equal_value = requires_equal_value, **kwargs )
diff --git a/cc/toolchains/tool.bzl b/cc/toolchains/tool.bzl index 159a9d6..0dc309d 100644 --- a/cc/toolchains/tool.bzl +++ b/cc/toolchains/tool.bzl
@@ -66,13 +66,17 @@ cfg = "exec", doc = """The underlying binary that this tool represents. -Usually just a single prebuilt (eg. @sysroot//:bin/clang), but may be any +Usually just a single prebuilt (eg. @toolchain//:bin/clang), but may be any executable label. """, ), "data": attr.label_list( allow_files = True, - doc = "Additional files that are required for this tool to run.", + doc = """Additional files that are required for this tool to run. + +Frequently, clang and gcc require additional files to execute as they often shell out to +other binaries (e.g. `cc1`). +""", ), "allowlist_include_directories": attr.label_list( providers = [DirectoryInfo], @@ -82,17 +86,34 @@ unless flags like `-nostdinc` are provided. Bazel checks that all included headers are properly provided by a dependency or allowlisted through this mechanism. + +As a rule of thumb, only use this if Bazel is complaining about absolute paths in your +toolchain and you've ensured that the toolchain is compiling with the `-no-canonical-prefixes` +and/or `-fno-canonical-system-headers` arguments. + +This can help work around errors like: +`the source file 'main.c' includes the following non-builtin files with absolute paths +(if these are builtin files, make sure these paths are in your toolchain)`. """, ), }, provides = [ToolInfo], - doc = """Declares a tool that can be bound to action configs. + doc = """Declares a tool for use by toolchain actions. -A tool is a binary with extra metadata for the action config rule to consume -(eg. execution_requirements). +`cc_tool` rules are used in a `cc_tool_map` rule to ensure all files and +metadata required to run a tool are available when constructing a `cc_toolchain`. + +In general, include all files that are always required to run a tool (e.g. libexec/** and +cross-referenced tools in bin/*) in the [data](#cc_tool-data) attribute. If some files are only +required when certain flags are passed to the tool, consider using a `cc_args` rule to +bind the files to the flags that require them. This reduces the overhead required to properly +enumerate a sandbox with all the files required to run a tool, and ensures that there isn't +unintentional leakage across configurations and actions. Example: ``` +load("//cc/toolchains:tool.bzl", "cc_tool") + cc_tool( name = "clang_tool", executable = "@llvm_toolchain//:bin/clang",
diff --git a/cc/toolchains/tool_map.bzl b/cc/toolchains/tool_map.bzl index 62e94e6..b4f7e35 100644 --- a/cc/toolchains/tool_map.bzl +++ b/cc/toolchains/tool_map.bzl
@@ -70,11 +70,12 @@ def cc_tool_map(name, tools, **kwargs): """A toolchain configuration rule that maps toolchain actions to tools. - A cc_tool_map aggregates all the tools that may be used for a given toolchain and maps them to - their corresponding actions. Conceptually, this is similar to the `CXX=/path/to/clang++` - environment variables that most build systems use to determine which tools to use for a given - action. To simplify usage, some actions have been grouped together (for example, - //cc/toolchains/actions:cpp_compile_actions) to + A `cc_tool_map` aggregates all the tools that may be used for a given toolchain + and maps them to their corresponding actions. Conceptually, this is similar to the + `CXX=/path/to/clang++` environment variables that most build systems use to determine which + tools to use for a given action. To simplify usage, some actions have been grouped together (for + example, + [//cc/toolchains/actions:cpp_compile_actions](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/actions/BUILD)) to logically express "all the C++ compile actions". In Bazel, there is a little more granularity to the mapping, so the mapping doesn't follow the @@ -106,7 +107,8 @@ Args: name: (str) The name of the target. - tools: (Dict[target providing ActionTypeSetInfo, Executable target]) A mapping between `cc_action_type` targets + tools: (Dict[Label, Label]) A mapping between + `cc_action_type`/`cc_action_type_set` targets and the `cc_tool` or executable target that implements that action. **kwargs: [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. """
diff --git a/cc/toolchains/toolchain.bzl b/cc/toolchains/toolchain.bzl index 8ee15de..ca4b639 100644 --- a/cc/toolchains/toolchain.bzl +++ b/cc/toolchains/toolchain.bzl
@@ -27,28 +27,28 @@ # work out what actions correspond to what file groups. _LEGACY_FILE_GROUPS = { "ar_files": [ - "@rules_cc//cc/toolchains/actions:ar_actions", # copybara-use-repo-external-label + Label("//cc/toolchains/actions:ar_actions"), ], "as_files": [ - "@rules_cc//cc/toolchains/actions:assembly_actions", # copybara-use-repo-external-label + Label("//cc/toolchains/actions:assembly_actions"), ], "compiler_files": [ - "@rules_cc//cc/toolchains/actions:cc_flags_make_variable", # copybara-use-repo-external-label - "@rules_cc//cc/toolchains/actions:c_compile", # copybara-use-repo-external-label - "@rules_cc//cc/toolchains/actions:cpp_compile", # copybara-use-repo-external-label - "@rules_cc//cc/toolchains/actions:cpp_header_parsing", # copybara-use-repo-external-label + Label("//cc/toolchains/actions:cc_flags_make_variable"), + Label("//cc/toolchains/actions:c_compile"), + Label("//cc/toolchains/actions:cpp_compile"), + Label("//cc/toolchains/actions:cpp_header_parsing"), ], # There are no actions listed for coverage, dwp, and objcopy in action_names.bzl. "coverage_files": [], "dwp_files": [], "linker_files": [ - "@rules_cc//cc/toolchains/actions:cpp_link_dynamic_library", # copybara-use-repo-external-label - "@rules_cc//cc/toolchains/actions:cpp_link_nodeps_dynamic_library", # copybara-use-repo-external-label - "@rules_cc//cc/toolchains/actions:cpp_link_executable", # copybara-use-repo-external-label + Label("//cc/toolchains/actions:cpp_link_dynamic_library"), + Label("//cc/toolchains/actions:cpp_link_nodeps_dynamic_library"), + Label("//cc/toolchains/actions:cpp_link_executable"), ], "objcopy_files": [], "strip_files": [ - "@rules_cc//cc/toolchains/actions:strip", # copybara-use-repo-external-label + Label("//cc/toolchains/actions:strip"), ], }
diff --git a/cc/toolchains/toolchain_api.md b/cc/toolchains/toolchain_api.md index 3a4a490..418ef52 100644 --- a/cc/toolchains/toolchain_api.md +++ b/cc/toolchains/toolchain_api.md
@@ -2,6 +2,577 @@ This is a list of rules/macros that should be exported as documentation. +<a id="cc_action_type"></a> + +## cc_action_type + +<pre> +cc_action_type(<a href="#cc_action_type-name">name</a>, <a href="#cc_action_type-action_name">action_name</a>) +</pre> + +A type of action (eg. c_compile, assemble, strip). + +[`cc_action_type`](#cc_action_type) rules are used to associate arguments and tools together to +perform a specific action. Bazel prescribes a set of known action types that are used to drive +typical C/C++/ObjC actions like compiling, linking, and archiving. The set of well-known action +types can be found in [@rules_cc//cc/toolchains/actions:BUILD](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/actions/BUILD). + +It's possible to create project-specific action types for use in toolchains. Be careful when +doing this, because every toolchain that encounters the action will need to be configured to +support the custom action type. If your project is a library, avoid creating new action types as +it will reduce compatibility with existing toolchains and increase setup complexity for users. + +Example: +``` +load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") +load("@rules_cc//cc/toolchains:actions.bzl", "cc_action_type") + +cc_action_type( + name = "cpp_compile", + action_name = = ACTION_NAMES.cpp_compile, +) +``` + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| <a id="cc_action_type-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | | +| <a id="cc_action_type-action_name"></a>action_name | - | String | required | | + + +<a id="cc_action_type_set"></a> + +## cc_action_type_set + +<pre> +cc_action_type_set(<a href="#cc_action_type_set-name">name</a>, <a href="#cc_action_type_set-actions">actions</a>, <a href="#cc_action_type_set-allow_empty">allow_empty</a>) +</pre> + +Represents a set of actions. + +This is a convenience rule to allow for more compact representation of a group of action types. +Use this anywhere a [`cc_action_type`](#cc_action_type) is accepted. + +Example: +``` +load("@rules_cc//cc/toolchains:actions.bzl", "cc_action_type_set") + +cc_action_type_set( + name = "link_executable_actions", + actions = [ + "@rules_cc//cc/toolchains/actions:cpp_link_executable", + "@rules_cc//cc/toolchains/actions:lto_index_for_executable", + ], +) +``` + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| <a id="cc_action_type_set-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | | +| <a id="cc_action_type_set-actions"></a>actions | A list of cc_action_type or cc_action_type_set | <a href="https://bazel.build/concepts/labels">List of labels</a> | required | | +| <a id="cc_action_type_set-allow_empty"></a>allow_empty | - | Boolean | optional | `False` | + + +<a id="cc_args_list"></a> + +## cc_args_list + +<pre> +cc_args_list(<a href="#cc_args_list-name">name</a>, <a href="#cc_args_list-args">args</a>) +</pre> + +An ordered list of cc_args. + +This is a convenience rule to allow you to group a set of multiple [`cc_args`](#cc_args) into a +single list. This particularly useful for toolchain behaviors that require different flags for +different actions. + +Note: The order of the arguments in `args` is preserved to support order-sensitive flags. + +Example usage: +``` +load("@rules_cc//cc/toolchains:cc_args.bzl", "cc_args") +load("@rules_cc//cc/toolchains:args_list.bzl", "cc_args_list") + +cc_args( + name = "gc_sections", + actions = [ + "@rules_cc//cc/toolchains/actions:link_actions", + ], + args = ["-Wl,--gc-sections"], +) + +cc_args( + name = "function_sections", + actions = [ + "@rules_cc//cc/toolchains/actions:compile_actions", + "@rules_cc//cc/toolchains/actions:link_actions", + ], + args = ["-ffunction-sections"], +) + +cc_args_list( + name = "gc_functions", + args = [ + ":function_sections", + ":gc_sections", + ], +) +``` + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| <a id="cc_args_list-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | | +| <a id="cc_args_list-args"></a>args | (ordered) cc_args to include in this list. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` | + + +<a id="cc_external_feature"></a> + +## cc_external_feature + +<pre> +cc_external_feature(<a href="#cc_external_feature-name">name</a>, <a href="#cc_external_feature-feature_name">feature_name</a>, <a href="#cc_external_feature-overridable">overridable</a>) +</pre> + +A declaration that a [feature](https://bazel.build/docs/cc-toolchain-config-reference#features) with this name is defined elsewhere. + +This rule communicates that a feature has been defined externally to make it possible to reference +features that live outside the rule-based cc toolchain ecosystem. This allows various toolchain +rules to reference the external feature without accidentally re-defining said feature. + +This rule is currently considered a private API of the toolchain rules to encourage the Bazel +ecosystem to migrate to properly defining their features as rules. + +Example: +``` +load("@rules_cc//cc/toolchains:external_feature.bzl", "cc_external_feature") + +# rules_rust defines a feature that is disabled whenever rust artifacts are being linked using +# the cc toolchain to signal that incompatible flags should be disabled as well. +cc_external_feature( + name = "rules_rust_unsupported_feature", + feature_name = "rules_rust_unsupported_feature", + overridable = False, +) +``` + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| <a id="cc_external_feature-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | | +| <a id="cc_external_feature-feature_name"></a>feature_name | The name of the feature | String | required | | +| <a id="cc_external_feature-overridable"></a>overridable | Whether the feature can be overridden | Boolean | required | | + + +<a id="cc_feature"></a> + +## cc_feature + +<pre> +cc_feature(<a href="#cc_feature-name">name</a>, <a href="#cc_feature-args">args</a>, <a href="#cc_feature-feature_name">feature_name</a>, <a href="#cc_feature-implies">implies</a>, <a href="#cc_feature-mutually_exclusive">mutually_exclusive</a>, <a href="#cc_feature-overrides">overrides</a>, <a href="#cc_feature-requires_any_of">requires_any_of</a>) +</pre> + +A dynamic set of toolchain flags that create a singular [feature](https://bazel.build/docs/cc-toolchain-config-reference#features) definition. + +A feature is basically a dynamically toggleable [`cc_args_list`](#cc_args_list). There are a variety of +dependencies and compatibility requirements that must be satisfied to enable a +[`cc_feature`](#cc_feature). Once those conditions are met, the arguments in [`cc_feature.args`](#cc_feature-args) +are expanded and added to the command-line. + +A feature may be enabled or disabled through the following mechanisms: +* Via command-line flags, or a `.bazelrc` file via the + [`--features` flag](https://bazel.build/reference/command-line-reference#flag--features) +* Through inter-feature relationships (via [`cc_feature.implies`](#cc_feature-implies)) where one + feature may implicitly enable another. +* Individual rules (e.g. `cc_library`) or `package` definitions may elect to manually enable or + disable features through the + [`features` attribute](https://bazel.build/reference/be/common-definitions#common.features). + +Note that a feature may alternate between enabled and disabled dynamically over the course of a +build. Because of their toggleable nature, it's generally best to avoid adding arguments to a +`cc_toolchain` as a [`cc_feature`](#cc_feature) unless strictly necessary. Instead, prefer to express arguments +via [`cc_toolchain.args`](#cc_toolchain-args) whenever possible. + +You should use a [`cc_feature`](#cc_feature) when any of the following apply: +* You need the flags to be dynamically toggled over the course of a build. +* You want build files to be able to configure the flags in question. For example, a + binary might specify `features = ["optimize_for_size"]` to create a small + binary instead of optimizing for performance. +* You need to carry forward Starlark toolchain behaviors. If you're migrating a + complex Starlark-based toolchain definition to these rules, many of the + workflows and flags were likely based on features. + +If you only need to configure flags via the Bazel command-line, instead +consider adding a +[`bool_flag`](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/common_settings_doc.md#bool_flag) +paired with a [`config_setting`](https://bazel.build/reference/be/general#config_setting) +and then make your [`cc_args`](#cc_args) rule `select` on the `config_setting`. + +For more details about how Bazel handles features, see the official Bazel +documentation at +https://bazel.build/docs/cc-toolchain-config-reference#features. + +Example: +``` +load("@rules_cc//cc/toolchains:feature.bzl", "cc_feature") + +# A feature that enables LTO, which may be incompatible when doing interop with various +# languages (e.g. rust, go), or may need to be disabled for particular `cc_binary` rules +# for various reasons. +cc_feature( + name = "lto", + feature_name = "lto", + args = [":lto_args"], +) +``` + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| <a id="cc_feature-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | | +| <a id="cc_feature-args"></a>args | A list of [`cc_args`](#cc_args) or [`cc_args_list`](#cc_args_list) labels that are expanded when this feature is enabled. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` | +| <a id="cc_feature-feature_name"></a>feature_name | The name of the feature that this rule implements.<br><br>The feature name is a string that will be used in the `features` attribute of rules to enable them (eg. `cc_binary(..., features = ["opt"])`.<br><br>While two features with the same `feature_name` may not be bound to the same toolchain, they can happily live alongside each other in the same BUILD file.<br><br>Example: <pre><code>cc_feature( name = "sysroot_macos", feature_name = "sysroot", ... ) cc_feature( name = "sysroot_linux", feature_name = "sysroot", ... )</code></pre> | String | optional | `""` | +| <a id="cc_feature-implies"></a>implies | List of features enabled along with this feature.<br><br>Warning: If any of the features cannot be enabled, this feature is silently disabled. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` | +| <a id="cc_feature-mutually_exclusive"></a>mutually_exclusive | A list of things that this feature is mutually exclusive with.<br><br>It can be either: * A feature, in which case the two features are mutually exclusive. * A [`cc_mutually_exclusive_category`](#cc_mutually_exclusive_category), in which case all features that write `mutually_exclusive = [":category"]` are mutually exclusive with each other.<br><br>If this feature has a side-effect of implementing another feature, it can be useful to list that feature here to ensure they aren't enabled at the same time. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` | +| <a id="cc_feature-overrides"></a>overrides | A declaration that this feature overrides a known feature.<br><br>In the example below, if you missed the "overrides" attribute, it would complain that the feature "opt" was defined twice.<br><br>Example: <pre><code>load("@rules_cc//cc/toolchains:feature.bzl", "cc_feature") cc_feature( name = "opt", feature_name = "opt", args = [":size_optimized"], overrides = "@rules_cc//cc/toolchains/features:opt", )</code></pre> | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` | +| <a id="cc_feature-requires_any_of"></a>requires_any_of | A list of feature sets that define toolchain compatibility.<br><br>If *at least one* of the listed [`cc_feature_set`](#cc_feature_set)s are fully satisfied (all features exist in the toolchain AND are currently enabled), this feature is deemed compatible and may be enabled.<br><br>Note: Even if `cc_feature.requires_any_of` is satisfied, a feature is not enabled unless another mechanism (e.g. command-line flags, `cc_feature.implies`, `cc_toolchain_config.enabled_features`) signals that the feature should actually be enabled. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` | + + +<a id="cc_feature_constraint"></a> + +## cc_feature_constraint + +<pre> +cc_feature_constraint(<a href="#cc_feature_constraint-name">name</a>, <a href="#cc_feature_constraint-all_of">all_of</a>, <a href="#cc_feature_constraint-none_of">none_of</a>) +</pre> + +Defines a compound relationship between features. + +This rule can be used with [`cc_args.require_any_of`](#cc_args-require_any_of) to specify that a set +of arguments are only enabled when a constraint is met. Both `all_of` and `none_of` must be +satisfied simultaneously. + +This is basically a [`cc_feature_set`](#cc_feature_set) that supports `none_of` expressions. This extra flexibility +is why this rule may only be used by [`cc_args.require_any_of`](#cc_args-require_any_of). + +Example: +``` +load("@rules_cc//cc/toolchains:feature_constraint.bzl", "cc_feature_constraint") + +# A constraint that requires a `linker_supports_thinlto` feature to be enabled, +# AND a `no_optimization` to be disabled. +cc_feature_constraint( + name = "thinlto_constraint", + all_of = [":linker_supports_thinlto"], + none_of = [":no_optimization"], +) +``` + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| <a id="cc_feature_constraint-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | | +| <a id="cc_feature_constraint-all_of"></a>all_of | - | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` | +| <a id="cc_feature_constraint-none_of"></a>none_of | - | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` | + + +<a id="cc_feature_set"></a> + +## cc_feature_set + +<pre> +cc_feature_set(<a href="#cc_feature_set-name">name</a>, <a href="#cc_feature_set-all_of">all_of</a>) +</pre> + +Defines a set of features. + +This may be used by both [`cc_feature`](#cc_feature) and [`cc_args`](#cc_args) rules, and is effectively a way to express +a logical `AND` operation across multiple requred features. + +Example: +``` +load("@rules_cc//cc/toolchains:feature_set.bzl", "cc_feature_set") + +cc_feature_set( + name = "thin_lto_requirements", + all_of = [ + ":thin_lto", + ":opt", + ], +) +``` + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| <a id="cc_feature_set-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | | +| <a id="cc_feature_set-all_of"></a>all_of | A set of features | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` | + + +<a id="cc_mutually_exclusive_category"></a> + +## cc_mutually_exclusive_category + +<pre> +cc_mutually_exclusive_category(<a href="#cc_mutually_exclusive_category-name">name</a>) +</pre> + +A rule used to categorize [`cc_feature`](#cc_feature) definitions for which only one can be enabled. + +This is used by [`cc_feature.mutually_exclusive`](#cc_feature-mutually_exclusive) to express groups +of [`cc_feature`](#cc_feature) definitions that are inherently incompatible with each other and must be treated as +mutually exclusive. + +Warning: These groups are keyed by name, so two [`cc_mutually_exclusive_category`](#cc_mutually_exclusive_category) definitions of the +same name in different packages will resolve to the same logical group. + +Example: +``` +load("@rules_cc//cc/toolchains:feature.bzl", "cc_feature") +load("@rules_cc//cc/toolchains:mutually_exclusive_category.bzl", "cc_mutually_exclusive_category") + +cc_mutually_exclusive_category( + name = "opt_level", +) + +cc_feature( + name = "speed_optimized", + mutually_exclusive = [":opt_level"], +) + +cc_feature( + name = "size_optimized", + mutually_exclusive = [":opt_level"], +) + +cc_feature( + name = "unoptimized", + mutually_exclusive = [":opt_level"], +) +``` + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| <a id="cc_mutually_exclusive_category-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | | + + +<a id="cc_tool"></a> + +## cc_tool + +<pre> +cc_tool(<a href="#cc_tool-name">name</a>, <a href="#cc_tool-src">src</a>, <a href="#cc_tool-data">data</a>, <a href="#cc_tool-allowlist_include_directories">allowlist_include_directories</a>) +</pre> + +Declares a tool for use by toolchain actions. + +[`cc_tool`](#cc_tool) rules are used in a [`cc_tool_map`](#cc_tool_map) rule to ensure all files and +metadata required to run a tool are available when constructing a `cc_toolchain`. + +In general, include all files that are always required to run a tool (e.g. libexec/** and +cross-referenced tools in bin/*) in the [data](#cc_tool-data) attribute. If some files are only +required when certain flags are passed to the tool, consider using a [`cc_args`](#cc_args) rule to +bind the files to the flags that require them. This reduces the overhead required to properly +enumerate a sandbox with all the files required to run a tool, and ensures that there isn't +unintentional leakage across configurations and actions. + +Example: +``` +load("@rules_cc//cc/toolchains:tool.bzl", "cc_tool") + +cc_tool( + name = "clang_tool", + executable = "@llvm_toolchain//:bin/clang", + # Suppose clang needs libc to run. + data = ["@llvm_toolchain//:lib/x86_64-linux-gnu/libc.so.6"] + tags = ["requires-network"], +) +``` + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| <a id="cc_tool-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | | +| <a id="cc_tool-src"></a>src | The underlying binary that this tool represents.<br><br>Usually just a single prebuilt (eg. @toolchain//:bin/clang), but may be any executable label. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` | +| <a id="cc_tool-data"></a>data | Additional files that are required for this tool to run.<br><br>Frequently, clang and gcc require additional files to execute as they often shell out to other binaries (e.g. `cc1`). | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` | +| <a id="cc_tool-allowlist_include_directories"></a>allowlist_include_directories | Include paths implied by using this tool.<br><br>Compilers may include a set of built-in headers that are implicitly available unless flags like `-nostdinc` are provided. Bazel checks that all included headers are properly provided by a dependency or allowlisted through this mechanism.<br><br>As a rule of thumb, only use this if Bazel is complaining about absolute paths in your toolchain and you've ensured that the toolchain is compiling with the `-no-canonical-prefixes` and/or `-fno-canonical-system-headers` arguments.<br><br>This can help work around errors like: `the source file 'main.c' includes the following non-builtin files with absolute paths (if these are builtin files, make sure these paths are in your toolchain)`. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` | + + +<a id="cc_args"></a> + +## cc_args + +<pre> +cc_args(<a href="#cc_args-name">name</a>, <a href="#cc_args-actions">actions</a>, <a href="#cc_args-allowlist_include_directories">allowlist_include_directories</a>, <a href="#cc_args-args">args</a>, <a href="#cc_args-data">data</a>, <a href="#cc_args-env">env</a>, <a href="#cc_args-format">format</a>, <a href="#cc_args-iterate_over">iterate_over</a>, <a href="#cc_args-nested">nested</a>, + <a href="#cc_args-requires_not_none">requires_not_none</a>, <a href="#cc_args-requires_none">requires_none</a>, <a href="#cc_args-requires_true">requires_true</a>, <a href="#cc_args-requires_false">requires_false</a>, <a href="#cc_args-requires_equal">requires_equal</a>, + <a href="#cc_args-requires_equal_value">requires_equal_value</a>, <a href="#cc_args-requires_any_of">requires_any_of</a>, <a href="#cc_args-kwargs">kwargs</a>) +</pre> + +Action-specific arguments for use with a cc_toolchain. + +This rule is the fundamental building building block for every toolchain tool invocation. Each +argument expressed in a toolchain tool invocation (e.g. `gcc`, `llvm-ar`) is declared in a +[`cc_args`](#cc_args) rule that applies an ordered list of arguments to a set of toolchain +actions. [`cc_args`](#cc_args) rules can be added unconditionally to a +`cc_toolchain`, conditionally via `select()` statements, or dynamically via an +intermediate [`cc_feature`](#cc_feature). + +Conceptually, this is similar to the old `CFLAGS`, `CPPFLAGS`, etc. environment variables that +many build systems use to determine which flags to use for a given action. The significant +difference is that [`cc_args`](#cc_args) rules are declared in a structured way that allows for +significantly more powerful and sharable toolchain configurations. Also, due to Bazel's more +granular action types, it's possible to bind flags to very specific actions (e.g. LTO indexing +for an executable vs a dynamic library) multiple different actions (e.g. C++ compile and link +simultaneously). + +Example usage: +``` +load("@rules_cc//cc/toolchains:args.bzl", "cc_args") + +# Basic usage: a trivial flag. +# +# An example of expressing `-Werror` as a [`cc_args`](#cc_args) rule. +cc_args( + name = "warnings_as_errors", + actions = [ + # Applies to all C/C++ compile actions. + "@rules_cc//cc/toolchains/actions:compile_actions", + ], + args = ["-Werror"], +) + +# Basic usage: ordered flags. +# +# An example of linking against libc++, which uses two flags that must be applied in order. +cc_args( + name = "link_libcxx", + actions = [ + # Applies to all link actions. + "@rules_cc//cc/toolchains/actions:link_actions", + ], + # On tool invocation, this appears as `-Xlinker -lc++`. Nothing will ever end up between + # the two flags. + args = [ + "-Xlinker", + "-lc++", + ], +) + +# Advanced usage: built-in variable expansions. +# +# Expands to `-L/path/to/search_dir` for each directory in the built-in variable +# `library_search_directories`. This variable is managed internally by Bazel through inherent +# behaviors of Bazel and the interactions between various C/C++ build rules. +cc_args( + name = "library_search_directories", + actions = [ + "@rules_cc//cc/toolchains/actions:link_actions", + ], + args = ["-L{search_dir}"], + iterate_over = "@rules_cc//cc/toolchains/variables:library_search_directories", + requires_not_none = "@rules_cc//cc/toolchains/variables:library_search_directories", + format = { + "search_dir": "@rules_cc//cc/toolchains/variables:library_search_directories", + }, +) +``` + +For more extensive examples, see the usages here: + https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args + + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| <a id="cc_args-name"></a>name | (str) The name of the target. | none | +| <a id="cc_args-actions"></a>actions | (List[Label]) A list of labels of [`cc_action_type`](#cc_action_type) or [`cc_action_type_set`](#cc_action_type_set) rules that dictate which actions these arguments should be applied to. | `None` | +| <a id="cc_args-allowlist_include_directories"></a>allowlist_include_directories | (List[Label]) A list of include paths that are implied by using this rule. These must point to a skylib [directory](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/directory_doc.md#directory) or [subdirectory](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/directory_subdirectory_doc.md#subdirectory) rule. Some flags (e.g. --sysroot) imply certain include paths are available despite not explicitly specifying a normal include path flag (`-I`, `-isystem`, etc.). Bazel checks that all included headers are properly provided by a dependency or allowlisted through this mechanism.<br><br>As a rule of thumb, only use this if Bazel is complaining about absolute paths in your toolchain and you've ensured that the toolchain is compiling with the `-no-canonical-prefixes` and/or `-fno-canonical-system-headers` arguments.<br><br>This can help work around errors like: `the source file 'main.c' includes the following non-builtin files with absolute paths (if these are builtin files, make sure these paths are in your toolchain)`. | `None` | +| <a id="cc_args-args"></a>args | (List[str]) The command-line arguments that are applied by using this rule. This is mutually exclusive with [nested](#cc_args-nested). | `None` | +| <a id="cc_args-data"></a>data | (List[Label]) A list of runtime data dependencies that are required for these arguments to work as intended. | `None` | +| <a id="cc_args-env"></a>env | (Dict[str, str]) Environment variables that should be set when the tool is invoked. | `None` | +| <a id="cc_args-format"></a>format | (Dict[str, Label]) A mapping of format strings to the label of the corresponding [`cc_variable`](#cc_variable) that the value should be pulled from. All instances of `{variable_name}` will be replaced with the expanded value of `variable_name` in this dictionary. The complete list of possible variables can be found in https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD. It is not possible to declare custom variables--these are inherent to Bazel itself. | `{}` | +| <a id="cc_args-iterate_over"></a>iterate_over | (Label) The label of a [`cc_variable`](#cc_variable) that should be iterated over. This is intended for use with built-in variables that are lists. | `None` | +| <a id="cc_args-nested"></a>nested | (List[Label]) A list of [`cc_nested_args`](#cc_nested_args) rules that should be expanded to command-line arguments when this rule is used. This is mutually exclusive with [args](#cc_args-args). | `None` | +| <a id="cc_args-requires_not_none"></a>requires_not_none | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for existence before expanding this rule. If the variable is None, this rule will be ignored. | `None` | +| <a id="cc_args-requires_none"></a>requires_none | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for non-existence before expanding this rule. If the variable is not None, this rule will be ignored. | `None` | +| <a id="cc_args-requires_true"></a>requires_true | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for truthiness before expanding this rule. If the variable is false, this rule will be ignored. | `None` | +| <a id="cc_args-requires_false"></a>requires_false | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for falsiness before expanding this rule. If the variable is true, this rule will be ignored. | `None` | +| <a id="cc_args-requires_equal"></a>requires_equal | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for equality before expanding this rule. If the variable is not equal to (requires_equal_value)[#cc_args-requires_equal_value], this rule will be ignored. | `None` | +| <a id="cc_args-requires_equal_value"></a>requires_equal_value | (str) The value to compare (requires_equal)[#cc_args-requires_equal] against. | `None` | +| <a id="cc_args-requires_any_of"></a>requires_any_of | (List[Label]) These arguments will be used in a tool invocation when at least one of the [cc_feature_constraint](#cc_feature_constraint) entries in this list are satisfied. If omitted, this flag set will be enabled unconditionally. | `None` | +| <a id="cc_args-kwargs"></a>kwargs | [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. | none | + + +<a id="cc_nested_args"></a> + +## cc_nested_args + +<pre> +cc_nested_args(<a href="#cc_nested_args-name">name</a>, <a href="#cc_nested_args-args">args</a>, <a href="#cc_nested_args-data">data</a>, <a href="#cc_nested_args-format">format</a>, <a href="#cc_nested_args-iterate_over">iterate_over</a>, <a href="#cc_nested_args-nested">nested</a>, <a href="#cc_nested_args-requires_not_none">requires_not_none</a>, <a href="#cc_nested_args-requires_none">requires_none</a>, + <a href="#cc_nested_args-requires_true">requires_true</a>, <a href="#cc_nested_args-requires_false">requires_false</a>, <a href="#cc_nested_args-requires_equal">requires_equal</a>, <a href="#cc_nested_args-requires_equal_value">requires_equal_value</a>, <a href="#cc_nested_args-kwargs">kwargs</a>) +</pre> + +Nested arguments for use in more complex [`cc_args`](#cc_args) expansions. + +While this rule is very similar in shape to [`cc_args`](#cc_args), it is intended to be used as a +dependency of [`cc_args`](#cc_args) to provide additional arguments that should be applied to the +same actions as defined by the parent [`cc_args`](#cc_args) rule. The key motivation for this rule +is to allow for more complex variable-based argument expensions. + +Prefer expressing collections of arguments as [`cc_args`](#cc_args) and +[`cc_args_list`](#cc_args_list) rules when possible. + +For living examples of how this rule is used, see the usages here: + https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/runtime_library_search_directories/BUILD + https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/libraries_to_link/BUILD + +Note: These examples are non-trivial, but they illustrate when it is absolutely necessary to +use this rule. + + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| <a id="cc_nested_args-name"></a>name | (str) The name of the target. | none | +| <a id="cc_nested_args-args"></a>args | (List[str]) The command-line arguments that are applied by using this rule. This is mutually exclusive with [nested](#cc_nested_args-nested). | `None` | +| <a id="cc_nested_args-data"></a>data | (List[Label]) A list of runtime data dependencies that are required for these arguments to work as intended. | `None` | +| <a id="cc_nested_args-format"></a>format | (Dict[str, Label]) A mapping of format strings to the label of the corresponding [`cc_variable`](#cc_variable) that the value should be pulled from. All instances of `{variable_name}` will be replaced with the expanded value of `variable_name` in this dictionary. The complete list of possible variables can be found in https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD. It is not possible to declare custom variables--these are inherent to Bazel itself. | `{}` | +| <a id="cc_nested_args-iterate_over"></a>iterate_over | (Label) The label of a [`cc_variable`](#cc_variable) that should be iterated over. This is intended for use with built-in variables that are lists. | `None` | +| <a id="cc_nested_args-nested"></a>nested | (List[Label]) A list of [`cc_nested_args`](#cc_nested_args) rules that should be expanded to command-line arguments when this rule is used. This is mutually exclusive with [args](#cc_nested_args-args). | `None` | +| <a id="cc_nested_args-requires_not_none"></a>requires_not_none | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for existence before expanding this rule. If the variable is None, this rule will be ignored. | `None` | +| <a id="cc_nested_args-requires_none"></a>requires_none | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for non-existence before expanding this rule. If the variable is not None, this rule will be ignored. | `None` | +| <a id="cc_nested_args-requires_true"></a>requires_true | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for truthiness before expanding this rule. If the variable is false, this rule will be ignored. | `None` | +| <a id="cc_nested_args-requires_false"></a>requires_false | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for falsiness before expanding this rule. If the variable is true, this rule will be ignored. | `None` | +| <a id="cc_nested_args-requires_equal"></a>requires_equal | (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for equality before expanding this rule. If the variable is not equal to (requires_equal_value)[#cc_nested_args-requires_equal_value], this rule will be ignored. | `None` | +| <a id="cc_nested_args-requires_equal_value"></a>requires_equal_value | (str) The value to compare (requires_equal)[#cc_nested_args-requires_equal] against. | `None` | +| <a id="cc_nested_args-kwargs"></a>kwargs | [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. | none | + + <a id="cc_tool_map"></a> ## cc_tool_map @@ -12,31 +583,32 @@ A toolchain configuration rule that maps toolchain actions to tools. -A cc_tool_map aggregates all the tools that may be used for a given toolchain and maps them to -their corresponding actions. Conceptually, this is similar to the `CXX=/path/to/clang++` -environment variables that most build systems use to determine which tools to use for a given -action. To simplify usage, some actions have been grouped together (for example, -//third_party/bazel_rules/rules_cc/cc/toolchains/actions:cpp_compile_actions) to +A [`cc_tool_map`](#cc_tool_map) aggregates all the tools that may be used for a given toolchain +and maps them to their corresponding actions. Conceptually, this is similar to the +`CXX=/path/to/clang++` environment variables that most build systems use to determine which +tools to use for a given action. To simplify usage, some actions have been grouped together (for +example, +[@rules_cc//cc/toolchains/actions:cpp_compile_actions](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/actions/BUILD)) to logically express "all the C++ compile actions". In Bazel, there is a little more granularity to the mapping, so the mapping doesn't follow the traditional `CXX`, `AR`, etc. naming scheme. For a comprehensive list of all the well-known -actions, see //third_party/bazel_rules/rules_cc/cc/toolchains/actions:BUILD. +actions, see @rules_cc//cc/toolchains/actions:BUILD. Example usage: ``` -load("//third_party/bazel_rules/rules_cc/cc/toolchains:tool_map.bzl", "cc_tool_map") +load("@rules_cc//cc/toolchains:tool_map.bzl", "cc_tool_map") cc_tool_map( name = "all_tools", tools = { - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:assembly_actions": ":asm", - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:c_compile": ":clang", - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:cpp_compile_actions": ":clang++", - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:link_actions": ":lld", - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:objcopy_embed_data": ":llvm-objcopy", - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:strip": ":llvm-strip", - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:ar_actions": ":llvm-ar", + "@rules_cc//cc/toolchains/actions:assembly_actions": ":asm", + "@rules_cc//cc/toolchains/actions:c_compile": ":clang", + "@rules_cc//cc/toolchains/actions:cpp_compile_actions": ":clang++", + "@rules_cc//cc/toolchains/actions:link_actions": ":lld", + "@rules_cc//cc/toolchains/actions:objcopy_embed_data": ":llvm-objcopy", + "@rules_cc//cc/toolchains/actions:strip": ":llvm-strip", + "@rules_cc//cc/toolchains/actions:ar_actions": ":llvm-ar", }, ) ``` @@ -53,7 +625,47 @@ | Name | Description | Default Value | | :------------- | :------------- | :------------- | | <a id="cc_tool_map-name"></a>name | (str) The name of the target. | none | -| <a id="cc_tool_map-tools"></a>tools | (Dict[target providing ActionTypeSetInfo, Executable target]) A mapping between `cc_action_type` targets and the `cc_tool` or executable target that implements that action. | none | +| <a id="cc_tool_map-tools"></a>tools | (Dict[Label, Label]) A mapping between [`cc_action_type`](#cc_action_type)/[`cc_action_type_set`](#cc_action_type_set) targets and the [`cc_tool`](#cc_tool) or executable target that implements that action. | none | | <a id="cc_tool_map-kwargs"></a>kwargs | [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. | none | +<a id="cc_variable"></a> + +## cc_variable + +<pre> +cc_variable(<a href="#cc_variable-name">name</a>, <a href="#cc_variable-type">type</a>, <a href="#cc_variable-kwargs">kwargs</a>) +</pre> + +Exposes a toolchain variable to use in toolchain argument expansions. + +This internal rule exposes [toolchain variables](https://bazel.build/docs/cc-toolchain-config-reference#cctoolchainconfiginfo-build-variables) +that may be expanded in [`cc_args`](#cc_args) or [`cc_nested_args`](#cc_nested_args) +rules. Because these varaibles merely expose variables inherrent to Bazel, +it's not possible to declare custom variables. + +For a full list of available variables, see +[@rules_cc//cc/toolchains/varaibles:BUILD](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD). + +Example: +``` +load("@rules_cc//cc/toolchains/impl:variables.bzl", "cc_variable") + +# Defines two targets, ":foo" and ":foo.bar" +cc_variable( + name = "foo", + type = types.list(types.struct(bar = types.string)), +) +``` + + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| <a id="cc_variable-name"></a>name | (str) The name of the outer variable, and the rule. | none | +| <a id="cc_variable-type"></a>type | The type of the variable, constructed using `types` factory in [@rules_cc//cc/toolchains/impl:variables.bzl](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/impl/variables.bzl). | none | +| <a id="cc_variable-kwargs"></a>kwargs | [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. | none | + +
diff --git a/tests/rule_based_toolchain/toolchain_config/BUILD b/tests/rule_based_toolchain/toolchain_config/BUILD index 981758e..b002eff 100644 --- a/tests/rule_based_toolchain/toolchain_config/BUILD +++ b/tests/rule_based_toolchain/toolchain_config/BUILD
@@ -63,7 +63,6 @@ ], enabled_features = [":simple_feature"], known_features = [":compile_feature"], - skip_experimental_flag_validation_for_test = True, tool_map = ":compile_tool_map", )