300 lines
12 KiB
Python
300 lines
12 KiB
Python
|
|
# 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,
|
||
|
|
)
|