xref: /aosp_15_r20/external/bazelbuild-rules_android/rules/native_deps.bzl (revision 9e965d6fece27a77de5377433c2f7e6999b8cc0b)
1*9e965d6fSRomain Jobredeaux# Copyright 2022 The Bazel Authors. All rights reserved.
2*9e965d6fSRomain Jobredeaux#
3*9e965d6fSRomain Jobredeaux# Licensed under the Apache License, Version 2.0 (the "License");
4*9e965d6fSRomain Jobredeaux# you may not use this file except in compliance with the License.
5*9e965d6fSRomain Jobredeaux# You may obtain a copy of the License at
6*9e965d6fSRomain Jobredeaux#
7*9e965d6fSRomain Jobredeaux#    http://www.apache.org/licenses/LICENSE-2.0
8*9e965d6fSRomain Jobredeaux#
9*9e965d6fSRomain Jobredeaux# Unless required by applicable law or agreed to in writing, software
10*9e965d6fSRomain Jobredeaux# distributed under the License is distributed on an "AS IS" BASIS,
11*9e965d6fSRomain Jobredeaux# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9e965d6fSRomain Jobredeaux# See the License for the specific language governing permissions and
13*9e965d6fSRomain Jobredeaux# limitations under the License.
14*9e965d6fSRomain Jobredeaux
15*9e965d6fSRomain Jobredeaux"""
16*9e965d6fSRomain JobredeauxDefines the native libs processing and an aspect to collect build configuration
17*9e965d6fSRomain Jobredeauxof split deps
18*9e965d6fSRomain Jobredeaux"""
19*9e965d6fSRomain Jobredeaux
20*9e965d6fSRomain Jobredeauxload("//rules:common.bzl", "common")
21*9e965d6fSRomain Jobredeaux
22*9e965d6fSRomain JobredeauxSplitConfigInfo = provider(
23*9e965d6fSRomain Jobredeaux    doc = "Provides information about configuration for a split config dep",
24*9e965d6fSRomain Jobredeaux    fields = dict(
25*9e965d6fSRomain Jobredeaux        build_config = "The build configuration of the dep.",
26*9e965d6fSRomain Jobredeaux        android_config = "Select fields from the android configuration of the dep.",
27*9e965d6fSRomain Jobredeaux        target_platform = "The target platform label of the dep.",
28*9e965d6fSRomain Jobredeaux    ),
29*9e965d6fSRomain Jobredeaux)
30*9e965d6fSRomain Jobredeaux
31*9e965d6fSRomain Jobredeauxdef _split_config_aspect_impl(__, ctx):
32*9e965d6fSRomain Jobredeaux    android_cfg = ctx.fragments.android
33*9e965d6fSRomain Jobredeaux    return SplitConfigInfo(
34*9e965d6fSRomain Jobredeaux        build_config = ctx.configuration,
35*9e965d6fSRomain Jobredeaux        android_config = struct(
36*9e965d6fSRomain Jobredeaux            incompatible_use_toolchain_resolution = android_cfg.incompatible_use_toolchain_resolution,
37*9e965d6fSRomain Jobredeaux            android_cpu = android_cfg.android_cpu,
38*9e965d6fSRomain Jobredeaux            hwasan = android_cfg.hwasan,
39*9e965d6fSRomain Jobredeaux        ),
40*9e965d6fSRomain Jobredeaux        target_platform = ctx.fragments.platform.platform,
41*9e965d6fSRomain Jobredeaux    )
42*9e965d6fSRomain Jobredeaux
43*9e965d6fSRomain Jobredeauxsplit_config_aspect = aspect(
44*9e965d6fSRomain Jobredeaux    implementation = _split_config_aspect_impl,
45*9e965d6fSRomain Jobredeaux    fragments = ["android"],
46*9e965d6fSRomain Jobredeaux)
47*9e965d6fSRomain Jobredeaux
48*9e965d6fSRomain Jobredeauxdef _get_libs_dir_name(android_config, target_platform):
49*9e965d6fSRomain Jobredeaux    if android_config.incompatible_use_toolchain_resolution:
50*9e965d6fSRomain Jobredeaux        name = target_platform.name
51*9e965d6fSRomain Jobredeaux    else:
52*9e965d6fSRomain Jobredeaux        # Legacy builds use the CPU as the name.
53*9e965d6fSRomain Jobredeaux        name = android_config.android_cpu
54*9e965d6fSRomain Jobredeaux    if android_config.hwasan:
55*9e965d6fSRomain Jobredeaux        name = name + "-hwasan"
56*9e965d6fSRomain Jobredeaux    return name
57*9e965d6fSRomain Jobredeaux
58*9e965d6fSRomain Jobredeauxdef process(ctx, filename, merged_native_libs = {}):
59*9e965d6fSRomain Jobredeaux    """ Links native deps into a shared library
60*9e965d6fSRomain Jobredeaux
61*9e965d6fSRomain Jobredeaux    Args:
62*9e965d6fSRomain Jobredeaux      ctx: The context.
63*9e965d6fSRomain Jobredeaux      filename: String. The name of the artifact containing the name of the
64*9e965d6fSRomain Jobredeaux            linked shared library
65*9e965d6fSRomain Jobredeaux      merged_native_libs: A dict that maps cpu to merged native libraries. This maps to empty
66*9e965d6fSRomain Jobredeaux            lists if native library merging is not enabled.
67*9e965d6fSRomain Jobredeaux
68*9e965d6fSRomain Jobredeaux    Returns:
69*9e965d6fSRomain Jobredeaux        Tuple of (libs, libs_name) where libs is a depset of all native deps
70*9e965d6fSRomain Jobredeaux        and libs_name is a File containing the basename of the linked shared
71*9e965d6fSRomain Jobredeaux        library
72*9e965d6fSRomain Jobredeaux    """
73*9e965d6fSRomain Jobredeaux    actual_target_name = ctx.label.name.removesuffix(common.PACKAGED_RESOURCES_SUFFIX)
74*9e965d6fSRomain Jobredeaux    native_libs_basename = None
75*9e965d6fSRomain Jobredeaux    libs_name = None
76*9e965d6fSRomain Jobredeaux    libs = dict()
77*9e965d6fSRomain Jobredeaux    for key, deps in ctx.split_attr.deps.items():
78*9e965d6fSRomain Jobredeaux        cc_toolchain_dep = ctx.split_attr._cc_toolchain_split[key]
79*9e965d6fSRomain Jobredeaux        cc_toolchain = cc_toolchain_dep[cc_common.CcToolchainInfo]
80*9e965d6fSRomain Jobredeaux        build_config = cc_toolchain_dep[SplitConfigInfo].build_config
81*9e965d6fSRomain Jobredeaux        libs_dir_name = _get_libs_dir_name(
82*9e965d6fSRomain Jobredeaux            cc_toolchain_dep[SplitConfigInfo].android_config,
83*9e965d6fSRomain Jobredeaux            cc_toolchain_dep[SplitConfigInfo].target_platform,
84*9e965d6fSRomain Jobredeaux        )
85*9e965d6fSRomain Jobredeaux        linker_input = cc_common.create_linker_input(
86*9e965d6fSRomain Jobredeaux            owner = ctx.label,
87*9e965d6fSRomain Jobredeaux            user_link_flags = ["-Wl,-soname=lib" + actual_target_name],
88*9e965d6fSRomain Jobredeaux        )
89*9e965d6fSRomain Jobredeaux        cc_info = cc_common.merge_cc_infos(
90*9e965d6fSRomain Jobredeaux            cc_infos = _concat(
91*9e965d6fSRomain Jobredeaux                [CcInfo(linking_context = cc_common.create_linking_context(
92*9e965d6fSRomain Jobredeaux                    linker_inputs = depset([linker_input]),
93*9e965d6fSRomain Jobredeaux                ))],
94*9e965d6fSRomain Jobredeaux                [dep[JavaInfo].cc_link_params_info for dep in deps if JavaInfo in dep],
95*9e965d6fSRomain Jobredeaux                [dep[AndroidCcLinkParamsInfo].link_params for dep in deps if AndroidCcLinkParamsInfo in dep],
96*9e965d6fSRomain Jobredeaux                [dep[CcInfo] for dep in deps if CcInfo in dep],
97*9e965d6fSRomain Jobredeaux            ),
98*9e965d6fSRomain Jobredeaux        )
99*9e965d6fSRomain Jobredeaux        libraries = []
100*9e965d6fSRomain Jobredeaux        if merged_native_libs:
101*9e965d6fSRomain Jobredeaux            libraries.extend(merged_native_libs[key])
102*9e965d6fSRomain Jobredeaux
103*9e965d6fSRomain Jobredeaux        native_deps_lib = _link_native_deps_if_present(ctx, cc_info, cc_toolchain, build_config, actual_target_name)
104*9e965d6fSRomain Jobredeaux        if native_deps_lib:
105*9e965d6fSRomain Jobredeaux            libraries.append(native_deps_lib)
106*9e965d6fSRomain Jobredeaux            native_libs_basename = native_deps_lib.basename
107*9e965d6fSRomain Jobredeaux
108*9e965d6fSRomain Jobredeaux        libraries.extend(_filter_unique_shared_libs(libraries, cc_info))
109*9e965d6fSRomain Jobredeaux
110*9e965d6fSRomain Jobredeaux        if libraries:
111*9e965d6fSRomain Jobredeaux            libs[libs_dir_name] = depset(libraries)
112*9e965d6fSRomain Jobredeaux
113*9e965d6fSRomain Jobredeaux    if libs and native_libs_basename:
114*9e965d6fSRomain Jobredeaux        libs_name = ctx.actions.declare_file("nativedeps_filename/" + actual_target_name + "/" + filename)
115*9e965d6fSRomain Jobredeaux        ctx.actions.write(output = libs_name, content = native_libs_basename)
116*9e965d6fSRomain Jobredeaux
117*9e965d6fSRomain Jobredeaux    transitive_native_libs = _get_transitive_native_libs(ctx)
118*9e965d6fSRomain Jobredeaux    return AndroidBinaryNativeLibsInfo(libs, libs_name, transitive_native_libs)
119*9e965d6fSRomain Jobredeaux
120*9e965d6fSRomain Jobredeaux# Collect all native shared libraries across split transitions. Some AARs
121*9e965d6fSRomain Jobredeaux# contain shared libraries across multiple architectures, e.g. x86 and
122*9e965d6fSRomain Jobredeaux# armeabi-v7a, and need to be packed into the APK.
123*9e965d6fSRomain Jobredeauxdef _get_transitive_native_libs(ctx):
124*9e965d6fSRomain Jobredeaux    return depset(
125*9e965d6fSRomain Jobredeaux        transitive = [
126*9e965d6fSRomain Jobredeaux            dep[AndroidNativeLibsInfo].native_libs
127*9e965d6fSRomain Jobredeaux            for deps in ctx.split_attr.deps.values()
128*9e965d6fSRomain Jobredeaux            for dep in deps
129*9e965d6fSRomain Jobredeaux            if AndroidNativeLibsInfo in dep
130*9e965d6fSRomain Jobredeaux        ],
131*9e965d6fSRomain Jobredeaux    )
132*9e965d6fSRomain Jobredeaux
133*9e965d6fSRomain Jobredeauxdef _all_inputs(cc_info):
134*9e965d6fSRomain Jobredeaux    return [
135*9e965d6fSRomain Jobredeaux        lib
136*9e965d6fSRomain Jobredeaux        for input in cc_info.linking_context.linker_inputs.to_list()
137*9e965d6fSRomain Jobredeaux        for lib in input.libraries
138*9e965d6fSRomain Jobredeaux    ]
139*9e965d6fSRomain Jobredeaux
140*9e965d6fSRomain Jobredeauxdef _filter_unique_shared_libs(linked_libs, cc_info):
141*9e965d6fSRomain Jobredeaux    basenames = {}
142*9e965d6fSRomain Jobredeaux    artifacts = {}
143*9e965d6fSRomain Jobredeaux    if linked_libs:
144*9e965d6fSRomain Jobredeaux        basenames = {
145*9e965d6fSRomain Jobredeaux            linked_lib.basename: linked_lib
146*9e965d6fSRomain Jobredeaux            for linked_lib in linked_libs
147*9e965d6fSRomain Jobredeaux        }
148*9e965d6fSRomain Jobredeaux        artifacts = {
149*9e965d6fSRomain Jobredeaux            linked_lib: None
150*9e965d6fSRomain Jobredeaux            for linked_lib in linked_libs
151*9e965d6fSRomain Jobredeaux        }
152*9e965d6fSRomain Jobredeaux    for input in _all_inputs(cc_info):
153*9e965d6fSRomain Jobredeaux        if input.pic_static_library or input.static_library:
154*9e965d6fSRomain Jobredeaux            # This is not a shared library and will not be loaded by Android, so skip it.
155*9e965d6fSRomain Jobredeaux            continue
156*9e965d6fSRomain Jobredeaux
157*9e965d6fSRomain Jobredeaux        artifact = None
158*9e965d6fSRomain Jobredeaux        if input.interface_library:
159*9e965d6fSRomain Jobredeaux            if input.resolved_symlink_interface_library:
160*9e965d6fSRomain Jobredeaux                artifact = input.resolved_symlink_interface_library
161*9e965d6fSRomain Jobredeaux            else:
162*9e965d6fSRomain Jobredeaux                artifact = input.interface_library
163*9e965d6fSRomain Jobredeaux        elif input.resolved_symlink_dynamic_library:
164*9e965d6fSRomain Jobredeaux            artifact = input.resolved_symlink_dynamic_library
165*9e965d6fSRomain Jobredeaux        else:
166*9e965d6fSRomain Jobredeaux            artifact = input.dynamic_library
167*9e965d6fSRomain Jobredeaux
168*9e965d6fSRomain Jobredeaux        if not artifact:
169*9e965d6fSRomain Jobredeaux            fail("Should never happen: did not find artifact for link!")
170*9e965d6fSRomain Jobredeaux
171*9e965d6fSRomain Jobredeaux        if artifact in artifacts:
172*9e965d6fSRomain Jobredeaux            # We have already reached this library, e.g., through a different solib symlink.
173*9e965d6fSRomain Jobredeaux            continue
174*9e965d6fSRomain Jobredeaux        artifacts[artifact] = None
175*9e965d6fSRomain Jobredeaux        basename = artifact.basename
176*9e965d6fSRomain Jobredeaux        if basename in basenames:
177*9e965d6fSRomain Jobredeaux            old_artifact = basenames[basename]
178*9e965d6fSRomain Jobredeaux            fail(
179*9e965d6fSRomain Jobredeaux                "Each library in the transitive closure must have a " +
180*9e965d6fSRomain Jobredeaux                "unique basename to avoid name collisions when packaged into " +
181*9e965d6fSRomain Jobredeaux                "an apk, but two libraries have the basename '" + basename +
182*9e965d6fSRomain Jobredeaux                "': " + str(artifact) + " and " + str(old_artifact) + (
183*9e965d6fSRomain Jobredeaux                    " (the library already seen by this target)" if old_artifact in linked_libs else ""
184*9e965d6fSRomain Jobredeaux                ),
185*9e965d6fSRomain Jobredeaux            )
186*9e965d6fSRomain Jobredeaux        else:
187*9e965d6fSRomain Jobredeaux            basenames[basename] = artifact
188*9e965d6fSRomain Jobredeaux
189*9e965d6fSRomain Jobredeaux    return artifacts.keys()
190*9e965d6fSRomain Jobredeaux
191*9e965d6fSRomain Jobredeauxdef _contains_code_to_link(input):
192*9e965d6fSRomain Jobredeaux    if not input.static_library and not input.pic_static_library:
193*9e965d6fSRomain Jobredeaux        # this is a shared library so we're going to have to copy it
194*9e965d6fSRomain Jobredeaux        return False
195*9e965d6fSRomain Jobredeaux    if input.objects:
196*9e965d6fSRomain Jobredeaux        object_files = input.objects
197*9e965d6fSRomain Jobredeaux    elif input.pic_objects:
198*9e965d6fSRomain Jobredeaux        object_files = input.pic_objects
199*9e965d6fSRomain Jobredeaux    elif _is_any_source_file(input.static_library, input.pic_static_library):
200*9e965d6fSRomain Jobredeaux        # this is an opaque library so we're going to have to link it
201*9e965d6fSRomain Jobredeaux        return True
202*9e965d6fSRomain Jobredeaux    else:
203*9e965d6fSRomain Jobredeaux        # if we reach here, this is a cc_library without sources generating an
204*9e965d6fSRomain Jobredeaux        # empty archive which does not need to be linked
205*9e965d6fSRomain Jobredeaux        # TODO(hvd): replace all such cc_library with exporting_cc_library
206*9e965d6fSRomain Jobredeaux        return False
207*9e965d6fSRomain Jobredeaux    for obj in object_files:
208*9e965d6fSRomain Jobredeaux        if not _is_shared_library(obj):
209*9e965d6fSRomain Jobredeaux            # this library was built with a non-shared-library object so we should link it
210*9e965d6fSRomain Jobredeaux            return True
211*9e965d6fSRomain Jobredeaux    return False
212*9e965d6fSRomain Jobredeaux
213*9e965d6fSRomain Jobredeauxdef _is_any_source_file(*files):
214*9e965d6fSRomain Jobredeaux    for file in files:
215*9e965d6fSRomain Jobredeaux        if file and file.is_source:
216*9e965d6fSRomain Jobredeaux            return True
217*9e965d6fSRomain Jobredeaux    return False
218*9e965d6fSRomain Jobredeaux
219*9e965d6fSRomain Jobredeauxdef _is_shared_library(lib_artifact):
220*9e965d6fSRomain Jobredeaux    if (lib_artifact.extension in ["so", "dll", "dylib"]):
221*9e965d6fSRomain Jobredeaux        return True
222*9e965d6fSRomain Jobredeaux
223*9e965d6fSRomain Jobredeaux    lib_name = lib_artifact.basename
224*9e965d6fSRomain Jobredeaux
225*9e965d6fSRomain Jobredeaux    # validate against the regex "^.+\\.((so)|(dylib))(\\.\\d\\w*)+$",
226*9e965d6fSRomain Jobredeaux    # must match VERSIONED_SHARED_LIBRARY.
227*9e965d6fSRomain Jobredeaux    for ext in (".so.", ".dylib."):
228*9e965d6fSRomain Jobredeaux        name, _, version = lib_name.rpartition(ext)
229*9e965d6fSRomain Jobredeaux        if name and version:
230*9e965d6fSRomain Jobredeaux            version_parts = version.split(".")
231*9e965d6fSRomain Jobredeaux            for part in version_parts:
232*9e965d6fSRomain Jobredeaux                if not part[0].isdigit():
233*9e965d6fSRomain Jobredeaux                    return False
234*9e965d6fSRomain Jobredeaux                for c in part[1:].elems():
235*9e965d6fSRomain Jobredeaux                    if not (c.isalnum() or c == "_"):
236*9e965d6fSRomain Jobredeaux                        return False
237*9e965d6fSRomain Jobredeaux            return True
238*9e965d6fSRomain Jobredeaux    return False
239*9e965d6fSRomain Jobredeaux
240*9e965d6fSRomain Jobredeauxdef _is_stamping_enabled(ctx):
241*9e965d6fSRomain Jobredeaux    if ctx.configuration.is_tool_configuration():
242*9e965d6fSRomain Jobredeaux        return 0
243*9e965d6fSRomain Jobredeaux    return getattr(ctx.attr, "stamp", 0)
244*9e965d6fSRomain Jobredeaux
245*9e965d6fSRomain Jobredeauxdef _get_build_info(ctx, cc_toolchain):
246*9e965d6fSRomain Jobredeaux    if _is_stamping_enabled(ctx):
247*9e965d6fSRomain Jobredeaux        return cc_toolchain.build_info_files().non_redacted_build_info_files.to_list()
248*9e965d6fSRomain Jobredeaux    else:
249*9e965d6fSRomain Jobredeaux        return cc_toolchain.build_info_files().redacted_build_info_files.to_list()
250*9e965d6fSRomain Jobredeaux
251*9e965d6fSRomain Jobredeauxdef _get_shared_native_deps_path(
252*9e965d6fSRomain Jobredeaux        linker_inputs,
253*9e965d6fSRomain Jobredeaux        link_opts,
254*9e965d6fSRomain Jobredeaux        linkstamps,
255*9e965d6fSRomain Jobredeaux        build_info_artifacts,
256*9e965d6fSRomain Jobredeaux        features,
257*9e965d6fSRomain Jobredeaux        is_test_target_partially_disabled_thin_lto):
258*9e965d6fSRomain Jobredeaux    fp = []
259*9e965d6fSRomain Jobredeaux    for artifact in linker_inputs:
260*9e965d6fSRomain Jobredeaux        fp.append(artifact.short_path)
261*9e965d6fSRomain Jobredeaux    fp.append(str(len(link_opts)))
262*9e965d6fSRomain Jobredeaux    for opt in link_opts:
263*9e965d6fSRomain Jobredeaux        fp.append(opt)
264*9e965d6fSRomain Jobredeaux    for artifact in linkstamps:
265*9e965d6fSRomain Jobredeaux        fp.append(artifact.short_path)
266*9e965d6fSRomain Jobredeaux    for artifact in build_info_artifacts:
267*9e965d6fSRomain Jobredeaux        fp.append(artifact.short_path)
268*9e965d6fSRomain Jobredeaux    for feature in features:
269*9e965d6fSRomain Jobredeaux        fp.append(feature)
270*9e965d6fSRomain Jobredeaux
271*9e965d6fSRomain Jobredeaux    fp.append("1" if is_test_target_partially_disabled_thin_lto else "0")
272*9e965d6fSRomain Jobredeaux
273*9e965d6fSRomain Jobredeaux    fingerprint = "%x" % hash("".join(fp))
274*9e965d6fSRomain Jobredeaux    return "_nativedeps/" + fingerprint
275*9e965d6fSRomain Jobredeaux
276*9e965d6fSRomain Jobredeauxdef _get_static_mode_params_for_dynamic_library_libraries(libs):
277*9e965d6fSRomain Jobredeaux    linker_inputs = []
278*9e965d6fSRomain Jobredeaux    for lib in libs:
279*9e965d6fSRomain Jobredeaux        if lib.pic_static_library:
280*9e965d6fSRomain Jobredeaux            linker_inputs.append(lib.pic_static_library)
281*9e965d6fSRomain Jobredeaux        elif lib.static_library:
282*9e965d6fSRomain Jobredeaux            linker_inputs.append(lib.static_library)
283*9e965d6fSRomain Jobredeaux        elif lib.interface_library:
284*9e965d6fSRomain Jobredeaux            linker_inputs.append(lib.interface_library)
285*9e965d6fSRomain Jobredeaux        else:
286*9e965d6fSRomain Jobredeaux            linker_inputs.append(lib.dynamic_library)
287*9e965d6fSRomain Jobredeaux    return linker_inputs
288*9e965d6fSRomain Jobredeaux
289*9e965d6fSRomain Jobredeauxdef _link_native_deps_if_present(ctx, cc_info, cc_toolchain, build_config, actual_target_name, is_test_rule_class = False):
290*9e965d6fSRomain Jobredeaux    needs_linking = False
291*9e965d6fSRomain Jobredeaux    all_inputs = _all_inputs(cc_info)
292*9e965d6fSRomain Jobredeaux    for input in all_inputs:
293*9e965d6fSRomain Jobredeaux        needs_linking = needs_linking or _contains_code_to_link(input)
294*9e965d6fSRomain Jobredeaux
295*9e965d6fSRomain Jobredeaux    if not needs_linking:
296*9e965d6fSRomain Jobredeaux        return None
297*9e965d6fSRomain Jobredeaux
298*9e965d6fSRomain Jobredeaux    # This does not need to be shareable, but we use this API to specify the
299*9e965d6fSRomain Jobredeaux    # custom file root (matching the configuration)
300*9e965d6fSRomain Jobredeaux    output_lib = ctx.actions.declare_shareable_artifact(
301*9e965d6fSRomain Jobredeaux        ctx.label.package + "/nativedeps/" + actual_target_name + "/lib" + actual_target_name + ".so",
302*9e965d6fSRomain Jobredeaux        build_config.bin_dir,
303*9e965d6fSRomain Jobredeaux    )
304*9e965d6fSRomain Jobredeaux
305*9e965d6fSRomain Jobredeaux    linker_inputs = cc_info.linking_context.linker_inputs.to_list()
306*9e965d6fSRomain Jobredeaux
307*9e965d6fSRomain Jobredeaux    link_opts = []
308*9e965d6fSRomain Jobredeaux    for linker_input in linker_inputs:
309*9e965d6fSRomain Jobredeaux        for flag in linker_input.user_link_flags:
310*9e965d6fSRomain Jobredeaux            link_opts.append(flag)
311*9e965d6fSRomain Jobredeaux
312*9e965d6fSRomain Jobredeaux    linkstamps = []
313*9e965d6fSRomain Jobredeaux    for linker_input in linker_inputs:
314*9e965d6fSRomain Jobredeaux        linkstamps.extend(linker_input.linkstamps)
315*9e965d6fSRomain Jobredeaux    linkstamps_dict = {linkstamp: None for linkstamp in linkstamps}
316*9e965d6fSRomain Jobredeaux
317*9e965d6fSRomain Jobredeaux    build_info_artifacts = _get_build_info(ctx, cc_toolchain) if linkstamps_dict else []
318*9e965d6fSRomain Jobredeaux    requested_features = ["static_linking_mode", "native_deps_link"]
319*9e965d6fSRomain Jobredeaux    requested_features.extend(ctx.features)
320*9e965d6fSRomain Jobredeaux    if not "legacy_whole_archive" in ctx.disabled_features:
321*9e965d6fSRomain Jobredeaux        requested_features.append("legacy_whole_archive")
322*9e965d6fSRomain Jobredeaux    requested_features = sorted(requested_features)
323*9e965d6fSRomain Jobredeaux    feature_config = cc_common.configure_features(
324*9e965d6fSRomain Jobredeaux        ctx = ctx,
325*9e965d6fSRomain Jobredeaux        cc_toolchain = cc_toolchain,
326*9e965d6fSRomain Jobredeaux        requested_features = requested_features,
327*9e965d6fSRomain Jobredeaux        unsupported_features = ctx.disabled_features,
328*9e965d6fSRomain Jobredeaux    )
329*9e965d6fSRomain Jobredeaux    partially_disabled_thin_lto = (
330*9e965d6fSRomain Jobredeaux        cc_common.is_enabled(
331*9e965d6fSRomain Jobredeaux            feature_name = "thin_lto_linkstatic_tests_use_shared_nonlto_backends",
332*9e965d6fSRomain Jobredeaux            feature_configuration = feature_config,
333*9e965d6fSRomain Jobredeaux        ) and not cc_common.is_enabled(
334*9e965d6fSRomain Jobredeaux            feature_name = "thin_lto_all_linkstatic_use_shared_nonlto_backends",
335*9e965d6fSRomain Jobredeaux            feature_configuration = feature_config,
336*9e965d6fSRomain Jobredeaux        )
337*9e965d6fSRomain Jobredeaux    )
338*9e965d6fSRomain Jobredeaux    test_only_target = ctx.attr.testonly or is_test_rule_class
339*9e965d6fSRomain Jobredeaux    share_native_deps = ctx.fragments.cpp.share_native_deps()
340*9e965d6fSRomain Jobredeaux
341*9e965d6fSRomain Jobredeaux    linker_inputs = _get_static_mode_params_for_dynamic_library_libraries(all_inputs)
342*9e965d6fSRomain Jobredeaux
343*9e965d6fSRomain Jobredeaux    if share_native_deps:
344*9e965d6fSRomain Jobredeaux        shared_path = _get_shared_native_deps_path(
345*9e965d6fSRomain Jobredeaux            linker_inputs,
346*9e965d6fSRomain Jobredeaux            link_opts,
347*9e965d6fSRomain Jobredeaux            [linkstamp.file() for linkstamp in linkstamps_dict],
348*9e965d6fSRomain Jobredeaux            build_info_artifacts,
349*9e965d6fSRomain Jobredeaux            requested_features,
350*9e965d6fSRomain Jobredeaux            test_only_target and partially_disabled_thin_lto,
351*9e965d6fSRomain Jobredeaux        )
352*9e965d6fSRomain Jobredeaux        linked_lib = ctx.actions.declare_shareable_artifact(shared_path + ".so", build_config.bin_dir)
353*9e965d6fSRomain Jobredeaux    else:
354*9e965d6fSRomain Jobredeaux        linked_lib = output_lib
355*9e965d6fSRomain Jobredeaux
356*9e965d6fSRomain Jobredeaux    cc_common.link(
357*9e965d6fSRomain Jobredeaux        name = ctx.label.name,
358*9e965d6fSRomain Jobredeaux        actions = ctx.actions,
359*9e965d6fSRomain Jobredeaux        linking_contexts = [cc_info.linking_context],
360*9e965d6fSRomain Jobredeaux        output_type = "dynamic_library",
361*9e965d6fSRomain Jobredeaux        never_link = True,
362*9e965d6fSRomain Jobredeaux        native_deps = True,
363*9e965d6fSRomain Jobredeaux        feature_configuration = feature_config,
364*9e965d6fSRomain Jobredeaux        cc_toolchain = cc_toolchain,
365*9e965d6fSRomain Jobredeaux        test_only_target = test_only_target,
366*9e965d6fSRomain Jobredeaux        stamp = getattr(ctx.attr, "stamp", 0),
367*9e965d6fSRomain Jobredeaux        main_output = linked_lib,
368*9e965d6fSRomain Jobredeaux        use_shareable_artifact_factory = True,
369*9e965d6fSRomain Jobredeaux        build_config = build_config,
370*9e965d6fSRomain Jobredeaux    )
371*9e965d6fSRomain Jobredeaux
372*9e965d6fSRomain Jobredeaux    if (share_native_deps):
373*9e965d6fSRomain Jobredeaux        ctx.actions.symlink(
374*9e965d6fSRomain Jobredeaux            output = output_lib,
375*9e965d6fSRomain Jobredeaux            target_file = linked_lib,
376*9e965d6fSRomain Jobredeaux        )
377*9e965d6fSRomain Jobredeaux        return output_lib
378*9e965d6fSRomain Jobredeaux    else:
379*9e965d6fSRomain Jobredeaux        return linked_lib
380*9e965d6fSRomain Jobredeaux
381*9e965d6fSRomain Jobredeauxdef _concat(*list_of_lists):
382*9e965d6fSRomain Jobredeaux    res = []
383*9e965d6fSRomain Jobredeaux    for list in list_of_lists:
384*9e965d6fSRomain Jobredeaux        res.extend(list)
385*9e965d6fSRomain Jobredeaux    return res
386