• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""
2Copyright (C) 2021 The Android Open Source Project
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15"""
16
17load(
18    ":cc_library_common.bzl",
19    "add_lists_defaulting_to_none",
20    "disable_crt_link",
21    "parse_sdk_version",
22    "system_dynamic_deps_defaults",
23)
24load(":cc_library_static.bzl", "cc_library_static")
25load(":cc_stub_library.bzl", "CcStubInfo", "cc_stub_gen")
26load(":generate_toc.bzl", "shared_library_toc", _CcTocInfo = "CcTocInfo")
27load(":stl.bzl", "shared_stl_deps")
28load(":stripped_cc_common.bzl", "stripped_shared_library")
29load(":versioned_cc_common.bzl", "versioned_shared_library")
30load("@rules_cc//examples:experimental_cc_shared_library.bzl", "cc_shared_library", _CcSharedLibraryInfo = "CcSharedLibraryInfo")
31load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain")
32
33CcTocInfo = _CcTocInfo
34CcSharedLibraryInfo = _CcSharedLibraryInfo
35
36def cc_library_shared(
37        name,
38        # Common arguments between shared_root and the shared library
39        features = [],
40        dynamic_deps = [],
41        implementation_dynamic_deps = [],
42        linkopts = [],
43        target_compatible_with = [],
44        # Ultimately _static arguments for shared_root production
45        srcs = [],
46        srcs_c = [],
47        srcs_as = [],
48        copts = [],
49        cppflags = [],
50        conlyflags = [],
51        asflags = [],
52        hdrs = [],
53        implementation_deps = [],
54        deps = [],
55        whole_archive_deps = [],
56        system_dynamic_deps = None,
57        export_includes = [],
58        export_absolute_includes = [],
59        export_system_includes = [],
60        local_includes = [],
61        absolute_includes = [],
62        rtti = False,
63        use_libcrt = True,  # FIXME: Unused below?
64        stl = "",
65        cpp_std = "",
66        c_std = "",
67        link_crt = True,
68        additional_linker_inputs = None,
69
70        # Purely _shared arguments
71        strip = {},
72        soname = "",
73
74        # TODO(b/202299295): Handle data attribute.
75        data = [],
76        use_version_lib = False,
77        stubs_symbol_file = None,
78        stubs_versions = [],
79        inject_bssl_hash = False,
80        sdk_version = "",
81        min_sdk_version = "",
82        **kwargs):
83    "Bazel macro to correspond with the cc_library_shared Soong module."
84
85    shared_root_name = name + "_root"
86    unstripped_name = name + "_unstripped"
87    stripped_name = name + "_stripped"
88    toc_name = name + "_toc"
89
90    if system_dynamic_deps == None:
91        system_dynamic_deps = system_dynamic_deps_defaults
92
93    # Force crtbegin and crtend linking unless explicitly disabled (i.e. bionic
94    # libraries do this)
95    if link_crt == False:
96        features = disable_crt_link(features)
97
98    if min_sdk_version:
99        features = features + [
100            "sdk_version_" + parse_sdk_version(min_sdk_version),
101            "-sdk_version_default",
102        ]
103
104    # The static library at the root of the shared library.
105    # This may be distinct from the static version of the library if e.g.
106    # the static-variant srcs are different than the shared-variant srcs.
107    cc_library_static(
108        name = shared_root_name,
109        hdrs = hdrs,
110        srcs = srcs,
111        srcs_c = srcs_c,
112        srcs_as = srcs_as,
113        copts = copts,
114        cppflags = cppflags,
115        conlyflags = conlyflags,
116        asflags = asflags,
117        export_includes = export_includes,
118        export_absolute_includes = export_absolute_includes,
119        export_system_includes = export_system_includes,
120        local_includes = local_includes,
121        absolute_includes = absolute_includes,
122        rtti = rtti,
123        stl = stl,
124        cpp_std = cpp_std,
125        c_std = c_std,
126        dynamic_deps = dynamic_deps,
127        implementation_deps = implementation_deps,
128        implementation_dynamic_deps = implementation_dynamic_deps,
129        system_dynamic_deps = system_dynamic_deps,
130        deps = deps + whole_archive_deps,
131        features = features,
132        use_version_lib = use_version_lib,
133        target_compatible_with = target_compatible_with,
134    )
135
136    stl_static, stl_shared = shared_stl_deps(stl)
137
138    # implementation_deps and deps are to be linked into the shared library via
139    # --no-whole-archive. In order to do so, they need to be dependencies of
140    # a "root" of the cc_shared_library, but may not be roots themselves.
141    # Below we define stub roots (which themselves have no srcs) in order to facilitate
142    # this.
143    imp_deps_stub = name + "_implementation_deps"
144    deps_stub = name + "_deps"
145    native.cc_library(
146        name = imp_deps_stub,
147        deps = implementation_deps + stl_static,
148        target_compatible_with = target_compatible_with,
149    )
150    native.cc_library(
151        name = deps_stub,
152        deps = deps,
153        target_compatible_with = target_compatible_with,
154    )
155
156    shared_dynamic_deps = add_lists_defaulting_to_none(
157        dynamic_deps,
158        system_dynamic_deps,
159        implementation_dynamic_deps,
160        stl_shared,
161    )
162
163    if len(soname) == 0:
164        soname = name + ".so"
165    soname_flag = "-Wl,-soname," + soname
166
167    cc_shared_library(
168        name = unstripped_name,
169        user_link_flags = linkopts + [soname_flag],
170        # b/184806113: Note this is  a workaround so users don't have to
171        # declare all transitive static deps used by this target.  It'd be great
172        # if a shared library could declare a transitive exported static dep
173        # instead of needing to declare each target transitively.
174        static_deps = ["//:__subpackages__"] + [shared_root_name, imp_deps_stub, deps_stub],
175        dynamic_deps = shared_dynamic_deps,
176        additional_linker_inputs = additional_linker_inputs,
177        roots = [shared_root_name, imp_deps_stub, deps_stub] + whole_archive_deps,
178        features = features,
179        target_compatible_with = target_compatible_with,
180        **kwargs
181    )
182
183    hashed_name = name + "_hashed"
184    _bssl_hash_injection(
185        name = hashed_name,
186        src = unstripped_name,
187        inject_bssl_hash = inject_bssl_hash,
188    )
189
190    versioned_name = name + "_versioned"
191    versioned_shared_library(
192        name = versioned_name,
193        src = hashed_name,
194        stamp_build_number = use_version_lib,
195    )
196
197    stripped_shared_library(
198        name = stripped_name,
199        src = versioned_name,
200        target_compatible_with = target_compatible_with,
201        **strip
202    )
203
204    shared_library_toc(
205        name = toc_name,
206        src = stripped_name,
207        target_compatible_with = target_compatible_with,
208    )
209
210    # Emit the stub version of this library (e.g. for libraries that are
211    # provided by the NDK)
212    stub_shared_libraries = []
213    if stubs_symbol_file and len(stubs_versions) > 0:
214        # TODO(b/193663198): This unconditionally creates stubs for every version, but
215        # that's not always true depending on whether this module is available
216        # on the host, ramdisk, vendor ramdisk. We currently don't have
217        # information about the image variant yet, so we'll create stub targets
218        # for all shared libraries with the stubs property for now.
219        #
220        # See: https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/library.go;l=2316-2377;drc=3d3b35c94ed2a3432b2e5e7e969a3a788a7a80b5
221        for version in stubs_versions:
222            stubs_library_name = "_".join([name, version, "stubs"])
223            cc_stub_library_shared(
224                name = stubs_library_name,
225                stubs_symbol_file = stubs_symbol_file,
226                version = version,
227                target_compatible_with = target_compatible_with,
228                features = features,
229            )
230            stub_shared_libraries.append(stubs_library_name)
231
232    _cc_library_shared_proxy(
233        name = name,
234        shared = stripped_name,
235        root = shared_root_name,
236        table_of_contents = toc_name,
237        output_file = soname,
238        target_compatible_with = target_compatible_with,
239        stub_shared_libraries = stub_shared_libraries,
240    )
241
242# cc_stub_library_shared creates a cc_library_shared target, but using stub C source files generated
243# from a library's .map.txt files and ndkstubgen. The top level target returns the same
244# providers as a cc_library_shared, with the addition of a CcStubInfo
245# containing metadata files and versions of the stub library.
246def cc_stub_library_shared(name, stubs_symbol_file, version, target_compatible_with, features):
247    # Call ndkstubgen to generate the stub.c source file from a .map.txt file. These
248    # are accessible in the CcStubInfo provider of this target.
249    cc_stub_gen(
250        name = name + "_files",
251        symbol_file = stubs_symbol_file,
252        version = version,
253        target_compatible_with = target_compatible_with,
254    )
255
256    # The static library at the root of the stub shared library.
257    cc_library_static(
258        name = name + "_root",
259        srcs_c = [name + "_files"],  # compile the stub.c file
260        features = disable_crt_link(features) + \
261            [
262                # Enable the stub library compile flags
263                "stub_library",
264                # Disable all include-related features to avoid including any headers
265                # that may cause conflicting type errors with the symbols in the
266                # generated stubs source code.
267                #  e.g.
268                #  double acos(double); // in header
269                #  void acos() {} // in the generated source code
270                # See https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/library.go;l=942-946;drc=d8a72d7dc91b2122b7b10b47b80cf2f7c65f9049
271                "-toolchain_include_directories",
272                "-includes",
273                "-include_paths",
274            ],
275        target_compatible_with = target_compatible_with,
276        stl = "none",
277        system_dynamic_deps = [],
278    )
279
280    # Create a .so for the stub library. This library is self contained, has
281    # no deps, and doesn't link against crt.
282    cc_shared_library(
283        name = name + "_so",
284        roots = [name + "_root"],
285        features = disable_crt_link(features),
286        target_compatible_with = target_compatible_with,
287    )
288
289    # Create a target with CcSharedLibraryInfo and CcStubInfo providers.
290    _cc_stub_library_shared(
291        name = name,
292        stub_target = name + "_files",
293        library_target = name + "_so",
294    )
295
296def _cc_stub_library_shared_impl(ctx):
297    return [
298        ctx.attr.library_target[DefaultInfo],
299        ctx.attr.library_target[CcSharedLibraryInfo],
300        ctx.attr.stub_target[CcStubInfo],
301    ]
302
303_cc_stub_library_shared = rule(
304    implementation = _cc_stub_library_shared_impl,
305    doc = "Top level rule to merge CcStubInfo and CcSharedLibraryInfo into a single target",
306    attrs = {
307        "stub_target": attr.label(mandatory = True),
308        "library_target": attr.label(mandatory = True),
309    },
310)
311
312def _swap_shared_linker_input(ctx, shared_info, new_output):
313    old_library_to_link = shared_info.linker_input.libraries[0]
314
315    cc_toolchain = find_cpp_toolchain(ctx)
316    feature_configuration = cc_common.configure_features(
317        ctx = ctx,
318        cc_toolchain = cc_toolchain,
319    )
320
321    new_library_to_link = cc_common.create_library_to_link(
322        actions = ctx.actions,
323        dynamic_library = new_output,
324        feature_configuration = feature_configuration,
325        cc_toolchain = cc_toolchain,
326    )
327
328    new_linker_input = cc_common.create_linker_input(
329        owner = shared_info.linker_input.owner,
330        libraries = depset([new_library_to_link]),
331    )
332
333    return CcSharedLibraryInfo(
334        dynamic_deps = shared_info.dynamic_deps,
335        exports = shared_info.exports,
336        link_once_static_libs = shared_info.link_once_static_libs,
337        linker_input = new_linker_input,
338        preloaded_deps = shared_info.preloaded_deps,
339    )
340
341CcStubLibrariesInfo = provider(
342    fields = {
343        "infos": "A list of dict, where each dict contains the CcStubInfo, CcSharedLibraryInfo and DefaultInfo of a version of a stub library.",
344    },
345)
346
347def _cc_library_shared_proxy_impl(ctx):
348    root_files = ctx.attr.root[DefaultInfo].files.to_list()
349    shared_files = ctx.attr.shared[DefaultInfo].files.to_list()
350
351    if len(shared_files) != 1:
352        fail("Expected only one shared library file")
353
354    shared_lib = shared_files[0]
355
356    ctx.actions.symlink(
357        output = ctx.outputs.output_file,
358        target_file = shared_lib,
359    )
360
361    files = root_files + [ctx.outputs.output_file, ctx.files.table_of_contents[0]]
362
363    stub_library_infos = []
364    for stub_library in ctx.attr.stub_shared_libraries:
365        providers = {
366            "CcStubInfo": stub_library[CcStubInfo],
367            "CcSharedLibraryInfo": stub_library[CcSharedLibraryInfo],
368            "DefaultInfo": stub_library[DefaultInfo],
369        }
370        stub_library_infos.append(providers)
371
372    return [
373        DefaultInfo(
374            files = depset(direct = files),
375            runfiles = ctx.runfiles(files = [ctx.outputs.output_file]),
376        ),
377        _swap_shared_linker_input(ctx, ctx.attr.shared[CcSharedLibraryInfo], ctx.outputs.output_file),
378        ctx.attr.table_of_contents[CcTocInfo],
379        # Propagate only includes from the root. Do not re-propagate linker inputs.
380        CcInfo(compilation_context = ctx.attr.root[CcInfo].compilation_context),
381        CcStubLibrariesInfo(infos = stub_library_infos),
382    ]
383
384_cc_library_shared_proxy = rule(
385    implementation = _cc_library_shared_proxy_impl,
386    attrs = {
387        "shared": attr.label(mandatory = True, providers = [CcSharedLibraryInfo]),
388        "root": attr.label(mandatory = True, providers = [CcInfo]),
389        "output_file": attr.output(mandatory = True),
390        "table_of_contents": attr.label(
391            mandatory = True,
392            # TODO(b/217908237): reenable allow_single_file
393            # allow_single_file = True,
394            providers = [CcTocInfo],
395        ),
396        "stub_shared_libraries": attr.label_list(providers = [CcStubInfo, CcSharedLibraryInfo]),
397    },
398    fragments = ["cpp"],
399    toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
400)
401
402def _bssl_hash_injection_impl(ctx):
403    if len(ctx.files.src) != 1:
404        fail("Expected only one shared library file")
405
406    hashed_file = ctx.files.src[0]
407    if ctx.attr.inject_bssl_hash:
408        hashed_file = ctx.actions.declare_file("lib" + ctx.attr.name + ".so")
409        args = ctx.actions.args()
410        args.add_all(["-sha256"])
411        args.add_all(["-in-object", ctx.files.src[0]])
412        args.add_all(["-o", hashed_file])
413
414        ctx.actions.run(
415            inputs = ctx.files.src,
416            outputs = [hashed_file],
417            executable = ctx.executable._bssl_inject_hash,
418            arguments = [args],
419            tools = [ctx.executable._bssl_inject_hash],
420            mnemonic = "BsslInjectHash",
421        )
422
423    return [
424        DefaultInfo(files = depset([hashed_file])),
425        ctx.attr.src[CcSharedLibraryInfo],
426    ]
427
428_bssl_hash_injection = rule(
429    implementation = _bssl_hash_injection_impl,
430    attrs = {
431        "src": attr.label(
432            mandatory = True,
433            # TODO(b/217908237): reenable allow_single_file
434            # allow_single_file = True,
435            providers = [CcSharedLibraryInfo],
436        ),
437        "inject_bssl_hash": attr.bool(
438            default = False,
439            doc = "Whether inject BSSL hash",
440        ),
441        "_bssl_inject_hash": attr.label(
442            cfg = "exec",
443            doc = "The BSSL hash injection tool.",
444            executable = True,
445            default = "//prebuilts/build-tools:linux-x86/bin/bssl_inject_hash",
446            allow_single_file = True,
447        ),
448    },
449)
450