blob: 674ee6698e89ec344f781056dc3f07c3eb808214 [file] [log] [blame] [edit]
# 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] == "/")