diff --git a/MODULE.bazel b/MODULE.bazel index 51a00b2..91092b0 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,11 +1,11 @@ module( name = "rules_cc", - version = "0.0.4", + version = "0.0.10", compatibility_level = 1, ) bazel_dep(name = "bazel_skylib", version = "1.7.1") -bazel_dep(name = "platforms", version = "0.0.7") +bazel_dep(name = "platforms", version = "0.0.10") bazel_dep(name = "stardoc", version = "0.7.0") cc_configure = use_extension("@bazel_tools//tools/cpp:cc_configure.bzl", "cc_configure_extension") diff --git a/WORKSPACE b/WORKSPACE index 875888e..a4587d5 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -41,10 +41,10 @@ http_archive( http_archive( name = "platforms", - sha256 = "3a561c99e7bdbe9173aa653fd579fe849f1d8d67395780ab4770b1f381431d51", + sha256 = "218efe8ee736d26a3572663b374a253c012b716d8af0c07e842e82f238a0a7ee", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.7/platforms-0.0.7.tar.gz", - "https://github.com/bazelbuild/platforms/releases/download/0.0.7/platforms-0.0.7.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.10/platforms-0.0.10.tar.gz", + "https://github.com/bazelbuild/platforms/releases/download/0.0.10/platforms-0.0.10.tar.gz", ], ) diff --git a/cc/action_names.bzl b/cc/action_names.bzl index 3df7cfa..6735d82 100644 --- a/cc/action_names.bzl +++ b/cc/action_names.bzl @@ -88,6 +88,9 @@ 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. diff --git a/cc/cc_binary.bzl b/cc/cc_binary.bzl index 70810a2..f36e431 100644 --- a/cc/cc_binary.bzl +++ b/cc/cc_binary.bzl @@ -19,7 +19,7 @@ # added as a dependency to @rules_cc//:link_extra_lib. The intermediate library # @bazel_tools@bazel_tools//tools/cpp:link_extra_lib should either be added as a dependency # to @rules_cc//:link_extra_lib, or removed entirely (if possible). -_LINK_EXTRA_LIB = "@rules_cc//:link_extra_lib" # copybara-use-repo-external-label +_LINK_EXTRA_LIB = Label("//:link_extra_lib") def cc_binary(**attrs): """Bazel cc_binary rule. diff --git a/cc/cc_test.bzl b/cc/cc_test.bzl index d3ba601..387fd18 100644 --- a/cc/cc_test.bzl +++ b/cc/cc_test.bzl @@ -20,7 +20,7 @@ # added as a dependency to @rules_cc//:link_extra_lib. The intermediate library # @bazel_tools@bazel_tools//tools/cpp:link_extra_lib should either be added as a dependency # to @rules_cc//:link_extra_lib, or removed entirely (if possible). -_LINK_EXTRA_LIB = "@rules_cc//:link_extra_lib" # copybara-use-repo-external-label +_LINK_EXTRA_LIB = Label("//:link_extra_lib") def cc_test(**attrs): """Bazel cc_test rule. diff --git a/cc/common/visibility.bzl b/cc/common/visibility.bzl index dfbc8ce..981ce86 100644 --- a/cc/common/visibility.bzl +++ b/cc/common/visibility.bzl @@ -1,3 +1,3 @@ """Bzl load visibility package specs""" -INTERNAL_VISIBILITY = ["//cc/..."] +INTERNAL_VISIBILITY = ["public"] diff --git a/cc/find_cc_toolchain.bzl b/cc/find_cc_toolchain.bzl index 4129680..c3e9ed4 100644 --- a/cc/find_cc_toolchain.bzl +++ b/cc/find_cc_toolchain.bzl @@ -29,7 +29,7 @@ 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/BUILD b/cc/toolchains/BUILD index 8ae4d97..98fe2cf 100644 --- a/cc/toolchains/BUILD +++ b/cc/toolchains/BUILD @@ -13,15 +13,11 @@ # limitations under the License. load("@bazel_skylib//:bzl_library.bzl", "bzl_library") -load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") load("@bazel_skylib//rules:diff_test.bzl", "diff_test") +load("@bazel_skylib//rules:expand_template.bzl", "expand_template") load("@stardoc//stardoc:stardoc.bzl", "stardoc") - -bool_flag( - name = "experimental_enable_rule_based_toolchains", - build_setting_default = False, - visibility = ["//visibility:public"], -) +load("//cc/toolchains/impl:documented_api.bzl", "DOCUMENTED_TOOLCHAIN_RULES") +load("//cc/toolchains/impl:markdown_helpers.bzl", "xref_substitutions") bzl_library( name = "toolchain_rules", @@ -49,11 +45,30 @@ 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"], ) +expand_template( + name = "toolchain_api_md", + out = "generated_toolchain_api.md", + # Dictionary order 100% matters here! + # buildifier: disable=unsorted-dict-items + substitutions = { + # Strip @rules_cc to prevent instances of @rules_cc@rules_cc//cc. + "@rules_cc//cc": "//cc", + # In GitHub, we prefer to clarify all the labels that come from + # rules_cc. + "//cc": "@rules_cc//cc", + } | xref_substitutions({ + "`{}`".format(rule_name): "#{}".format(rule_name) + for rule_name in DOCUMENTED_TOOLCHAIN_RULES + }), + # buildifier: enable=unsorted-dict-items + template = ":raw_generated_toolchain_api.md", +) + diff_test( name = "toolchain_api_diff_test", file1 = ":generated_toolchain_api.md", diff --git a/cc/toolchains/actions.bzl b/cc/toolchains/actions.bzl index fc91787..78c1fc6 100644 --- a/cc/toolchains/actions.bzl +++ b/cc/toolchains/actions.bzl @@ -37,14 +37,26 @@ 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/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", ], ) diff --git a/cc/toolchains/args.bzl b/cc/toolchains/args.bzl index 4f71986..bdcf7ce 100644 --- a/cc/toolchains/args.bzl +++ b/cc/toolchains/args.bzl @@ -86,30 +86,18 @@ _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,175 @@ 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/tree/main/doc/directory_doc.md#directory) + or [subdirectory](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/directory_subdirectory_doc.md#subdirectory) rule. + Some flags (e.g. --sysroot) imply certain include paths are available despite + not explicitly specifying a normal include path flag (`-I`, `-isystem`, etc.). + Bazel checks that all included headers are properly provided by a dependency or + allowlisted through this mechanism. + + As a rule of thumb, only use this if Bazel is complaining about absolute paths in + your toolchain and you've ensured that the toolchain is compiling with the + `-no-canonical-prefixes` and/or `-fno-canonical-system-headers` arguments. + + This can help work around errors like: + `the source file 'main.c' includes the following non-builtin files with absolute paths + (if these are builtin files, make sure these paths are in your toolchain)`. + args: (List[str]) The command-line arguments that are applied by using this rule. This is + mutually exclusive with [nested](#cc_args-nested). + data: (List[Label]) A list of runtime data dependencies that are required for these + arguments to work as intended. + env: (Dict[str, str]) Environment variables that should be set when the tool is invoked. + format: (Dict[str, Label]) A mapping of format strings to the label of the corresponding + `cc_variable` that the value should be pulled from. All instances of + `{variable_name}` will be replaced with the expanded value of `variable_name` in this + dictionary. The complete list of possible variables can be found in + https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD. + It is not possible to declare custom variables--these are inherent to Bazel itself. + iterate_over: (Label) The label of a `cc_variable` that should be iterated over. This is + intended for use with built-in variables that are lists. + nested: (List[Label]) A list of `cc_nested_args` rules that should be + expanded to command-line arguments when this rule is used. This is mutually exclusive + with [args](#cc_args-args). + requires_not_none: (Label) The label of a `cc_variable` that should be checked + for existence before expanding this rule. If the variable is None, this rule will be + ignored. + requires_none: (Label) The label of a `cc_variable` that should be checked for + non-existence before expanding this rule. If the variable is not None, this rule will be + ignored. + requires_true: (Label) The label of a `cc_variable` that should be checked for + truthiness before expanding this rule. If the variable is false, this rule will be + ignored. + requires_false: (Label) The label of a `cc_variable` that should be checked + for falsiness before expanding this rule. If the variable is true, this rule will be + ignored. + requires_equal: (Label) The label of a `cc_variable` that should be checked + for equality before expanding this rule. If the variable is not equal to + (requires_equal_value)[#cc_args-requires_equal_value], this rule will be ignored. + requires_equal_value: (str) The value to compare (requires_equal)[#cc_args-requires_equal] + against. + requires_any_of: (List[Label]) These arguments will be used + in a tool invocation when at least one of the [cc_feature_constraint](#cc_feature_constraint) + entries in this list are satisfied. If omitted, this flag set will be enabled + unconditionally. + **kwargs: [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. + """ return _cc_args( name = name, + actions = actions, + allowlist_include_directories = allowlist_include_directories, + args = args, + data = data, + env = env, + # We flip the key/value pairs in the dictionary here because Bazel doesn't have a + # string-keyed label dict attribute type. format = {k: v for v, k in format.items()}, + iterate_over = iterate_over, + nested = nested, + requires_not_none = requires_not_none, + requires_none = requires_none, + requires_true = requires_true, + requires_false = requires_false, + requires_equal = requires_equal, + requires_equal_value = requires_equal_value, + requires_any_of = requires_any_of, **kwargs ) diff --git a/cc/toolchains/args/archiver_flags/BUILD b/cc/toolchains/args/archiver_flags/BUILD index d293ed9..4e3c97f 100644 --- a/cc/toolchains/args/archiver_flags/BUILD +++ b/cc/toolchains/args/archiver_flags/BUILD @@ -16,7 +16,7 @@ cc_args_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"], ) diff --git a/cc/toolchains/args_list.bzl b/cc/toolchains/args_list.bzl index fbbaad5..0747acb 100644 --- a/cc/toolchains/args_list.bzl +++ b/cc/toolchains/args_list.bzl @@ -24,11 +24,49 @@ 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` into a + single list. This particularly useful for toolchain behaviors that require different flags for + different actions. + + Note: The order of the arguments in `args` is preserved to support order-sensitive flags. + + Example usage: + ``` + load("//cc/toolchains:cc_args.bzl", "cc_args") + load("//cc/toolchains:args_list.bzl", "cc_args_list") + + cc_args( + name = "gc_sections", + actions = [ + "//cc/toolchains/actions:link_actions", + ], + args = ["-Wl,--gc-sections"], + ) + + cc_args( + name = "function_sections", + actions = [ + "//cc/toolchains/actions:compile_actions", + "//cc/toolchains/actions:link_actions", + ], + args = ["-ffunction-sections"], + ) + + cc_args_list( + name = "gc_functions", + args = [ + ":function_sections", + ":gc_sections", + ], + ) + ``` + """, attrs = { "args": attr.label_list( providers = [ArgsListInfo], - doc = "The cc_args to include", + doc = "(ordered) cc_args to include in this list.", ), }, provides = [ArgsListInfo], diff --git a/cc/toolchains/feature.bzl b/cc/toolchains/feature.bzl index a282762..f0acbfe 100644 --- a/cc/toolchains/feature.bzl +++ b/cc/toolchains/feature.bzl @@ -110,22 +110,23 @@ 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 d840b7e..a863290 100644 --- a/cc/toolchains/impl/documented_api.bzl +++ b/cc/toolchains/impl/documented_api.bzl @@ -13,6 +13,48 @@ # limitations under the License. """This is a list of rules/macros that should be exported as documentation.""" +load("//cc/toolchains:actions.bzl", _cc_action_type = "cc_action_type", _cc_action_type_set = "cc_action_type_set") +load("//cc/toolchains:args.bzl", _cc_args = "cc_args") +load("//cc/toolchains:args_list.bzl", _cc_args_list = "cc_args_list") +load("//cc/toolchains:feature.bzl", _cc_feature = "cc_feature") +load("//cc/toolchains:feature_constraint.bzl", _cc_feature_constraint = "cc_feature_constraint") +load("//cc/toolchains:feature_set.bzl", _cc_feature_set = "cc_feature_set") +load("//cc/toolchains:mutually_exclusive_category.bzl", _cc_mutually_exclusive_category = "cc_mutually_exclusive_category") +load("//cc/toolchains:nested_args.bzl", _cc_nested_args = "cc_nested_args") +load("//cc/toolchains:tool.bzl", _cc_tool = "cc_tool") load("//cc/toolchains:tool_map.bzl", _cc_tool_map = "cc_tool_map") +load("//cc/toolchains/impl:external_feature.bzl", _cc_external_feature = "cc_external_feature") +load("//cc/toolchains/impl:variables.bzl", _cc_variable = "cc_variable") cc_tool_map = _cc_tool_map +cc_tool = _cc_tool +cc_args = _cc_args +cc_nested_args = _cc_nested_args +cc_args_list = _cc_args_list +cc_action_type = _cc_action_type +cc_action_type_set = _cc_action_type_set +cc_variable = _cc_variable +cc_feature = _cc_feature +cc_feature_constraint = _cc_feature_constraint +cc_feature_set = _cc_feature_set +cc_mutually_exclusive_category = _cc_mutually_exclusive_category +cc_external_feature = _cc_external_feature + +# This list is used to automatically remap instances of `foo` to [`foo`](#foo) +# links in the generated documentation so that maintainers don't need to manually +# ensure every reference to a rule is properly linked. +DOCUMENTED_TOOLCHAIN_RULES = [ + "cc_tool_map", + "cc_tool", + "cc_args", + "cc_nested_args", + "cc_args_list", + "cc_action_type", + "cc_action_type_set", + "cc_variable", + "cc_feature", + "cc_feature_constraint", + "cc_feature_set", + "cc_mutually_exclusive_category", + "cc_external_feature", +] diff --git a/cc/toolchains/impl/external_feature.bzl b/cc/toolchains/impl/external_feature.bzl index 1e11bc9..027738f 100644 --- a/cc/toolchains/impl/external_feature.bzl +++ b/cc/toolchains/impl/external_feature.bzl @@ -69,5 +69,26 @@ 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/impl/markdown_helpers.bzl b/cc/toolchains/impl/markdown_helpers.bzl new file mode 100644 index 0000000..1ae401f --- /dev/null +++ b/cc/toolchains/impl/markdown_helpers.bzl @@ -0,0 +1,53 @@ +# Copyright 2024 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""A few small helpers for working with Markdown.""" + +def markdown_link(link_text, href): + """Creates a markdown link. + + Args: + link_text: The text to display for the link. + href: The href for the link. + + Returns: + A markdown link. + """ + return "[" + link_text + "](" + href + ")" + +def xref_substitutions(match_text_patterns): + """Creates a dictionary of substitutions for use for linkification of text. + + Example: + ``` + # Produces a dictionary containing: + # { + # "foo": "[foo](http://foo.com)" + # "bar": "[bar](http://bar.com)" + # } + substitutions = xref_substitutions({ + "foo": "http://foo.com", + "bar": "http://bar.com", + }) + ``` + + Args: + match_text_patterns: A dictionary mapping string literals to the links they should point to. + + Returns: + A dictionary of string literals mapped to their linkified substitutions. + """ + return { + match_text: markdown_link(match_text, href) + for match_text, href in match_text_patterns.items() + } diff --git a/cc/toolchains/impl/toolchain_config.bzl b/cc/toolchains/impl/toolchain_config.bzl index 5c8d69c..da2a873 100644 --- a/cc/toolchains/impl/toolchain_config.bzl +++ b/cc/toolchains/impl/toolchain_config.bzl @@ -13,7 +13,6 @@ # limitations under the License. """Implementation of the cc_toolchain rule.""" -load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") load( "//cc/toolchains:cc_toolchain_info.bzl", "ActionTypeSetInfo", @@ -52,9 +51,6 @@ 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], @@ -86,7 +82,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())), @@ -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/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/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/nested_args.bzl b/cc/toolchains/nested_args.bzl index 1d31275..d81dd99 100644 --- a/cc/toolchains/nested_args.bzl +++ b/cc/toolchains/nested_args.bzl @@ -41,9 +41,88 @@ 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`, it is intended to be used as a + dependency of `cc_args` to provide additional arguments that should be applied to the + same actions as defined by the parent `cc_args` rule. The key motivation for this rule + is to allow for more complex variable-based argument expensions. + + Prefer expressing collections of arguments as `cc_args` and + `cc_args_list` rules when possible. + + For living examples of how this rule is used, see the usages here: + https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/runtime_library_search_directories/BUILD + https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/libraries_to_link/BUILD + + Note: These examples are non-trivial, but they illustrate when it is absolutely necessary to + use this rule. + + Args: + name: (str) The name of the target. + args: (List[str]) The command-line arguments that are applied by using this rule. This is + mutually exclusive with [nested](#cc_nested_args-nested). + data: (List[Label]) A list of runtime data dependencies that are required for these + arguments to work as intended. + format: (Dict[str, Label]) A mapping of format strings to the label of the corresponding + `cc_variable` that the value should be pulled from. All instances of + `{variable_name}` will be replaced with the expanded value of `variable_name` in this + dictionary. The complete list of possible variables can be found in + https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD. + It is not possible to declare custom variables--these are inherent to Bazel itself. + iterate_over: (Label) The label of a `cc_variable` that should be iterated + over. This is intended for use with built-in variables that are lists. + nested: (List[Label]) A list of `cc_nested_args` rules that should be + expanded to command-line arguments when this rule is used. This is mutually exclusive + with [args](#cc_nested_args-args). + requires_not_none: (Label) The label of a `cc_variable` that should be checked + for existence before expanding this rule. If the variable is None, this rule will be + ignored. + requires_none: (Label) The label of a `cc_variable` that should be checked for + non-existence before expanding this rule. If the variable is not None, this rule will be + ignored. + requires_true: (Label) The label of a `cc_variable` that should be checked for + truthiness before expanding this rule. If the variable is false, this rule will be + ignored. + requires_false: (Label) The label of a `cc_variable` that should be checked + for falsiness before expanding this rule. If the variable is true, this rule will be + ignored. + requires_equal: (Label) The label of a `cc_variable` that should be checked + for equality before expanding this rule. If the variable is not equal to + (requires_equal_value)[#cc_nested_args-requires_equal_value], this rule will be ignored. + requires_equal_value: (str) The value to compare + (requires_equal)[#cc_nested_args-requires_equal] against. + **kwargs: [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule. + """ return _cc_nested_args( name = name, + args = args, + data = data, + # We flip the key/value pairs in the dictionary here because Bazel doesn't have a + # string-keyed label dict attribute type. format = {k: v for v, k in format.items()}, + iterate_over = iterate_over, + nested = nested, + requires_not_none = requires_not_none, + requires_none = requires_none, + requires_true = requires_true, + requires_false = requires_false, + requires_equal = requires_equal, + requires_equal_value = requires_equal_value, **kwargs ) diff --git a/cc/toolchains/tool.bzl b/cc/toolchains/tool.bzl index 159a9d6..0dc309d 100644 --- a/cc/toolchains/tool.bzl +++ b/cc/toolchains/tool.bzl @@ -66,13 +66,17 @@ 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.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"), ], } diff --git a/cc/toolchains/toolchain_api.md b/cc/toolchains/toolchain_api.md index 3a4a490..418ef52 100644 --- a/cc/toolchains/toolchain_api.md +++ b/cc/toolchains/toolchain_api.md @@ -2,6 +2,577 @@ This is a list of rules/macros that should be exported as documentation. + + +## 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 + +
+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("@rules_cc//cc/toolchains:cc_args.bzl", "cc_args") +load("@rules_cc//cc/toolchains:args_list.bzl", "cc_args_list") + +cc_args( + name = "gc_sections", + actions = [ + "@rules_cc//cc/toolchains/actions:link_actions", + ], + args = ["-Wl,--gc-sections"], +) + +cc_args( + name = "function_sections", + actions = [ + "@rules_cc//cc/toolchains/actions:compile_actions", + "@rules_cc//cc/toolchains/actions:link_actions", + ], + args = ["-ffunction-sections"], +) + +cc_args_list( + name = "gc_functions", + args = [ + ":function_sections", + ":gc_sections", + ], +) +``` + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| 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 + +
+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 + +
+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`](#cc_args) rule that applies an ordered list of arguments to a set of toolchain +actions. [`cc_args`](#cc_args) rules can be added unconditionally to a +`cc_toolchain`, conditionally via `select()` statements, or dynamically via an +intermediate [`cc_feature`](#cc_feature). + +Conceptually, this is similar to the old `CFLAGS`, `CPPFLAGS`, etc. environment variables that +many build systems use to determine which flags to use for a given action. The significant +difference is that [`cc_args`](#cc_args) rules are declared in a structured way that allows for +significantly more powerful and sharable toolchain configurations. Also, due to Bazel's more +granular action types, it's possible to bind flags to very specific actions (e.g. LTO indexing +for an executable vs a dynamic library) multiple different actions (e.g. C++ compile and link +simultaneously). + +Example usage: +``` +load("@rules_cc//cc/toolchains:args.bzl", "cc_args") + +# Basic usage: a trivial flag. +# +# An example of expressing `-Werror` as a [`cc_args`](#cc_args) rule. +cc_args( + name = "warnings_as_errors", + actions = [ + # Applies to all C/C++ compile actions. + "@rules_cc//cc/toolchains/actions:compile_actions", + ], + args = ["-Werror"], +) + +# Basic usage: ordered flags. +# +# An example of linking against libc++, which uses two flags that must be applied in order. +cc_args( + name = "link_libcxx", + actions = [ + # Applies to all link actions. + "@rules_cc//cc/toolchains/actions:link_actions", + ], + # On tool invocation, this appears as `-Xlinker -lc++`. Nothing will ever end up between + # the two flags. + args = [ + "-Xlinker", + "-lc++", + ], +) + +# Advanced usage: built-in variable expansions. +# +# Expands to `-L/path/to/search_dir` for each directory in the built-in variable +# `library_search_directories`. This variable is managed internally by Bazel through inherent +# behaviors of Bazel and the interactions between various C/C++ build rules. +cc_args( + name = "library_search_directories", + actions = [ + "@rules_cc//cc/toolchains/actions:link_actions", + ], + args = ["-L{search_dir}"], + iterate_over = "@rules_cc//cc/toolchains/variables:library_search_directories", + requires_not_none = "@rules_cc//cc/toolchains/variables:library_search_directories", + format = { + "search_dir": "@rules_cc//cc/toolchains/variables:library_search_directories", + }, +) +``` + +For more extensive examples, see the usages here: + https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args + + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| name | (str) The name of the target. | 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`](#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](#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`](#cc_args) expansions. + +While this rule is very similar in shape to [`cc_args`](#cc_args), it is intended to be used as a +dependency of [`cc_args`](#cc_args) to provide additional arguments that should be applied to the +same actions as defined by the parent [`cc_args`](#cc_args) rule. The key motivation for this rule +is to allow for more complex variable-based argument expensions. + +Prefer expressing collections of arguments as [`cc_args`](#cc_args) and +[`cc_args_list`](#cc_args_list) rules when possible. + +For living examples of how this rule is used, see the usages here: + https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/runtime_library_search_directories/BUILD + https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/libraries_to_link/BUILD + +Note: These examples are non-trivial, but they illustrate when it is absolutely necessary to +use this rule. + + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| 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`](#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 | + + ## cc_tool_map @@ -12,31 +583,32 @@ 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, -//third_party/bazel_rules/rules_cc/cc/toolchains/actions:cpp_compile_actions) to +A [`cc_tool_map`](#cc_tool_map) aggregates all the tools that may be used for a given toolchain +and maps them to their corresponding actions. Conceptually, this is similar to the +`CXX=/path/to/clang++` environment variables that most build systems use to determine which +tools to use for a given action. To simplify usage, some actions have been grouped together (for +example, +[@rules_cc//cc/toolchains/actions:cpp_compile_actions](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/actions/BUILD)) to logically express "all the C++ compile actions". In Bazel, there is a little more granularity to the mapping, so the mapping doesn't follow the traditional `CXX`, `AR`, etc. naming scheme. For a comprehensive list of all the well-known -actions, see //third_party/bazel_rules/rules_cc/cc/toolchains/actions:BUILD. +actions, see @rules_cc//cc/toolchains/actions:BUILD. Example usage: ``` -load("//third_party/bazel_rules/rules_cc/cc/toolchains:tool_map.bzl", "cc_tool_map") +load("@rules_cc//cc/toolchains:tool_map.bzl", "cc_tool_map") cc_tool_map( name = "all_tools", tools = { - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:assembly_actions": ":asm", - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:c_compile": ":clang", - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:cpp_compile_actions": ":clang++", - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:link_actions": ":lld", - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:objcopy_embed_data": ":llvm-objcopy", - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:strip": ":llvm-strip", - "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:ar_actions": ":llvm-ar", + "@rules_cc//cc/toolchains/actions:assembly_actions": ":asm", + "@rules_cc//cc/toolchains/actions:c_compile": ":clang", + "@rules_cc//cc/toolchains/actions:cpp_compile_actions": ":clang++", + "@rules_cc//cc/toolchains/actions:link_actions": ":lld", + "@rules_cc//cc/toolchains/actions:objcopy_embed_data": ":llvm-objcopy", + "@rules_cc//cc/toolchains/actions:strip": ":llvm-strip", + "@rules_cc//cc/toolchains/actions:ar_actions": ":llvm-ar", }, ) ``` @@ -53,7 +625,47 @@ 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 | + + 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", )