From ce4bc8a8de1b7e886e0852c6ec94c9579efb3606 Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 10 Sep 2024 06:52:49 -0700 Subject: [PATCH 01/12] Make `cc_helper.bzl` publicly `load()`-able for `@rules_java` PiperOrigin-RevId: 672945291 Change-Id: I0c2a32475c1f2fdeffe28239cb0b9bead70295a7 --- cc/common/visibility.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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"] From 96ac608d348b73a58c5735733f68bd4e660206d4 Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 10 Sep 2024 22:03:38 -0700 Subject: [PATCH 02/12] No public description PiperOrigin-RevId: 673231375 Change-Id: I61110c5d47898c0ef27af650ad56de6f107d3976 --- cc/cc_binary.bzl | 2 +- cc/cc_test.bzl | 2 +- cc/find_cc_toolchain.bzl | 4 ++-- cc/toolchains/impl/toolchain_config.bzl | 2 +- cc/toolchains/toolchain.bzl | 20 ++++++++++---------- 5 files changed, 15 insertions(+), 15 deletions(-) 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/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 @@ to depend on and find a cc toolchain. 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 @@ https://github.com/bazelbuild/bazel/issues/7260 is flipped (and support for old 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/impl/toolchain_config.bzl b/cc/toolchains/impl/toolchain_config.bzl index 5c8d69c..d4c229c 100644 --- a/cc/toolchains/impl/toolchain_config.bzl +++ b/cc/toolchains/impl/toolchain_config.bzl @@ -86,7 +86,7 @@ def _cc_toolchain_config_impl(ctx): ), # 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())), 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 @@ visibility("public") # 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"), ], } From 7a67e9887bb100977408de99a797145062f2e7ca Mon Sep 17 00:00:00 2001 From: Ivo List Date: Wed, 11 Sep 2024 05:56:07 -0700 Subject: [PATCH 03/12] Copybara Merge: https://github.com/bazelbuild/rules_cc/pull/238 BEGIN_PUBLIC Copybara import of the project: -- 2803a12428e6493e48176f46f352a3e78820e7da by Ivo List : Prepare for release 0.0.10-rc2 -- 3423c7320893a84a5166aa9962ce57c3715c4660 by Ivo List : Format WORKSPACE -- a99403a6b0ee72aea634b84b3caa065a9290a6fb by Ivo List : Touch module -- 258d8c9f2410796715cb8fe8a07e2dacf9b217e0 by Ivo List : Revert "Touch module" This reverts commit a99403a6b0ee72aea634b84b3caa065a9290a6fb. END_PUBLIC COPYBARA_INTEGRATE_REVIEW=https://github.com/bazelbuild/rules_cc/pull/238 from comius:release-0.0.10-rc2 258d8c9f2410796715cb8fe8a07e2dacf9b217e0 PiperOrigin-RevId: 673358956 Change-Id: Iabc9c29e6f168cfdfd2f0657438b71654f470cc9 --- MODULE.bazel | 4 ++-- WORKSPACE | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 51a00b2..c8dd2a9 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,11 +1,11 @@ module( name = "rules_cc", - version = "0.0.4", + version = "0.0.10-rc2", 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( 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", ], ) From da1ac71c8e45e27dd57b19c04373b302c34783ed Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 11 Sep 2024 08:46:11 -0700 Subject: [PATCH 04/12] Create group for c compile actions BEGIN_PUBLIC Create group for c compile actions Adds `c_compile_actions` group to provide a logical C equivalent for `cpp_compile_actions`. END_PUBLIC PiperOrigin-RevId: 673408772 Change-Id: Ic5ccb57bc1fa7a98999d944316b97a39aac571ac --- cc/toolchains/actions/BUILD | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) 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 @@ -184,6 +184,13 @@ cc_action_type_set( ], ) +cc_action_type_set( + name = "c_compile_actions", + actions = [ + ":c_compile", + ], +) + cc_action_type_set( name = "cpp_compile_actions", actions = [ @@ -201,7 +208,7 @@ cc_action_type_set( name = "compile_actions", actions = [ ":cpp_compile_actions", - ":c_compile", + ":c_compile_actions", ":assembly_actions", ], ) From 0d5561bcba6c230db1b598da89d6546810070ff6 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 12 Sep 2024 11:04:43 -0700 Subject: [PATCH 05/12] Consolidate action labels in toolchain args BEGIN_PUBLIC Consolidate action labels in toolchain args Consolidates action labels used by re-implementation of legacy features to use logical groups rather than individually listing every action. This simplifies the rule definitions slightly. END_PUBLIC PiperOrigin-RevId: 673920103 Change-Id: If5453dd5b45d5549ff75d656da8a2873232117ae --- cc/toolchains/args/archiver_flags/BUILD | 6 +++--- cc/toolchains/args/force_pic_flags/BUILD | 5 +---- cc/toolchains/args/libraries_to_link/BUILD | 9 +-------- cc/toolchains/args/linker_param_file/BUILD | 9 ++------- .../runtime_library_search_directories/BUILD | 18 ++---------------- cc/toolchains/args/shared_flag/BUILD | 7 +------ 6 files changed, 10 insertions(+), 44 deletions(-) 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_list( 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( 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( 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 @@ package(default_visibility = ["//visibility:private"]) 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 @@ package(default_visibility = ["//visibility:private"]) 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_list( 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_list( 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 @@ cc_nested_args( # 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 @@ package(default_visibility = ["//visibility:private"]) 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"], ) From de86823ddefb9494534931482eeb682772ff3cb7 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 12 Sep 2024 11:08:30 -0700 Subject: [PATCH 06/12] Document args-related toolchain rules BEGIN_PUBLIC Document args-related toolchain rules Adds comprehensive documentation for cc_args, cc_nested_args, and cc_args_list. END_PUBLIC PiperOrigin-RevId: 673921558 Change-Id: I1c9c0731925a03dedec983083072f52c6d4c270f --- cc/toolchains/args.bzl | 174 ++++++++++++++++++--- cc/toolchains/args_list.bzl | 42 +++++- cc/toolchains/impl/documented_api.bzl | 6 + cc/toolchains/nested_args.bzl | 78 +++++++++- cc/toolchains/toolchain_api.md | 209 ++++++++++++++++++++++++++ 5 files changed, 489 insertions(+), 20 deletions(-) diff --git a/cc/toolchains/args.bzl b/cc/toolchains/args.bzl index 4f71986..eb3833e 100644 --- a/cc/toolchains/args.bzl +++ b/cc/toolchains/args.bzl @@ -86,30 +86,18 @@ _cc_args = rule( "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,161 @@ Examples: """, ) -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/blob/main/docs/directory_doc.md#directory) + or [subdirectory](https://github.com/bazelbuild/bazel-skylib/blob/main/docs/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. + 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/blob/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](#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` 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_list.bzl b/cc/toolchains/args_list.bzl index fbbaad5..1f93a84 100644 --- a/cc/toolchains/args_list.bzl +++ b/cc/toolchains/args_list.bzl @@ -24,11 +24,49 @@ def _cc_args_list_impl(ctx): 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](#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/impl/documented_api.bzl b/cc/toolchains/impl/documented_api.bzl index d840b7e..b2ca091 100644 --- a/cc/toolchains/impl/documented_api.bzl +++ b/cc/toolchains/impl/documented_api.bzl @@ -13,6 +13,12 @@ # limitations under the License. """This is a list of rules/macros that should be exported as documentation.""" +load("//cc/toolchains:args.bzl", _cc_args = "cc_args") +load("//cc/toolchains:args_list.bzl", _cc_args_list = "cc_args_list") +load("//cc/toolchains:nested_args.bzl", _cc_nested_args = "cc_nested_args") load("//cc/toolchains:tool_map.bzl", _cc_tool_map = "cc_tool_map") cc_tool_map = _cc_tool_map +cc_args = _cc_args +cc_nested_args = _cc_nested_args +cc_args_list = _cc_args_list diff --git a/cc/toolchains/nested_args.bzl b/cc/toolchains/nested_args.bzl index 1d31275..0f27a0f 100644 --- a/cc/toolchains/nested_args.bzl +++ b/cc/toolchains/nested_args.bzl @@ -41,9 +41,85 @@ Examples: """, ) -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](#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/blob/main/cc/toolchains/args/runtime_library_search_directories/BUILD + https://github.com/bazelbuild/rules_cc/blob/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/blob/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](#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/toolchain_api.md b/cc/toolchains/toolchain_api.md index 3a4a490..ae92f14 100644 --- a/cc/toolchains/toolchain_api.md +++ b/cc/toolchains/toolchain_api.md @@ -2,6 +2,215 @@ This is a list of rules/macros that should be exported as documentation. + + +## cc_args_list + +
+cc_args_list(name, args)
+
+ +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("//third_party/bazel_rules/rules_cc/cc/toolchains:cc_args.bzl", "cc_args") +load("//third_party/bazel_rules/rules_cc/cc/toolchains:args_list.bzl", "cc_args_list") + +cc_args( + name = "gc_sections", + actions = [ + "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:link_actions", + ], + args = ["-Wl,--gc-sections"], +) + +cc_args( + name = "function_sections", + actions = [ + "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:compile_actions", + "//third_party/bazel_rules/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 | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| args | (ordered) cc_args to include in this list. | List of labels | optional | `[]` | + + + + +## cc_args + +
+cc_args(name, actions, allowlist_include_directories, args, data, env, format, iterate_over, nested,
+        requires_not_none, requires_none, requires_true, requires_false, requires_equal,
+        requires_equal_value, requires_any_of, 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("//third_party/bazel_rules/rules_cc/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. + "//third_party/bazel_rules/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. + "//third_party/bazel_rules/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 = [ + "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:link_actions", + ], + args = ["-L{search_dir}"], + iterate_over = "//third_party/bazel_rules/rules_cc/cc/toolchains/variables:library_search_directories", + requires_not_none = "//third_party/bazel_rules/rules_cc/cc/toolchains/variables:library_search_directories", + format = { + "search_dir": "//third_party/bazel_rules/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 | +| :------------- | :------------- | :------------- | +| name | (str) The name of the target. | none | +| 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. | `None` | +| 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/blob/main/docs/directory_doc.md#directory) or [subdirectory](https://github.com/bazelbuild/bazel-skylib/blob/main/docs/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. | `None` | +| args | (List[str]) The command-line arguments that are applied by using this rule. This is mutually exclusive with [nested](#cc_args-nested). | `None` | +| data | (List[Label]) A list of runtime data dependencies that are required for these arguments to work as intended. | `None` | +| env | (Dict[str, str]) Environment variables that should be set when the tool is invoked. | `None` | +| 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/blob/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. | `None` | +| 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` | +| 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. | `None` | +| 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. | `None` | +| 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. | `None` | +| 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. | `None` | +| 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. | `None` | +| requires_equal_value | (str) The value to compare (requires_equal)[#cc_args-requires_equal] against. | `None` | +| requires_any_of | (List[Label]) These arguments will be used in a tool invocation when at least one of the `cc_feature_constraint` entries in this list are satisfied. If omitted, this flag set will be enabled unconditionally. | `None` | +| kwargs | [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. | none | + + + + +## cc_nested_args + +
+cc_nested_args(name, args, data, format, iterate_over, nested, requires_not_none, requires_none,
+               requires_true, requires_false, requires_equal, requires_equal_value, kwargs)
+
+ +Nested arguments for use in more complex 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/blob/main/cc/toolchains/args/runtime_library_search_directories/BUILD + https://github.com/bazelbuild/rules_cc/blob/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 | +| :------------- | :------------- | :------------- | +| name | (str) The name of the target. | none | +| 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` | +| data | (List[Label]) A list of runtime data dependencies that are required for these arguments to work as intended. | `None` | +| 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/blob/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. | `None` | +| 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` | +| 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. | `None` | +| 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. | `None` | +| 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. | `None` | +| 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. | `None` | +| 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. | `None` | +| requires_equal_value | (str) The value to compare (requires_equal)[#cc_nested_args-requires_equal] against. | `None` | +| kwargs | [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. | none | + + ## cc_tool_map From 58debbffe4fa5ff61ced86820ed9bc3fa4fd3cec Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 12 Sep 2024 17:30:42 -0700 Subject: [PATCH 07/12] Remove experimental_enable_rule_based_toolchains flag BEGIN_PUBLIC Remove experimental_enable_rule_based_toolchains flag Rule-based toolchains will not be gated by a flag when released with rules_cc v0.0.10. Also, this flag is unfortunately inherently incompatible with --experimental_exclude_starlark_flags_from_exec_config. END_PUBLIC PiperOrigin-RevId: 674072362 Change-Id: Iebda45d4daf4cec27c48296d61092dc513442911 --- cc/toolchains/BUILD | 7 ------- cc/toolchains/impl/toolchain_config.bzl | 6 ------ tests/rule_based_toolchain/toolchain_config/BUILD | 1 - 3 files changed, 14 deletions(-) diff --git a/cc/toolchains/BUILD b/cc/toolchains/BUILD index 8ae4d97..6c876ba 100644 --- a/cc/toolchains/BUILD +++ b/cc/toolchains/BUILD @@ -13,16 +13,9 @@ # 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("@stardoc//stardoc:stardoc.bzl", "stardoc") -bool_flag( - name = "experimental_enable_rule_based_toolchains", - build_setting_default = False, - visibility = ["//visibility:public"], -) - bzl_library( name = "toolchain_rules", srcs = glob(["*.bzl"]), diff --git a/cc/toolchains/impl/toolchain_config.bzl b/cc/toolchains/impl/toolchain_config.bzl index d4c229c..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 @@ def _cc_toolchain_config_impl(ctx): 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], @@ -101,9 +97,7 @@ cc_toolchain_config = rule( "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/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 @@ util.helper_target( ], enabled_features = [":simple_feature"], known_features = [":compile_feature"], - skip_experimental_flag_validation_for_test = True, tool_map = ":compile_tool_map", ) From 91f050e46125fcba5959c157c59c9da53212d355 Mon Sep 17 00:00:00 2001 From: Googler Date: Fri, 13 Sep 2024 08:28:49 -0700 Subject: [PATCH 08/12] Release rules_cc 0.0.10 PiperOrigin-RevId: 674308086 Change-Id: I1b673c7b1c04e3d47b826160903357fa1dbb3ba9 --- MODULE.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MODULE.bazel b/MODULE.bazel index c8dd2a9..91092b0 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "rules_cc", - version = "0.0.10-rc2", + version = "0.0.10", compatibility_level = 1, ) From 848d56aa290b17535797f56ceafca39ab64d577f Mon Sep 17 00:00:00 2001 From: Googler Date: Mon, 23 Sep 2024 11:54:08 -0700 Subject: [PATCH 09/12] Update copybara to improve docs handling BEGIN_PUBLIC Add `@rules_cc` to generated docs Ensures when docs are generated that the `@rules_cc` prefix is used for anything that appears to come from the repo. END_PUBLIC PiperOrigin-RevId: 677883741 Change-Id: I82b910b338aea8b14ecb7b192b5f3d3907be30ee --- cc/toolchains/BUILD | 13 +++++++++- cc/toolchains/toolchain_api.md | 44 +++++++++++++++++----------------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/cc/toolchains/BUILD b/cc/toolchains/BUILD index 6c876ba..45883c6 100644 --- a/cc/toolchains/BUILD +++ b/cc/toolchains/BUILD @@ -14,6 +14,7 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("@bazel_skylib//rules:diff_test.bzl", "diff_test") +load("@bazel_skylib//rules:expand_template.bzl", "expand_template") load("@stardoc//stardoc:stardoc.bzl", "stardoc") bzl_library( @@ -42,11 +43,21 @@ filegroup( 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"], ) +# In GitHub, we prefer to clarify all the labels that come from rules_cc. +expand_template( + name = "toolchain_api_md", + out = "generated_toolchain_api.md", + substitutions = { + "\"//cc": "\"@rules_cc//cc", + }, + template = ":raw_generated_toolchain_api.md", +) + diff_test( name = "toolchain_api_diff_test", file1 = ":generated_toolchain_api.md", diff --git a/cc/toolchains/toolchain_api.md b/cc/toolchains/toolchain_api.md index ae92f14..8d17b6e 100644 --- a/cc/toolchains/toolchain_api.md +++ b/cc/toolchains/toolchain_api.md @@ -20,13 +20,13 @@ Note: The order of the arguments in `args` is preserved to support order-sensiti Example usage: ``` -load("//third_party/bazel_rules/rules_cc/cc/toolchains:cc_args.bzl", "cc_args") -load("//third_party/bazel_rules/rules_cc/cc/toolchains:args_list.bzl", "cc_args_list") +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 = [ - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:link_actions", + "@rules_cc//cc/toolchains/actions:link_actions", ], args = ["-Wl,--gc-sections"], ) @@ -34,8 +34,8 @@ cc_args( cc_args( name = "function_sections", actions = [ - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:compile_actions", - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:link_actions", + "@rules_cc//cc/toolchains/actions:compile_actions", + "@rules_cc//cc/toolchains/actions:link_actions", ], args = ["-ffunction-sections"], ) @@ -86,7 +86,7 @@ simultaneously). Example usage: ``` -load("//third_party/bazel_rules/rules_cc/cc/toolchains:args.bzl", "cc_args") +load("@rules_cc//cc/toolchains:args.bzl", "cc_args") # Basic usage: a trivial flag. # @@ -95,7 +95,7 @@ cc_args( name = "warnings_as_errors", actions = [ # Applies to all C/C++ compile actions. - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:compile_actions", + "@rules_cc//cc/toolchains/actions:compile_actions", ], args = ["-Werror"], ) @@ -107,7 +107,7 @@ cc_args( name = "link_libcxx", actions = [ # Applies to all link actions. - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions: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. @@ -125,13 +125,13 @@ cc_args( cc_args( name = "library_search_directories", actions = [ - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:link_actions", + "@rules_cc//cc/toolchains/actions:link_actions", ], args = ["-L{search_dir}"], - iterate_over = "//third_party/bazel_rules/rules_cc/cc/toolchains/variables:library_search_directories", - requires_not_none = "//third_party/bazel_rules/rules_cc/cc/toolchains/variables:library_search_directories", + iterate_over = "@rules_cc//cc/toolchains/variables:library_search_directories", + requires_not_none = "@rules_cc//cc/toolchains/variables:library_search_directories", format = { - "search_dir": "//third_party/bazel_rules/rules_cc/cc/toolchains/variables:library_search_directories", + "search_dir": "@rules_cc//cc/toolchains/variables:library_search_directories", }, ) ``` @@ -225,27 +225,27 @@ A cc_tool_map aggregates all the tools that may be used for a given toolchain an 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 +@rules_cc//cc/toolchains/actions:cpp_compile_actions) 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", }, ) ``` From 9cb80cfc3226bfe004e8784c3ae999601bf3fd0f Mon Sep 17 00:00:00 2001 From: Googler Date: Mon, 30 Sep 2024 08:06:53 -0700 Subject: [PATCH 10/12] Add objcopy_embed_data to rules_cc action_names.bzl. PiperOrigin-RevId: 680579470 Change-Id: I73600ea8df35aa8a7983ebc4e2e278945d2e65cb --- cc/action_names.bzl | 4 ++++ 1 file changed, 4 insertions(+) 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 @@ OBJC_FULLY_LINK_ACTION_NAME = "objc-fully-link" # 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 @@ ACTION_NAMES = struct( 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. From b06d2f7d53460f516b9d286b0ac0d7a01bdc6ea5 Mon Sep 17 00:00:00 2001 From: Googler Date: Mon, 30 Sep 2024 09:14:24 -0700 Subject: [PATCH 11/12] Add cc_action_type and cc_tool documentation BEGIN_PUBLIC Add cc_action_type and cc_tool documentation Extends the toolchain API documentation to include docs for cc_action_type, cc_action_type_set, cc_variable, and cc_tool. Also improves cross-reference links and copybara behavior for docs. END_PUBLIC PiperOrigin-RevId: 680601617 Change-Id: Idbbdfbcb2c5a1c3598b6a7e7ba985ed14f871099 --- cc/toolchains/BUILD | 17 +- cc/toolchains/actions.bzl | 30 ++- cc/toolchains/args.bzl | 64 ++++--- cc/toolchains/args_list.bzl | 2 +- cc/toolchains/impl/documented_api.bzl | 21 +++ cc/toolchains/impl/markdown_helpers.bzl | 53 ++++++ cc/toolchains/impl/variables.bzl | 29 ++- cc/toolchains/nested_args.bzl | 55 +++--- cc/toolchains/tool.bzl | 31 ++- cc/toolchains/tool_map.bzl | 14 +- cc/toolchains/toolchain_api.md | 240 ++++++++++++++++++++---- 11 files changed, 437 insertions(+), 119 deletions(-) create mode 100644 cc/toolchains/impl/markdown_helpers.bzl diff --git a/cc/toolchains/BUILD b/cc/toolchains/BUILD index 45883c6..98fe2cf 100644 --- a/cc/toolchains/BUILD +++ b/cc/toolchains/BUILD @@ -16,6 +16,8 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("@bazel_skylib//rules:diff_test.bzl", "diff_test") load("@bazel_skylib//rules:expand_template.bzl", "expand_template") load("@stardoc//stardoc:stardoc.bzl", "stardoc") +load("//cc/toolchains/impl:documented_api.bzl", "DOCUMENTED_TOOLCHAIN_RULES") +load("//cc/toolchains/impl:markdown_helpers.bzl", "xref_substitutions") bzl_library( name = "toolchain_rules", @@ -48,13 +50,22 @@ stardoc( deps = [":toolchain_rules"], ) -# In GitHub, we prefer to clarify all the labels that come from rules_cc. expand_template( name = "toolchain_api_md", out = "generated_toolchain_api.md", + # Dictionary order 100% matters here! + # buildifier: disable=unsorted-dict-items substitutions = { - "\"//cc": "\"@rules_cc//cc", - }, + # 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 --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 @@ cc_action_type = rule( }, 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 @@ def _cc_action_type_set_impl(ctx): 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/args.bzl b/cc/toolchains/args.bzl index eb3833e..bdcf7ce 100644 --- a/cc/toolchains/args.bzl +++ b/cc/toolchains/args.bzl @@ -139,9 +139,10 @@ def cc_args( 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`. + `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 @@ -208,49 +209,62 @@ def cc_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. + 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/blob/main/docs/directory_doc.md#directory) - or [subdirectory](https://github.com/bazelbuild/bazel-skylib/blob/main/docs/directory_subdirectory_doc.md#subdirectory) rule. + [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/blob/main/cc/toolchains/variables/BUILD. it is - not possible to declare custom variables--these are inherent to Bazel itself. + `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](#cc_nested_args) rules that should be + 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 + 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_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` entries in this - list are satisfied. If omitted, this flag set will be enabled unconditionally. + 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( diff --git a/cc/toolchains/args_list.bzl b/cc/toolchains/args_list.bzl index 1f93a84..0747acb 100644 --- a/cc/toolchains/args_list.bzl +++ b/cc/toolchains/args_list.bzl @@ -26,7 +26,7 @@ cc_args_list = rule( implementation = _cc_args_list_impl, doc = """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 + 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. diff --git a/cc/toolchains/impl/documented_api.bzl b/cc/toolchains/impl/documented_api.bzl index b2ca091..827d7fb 100644 --- a/cc/toolchains/impl/documented_api.bzl +++ b/cc/toolchains/impl/documented_api.bzl @@ -13,12 +13,33 @@ # 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: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: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 + +# 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", +] 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/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 @@ _cc_variable = rule( ) 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/nested_args.bzl b/cc/toolchains/nested_args.bzl index 0f27a0f..d81dd99 100644 --- a/cc/toolchains/nested_args.bzl +++ b/cc/toolchains/nested_args.bzl @@ -56,19 +56,19 @@ def cc_nested_args( requires_equal = None, requires_equal_value = None, **kwargs): - """Nested arguments for use in more complex cc_args expansions. + """Nested arguments for use in more complex `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 + 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](#cc_args) and - [cc_args_list](#cc_args_list) rules when possible. + 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/blob/main/cc/toolchains/args/runtime_library_search_directories/BUILD - https://github.com/bazelbuild/rules_cc/blob/main/cc/toolchains/args/libraries_to_link/BUILD + 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. @@ -80,27 +80,30 @@ def cc_nested_args( 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/blob/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](#cc_nested_args) rules that should be + `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 + 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_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. 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 @@ cc_tool = rule( 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 @@ 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. + +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 @@ The tool may be a `cc_tool` or other executable rule. 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 @@ def cc_tool_map(name, tools, **kwargs): 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_api.md b/cc/toolchains/toolchain_api.md index 8d17b6e..013df8a 100644 --- a/cc/toolchains/toolchain_api.md +++ b/cc/toolchains/toolchain_api.md @@ -2,6 +2,82 @@ This is a list of rules/macros that should be exported as documentation. + + +## cc_action_type + +
+cc_action_type(name, action_name)
+
+ +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 | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| action_name | - | String | required | | + + + + +## cc_action_type_set + +
+cc_action_type_set(name, actions, allow_empty)
+
+ +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 | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| actions | A list of cc_action_type or cc_action_type_set | List of labels | required | | +| allow_empty | - | Boolean | optional | `False` | + + ## cc_args_list @@ -12,7 +88,7 @@ cc_args_list(name, args | (ordered) cc_args to include in this list. | List of labels | optional | `[]` | + + +## cc_tool + +
+cc_tool(name, src, data, allowlist_include_directories)
+
+ +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 | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| src | The underlying binary that this tool represents.

Usually just a single prebuilt (eg. @toolchain//:bin/clang), but may be any executable label. | Label | optional | `None` | +| data | 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`). | List of labels | optional | `[]` | +| allowlist_include_directories | Include paths implied by using this tool.

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.

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)`. | List of labels | optional | `[]` | + + ## cc_args @@ -72,13 +192,14 @@ 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`. +[`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`. 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 +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 @@ -90,7 +211,7 @@ load("@rules_cc//cc/toolchains:args.bzl", "cc_args") # Basic usage: a trivial flag. # -# An example of expressing `-Werror` as a `cc_args` rule. +# An example of expressing `-Werror` as a [`cc_args`](#cc_args) rule. cc_args( name = "warnings_as_errors", actions = [ @@ -146,21 +267,21 @@ For more extensive examples, see the usages here: | Name | Description | Default Value | | :------------- | :------------- | :------------- | | name | (str) The name of the target. | none | -| 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. | `None` | -| 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/blob/main/docs/directory_doc.md#directory) or [subdirectory](https://github.com/bazelbuild/bazel-skylib/blob/main/docs/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. | `None` | +| 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` | +| 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)`. | `None` | | args | (List[str]) The command-line arguments that are applied by using this rule. This is mutually exclusive with [nested](#cc_args-nested). | `None` | | data | (List[Label]) A list of runtime data dependencies that are required for these arguments to work as intended. | `None` | | env | (Dict[str, str]) Environment variables that should be set when the tool is invoked. | `None` | -| 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/blob/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. | `None` | -| 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` | -| 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. | `None` | -| 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. | `None` | -| 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. | `None` | -| 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. | `None` | -| 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. | `None` | +| 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. | `{}` | +| 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` | +| 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` | +| 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` | +| 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` | +| 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` | +| 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` | +| 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` | | requires_equal_value | (str) The value to compare (requires_equal)[#cc_args-requires_equal] against. | `None` | -| requires_any_of | (List[Label]) These arguments will be used in a tool invocation when at least one of the `cc_feature_constraint` entries in this list are satisfied. If omitted, this flag set will be enabled unconditionally. | `None` | +| 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` | | kwargs | [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. | none | @@ -173,19 +294,19 @@ cc_nested_args(name, requires_true, requires_false, requires_equal, requires_equal_value, kwargs) -Nested arguments for use in more complex cc_args expansions. +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 +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. +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/blob/main/cc/toolchains/args/runtime_library_search_directories/BUILD - https://github.com/bazelbuild/rules_cc/blob/main/cc/toolchains/args/libraries_to_link/BUILD + 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. @@ -199,14 +320,14 @@ use this rule. | name | (str) The name of the target. | none | | 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` | | data | (List[Label]) A list of runtime data dependencies that are required for these arguments to work as intended. | `None` | -| 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/blob/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. | `None` | -| 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` | -| 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. | `None` | -| 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. | `None` | -| 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. | `None` | -| 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. | `None` | -| 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. | `None` | +| 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. | `{}` | +| 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` | +| 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` | +| 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` | +| 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` | +| 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` | +| 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` | +| 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` | | requires_equal_value | (str) The value to compare (requires_equal)[#cc_nested_args-requires_equal] against. | `None` | | kwargs | [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. | none | @@ -221,11 +342,12 @@ cc_tool_map(name, t 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, -@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 @@ -262,7 +384,47 @@ Note: | Name | Description | Default Value | | :------------- | :------------- | :------------- | | name | (str) The name of the target. | none | -| 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 | +| 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 | | kwargs | [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. | none | + + +## cc_variable + +
+cc_variable(name, type, kwargs)
+
+ +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 | +| :------------- | :------------- | :------------- | +| name | (str) The name of the outer variable, and the rule. | none | +| 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 | +| kwargs | [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. | none | + + From 1af2140e7366e4dcb112fbab7b187a0252a5beca Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 2 Oct 2024 09:09:54 -0700 Subject: [PATCH 12/12] Document feature-related toolchain rules BEGIN_PUBLIC Document feature-related toolchain rules Extends the toolchain API documentation to cover all feature-related rules. END_PUBLIC PiperOrigin-RevId: 681476538 Change-Id: Icfe35e03937bdb0bc55eae24f57eafe0db7b16eb --- cc/toolchains/feature.bzl | 114 ++++---- cc/toolchains/feature_constraint.bzl | 24 +- cc/toolchains/feature_set.bzl | 22 +- cc/toolchains/impl/documented_api.bzl | 15 ++ cc/toolchains/impl/external_feature.bzl | 23 +- cc/toolchains/mutually_exclusive_category.bzl | 35 ++- cc/toolchains/toolchain_api.md | 243 +++++++++++++++++- 7 files changed, 409 insertions(+), 67 deletions(-) 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 @@ 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. 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 @@ silently disabled. ), "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 @@ In the example below, if you missed the "overrides" attribute, it would complain 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 @@ Example: 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 @@ cc_feature_constraint = rule( ), }, 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 @@ cc_feature_set = rule( 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 827d7fb..a863290 100644 --- a/cc/toolchains/impl/documented_api.bzl +++ b/cc/toolchains/impl/documented_api.bzl @@ -16,9 +16,14 @@ 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 @@ -29,6 +34,11 @@ 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 @@ -42,4 +52,9 @@ DOCUMENTED_TOOLCHAIN_RULES = [ "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 @@ cc_external_feature = rule( ), }, 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/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 @@ def _cc_mutually_exclusive_category_impl(ctx): 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/toolchain_api.md b/cc/toolchains/toolchain_api.md index 013df8a..418ef52 100644 --- a/cc/toolchains/toolchain_api.md +++ b/cc/toolchains/toolchain_api.md @@ -134,6 +134,247 @@ cc_args_list( | args | (ordered) cc_args to include in this list. | List of labels | optional | `[]` | + + +## cc_external_feature + +
+cc_external_feature(name, feature_name, overridable)
+
+ +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 | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| feature_name | The name of the feature | String | required | | +| overridable | Whether the feature can be overridden | Boolean | required | | + + + + +## cc_feature + +
+cc_feature(name, args, feature_name, implies, mutually_exclusive, overrides, requires_any_of)
+
+ +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 | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| args | A list of [`cc_args`](#cc_args) or [`cc_args_list`](#cc_args_list) labels that are expanded when this feature is enabled. | List of labels | optional | `[]` | +| feature_name | The name of the feature that this rule implements.

The feature name is a string that will be used in the `features` attribute of rules to enable them (eg. `cc_binary(..., features = ["opt"])`.

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.

Example:
cc_feature(
    name = "sysroot_macos",
    feature_name = "sysroot",
    ...
)

cc_feature(
    name = "sysroot_linux",
    feature_name = "sysroot",
    ...
)
| String | optional | `""` | +| implies | List of features enabled along with this feature.

Warning: If any of the features cannot be enabled, this feature is silently disabled. | List of labels | optional | `[]` | +| mutually_exclusive | 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. * 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.

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. | List of labels | optional | `[]` | +| overrides | A declaration that this feature overrides a known feature.

In the example below, if you missed the "overrides" attribute, it would complain that the feature "opt" was defined twice.

Example:
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",
)
| Label | optional | `None` | +| requires_any_of | A list of feature sets that define toolchain compatibility.

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.

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. | List of labels | optional | `[]` | + + + + +## cc_feature_constraint + +
+cc_feature_constraint(name, all_of, none_of)
+
+ +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 | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| all_of | - | List of labels | optional | `[]` | +| none_of | - | List of labels | optional | `[]` | + + + + +## cc_feature_set + +
+cc_feature_set(name, all_of)
+
+ +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 | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| all_of | A set of features | List of labels | optional | `[]` | + + + + +## cc_mutually_exclusive_category + +
+cc_mutually_exclusive_category(name)
+
+ +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 | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | + + ## cc_tool @@ -195,7 +436,7 @@ argument expressed in a toolchain tool invocation (e.g. `gcc`, `llvm-ar`) is dec [`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`. +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