blob: ef12daed6e5380d78a6dae4ccbe95e861903749a [file] [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.
"""
A module to create C/C++ link actions in a consistent way.
"""
load("@bazel_skylib//lib:paths.bzl", "paths")
load(
"//cc/common:cc_helper_internal.bzl",
"root_relative_path",
"wrap_with_check_private_api",
_use_pic_for_binaries = "use_pic_for_binaries",
_use_pic_for_dynamic_libs = "use_pic_for_dynamic_libs",
artifact_category = "artifact_category_names",
)
load("//cc/private:cc_internal.bzl", _cc_internal = "cc_internal")
load("//cc/private/compile:cc_compilation_outputs.bzl", "EMPTY_COMPILATION_OUTPUTS")
load("//cc/private/link:cpp_link_action.bzl", "link_action")
load("//cc/private/link:create_library_to_link.bzl", "make_library_to_link")
load(
"//cc/private/link:dynamic_library_symlink.bzl",
"dynamic_library_soname",
"dynamic_library_symlink",
)
load("//cc/private/link:lto_indexing_action.bzl", "create_lto_artifacts_and_lto_indexing_action")
load("//cc/private/link:target_types.bzl", "LINKING_MODE", "LINK_TARGET_TYPE", "USE_ARCHIVER", "is_dynamic_library")
# TODO(b/331164666): remove alwayslink
# This is only set here for naming always to link static libraries with the *.lo
# extension. This is no longer needed because `LibraryToLink`s already carry
# information about whether a library should always be linked or not. This will be
# removed when we no longer use *.lo for always to link static libraries in native
# cc_library.
# TODO(b/338618120): Split the code into direct and transitive linking parts,
# this can be done after removing Objc archives from cc_common.link.
def create_cc_link_actions(
actions,
name,
static_link_type,
dynamic_link_type,
linking_mode,
feature_configuration,
cc_toolchain,
compilation_outputs,
linking_contexts = [],
linkopts = [],
stamp = 0,
additional_linker_inputs = [], # TODO(b/331164666): rename to linker_inputs
linker_outputs = [],
variables_extension = {},
# Originating from private APIs:
use_test_only_flags = False,
neverlink = False,
test_only_target = False,
whole_archive = False,
native_deps = False,
additional_linkstamp_defines = [],
alwayslink = False,
linker_output_artifact = None, # TODO(b/331164666): rename to main_output
emit_interface_shared_libraries = True,
linked_dll_name_suffix = ""):
"""Constructs the C++ linker actions.
It generally generates two actions, one for a static library
and one for a dynamic library. If PIC is required for shared libraries, but not for binaries,
it additionally creates a third action to generate a PIC static library. If PIC is required for
shared libraries and binaries, then only PIC actions are registered.
For dynamic libraries, this method can additionally create an interface shared library that
can be used for linking, but doesn't contain any executable code. This increases the number of
cache hits for link actions. Call with `emit_interface_shared_libraries` to enable this
behavior.
Args:
actions: (Actions) `actions` object.
name: (str) This is used for naming the output artifacts of actions created by this method.
static_link_type: (None|LINK_TARGET_TYPE) Type of static libraries to create.
dynamic_link_type: (None|LINK_TARGET_TYPE) Type of dynamic libraries to create.
linking_mode: (LINKING_MODE) Linking mode used for dynamic libraries.
feature_configuration: (FeatureConfiguration) `feature_configuration` to be queried.
cc_toolchain: (CcToolchainInfo) CcToolchainInfo provider to be used.
compilation_outputs: (CompilationOutputs) Compilation outputs containing object files to link.
linking_contexts: (list[LinkingContext]) Linking contexts from dependencies to be linked
into the linking context generated by this rule.
linkopts: (list[str]) Additional list of linker options.
stamp: (-1|0|1): Whether to include build information in the linked executable, if output_type is
'executable'. If 1, build information is always included. If 0 (the
default build information is always excluded. If -1, uses the default
behavior, which may be overridden by the --[no]stamp flag. This should be
unset (or set to 0) when generating the executable output for test rules.
additional_linker_inputs: (list[File]|depset[File]) For additional inputs to the linking action,
e.g.: linking scripts.
linker_outputs: (list[File]) For additional outputs to the linking action, e.g.: map files.
variables_extension: (dict[str, str|list[str]|depset[str]]) Additional variables to pass to
the toolchain configuration when creating link command line.
use_test_only_flags: (bool) undocumented.
neverlink: (bool) Marks the resulting code as neverlink, i.e., the code will not be linked into dependent
libraries or binaries - the header files are still available.
test_only_target: (bool) undocumented.
native_deps: (bool) undocumented.
whole_archive: (bool) undocumented.
additional_linkstamp_defines: (list[str]) undocumented.
alwayslink: (bool) undocumented.
linker_output_artifact: (None|File) Name of the main output artifact that will be produced by the linker.
Only set this if the default name generation does not match you needs
For output_type=executable, this is the final executable filename.
For output_type=dynamic_library, this is the shared library filename.
If not specified, then one will be computed based on `name` and `output_type`.
emit_interface_shared_libraries: (bool)
Enables the optional generation of interface dynamic libraries - this is only used when the
linker generates a dynamic library, and only if the crosstool supports it.
linked_dll_name_suffix: (str)
Adds a suffix (_{hash}) for path of linked DLL. This will be enabled only when rename_dll is
enabled and the linked artifact's LinkTargetType is NODEPS_DYNAMIC_LIBRARY
(i.e DLL generated by cc_library). We have to add the suffix to make sure the CppLinkAction
link against the renamed DLL. If not, CppLinkAction will link against the DLL whose name is the
same as the name of cc_library.
Returns:
(CcLinkingOutputs = {
library_to_link: LibraryToLink,
all_lto_artifacts: list[LtoBackendArtifacts],
executable: None|File
})
"""
# Create link actions (only if there are object files or if explicitly requested).
#
# On some systems, the linker gives an error message if there are no input files.
# This can still happen if there is a .nopic.o or .o files in srcs, but no
# other files. To fix that, we'd have to check for each link action individually.
#
# An additional pre-existing issue is that the header check tokens are dropped if we don't
# generate any link actions, effectively disabling header checking in some cases.
if stamp not in [-1, 0, 1]:
fail("stamp value %d is not supported, must be 0 (disabled), 1 (enabled), or -1 (default)" % stamp)
stamping = False if cc_toolchain._is_tool_configuration else (stamp == 1 or (stamp == -1 and cc_toolchain._stamp_binaries))
if not compilation_outputs:
compilation_outputs = EMPTY_COMPILATION_OUTPUTS
linkopts = list(linkopts)
cpp_config = cc_toolchain._cpp_configuration
use_pic_for_binaries = _use_pic_for_binaries(cpp_config, feature_configuration)
use_pic_for_dynamic_libs = _use_pic_for_dynamic_libs(cpp_config, feature_configuration)
link_action_kwargs = dict(
actions = actions,
stamping = stamping,
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
compilation_outputs = compilation_outputs,
# Inputs from linking_contexts and toolchain:
linkopts = [],
non_code_inputs = [],
# Custom user input/output files and variables:
additional_linker_inputs = additional_linker_inputs,
link_action_outputs = linker_outputs,
variables_extensions = variables_extension,
# Originating from private APIs:
use_test_only_flags = use_test_only_flags,
whole_archive = whole_archive,
native_deps = native_deps,
additional_linkstamp_defines = additional_linkstamp_defines,
)
static_library = {}
if static_link_type:
static_library = _create_no_pic_and_pic_static_libs_actions(
actions,
name,
static_link_type,
cc_toolchain,
use_pic_for_binaries,
use_pic_for_dynamic_libs,
link_action_kwargs,
)
dynamic_library = {}
all_lto_artifacts = []
if dynamic_link_type:
if dynamic_link_type.executable:
use_pic = use_pic_for_binaries
else:
use_pic = use_pic_for_dynamic_libs
# TODO(bazel-team): There is no practical difference in non-code inputs and additional linker
# inputs in CppLinkActionBuilder. So these should be merged. Even before that happens, it's
# totally fine for nonCodeLinkerInputs to contains precompiled libraries.
link_action_kwargs["non_code_inputs"] = list(compilation_outputs._header_tokens)
# linkopts attribute is only passed when creating .so files
link_action_kwargs["linkopts"] = linkopts
dynamic_library, all_lto_artifacts, linker_output_artifact = \
_create_dynamic_link_actions(
actions,
name,
dynamic_link_type,
linking_mode,
use_pic,
feature_configuration,
cc_toolchain,
linking_contexts,
linker_output_artifact,
neverlink,
test_only_target,
emit_interface_shared_libraries,
linked_dll_name_suffix,
link_action_kwargs,
)
if static_link_type == LINK_TARGET_TYPE.ALWAYS_LINK_STATIC_LIBRARY and \
feature_configuration.is_enabled("disable_whole_archive_for_static_lib"):
fail("Attribute alwayslink: alwayslink should not be True for a target" +
" with the disable_whole_archive_for_static_lib feature enabled.")
library_to_link = None
if dynamic_library | static_library:
library_to_link = make_library_to_link(
**(dynamic_library | static_library |
dict(
_disable_whole_archive =
feature_configuration.is_enabled("disable_whole_archive_for_static_lib"),
alwayslink = alwayslink,
_contains_objects = True,
))
)
return struct(
library_to_link = library_to_link,
all_lto_artifacts = wrap_with_check_private_api(all_lto_artifacts),
executable = linker_output_artifact if dynamic_link_type and dynamic_link_type.executable else None,
)
def _create_dynamic_link_actions(
actions,
name,
dynamic_link_type,
linking_mode,
use_pic,
feature_configuration,
cc_toolchain,
linking_contexts,
linker_output_artifact,
neverlink,
test_only_target,
emit_interface_shared_libraries,
linked_dll_name_suffix,
link_action_kwargs):
"""Creates dynamic library."""
if linker_output_artifact:
# This branch is only used for vestigial Google-internal rules where the name of the output
# file is explicitly specified in the BUILD file and as such, is platform-dependent. Thus,
# we just hardcode some reasonable logic to compute the library identifier and hope that this
# will eventually go away.
linker_output = linker_output_artifact
main_library_identifier = paths.replace_extension(linker_output_artifact.path, "")
else:
# If the crosstool is configured to select an output artifact, we use that selection.
# Otherwise, we use linux defaults.
linker_output, main_library_identifier = _get_linked_artifact(
actions,
name,
dynamic_link_type,
cc_toolchain,
linked_dll_name_suffix,
)
so_interface = None
# Should interface shared objects should be used in the build implied by the given
# cpp_config and toolchain.
emit_interface_shared_libraries = emit_interface_shared_libraries and (
feature_configuration.is_enabled("supports_interface_shared_libraries") and
cc_toolchain._cpp_configuration.interface_shared_objects()
)
if emit_interface_shared_libraries:
so_interface, _ = _get_linked_artifact(actions, name, LINK_TARGET_TYPE.INTERFACE_DYNAMIC_LIBRARY, cc_toolchain)
# TODO(b/28946988): Remove this hard-coded flag.
if not feature_configuration.is_enabled("targets_windows") and not feature_configuration.is_enabled("set_soname"):
link_action_kwargs["linkopts"].append("-Wl,-soname=" + dynamic_library_soname(
actions,
# Must match https://github.com/bazelbuild/bazel/blob/795af54db5c348af5ca8b2961a982b399206ea20/src/main/java/com/google/devtools/build/lib/rules/cpp/SolibSymlinkAction.java#L169.
root_relative_path(linker_output),
dynamic_link_type != LINK_TARGET_TYPE.NODEPS_DYNAMIC_LIBRARY,
))
mnemonic = "ObjcLink" if dynamic_link_type == LINK_TARGET_TYPE.OBJC_EXECUTABLE else None
if linking_mode == LINKING_MODE.DYNAMIC:
toolchain_libraries = [make_library_to_link(
_library_identifier = lib.path,
dynamic_library = lib,
_disable_whole_archive = True,
) for lib in cc_toolchain.dynamic_runtime_lib(feature_configuration = feature_configuration).to_list()]
else:
toolchain_libraries = [make_library_to_link(
_library_identifier = lib.path,
static_library = lib,
# Adding toolchain libraries without whole archive no-matter-what. People don't want to
# include whole libstdc++ in their binary ever.
_disable_whole_archive = True,
) for lib in cc_toolchain.static_runtime_lib(feature_configuration = feature_configuration).to_list()]
libraries_to_link, linkstamps, linkopts, non_code_inputs = \
_maybe_link_transitively(feature_configuration, dynamic_link_type, linking_mode, linking_contexts)
libraries_to_link.extend(toolchain_libraries)
if linkopts:
link_action_kwargs["linkopts"].extend(linkopts)
if non_code_inputs:
link_action_kwargs["non_code_inputs"].extend(non_code_inputs)
all_lto_artifacts, allow_lto_indexing, thinlto_param_file, additional_object_files = \
_maybe_do_lto_indexing(
link_type = dynamic_link_type,
linking_mode = linking_mode,
use_pic = use_pic,
libraries_to_link = libraries_to_link,
output = linker_output,
test_only_target = test_only_target,
**link_action_kwargs
)
impl_library_link_artifact = None
if dynamic_link_type == LINK_TARGET_TYPE.DYNAMIC_LIBRARY and not neverlink and \
not feature_configuration.is_enabled("copy_dynamic_libraries_to_binary"):
impl_library_link_artifact = dynamic_library_symlink(
actions,
linker_output,
cc_toolchain._solib_dir,
True,
False,
)
dynamic_library, interface_library = link_action(
mnemonic = mnemonic,
library_identifier = main_library_identifier if not dynamic_link_type.executable else None,
link_type = dynamic_link_type,
linking_mode = linking_mode,
use_pic = use_pic,
# Inputs from compilation
additional_object_files = additional_object_files,
# Inputs from linking_contexts:
libraries_to_link = libraries_to_link,
linkstamps = linkstamps,
# Output files:
output = linker_output,
interface_output = so_interface,
dynamic_library_solib_symlink_output = impl_library_link_artifact,
# LTO:
all_lto_artifacts = all_lto_artifacts,
thinlto_param_file = thinlto_param_file,
allow_lto_indexing = allow_lto_indexing,
**link_action_kwargs
)
library_to_link = _construct_dynamic_library_to_link(
actions,
dynamic_link_type,
interface_library,
dynamic_library,
impl_library_link_artifact,
neverlink,
feature_configuration,
cc_toolchain,
)
return library_to_link, all_lto_artifacts, linker_output
# buildifier: disable=unused-variable
def _maybe_link_transitively(feature_configuration, dynamic_link_type, linking_mode, linking_contexts):
# This is where transitive linking happens. If it doesn't we pass empty libraries to link_action.
# On Windows, we cannot build a shared library with symbols unresolved, so here we
# dynamically link to all its dependencies, even for LINK_TARGET_TYPE.NODEPS_DYNAMIC_LIBRARY.
should_link_transitively = (feature_configuration.is_enabled("targets_windows") or
dynamic_link_type != LINK_TARGET_TYPE.NODEPS_DYNAMIC_LIBRARY)
if not should_link_transitively:
return [], [], [], [] # libraries_to_link, linkstamps, linkopts, non_code_inputs
linker_inputs = depset(
transitive = [linking_context.linker_inputs for linking_context in linking_contexts],
order = "topological",
).to_list()
if dynamic_link_type != LINK_TARGET_TYPE.NODEPS_DYNAMIC_LIBRARY:
linkstamps = [stamp for linker_input in linker_inputs for stamp in linker_input.linkstamps]
else:
linkstamps = []
linkopts = [flag for linker_input in linker_inputs for flag in linker_input.user_link_flags]
non_code_inputs = \
[input for linker_input in linker_inputs for input in linker_input.additional_inputs]
# This ordering of LinkerInputs and Librar(-ies)ToLink is really sensitive, changes result in
# subtle breakages.
libraries_to_link = depset(
[lib for linker_input in linker_inputs for lib in linker_input.libraries],
order = "topological",
).to_list()
return libraries_to_link, linkstamps, linkopts, non_code_inputs
def _maybe_do_lto_indexing(*, link_type, linking_mode, compilation_outputs, libraries_to_link, feature_configuration, **link_action_kwargs):
all_lto_artifacts = []
thinlto_param_file = None
additional_object_files = []
allow_lto_indexing = False
if not feature_configuration.is_enabled("thin_lto"):
return all_lto_artifacts, allow_lto_indexing, thinlto_param_file, additional_object_files
lto_compilation_context = compilation_outputs._lto_compilation_context
has_lto_bitcode_inputs = lto_compilation_context.lto_bitcode_inputs
# TODO(b/338618120): deduplicate prefer_static_lib, prefer_pic_libs computed in finalize_link_action as well
prefer_static_libs = linking_mode == LINKING_MODE.STATIC or \
not feature_configuration.is_enabled("supports_dynamic_linker")
prefer_pic_libs = is_dynamic_library(link_type)
static_libraries_to_link = []
for lib in libraries_to_link:
if prefer_static_libs:
if lib.static_library != None or lib.pic_static_library != None:
static_libraries_to_link.append(lib)
elif lib.interface_library == None and lib.dynamic_library == None:
static_libraries_to_link.append(lib)
if not has_lto_bitcode_inputs:
for lib in static_libraries_to_link:
pic = (prefer_pic_libs and lib.pic_static_library != None) or lib.static_library == None
context = lib._pic_lto_compilation_context if pic else lib._lto_compilation_context
if context and context.lto_bitcode_inputs:
has_lto_bitcode_inputs = True
break
if has_lto_bitcode_inputs:
if not feature_configuration.is_enabled("supports_start_end_lib"):
fail("When using LTO. The feature supports_start_end_lib must be enabled.")
all_lto_artifacts, allow_lto_indexing, thinlto_param_file, thinlto_merged_object_file = \
create_lto_artifacts_and_lto_indexing_action(
link_type = link_type,
linking_mode = linking_mode,
compilation_outputs = compilation_outputs,
libraries_to_link = libraries_to_link,
static_libraries_to_link = static_libraries_to_link,
prefer_pic_libs = prefer_pic_libs,
feature_configuration = feature_configuration,
lto_compilation_context = lto_compilation_context,
**link_action_kwargs
)
if thinlto_merged_object_file:
additional_object_files = [thinlto_merged_object_file]
return all_lto_artifacts, allow_lto_indexing, thinlto_param_file, additional_object_files
def _construct_dynamic_library_to_link(
actions,
dynamic_link_type,
interface_library,
dynamic_library,
impl_library_link_artifact,
neverlink,
feature_configuration,
cc_toolchain):
library_to_link = {}
if dynamic_library:
library_to_link = dict(_library_identifier = dynamic_library.library_identifier)
if neverlink or feature_configuration.is_enabled("copy_dynamic_libraries_to_binary"):
if interface_library:
library_to_link["interface_library"] = interface_library.file
library_to_link["dynamic_library"] = dynamic_library.file
else:
if dynamic_link_type == LINK_TARGET_TYPE.NODEPS_DYNAMIC_LIBRARY:
impl_library_link_artifact = dynamic_library_symlink(
actions,
dynamic_library.file,
cc_toolchain._solib_dir,
False,
False,
)
library_to_link["dynamic_library"] = impl_library_link_artifact
library_to_link["resolved_symlink_dynamic_library"] = dynamic_library.file
if interface_library:
library_link_artifact = dynamic_library_symlink(
actions,
interface_library.file,
cc_toolchain._solib_dir,
dynamic_link_type != LINK_TARGET_TYPE.NODEPS_DYNAMIC_LIBRARY,
False,
)
library_to_link["interface_library"] = library_link_artifact
library_to_link["resolved_symlink_interface_library"] = interface_library.file
return library_to_link
# TODO(b/338618120): There's a second get_linked_artifact in cc_helper. Simplify this one and converge the two.
def _get_linked_artifact(actions, name, link_target_type, cc_toolchain, linked_dll_name_suffix = ""):
maybe_pic_name = name
if link_target_type.is_pic:
maybe_pic_name = _cc_internal.get_artifact_name_for_category(
cc_toolchain = cc_toolchain,
category = artifact_category.PIC_FILE,
output_name = maybe_pic_name,
)
linked_name = maybe_pic_name
if link_target_type == LINK_TARGET_TYPE.NODEPS_DYNAMIC_LIBRARY:
linked_name += linked_dll_name_suffix
linked_name = _cc_internal.get_artifact_name_for_category(
cc_toolchain = cc_toolchain,
category = link_target_type.linker_output,
output_name = linked_name,
)
if link_target_type == LINK_TARGET_TYPE.OBJC_FULLY_LINKED_ARCHIVE:
# TODO(blaze-team): This unfortunate editing of the name is here because Objective-C rules
# were creating this type of archive without the lib prefix, unlike what the objective-c
# toolchain says with getArtifactNameForCategory.
# This can be fixed either when implicit outputs are removed from objc_library by keeping the
# lib prefix, or by editing the toolchain not to add it.
if linked_name.startswith("lib"):
linked_name = linked_name[3:] # TODO handle subdirectories
# TODO(b/331164666): create a fail action if the name doesn't match linux default name
# see getLinuxLinkedArtifact
file = actions.declare_file(linked_name)
return file, file.short_path[:-len(linked_name)] + "lib" + name
def _create_no_pic_and_pic_static_libs_actions(
actions,
name,
static_link_type,
cc_toolchain,
use_pic_for_binaries,
use_pic_for_dynamic_libs,
link_action_kwargs):
# Create static library (.a). The staticLinkType only reflects whether the library is
# alwayslink or not. The PIC-ness is determined by whether we need to use PIC or not. There
# are four cases:
# for (usePicForDynamicLibs usePicForBinaries):
#
# (1) (false false) -> no pic code is when toolchain and cppOptions don't need pic code for
# dynamic libraries or binaries
# (2) (true false) -> shared libraries as pic, but not binaries
# (3) (true true) -> both shared libraries and binaries as pic
# (4) (false true) -> only pic files generated when toolchain needs pic for shared libraries
# and {@link #willOnlyBeLinkedIntoDynamicLibraries} is set to true.
# In case (3), we always need PIC, so only create one static library containing the PIC
# object files. The name therefore does not match the content.
#
# Presumably, it is done this way because the .a file is an implicit output of every
# cc_library rule, so we can't use ".pic.a" that in the always-PIC case.
# If the crosstool is configured to select an output artifact, we use that selection.
# Otherwise, we use linux defaults.
if static_link_type.linker_or_archiver != USE_ARCHIVER:
fail("Only archiving of static libraries is supported, not linking.")
create_no_pic_action = not use_pic_for_binaries
create_pic_action = use_pic_for_binaries or use_pic_for_dynamic_libs
no_pic_library_to_link = {}
if create_no_pic_action:
# Linker_inputs.Library_to_link
no_pic_library_to_link = _create_action_for_static_library(
actions,
name,
static_link_type,
False, # use_pic
cc_toolchain,
link_action_kwargs,
)
pic_library_to_link = {}
if create_pic_action:
if not create_no_pic_action:
# Only PIC library created, name does not match content.
link_target_type_used_for_naming = static_link_type
elif static_link_type == LINK_TARGET_TYPE.ALWAYS_LINK_STATIC_LIBRARY:
link_target_type_used_for_naming = LINK_TARGET_TYPE.ALWAYS_LINK_PIC_STATIC_LIBRARY
else:
link_target_type_used_for_naming = LINK_TARGET_TYPE.PIC_STATIC_LIBRARY
pic_library_to_link = _create_action_for_static_library(
actions,
name,
link_target_type_used_for_naming,
True, # use_pic
cc_toolchain,
link_action_kwargs,
)
return no_pic_library_to_link | pic_library_to_link
def _create_action_for_static_library(
actions,
name,
link_target_type_used_for_naming,
use_pic,
cc_toolchain,
link_action_kwargs):
linked_artifact, library_identifier = _get_linked_artifact(actions, name, link_target_type_used_for_naming, cc_toolchain)
output_library, _ = link_action(
mnemonic = "CppArchive",
library_identifier = library_identifier,
link_type = link_target_type_used_for_naming,
linking_mode = LINKING_MODE.STATIC,
use_pic = use_pic,
# Inputs from linking contexts:
linkstamps = [],
libraries_to_link = [],
# Output files:
output = linked_artifact, # output
interface_output = None,
dynamic_library_solib_symlink_output = None,
# LTO:
all_lto_artifacts = [],
thinlto_param_file = None,
allow_lto_indexing = False,
**link_action_kwargs
)
if not use_pic:
return dict(
_library_identifier = library_identifier,
static_library = output_library.file,
objects = output_library.object_files,
_lto_compilation_context = output_library.lto_compilation_context,
_shared_non_lto_backends = output_library.shared_non_lto_backends,
alwayslink = output_library.artifact_category == artifact_category.ALWAYSLINK_STATIC_LIBRARY,
)
else:
return dict(
_library_identifier = library_identifier,
pic_static_library = output_library.file,
pic_objects = output_library.object_files,
_pic_lto_compilation_context = output_library.lto_compilation_context,
_pic_shared_non_lto_backends = output_library.shared_non_lto_backends,
alwayslink = output_library.artifact_category == artifact_category.ALWAYSLINK_STATIC_LIBRARY,
)