diff --git a/cc/toolchains/artifacts.bzl b/cc/toolchains/artifacts.bzl new file mode 100644 index 00000000..546064c8 --- /dev/null +++ b/cc/toolchains/artifacts.bzl @@ -0,0 +1,103 @@ +# Copyright 2025 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. + +"""Rules to turn artifact categories into targets.""" + +load(":cc_toolchain_info.bzl", "ArtifactCategoryInfo", "ArtifactNamePatternInfo") + +visibility("public") + +def _cc_artifact_category_impl(ctx): + return [ + ArtifactCategoryInfo( + label = ctx.label, + name = ctx.attr.name, + ), + ] + +cc_artifact_category = rule( + implementation = _cc_artifact_category_impl, + doc = """ +An artifact category (eg. static_library, executable, object_file). + +Example: +``` +load("//cc/toolchains:artifacts.bzl", "cc_artifact_category") + +cc_artifact_category( + name = "static_library", +) +``` +""", + provides = [ + ArtifactCategoryInfo, + ], +) + +def _cc_artifact_name_pattern_impl(ctx): + return [ + ArtifactNamePatternInfo( + label = ctx.label, + category = ctx.attr.category[ArtifactCategoryInfo], + prefix = ctx.attr.prefix, + extension = ctx.attr.extension, + ), + ] + +cc_artifact_name_pattern = rule( + implementation = _cc_artifact_name_pattern_impl, + attrs = { + "category": attr.label( + mandatory = True, + providers = [ + ArtifactCategoryInfo, + ], + ), + "prefix": attr.string( + mandatory = True, + ), + "extension": attr.string( + mandatory = True, + ), + }, + doc = """ +The name for an artifact of a given category of input or output artifacts to an +action. + +This is used to declare that executables should follow `.exe` on Windows, +or shared libraries should follow `lib.dylib` on macOS. + +Example: +``` +load("//cc/toolchains:artifacts.bzl", "cc_artifact_name_pattern") + +cc_artifact_name_pattern( + name = "static_library", + category = "//cc/toolchains/artifacts:static_library", + prefix = "lib", + extension = ".a", +) + +cc_artifact_name_pattern( + name = "executable", + category = "//cc/toolchains/artifacts:executable", + prefix = "", + extension = "", +) +``` +""", + provides = [ + ArtifactNamePatternInfo, + ], +) diff --git a/cc/toolchains/artifacts/BUILD b/cc/toolchains/artifacts/BUILD new file mode 100644 index 00000000..1fb0de2b --- /dev/null +++ b/cc/toolchains/artifacts/BUILD @@ -0,0 +1,137 @@ +# Copyright 2025 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. + +# Derived from @bazel//src/main/starlark/builtins_bzl/common/cc:cc_helper_internal.bzl + +load("//cc/toolchains:artifacts.bzl", "cc_artifact_category") + +cc_artifact_category( + name = "alwayslink_static_library", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "clif_output_proto", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "coverage_data_file", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "cpp_module", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "cpp_module_gcm", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "cpp_module_ifc", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "cpp_modules_ddi", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "cpp_modules_info", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "cpp_modules_modmap", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "cpp_modules_modmap_input", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "dynamic_library", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "executable", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "generated_assembly", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "generated_header", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "included_file_list", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "interface_library", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "object_file", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "pic_file", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "pic_object_file", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "preprocessed_c_source", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "preprocessed_cpp_source", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "processed_header", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "serialized_diagnostics_file", + visibility = ["//visibility:public"], +) + +cc_artifact_category( + name = "static_library", + visibility = ["//visibility:public"], +) diff --git a/cc/toolchains/cc_toolchain_info.bzl b/cc/toolchains/cc_toolchain_info.bzl index 17881a8d..d98fa00f 100644 --- a/cc/toolchains/cc_toolchain_info.bzl +++ b/cc/toolchains/cc_toolchain_info.bzl @@ -45,6 +45,26 @@ ActionTypeSetInfo = provider( }, ) +ArtifactCategoryInfo = provider( + doc = "A category of artifacts (eg. static_library, executable, object_file)", + # @unsorted-dict-items + fields = { + "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", + "name": "(str) The name of the artifact category, as defined by Bazel", + }, +) + +ArtifactNamePatternInfo = provider( + doc = "A name pattern for artifacts", + # @unsorted-dict-items + fields = { + "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", + "category": "(ArtifactCategoryInfo) The artifact category this pattern is for", + "prefix": "(str) The prefix for creating the artifact", + "extension": "(str) The extension for creating the artifact", + }, +) + VariableInfo = provider( """A variable defined by the toolchain""", # @unsorted-dict-items @@ -187,6 +207,7 @@ ToolchainConfigInfo = provider( "enabled_features": "(Sequence[FeatureInfo]) The features That are enabled by default for this toolchain", "tool_map": "(ToolConfigInfo) A provider mapping toolchain action types to tools.", "args": "(Sequence[ArgsInfo]) A list of arguments to be unconditionally applied to the toolchain.", + "artifact_name_patterns": "Sequence[ArtifactNamePatternInfo] A artifact name patterns for this toolchain", "files": "(dict[ActionTypeInfo, depset[File]]) Files required for the toolchain, keyed by the action type.", "allowlist_include_directories": "(depset[DirectoryInfo]) Built-in include directories implied by this toolchain's args and tools that should be allowlisted in Bazel's include checker", }, diff --git a/cc/toolchains/impl/legacy_converter.bzl b/cc/toolchains/impl/legacy_converter.bzl index 6eafc4f7..a7b6a659 100644 --- a/cc/toolchains/impl/legacy_converter.bzl +++ b/cc/toolchains/impl/legacy_converter.bzl @@ -16,6 +16,7 @@ load( "//cc:cc_toolchain_config_lib.bzl", legacy_action_config = "action_config", + legacy_artifact_name_pattern = "artifact_name_pattern", legacy_env_entry = "env_entry", legacy_env_set = "env_set", legacy_feature = "feature", @@ -201,8 +202,18 @@ def convert_toolchain(toolchain): for d in toolchain.allowlist_include_directories.to_list() ] + artifact_name_patterns = [ + legacy_artifact_name_pattern( + category_name = p.category.name, + prefix = p.prefix, + extension = p.extension, + ) + for p in toolchain.artifact_name_patterns + ] + return struct( features = [ft for ft in features if ft != None], action_configs = sorted(action_configs, key = lambda ac: ac.action_name), cxx_builtin_include_directories = cxx_builtin_include_directories, + artifact_name_patterns = artifact_name_patterns, ) diff --git a/cc/toolchains/impl/toolchain_config.bzl b/cc/toolchains/impl/toolchain_config.bzl index 400df483..c364a7f1 100644 --- a/cc/toolchains/impl/toolchain_config.bzl +++ b/cc/toolchains/impl/toolchain_config.bzl @@ -18,6 +18,7 @@ load( "//cc/toolchains:cc_toolchain_info.bzl", "ActionTypeSetInfo", "ArgsListInfo", + "ArtifactNamePatternInfo", "FeatureSetInfo", "ToolConfigInfo", "ToolchainConfigInfo", @@ -58,6 +59,7 @@ def _cc_toolchain_config_impl(ctx): enabled_features = ctx.attr.enabled_features, tool_map = ctx.attr.tool_map, args = ctx.attr.args, + artifact_name_patterns = ctx.attr.artifact_name_patterns, ) legacy = convert_toolchain(toolchain_config) @@ -67,6 +69,7 @@ def _cc_toolchain_config_impl(ctx): cc_common.create_cc_toolchain_config_info( ctx = ctx, action_configs = legacy.action_configs, + artifact_name_patterns = legacy.artifact_name_patterns, features = legacy.features, cxx_builtin_include_directories = legacy.cxx_builtin_include_directories, # toolchain_identifier is deprecated, but setting it to None results @@ -102,6 +105,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]), + "artifact_name_patterns": attr.label_list(providers = [ArtifactNamePatternInfo]), "_builtin_features": attr.label(default = "//cc/toolchains/features:all_builtin_features"), }, provides = [ToolchainConfigInfo], diff --git a/cc/toolchains/impl/toolchain_config_info.bzl b/cc/toolchains/impl/toolchain_config_info.bzl index 3c8c65cb..60bff7af 100644 --- a/cc/toolchains/impl/toolchain_config_info.bzl +++ b/cc/toolchains/impl/toolchain_config_info.bzl @@ -13,7 +13,7 @@ # limitations under the License. """Helper functions to create and validate a ToolchainConfigInfo.""" -load("//cc/toolchains:cc_toolchain_info.bzl", "ToolConfigInfo", "ToolchainConfigInfo") +load("//cc/toolchains:cc_toolchain_info.bzl", "ArtifactNamePatternInfo", "ToolConfigInfo", "ToolchainConfigInfo") load(":args_utils.bzl", "get_action_type") load(":collect.bzl", "collect_args_lists", "collect_features") @@ -130,7 +130,7 @@ def _collect_files_for_action_type(action_type, tool_map, features, args): return depset(transitive = transitive_files) -def toolchain_config_info(label, known_features = [], enabled_features = [], args = [], tool_map = None, fail = fail): +def toolchain_config_info(label, known_features = [], enabled_features = [], args = [], artifact_name_patterns = [], tool_map = None, fail = fail): """Generates and validates a ToolchainConfigInfo from lists of labels. Args: @@ -139,6 +139,7 @@ def toolchain_config_info(label, known_features = [], enabled_features = [], arg enabled_features: (List[Target]) A list of features that are enabled by default. Every enabled feature is implicitly also a known feature. args: (List[Target]) A list of targets providing ArgsListInfo + artifact_name_patterns: (List[Target]) A list of targets providing ArtifactNamePatternInfo. tool_map: (Target) A target providing ToolMapInfo. fail: A fail function. Use only during tests. Returns: @@ -179,6 +180,7 @@ def toolchain_config_info(label, known_features = [], enabled_features = [], arg args = args, files = files, allowlist_include_directories = allowlist_include_directories, + artifact_name_patterns = [t[ArtifactNamePatternInfo] for t in artifact_name_patterns], ) _validate_toolchain(toolchain_config, fail = fail) return toolchain_config diff --git a/tests/rule_based_toolchain/subjects.bzl b/tests/rule_based_toolchain/subjects.bzl index be36b1c1..58b0fbd1 100644 --- a/tests/rule_based_toolchain/subjects.bzl +++ b/tests/rule_based_toolchain/subjects.bzl @@ -221,6 +221,7 @@ _ToolchainConfigFactory = generate_factory( args = ProviderSequence(_ArgsFactory), files = dict_key_subject(_subjects.depset_file), allowlist_include_directories = _FakeDirectoryDepset, + artifact_name_patterns = [], ), )