blob: f4f85f5cbf086a4f215f0910d7615c40b2a1488f [file] [log] [blame]
# 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.
load(":common/cc/cc_helper_internal.bzl", "should_create_per_object_debug_info")
cc_common_internal = _builtins.internal.cc_common
cc_internal = _builtins.internal.cc_internal
def create_lto_backends(
actions,
lto_compilation_context,
feature_configuration,
cc_toolchain,
use_pic,
object_file_inputs,
lto_output_root_prefix,
lto_obj_root_prefix,
static_libraries_to_link,
allow_lto_indexing,
include_link_static_in_lto_indexing,
prefer_pic_libs):
cpp_config = cc_toolchain._cpp_configuration
debug = should_create_per_object_debug_info(feature_configuration, cpp_config)
compiled = set()
static_library_files = set()
for lib in static_libraries_to_link:
pic = (prefer_pic_libs and lib.pic_static_library != None) or \
lib.static_library == None
library_file = lib.pic_static_library if pic else lib.static_library
if library_file in static_library_files:
# Duplicated static libraries are linked just once and don't error out.
# TODO(b/413333884): Clean up violations and error out
continue
static_library_files.add(library_file)
context = lib._pic_lto_compilation_context if pic else lib._lto_compilation_context
if context:
compiled.update(context.lto_bitcode_inputs().keys())
all_bitcode = []
# Since this link includes object files from another library, we know that library must be
# statically linked, so we need to look at includeLinkStaticInLtoIndexing to decide whether
# to include its objects in the LTO indexing for this target.
if include_link_static_in_lto_indexing:
for lib in static_libraries_to_link:
if not lib._contains_objects:
continue
pic = (prefer_pic_libs and lib.pic_static_library != None) or \
lib.static_library == None
objects = lib.pic_objects if pic else lib.objects
for obj in objects:
if obj in compiled:
all_bitcode.append(obj)
for obj in object_file_inputs:
if obj in lto_compilation_context.lto_bitcode_inputs():
all_bitcode.append(obj)
if lto_output_root_prefix == lto_obj_root_prefix:
for file in all_bitcode:
if file.is_directory:
fail("Thinlto with tree artifacts requires feature use_lto_native_object_directory.")
# Make this a NestedSet to return from LtoBackendAction.getAllowedDerivedInputs. For M binaries
# and N .o files, this is O(M*N). If we had nested sets of bitcode files, it would be O(M + N).
all_bitcode_depset = depset(all_bitcode)
lto_outputs = []
for lib in static_libraries_to_link:
if not lib._contains_objects:
continue
pic = (prefer_pic_libs and lib.pic_static_library != None) or \
lib.static_library == None
objects = lib.pic_objects if pic else lib.objects
lib_lto_compilation_context = lib._pic_lto_compilation_context if pic else lib._lto_compilation_context
shared_lto_backends = lib._pic_shared_non_lto_backends if pic else lib._shared_non_lto_backends
for obj in objects:
if obj not in compiled:
continue
if include_link_static_in_lto_indexing:
backend_user_compile_flags = _backend_user_compile_flags(cpp_config, obj, lib_lto_compilation_context)
lto_outputs.append(cc_common_internal.create_lto_backend_artifacts(
actions = actions,
lto_output_root_prefix = lto_output_root_prefix,
lto_obj_root_prefix = lto_obj_root_prefix,
bitcode_file = obj,
all_bitcode_files = all_bitcode_depset,
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
fdo_context = cc_toolchain._fdo_context, #TODO: remove
use_pic = use_pic,
should_create_per_object_debug_info = debug,
argv = backend_user_compile_flags,
))
else:
if not shared_lto_backends:
fail(("Statically linked test target requires non-LTO backends for its library inputs," +
" but library input %s does not specify shared_non_lto_backends") % lib)
lto_outputs.append(shared_lto_backends[obj])
for obj in object_file_inputs:
if obj not in lto_compilation_context.lto_bitcode_inputs():
continue
backend_user_compile_flags = _backend_user_compile_flags(cpp_config, obj, lto_compilation_context)
lto_outputs.append(cc_common_internal.create_lto_backend_artifacts(
actions = actions,
lto_output_root_prefix = lto_output_root_prefix,
lto_obj_root_prefix = lto_obj_root_prefix,
bitcode_file = obj,
all_bitcode_files = all_bitcode_depset if allow_lto_indexing else None,
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
fdo_context = cc_toolchain._fdo_context, #TODO: remove
use_pic = use_pic,
should_create_per_object_debug_info = debug,
create_shared_non_lto = not allow_lto_indexing,
argv = backend_user_compile_flags,
))
return lto_outputs
def _backend_user_compile_flags(cpp_config, obj, context):
argv = []
lto_bitcode_files = context.lto_bitcode_inputs()
if obj in lto_bitcode_files:
argv.extend(lto_bitcode_files[obj].copts)
argv.extend(cpp_config.lto_backend_options)
argv.extend(cc_internal.collect_per_file_lto_backend_opts(cpp_config, obj))
return argv
def create_shared_non_lto_artifacts(
actions,
lto_compilation_context,
is_linker,
feature_configuration,
cc_toolchain,
use_pic,
object_file_inputs):
# Only create the shared LTO artifacts for a statically linked library that has bitcode files.
if not lto_compilation_context or is_linker:
return {}
lto_output_root_prefix = "shared.nonlto"
if feature_configuration.is_enabled("use_lto_native_object_directory"):
lto_obj_root_prefix = "shared.nonlto-obj"
else:
lto_obj_root_prefix = "shared.nonlto"
cpp_config = cc_toolchain._cpp_configuration
debug = should_create_per_object_debug_info(feature_configuration, cpp_config)
shared_non_lto_backends = {}
for obj in object_file_inputs:
if obj not in lto_compilation_context.lto_bitcode_inputs():
continue
backend_user_compile_flags = _backend_user_compile_flags(cpp_config, obj, lto_compilation_context)
shared_non_lto_backends[obj] = cc_common_internal.create_lto_backend_artifacts(
actions = actions,
lto_output_root_prefix = lto_output_root_prefix,
lto_obj_root_prefix = lto_obj_root_prefix,
bitcode_file = obj,
all_bitcode_files = None,
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
fdo_context = cc_toolchain._fdo_context, #TODO: remove
use_pic = use_pic,
should_create_per_object_debug_info = debug,
create_shared_non_lto = True,
argv = backend_user_compile_flags,
)
return shared_non_lto_backends