| """ |
| Copyright (C) 2021 The Android Open Source Project |
| |
| 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(":cc_library_common.bzl", "add_lists_defaulting_to_none", "disable_crt_link", "system_dynamic_deps_defaults") |
| load(":cc_library_static.bzl", "cc_library_static") |
| load(":cc_stub_library.bzl", "cc_stub_gen", "CcStubInfo") |
| load(":generate_toc.bzl", "shared_library_toc", _CcTocInfo = "CcTocInfo") |
| load(":stl.bzl", "shared_stl_deps") |
| load(":stripped_cc_common.bzl", "stripped_shared_library") |
| load("@rules_cc//examples:experimental_cc_shared_library.bzl", "cc_shared_library", _CcSharedLibraryInfo = "CcSharedLibraryInfo") |
| load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain") |
| |
| CcTocInfo = _CcTocInfo |
| CcSharedLibraryInfo = _CcSharedLibraryInfo |
| |
| def cc_library_shared( |
| name, |
| # Common arguments between shared_root and the shared library |
| features = [], |
| dynamic_deps = [], |
| implementation_dynamic_deps = [], |
| linkopts = [], |
| target_compatible_with = [], |
| # Ultimately _static arguments for shared_root production |
| srcs = [], |
| srcs_c = [], |
| srcs_as = [], |
| copts = [], |
| cppflags = [], |
| conlyflags = [], |
| asflags = [], |
| hdrs = [], |
| implementation_deps = [], |
| deps = [], |
| whole_archive_deps = [], |
| system_dynamic_deps = None, |
| export_includes = [], |
| export_absolute_includes = [], |
| export_system_includes = [], |
| local_includes = [], |
| absolute_includes = [], |
| rtti = False, |
| use_libcrt = True, # FIXME: Unused below? |
| stl = "", |
| cpp_std = "", |
| c_std = "", |
| link_crt = True, |
| additional_linker_inputs = None, |
| |
| # Purely _shared arguments |
| strip = {}, |
| soname = "", |
| |
| # TODO(b/202299295): Handle data attribute. |
| data = [], |
| |
| use_version_lib = False, |
| |
| stubs_symbol_file = None, |
| stubs_versions = [], |
| inject_bssl_hash = False, |
| **kwargs): |
| "Bazel macro to correspond with the cc_library_shared Soong module." |
| |
| if use_version_lib: |
| libbuildversionLabel = "//build/soong/cc/libbuildversion:libbuildversion" |
| whole_archive_deps = whole_archive_deps + [libbuildversionLabel] |
| |
| shared_root_name = name + "_root" |
| unstripped_name = name + "_unstripped" |
| stripped_name = name + "_stripped" |
| toc_name = name + "_toc" |
| |
| if system_dynamic_deps == None: |
| system_dynamic_deps = system_dynamic_deps_defaults |
| |
| # Force crtbegin and crtend linking unless explicitly disabled (i.e. bionic |
| # libraries do this) |
| if link_crt == False: |
| features = disable_crt_link(features) |
| |
| # The static library at the root of the shared library. |
| # This may be distinct from the static version of the library if e.g. |
| # the static-variant srcs are different than the shared-variant srcs. |
| cc_library_static( |
| name = shared_root_name, |
| hdrs = hdrs, |
| srcs = srcs, |
| srcs_c = srcs_c, |
| srcs_as = srcs_as, |
| copts = copts, |
| cppflags = cppflags, |
| conlyflags = conlyflags, |
| asflags = asflags, |
| export_includes = export_includes, |
| export_absolute_includes = export_absolute_includes, |
| export_system_includes = export_system_includes, |
| local_includes = local_includes, |
| absolute_includes = absolute_includes, |
| rtti = rtti, |
| stl = stl, |
| cpp_std = cpp_std, |
| c_std = c_std, |
| dynamic_deps = dynamic_deps, |
| implementation_deps = implementation_deps, |
| implementation_dynamic_deps = implementation_dynamic_deps, |
| system_dynamic_deps = system_dynamic_deps, |
| deps = deps + whole_archive_deps, |
| features = features, |
| use_version_lib = use_version_lib, |
| target_compatible_with = target_compatible_with, |
| ) |
| |
| stl_static, stl_shared = shared_stl_deps(stl) |
| |
| # implementation_deps and deps are to be linked into the shared library via |
| # --no-whole-archive. In order to do so, they need to be dependencies of |
| # a "root" of the cc_shared_library, but may not be roots themselves. |
| # Below we define stub roots (which themselves have no srcs) in order to facilitate |
| # this. |
| imp_deps_stub = name + "_implementation_deps" |
| deps_stub = name + "_deps" |
| native.cc_library( |
| name = imp_deps_stub, |
| deps = implementation_deps + stl_static, |
| target_compatible_with = target_compatible_with, |
| ) |
| native.cc_library( |
| name = deps_stub, |
| deps = deps, |
| target_compatible_with = target_compatible_with, |
| ) |
| |
| shared_dynamic_deps = add_lists_defaulting_to_none( |
| dynamic_deps, |
| system_dynamic_deps, |
| implementation_dynamic_deps, |
| stl_shared, |
| ) |
| |
| if len(soname) == 0: |
| soname = name + ".so" |
| soname_flag = "-Wl,-soname," + soname |
| cc_shared_library( |
| name = unstripped_name, |
| user_link_flags = linkopts + [soname_flag], |
| # b/184806113: Note this is a workaround so users don't have to |
| # declare all transitive static deps used by this target. It'd be great |
| # if a shared library could declare a transitive exported static dep |
| # instead of needing to declare each target transitively. |
| static_deps = ["//:__subpackages__"] + [shared_root_name, imp_deps_stub, deps_stub], |
| dynamic_deps = shared_dynamic_deps, |
| additional_linker_inputs = additional_linker_inputs, |
| roots = [shared_root_name, imp_deps_stub, deps_stub] + whole_archive_deps, |
| features = features, |
| target_compatible_with = target_compatible_with, |
| **kwargs |
| ) |
| |
| hashed_name = name + "_hashed" |
| _bssl_hash_injection( |
| name = hashed_name, |
| src = unstripped_name, |
| inject_bssl_hash = inject_bssl_hash, |
| ) |
| |
| stripped_shared_library( |
| name = stripped_name, |
| src = hashed_name, |
| target_compatible_with = target_compatible_with, |
| **strip |
| ) |
| |
| shared_library_toc( |
| name = toc_name, |
| src = stripped_name, |
| target_compatible_with = target_compatible_with, |
| ) |
| |
| # Emit the stub version of this library (e.g. for libraries that are |
| # provided by the NDK) |
| stub_shared_libraries = [] |
| if stubs_symbol_file and len(stubs_versions) > 0: |
| # TODO(b/193663198): This unconditionally creates stubs for every version, but |
| # that's not always true depending on whether this module is available |
| # on the host, ramdisk, vendor ramdisk. We currently don't have |
| # information about the image variant yet, so we'll create stub targets |
| # for all shared libraries with the stubs property for now. |
| # |
| # See: https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/library.go;l=2316-2377;drc=3d3b35c94ed2a3432b2e5e7e969a3a788a7a80b5 |
| for version in stubs_versions: |
| stubs_library_name = "_".join([name, version, "stubs"]) |
| cc_stub_library_shared( |
| name = stubs_library_name, |
| stubs_symbol_file = stubs_symbol_file, |
| version = version, |
| target_compatible_with = target_compatible_with, |
| features = features, |
| ) |
| stub_shared_libraries.append(stubs_library_name) |
| |
| _cc_library_shared_proxy( |
| name = name, |
| shared = stripped_name, |
| root = shared_root_name, |
| table_of_contents = toc_name, |
| output_file = soname, |
| target_compatible_with = target_compatible_with, |
| stub_shared_libraries = stub_shared_libraries, |
| ) |
| |
| # cc_stub_library_shared creates a cc_library_shared target, but using stub C source files generated |
| # from a library's .map.txt files and ndkstubgen. The top level target returns the same |
| # providers as a cc_library_shared, with the addition of a CcStubInfo |
| # containing metadata files and versions of the stub library. |
| def cc_stub_library_shared(name, stubs_symbol_file, version, target_compatible_with, features): |
| # Call ndkstubgen to generate the stub.c source file from a .map.txt file. These |
| # are accessible in the CcStubInfo provider of this target. |
| cc_stub_gen( |
| name = name + "_files", |
| symbol_file = stubs_symbol_file, |
| version = version, |
| target_compatible_with = target_compatible_with, |
| ) |
| # The static library at the root of the stub shared library. |
| cc_library_static( |
| name = name + "_root", |
| srcs_c = [name + "_files"], # compile the stub.c file |
| features = disable_crt_link(features) + \ |
| [ |
| # Enable the stub library compile flags |
| "stub_library", |
| # Disable all include-related features to avoid including any headers |
| # that may cause conflicting type errors with the symbols in the |
| # generated stubs source code. |
| # e.g. |
| # double acos(double); // in header |
| # void acos() {} // in the generated source code |
| # See https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/library.go;l=942-946;drc=d8a72d7dc91b2122b7b10b47b80cf2f7c65f9049 |
| "-toolchain_include_directories", |
| "-includes", |
| "-include_paths", |
| ], |
| target_compatible_with = target_compatible_with, |
| stl = "none", |
| system_dynamic_deps = [], |
| ) |
| # Create a .so for the stub library. This library is self contained, has |
| # no deps, and doesn't link against crt. |
| cc_shared_library( |
| name = name + "_so", |
| roots = [name + "_root"], |
| features = disable_crt_link(features), |
| target_compatible_with = target_compatible_with, |
| ) |
| |
| # Create a target with CcSharedLibraryInfo and CcStubInfo providers. |
| _cc_stub_library_shared( |
| name = name, |
| stub_target = name + "_files", |
| library_target = name + "_so", |
| ) |
| |
| def _cc_stub_library_shared_impl(ctx): |
| return [ |
| ctx.attr.library_target[DefaultInfo], |
| ctx.attr.library_target[CcSharedLibraryInfo], |
| ctx.attr.stub_target[CcStubInfo], |
| ] |
| |
| _cc_stub_library_shared = rule( |
| implementation = _cc_stub_library_shared_impl, |
| doc = "Top level rule to merge CcStubInfo and CcSharedLibraryInfo into a single target", |
| attrs = { |
| "stub_target": attr.label(mandatory = True), |
| "library_target": attr.label(mandatory = True), |
| }, |
| ) |
| |
| def _swap_shared_linker_input(ctx, shared_info, new_output): |
| old_library_to_link = shared_info.linker_input.libraries[0] |
| |
| cc_toolchain = find_cpp_toolchain(ctx) |
| feature_configuration = cc_common.configure_features( |
| ctx = ctx, |
| cc_toolchain = cc_toolchain, |
| ) |
| |
| new_library_to_link = cc_common.create_library_to_link( |
| actions = ctx.actions, |
| dynamic_library = new_output, |
| feature_configuration = feature_configuration, |
| cc_toolchain = cc_toolchain, |
| ) |
| |
| new_linker_input = cc_common.create_linker_input( |
| owner = shared_info.linker_input.owner, |
| libraries = depset([new_library_to_link]), |
| ) |
| |
| return CcSharedLibraryInfo( |
| dynamic_deps = shared_info.dynamic_deps, |
| exports = shared_info.exports, |
| link_once_static_libs = shared_info.link_once_static_libs, |
| linker_input = new_linker_input, |
| preloaded_deps = shared_info.preloaded_deps, |
| ) |
| |
| CcStubLibrariesInfo = provider( |
| fields = { |
| "infos": "A list of dict, where each dict contains the CcStubInfo, CcSharedLibraryInfo and DefaultInfo of a version of a stub library.", |
| }, |
| ) |
| |
| def _cc_library_shared_proxy_impl(ctx): |
| root_files = ctx.attr.root[DefaultInfo].files.to_list() |
| shared_files = ctx.attr.shared[DefaultInfo].files.to_list() |
| |
| if len(shared_files) != 1: |
| fail("Expected only one shared library file") |
| |
| shared_lib = shared_files[0] |
| |
| ctx.actions.symlink( |
| output = ctx.outputs.output_file, |
| target_file = shared_lib, |
| ) |
| |
| files = root_files + [ctx.outputs.output_file, ctx.files.table_of_contents[0]] |
| |
| stub_library_infos = [] |
| for stub_library in ctx.attr.stub_shared_libraries: |
| providers = { |
| "CcStubInfo": stub_library[CcStubInfo], |
| "CcSharedLibraryInfo": stub_library[CcSharedLibraryInfo], |
| "DefaultInfo": stub_library[DefaultInfo], |
| } |
| stub_library_infos.append(providers) |
| |
| return [ |
| DefaultInfo( |
| files = depset(direct = files), |
| runfiles = ctx.runfiles(files = [ctx.outputs.output_file]), |
| ), |
| _swap_shared_linker_input(ctx, ctx.attr.shared[CcSharedLibraryInfo], ctx.outputs.output_file), |
| ctx.attr.table_of_contents[CcTocInfo], |
| # Propagate only includes from the root. Do not re-propagate linker inputs. |
| CcInfo(compilation_context = ctx.attr.root[CcInfo].compilation_context), |
| CcStubLibrariesInfo(infos = stub_library_infos), |
| ] |
| |
| _cc_library_shared_proxy = rule( |
| implementation = _cc_library_shared_proxy_impl, |
| attrs = { |
| "shared": attr.label(mandatory = True, providers = [CcSharedLibraryInfo]), |
| "root": attr.label(mandatory = True, providers = [CcInfo]), |
| "output_file": attr.output(mandatory = True), |
| "table_of_contents": attr.label( |
| mandatory = True, |
| # TODO(b/217908237): reenable allow_single_file |
| # allow_single_file = True, |
| providers = [CcTocInfo], |
| ), |
| "stub_shared_libraries": attr.label_list(providers = [CcStubInfo, CcSharedLibraryInfo]), |
| }, |
| fragments = ["cpp"], |
| toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], |
| ) |
| |
| def _bssl_hash_injection_impl(ctx): |
| if len(ctx.files.src) != 1: |
| fail("Expected only one shared library file") |
| |
| hashed_file = ctx.files.src[0] |
| if ctx.attr.inject_bssl_hash: |
| hashed_file = ctx.actions.declare_file("lib" + ctx.attr.name + ".so") |
| args = ctx.actions.args() |
| args.add_all(["-sha256"]) |
| args.add_all(["-in-object", ctx.files.src[0]]) |
| args.add_all(["-o", hashed_file]) |
| |
| ctx.actions.run( |
| inputs = ctx.files.src, |
| outputs = [hashed_file], |
| executable = ctx.executable._bssl_inject_hash, |
| arguments = [args], |
| tools = [ctx.executable._bssl_inject_hash], |
| mnemonic = "BsslInjectHash", |
| ) |
| |
| return [ |
| DefaultInfo(files = depset([hashed_file])), |
| ctx.attr.src[CcSharedLibraryInfo], |
| ] |
| |
| _bssl_hash_injection = rule( |
| implementation = _bssl_hash_injection_impl, |
| attrs = { |
| "src": attr.label( |
| mandatory = True, |
| # TODO(b/217908237): reenable allow_single_file |
| # allow_single_file = True, |
| providers = [CcSharedLibraryInfo] |
| ), |
| "inject_bssl_hash": attr.bool( |
| default = False, |
| doc = "Whether inject BSSL hash", |
| ), |
| "_bssl_inject_hash": attr.label( |
| cfg = "exec", |
| doc = "The BSSL hash injection tool.", |
| executable = True, |
| default = "//prebuilts/build-tools:linux-x86/bin/bssl_inject_hash", |
| allow_single_file = True, |
| ), |
| }, |
| ) |