| # 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. | 
 |  | 
 | """ | 
 | Utility functions for C++ rules that don't depend on cc_common. | 
 |  | 
 | Only use those within C++ implementation. The others need to go through cc_common. | 
 | """ | 
 |  | 
 | load("@bazel_skylib//lib:paths.bzl", "paths") | 
 | load("//cc/private:paths.bzl", "is_path_absolute") | 
 |  | 
 | # LINT.IfChange(forked_exports) | 
 |  | 
 | _CC_SOURCE = [".cc", ".cpp", ".cxx", ".c++", ".C", ".cu", ".cl"] | 
 | _C_SOURCE = [".c"] | 
 | _OBJC_SOURCE = [".m"] | 
 | _OBJCPP_SOURCE = [".mm"] | 
 | _CLIF_INPUT_PROTO = [".ipb"] | 
 | _CLIF_OUTPUT_PROTO = [".opb"] | 
 | _CC_HEADER = [".h", ".hh", ".hpp", ".ipp", ".hxx", ".h++", ".inc", ".inl", ".tlh", ".tli", ".H", ".tcc"] | 
 | _CC_TEXTUAL_INCLUDE = [".inc"] | 
 | _ASSEMBLER_WITH_C_PREPROCESSOR = [".S"] | 
 | _ASSEMBLER = [".s", ".asm"] | 
 | _ARCHIVE = [".a", ".lib"] | 
 | _PIC_ARCHIVE = [".pic.a"] | 
 | _ALWAYSLINK_LIBRARY = [".lo"] | 
 | _ALWAYSLINK_PIC_LIBRARY = [".pic.lo"] | 
 | _SHARED_LIBRARY = [".so", ".dylib", ".dll", ".wasm"] | 
 | _INTERFACE_SHARED_LIBRARY = [".ifso", ".tbd", ".lib", ".dll.a"] | 
 | _OBJECT_FILE = [".o", ".obj"] | 
 | _PIC_OBJECT_FILE = [".pic.o"] | 
 | _CPP_MODULE = [".pcm", ".gcm", ".ifc"] | 
 | _CPP_MODULE_MAP = [".cppmap"] | 
 | _LTO_INDEXING_OBJECT_FILE = [".indexing.o"] | 
 |  | 
 | _CC_AND_OBJC = [] | 
 | _CC_AND_OBJC.extend(_CC_SOURCE) | 
 | _CC_AND_OBJC.extend(_C_SOURCE) | 
 | _CC_AND_OBJC.extend(_OBJC_SOURCE) | 
 | _CC_AND_OBJC.extend(_OBJCPP_SOURCE) | 
 | _CC_AND_OBJC.extend(_CC_HEADER) | 
 | _CC_AND_OBJC.extend(_ASSEMBLER) | 
 | _CC_AND_OBJC.extend(_ASSEMBLER_WITH_C_PREPROCESSOR) | 
 |  | 
 | _DISALLOWED_HDRS_FILES = [] | 
 | _DISALLOWED_HDRS_FILES.extend(_ARCHIVE) | 
 | _DISALLOWED_HDRS_FILES.extend(_PIC_ARCHIVE) | 
 | _DISALLOWED_HDRS_FILES.extend(_ALWAYSLINK_LIBRARY) | 
 | _DISALLOWED_HDRS_FILES.extend(_ALWAYSLINK_PIC_LIBRARY) | 
 | _DISALLOWED_HDRS_FILES.extend(_SHARED_LIBRARY) | 
 | _DISALLOWED_HDRS_FILES.extend(_INTERFACE_SHARED_LIBRARY) | 
 | _DISALLOWED_HDRS_FILES.extend(_OBJECT_FILE) | 
 | _DISALLOWED_HDRS_FILES.extend(_PIC_OBJECT_FILE) | 
 |  | 
 | extensions = struct( | 
 |     CC_SOURCE = _CC_SOURCE, | 
 |     C_SOURCE = _C_SOURCE, | 
 |     OBJC_SOURCE = _OBJC_SOURCE, | 
 |     OBJCPP_SOURCE = _OBJCPP_SOURCE, | 
 |     CC_HEADER = _CC_HEADER, | 
 |     CC_TEXTUAL_INCLUDE = _CC_TEXTUAL_INCLUDE, | 
 |     ASSEMBLER_WITH_C_PREPROCESSOR = _ASSEMBLER_WITH_C_PREPROCESSOR, | 
 |     # TODO(b/345158656): Remove ASSESMBLER_WITH_C_PREPROCESSOR after next blaze release | 
 |     ASSESMBLER_WITH_C_PREPROCESSOR = _ASSEMBLER_WITH_C_PREPROCESSOR, | 
 |     ASSEMBLER = _ASSEMBLER, | 
 |     CLIF_INPUT_PROTO = _CLIF_INPUT_PROTO, | 
 |     CLIF_OUTPUT_PROTO = _CLIF_OUTPUT_PROTO, | 
 |     ARCHIVE = _ARCHIVE, | 
 |     PIC_ARCHIVE = _PIC_ARCHIVE, | 
 |     ALWAYSLINK_LIBRARY = _ALWAYSLINK_LIBRARY, | 
 |     ALWAYSLINK_PIC_LIBRARY = _ALWAYSLINK_PIC_LIBRARY, | 
 |     SHARED_LIBRARY = _SHARED_LIBRARY, | 
 |     OBJECT_FILE = _OBJECT_FILE, | 
 |     PIC_OBJECT_FILE = _PIC_OBJECT_FILE, | 
 |     CC_AND_OBJC = _CC_AND_OBJC, | 
 |     DISALLOWED_HDRS_FILES = _DISALLOWED_HDRS_FILES,  # Also includes VERSIONED_SHARED_LIBRARY files. | 
 |     CPP_MODULE = _CPP_MODULE, | 
 |     CPP_MODULE_MAP = _CPP_MODULE_MAP, | 
 |     LTO_INDEXING_OBJECT_FILE = _LTO_INDEXING_OBJECT_FILE, | 
 | ) | 
 |  | 
 | def _artifact_category_info_init(name, default_prefix, *extensions): | 
 |     return { | 
 |         "allowed_extensions": extensions, | 
 |         "default_extension": extensions[0], | 
 |         "default_prefix": default_prefix, | 
 |         "name": name, | 
 |     } | 
 |  | 
 | # buildifier: disable=unused-variable | 
 | _ArtifactCategoryInfo, _unused_new_aci = provider( | 
 |     """A category of artifacts that are candidate input/output to an action, for | 
 |      which the toolchain can select a single artifact.""", | 
 |     fields = ["name", "default_prefix", "default_extension", "allowed_extensions"], | 
 |     init = _artifact_category_info_init, | 
 | ) | 
 |  | 
 | # TODO: b/433485282 - remove duplicated extensions lists with above constants | 
 | _artifact_categories = [ | 
 |     _ArtifactCategoryInfo("STATIC_LIBRARY", "lib", ".a", ".lib"), | 
 |     _ArtifactCategoryInfo("ALWAYSLINK_STATIC_LIBRARY", "lib", ".lo", ".lo.lib"), | 
 |     _ArtifactCategoryInfo("DYNAMIC_LIBRARY", "lib", ".so", ".dylib", ".dll", ".wasm"), | 
 |     _ArtifactCategoryInfo("EXECUTABLE", "", "", ".exe", ".wasm"), | 
 |     _ArtifactCategoryInfo("INTERFACE_LIBRARY", "lib", ".ifso", ".tbd", ".if.lib", ".lib"), | 
 |     _ArtifactCategoryInfo("PIC_FILE", "", ".pic"), | 
 |     _ArtifactCategoryInfo("INCLUDED_FILE_LIST", "", ".d"), | 
 |     _ArtifactCategoryInfo("SERIALIZED_DIAGNOSTICS_FILE", "", ".dia"), | 
 |     _ArtifactCategoryInfo("OBJECT_FILE", "", ".o", ".obj"), | 
 |     _ArtifactCategoryInfo("PIC_OBJECT_FILE", "", ".pic.o"), | 
 |     _ArtifactCategoryInfo("CPP_MODULE", "", ".pcm"), | 
 |     _ArtifactCategoryInfo("CPP_MODULE_GCM", "", ".gcm"), | 
 |     _ArtifactCategoryInfo("CPP_MODULE_IFC", "", ".ifc"), | 
 |     _ArtifactCategoryInfo("CPP_MODULES_INFO", "", ".CXXModules.json"), | 
 |     _ArtifactCategoryInfo("CPP_MODULES_DDI", "", ".ddi"), | 
 |     _ArtifactCategoryInfo("CPP_MODULES_MODMAP", "", ".modmap"), | 
 |     _ArtifactCategoryInfo("CPP_MODULES_MODMAP_INPUT", "", ".modmap.input"), | 
 |     _ArtifactCategoryInfo("GENERATED_ASSEMBLY", "", ".s", ".asm"), | 
 |     _ArtifactCategoryInfo("PROCESSED_HEADER", "", ".processed"), | 
 |     _ArtifactCategoryInfo("GENERATED_HEADER", "", ".h"), | 
 |     _ArtifactCategoryInfo("PREPROCESSED_C_SOURCE", "", ".i"), | 
 |     _ArtifactCategoryInfo("PREPROCESSED_CPP_SOURCE", "", ".ii"), | 
 |     _ArtifactCategoryInfo("COVERAGE_DATA_FILE", "", ".gcno"), | 
 |     # A matched-clif protobuf. Typically in binary format, but could be text | 
 |     # depending on the options passed to the clif_matcher. | 
 |     _ArtifactCategoryInfo("CLIF_OUTPUT_PROTO", "", ".opb"), | 
 | ] | 
 |  | 
 | artifact_category_names = struct(**{ac.name: ac.name for ac in _artifact_categories}) | 
 |  | 
 | output_subdirectories = struct( | 
 |     OBJS = "_objs", | 
 |     PIB_OBJS = "_pic_objs", | 
 |     DOTD_FILES = "_dotd", | 
 |     PIC_DOTD_FILES = "_pic_dotd", | 
 |     DIA_FILES = "_dia", | 
 |     PIC_DIA_FILES = "_pic_dia", | 
 | ) | 
 |  | 
 | def should_create_per_object_debug_info(feature_configuration, cpp_configuration): | 
 |     return cpp_configuration.fission_active_for_current_compilation_mode() and \ | 
 |            feature_configuration.is_enabled("per_object_debug_info") | 
 |  | 
 | def is_versioned_shared_library_extension_valid(shared_library_name): | 
 |     """Validates the name against the regex "^.+\\.((so)|(dylib))(\\.\\d\\w*)+$", | 
 |  | 
 |     Args: | 
 |         shared_library_name: (str) the name to validate | 
 |  | 
 |     Returns: | 
 |         (bool) | 
 |     """ | 
 |  | 
 |     # must match VERSIONED_SHARED_LIBRARY. | 
 |     for ext in (".so.", ".dylib."): | 
 |         name, _, version = shared_library_name.rpartition(ext) | 
 |         if name and version: | 
 |             version_parts = version.split(".") | 
 |             for part in version_parts: | 
 |                 if not part[0].isdigit(): | 
 |                     return False | 
 |                 for c in part[1:].elems(): | 
 |                     if not (c.isalnum() or c == "_"): | 
 |                         return False | 
 |             return True | 
 |     return False | 
 |  | 
 | def _is_repository_main(repository): | 
 |     return repository == "" | 
 |  | 
 | def package_source_root(repository, package, sibling_repository_layout): | 
 |     """ | 
 |     Determines the source root for a given repository and package. | 
 |  | 
 |     Args: | 
 |       repository: The repository to get the source root for. | 
 |       package: The package to get the source root for. | 
 |       sibling_repository_layout: Whether the repository layout is a sibling repository layout. | 
 |  | 
 |     Returns: | 
 |       The source root for the given repository and package. | 
 |     """ | 
 |     if _is_repository_main(repository) or sibling_repository_layout: | 
 |         return package | 
 |     if repository.startswith("@"): | 
 |         repository = repository[1:] | 
 |     return get_relative_path(get_relative_path("external", repository), package) | 
 |  | 
 | def repository_exec_path(repository, sibling_repository_layout): | 
 |     """ | 
 |     Determines the exec path for a given repository. | 
 |  | 
 |     Args: | 
 |       repository: The repository to get the exec path for. | 
 |       sibling_repository_layout: Whether the repository layout is a sibling repository layout. | 
 |  | 
 |     Returns: | 
 |       The exec path for the given repository. | 
 |     """ | 
 |     if _is_repository_main(repository): | 
 |         return "" | 
 |     prefix = "external" | 
 |     if sibling_repository_layout: | 
 |         prefix = ".." | 
 |     if repository.startswith("@"): | 
 |         repository = repository[1:] | 
 |     return get_relative_path(prefix, repository) | 
 |  | 
 | def is_stamping_enabled(ctx): | 
 |     """Returns whether to encode build information into the binary. | 
 |  | 
 |     Args: | 
 |         ctx: The rule context. | 
 |  | 
 |     Returns: | 
 |     (int): 1: Always stamp the build information into the binary, even in [--nostamp][stamp] builds. | 
 |         This setting should be avoided, since it potentially kills remote caching for the binary and | 
 |         any downstream actions that depend on it. | 
 |         0: Always replace build information by constant values. This gives good build result caching. | 
 |         -1: Embedding of build information is controlled by the [--[no]stamp][stamp] flag. | 
 |     """ | 
 |     if ctx.configuration.is_tool_configuration(): | 
 |         return 0 | 
 |     stamp = 0 | 
 |     if hasattr(ctx.attr, "stamp"): | 
 |         stamp = ctx.attr.stamp | 
 |     return stamp | 
 |  | 
 | # LINT.ThenChange(https://github.com/bazelbuild/bazel/blob/master/src/main/starlark/builtins_bzl/common/cc/cc_helper_internal.bzl:forked_exports) | 
 |  | 
 | def get_relative_path(path_a, path_b): | 
 |     if is_path_absolute(path_b): | 
 |         return path_b | 
 |     return paths.normalize(paths.join(path_a, path_b)) | 
 |  | 
 | def path_contains_up_level_references(path): | 
 |     return path.startswith("..") and (len(path) == 2 or path[2] == "/") |