unplugged-system/build/bazel/rules/cc/cc_stub_library.bzl

300 lines
12 KiB
Python
Raw Normal View History

# Copyright (C) 2022 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("//build/bazel/platforms:platform_utils.bzl", "platforms")
load("//build/bazel/rules/apis:api_surface.bzl", "MODULE_LIB_API")
load("//build/bazel/rules/common:api.bzl", "api")
load(":cc_library_headers.bzl", "cc_library_headers")
load(":cc_library_shared.bzl", "CcStubLibrariesInfo")
load(":cc_library_static.bzl", "cc_library_static")
load(":fdo_profile_transitions.bzl", "drop_fdo_profile_transition")
load(":generate_toc.bzl", "CcTocInfo", "generate_toc")
# This file contains the implementation for the cc_stub_library rule.
#
# TODO(b/207812332):
# - ndk_api_coverage_parser: https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/coverage.go;l=248-262;drc=master
CcStubInfo = provider(
fields = {
"stub_map": "The .map file containing library symbols for the specific API version.",
"version": "The API version of this library.",
"abi_symbol_list": "A plain-text list of all symbols of this library for the specific API version.",
},
)
def _cc_stub_gen_impl(ctx):
# The name of this target.
name = ctx.attr.name
# All declared outputs of ndkstubgen.
out_stub_c = ctx.actions.declare_file("/".join([name, "stub.c"]))
out_stub_map = ctx.actions.declare_file("/".join([name, "stub.map"]))
out_abi_symbol_list = ctx.actions.declare_file("/".join([name, "abi_symbol_list.txt"]))
outputs = [out_stub_c, out_stub_map, out_abi_symbol_list]
ndkstubgen_args = ctx.actions.args()
ndkstubgen_args.add_all(["--arch", platforms.get_target_arch(ctx.attr._platform_utils)])
ndkstubgen_args.add_all(["--api", ctx.attr.version])
ndkstubgen_args.add_all(["--api-map", ctx.file._api_levels_file])
# TODO(b/207812332): This always parses and builds the stub library as a dependency of an APEX. Parameterize this
# for non-APEX use cases.
ndkstubgen_args.add_all(["--systemapi", "--apex", ctx.file.symbol_file])
ndkstubgen_args.add_all(outputs)
ctx.actions.run(
executable = ctx.executable._ndkstubgen,
inputs = [
ctx.file.symbol_file,
ctx.file._api_levels_file,
],
outputs = outputs,
arguments = [ndkstubgen_args],
)
return [
# DefaultInfo.files contains the .stub.c file only so that this target
# can be used directly in the srcs of a cc_library.
DefaultInfo(files = depset([out_stub_c])),
CcStubInfo(
stub_map = out_stub_map,
abi_symbol_list = out_abi_symbol_list,
version = ctx.attr.version,
),
OutputGroupInfo(
stub_map = [out_stub_map],
),
]
cc_stub_gen = rule(
implementation = _cc_stub_gen_impl,
attrs = {
# Public attributes
"symbol_file": attr.label(mandatory = True, allow_single_file = [".map.txt"]),
"version": attr.string(mandatory = True, default = "current"),
# Private attributes
"_api_levels_file": attr.label(default = "@soong_injection//api_levels:api_levels.json", allow_single_file = True),
"_ndkstubgen": attr.label(default = "//build/soong/cc/ndkstubgen", executable = True, cfg = "exec"),
"_platform_utils": attr.label(default = Label("//build/bazel/platforms:platform_utils")),
},
)
CcStubLibrarySharedInfo = provider(
fields = {
"source_library_label": "The source library label of the cc_stub_library_shared",
},
)
# 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, export_includes, soname, source_library_label, deps, target_compatible_with, features, tags):
# 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,
tags = ["manual"],
)
# Disable coverage for stub libraries.
features = features + ["-coverage", "-link_crt"]
# 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
copts = ["-fno-builtin"], # ignore conflicts with builtin function signatures
features = [
# Don't link the C runtime
"-link_crt",
# 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 = [],
tags = ["manual"],
export_includes = export_includes,
# deps is used to export includes that specified using "header_libs" in Android.bp, e.g. "libc_headers".
deps = deps,
)
# Create a .so for the stub library. This library is self contained, has
# no deps, and doesn't link against crt.
if len(soname) == 0:
fail("For stub libraries 'soname' is mandatory and must be same as the soname of its source library.")
soname_flag = "-Wl,-soname," + soname
stub_map = name + "_stub_map"
native.filegroup(
name = stub_map,
srcs = [name + "_files"],
output_group = "stub_map",
tags = ["manual"],
)
version_script_flag = "-Wl,--version-script,$(location %s)" % stub_map
native.cc_shared_library(
name = name + "_so",
additional_linker_inputs = [stub_map],
user_link_flags = [soname_flag, version_script_flag],
roots = [name + "_root"],
features = features + ["-link_crt"],
target_compatible_with = target_compatible_with,
tags = ["manual"],
)
# Create a target with CcSharedLibraryInfo and CcStubInfo providers.
_cc_stub_library_shared(
name = name,
stub_target = name + "_files",
library_target = name + "_so",
root = name + "_root",
source_library_label = source_library_label,
version = version,
tags = tags,
)
def _cc_stub_library_shared_impl(ctx):
source_library_label = Label(ctx.attr.source_library_label)
api_level = str(api.parse_api_level_from_version(ctx.attr.version))
version_macro_name = "__" + source_library_label.name.upper() + "_API__=" + api_level
compilation_context = cc_common.create_compilation_context(
defines = depset([version_macro_name]),
)
cc_info = cc_common.merge_cc_infos(cc_infos = [
ctx.attr.root[CcInfo],
CcInfo(compilation_context = compilation_context),
])
toc_info = generate_toc(ctx, ctx.attr.name, ctx.attr.library_target.files.to_list()[0])
return [
ctx.attr.library_target[DefaultInfo],
ctx.attr.library_target[CcSharedLibraryInfo],
ctx.attr.stub_target[CcStubInfo],
toc_info,
cc_info,
CcStubLibrariesInfo(has_stubs = True),
OutputGroupInfo(rule_impl_debug_files = depset()),
CcStubLibrarySharedInfo(source_library_label = source_library_label),
]
_cc_stub_library_shared = rule(
implementation = _cc_stub_library_shared_impl,
doc = "Top level rule to merge CcStubInfo and CcSharedLibraryInfo into a single target",
# Incoming transition to reset //command_line_option:fdo_profile to None
# to converge the configurations of the stub targets
cfg = drop_fdo_profile_transition,
attrs = {
"stub_target": attr.label(
providers = [CcStubInfo],
mandatory = True,
),
"library_target": attr.label(
providers = [CcSharedLibraryInfo],
mandatory = True,
),
"root": attr.label(
providers = [CcInfo],
mandatory = True,
),
"source_library_label": attr.string(mandatory = True),
"version": attr.string(mandatory = True),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
"_toc_script": attr.label(
cfg = "exec",
executable = True,
allow_single_file = True,
default = "//build/soong/scripts:toc.sh",
),
"_readelf": attr.label(
cfg = "exec",
executable = True,
allow_single_file = True,
default = "//prebuilts/clang/host/linux-x86:llvm-readelf",
),
},
provides = [
CcSharedLibraryInfo,
CcTocInfo,
CcInfo,
CcStubInfo,
CcStubLibrariesInfo,
CcStubLibrarySharedInfo,
],
)
def cc_stub_suite(
name,
source_library_label,
versions,
symbol_file,
export_includes = [],
soname = "",
deps = [],
data = [], # @unused
target_compatible_with = [],
features = [],
tags = ["manual"]):
# Implicitly add "current" to versions. This copies the behavior from Soong (aosp/1641782)
if "current" not in versions:
versions.append("current")
for version in versions:
cc_stub_library_shared(
# Use - as the seperator of name and version. "current" might be the version of some libraries.
name = name + "-" + version,
version = version,
stubs_symbol_file = symbol_file,
export_includes = export_includes,
soname = soname,
source_library_label = str(native.package_relative_label(source_library_label)),
deps = deps,
target_compatible_with = target_compatible_with,
features = features,
tags = tags,
)
# Create a header library target for this API surface (ModuleLibApi)
# The external @api_surfaces repository will contain an alias to this header library.
cc_library_headers(
name = "%s_%s_headers" % (name, MODULE_LIB_API),
export_includes = export_includes,
deps = deps, # Necessary for exporting headers that might exist in a different directory (e.g. libEGL)
)
native.alias(
# Use _ as the seperator of name and version in alias. So there is no
# duplicated name if "current" is one of the versions of a library.
name = name + "_current",
actual = name + "-" + "current",
tags = tags,
)