blob: 6dd94ff35f20cf174a8fa07c29976b48c513ac09 [file] [log] [blame]
# Copyright 2022 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/compiled_action.gni")
import("//build/python/python_action.gni")
import("//build/rust/rustc_library.gni")
# Helper template to run the aidl compiler.
#
# Parameters
#
# base (base or bases is required)
# Base path for the library
#
# bases (base or bases is required)
# Base paths for the library
#
# outputs (required)
# Outputs of the generator
#
# args (required)
# Additional arguments
#
# parcelables (optional)
# List of the sources of the parcelables defined by the library
#
# interfaces (optional)
# List of the sources of the interfaces defined by the library
#
# deps (optional)
# AIDL dependencies
#
# stability (optional)
# The stability requirement of this interface.
#
# structured (optional, defaults to true)
# Whether to use structured AIDL.
#
# version (optional, if stability is not defined, mandatory otherwise)
# Which stable version; this being set also causes getInterfaceVersion code
# to be generated.
#
template("_aidl_gen") {
assert(!defined(invoker.stability) || defined(invoker.version),
"version must be defined when stability is defined")
aidl_sources = []
if (defined(invoker.parcelables)) {
aidl_sources += invoker.parcelables
}
if (defined(invoker.interfaces)) {
aidl_sources += invoker.interfaces
}
action_sources = aidl_sources
action_inputs = []
bases = []
if (defined(invoker.bases)) {
bases = invoker.bases
}
if (defined(invoker.base)) {
bases += [ invoker.base ]
}
dependency_dir = "$target_gen_dir/$target_name"
aidl_sources_file = "$dependency_dir/aidl_sources"
meta_files = [
"aidl_package",
"aidl_bases",
"aidl_rust_glue_args",
]
write_file(aidl_sources_file, rebase_path(aidl_sources, root_build_dir))
action_inputs += [ aidl_sources_file ]
aidl_gen_target = "//src/lib/android/aidl:aidl_gen($host_toolchain)"
aidl_gen_output_name = get_label_info(aidl_gen_target, "name")
aidl_gen_output_dir = get_label_info(aidl_gen_target, "root_out_dir")
aidl_gen_executable = "$aidl_gen_output_dir/$aidl_gen_output_name"
action_inputs += [ aidl_gen_executable ]
raw_args = invoker.args
raw_args += [ "--min_sdk_version=31" ]
if (defined(invoker.stability)) {
raw_args += [ "--stability=${invoker.stability}" ]
}
if (!defined(invoker.structured) || invoker.structured) {
raw_args += [ "--structured" ]
}
action_args = [
"--aidl-path",
rebase_path(aidl_gen_executable, root_build_dir),
"--dependency-dir",
rebase_path(dependency_dir, root_build_dir),
"--inputs-path",
rebase_path(aidl_sources_file, root_build_dir),
]
# The --version argument is necessary to generate getInterfaceVersion() and
# getInterfaceHash() code.
if (defined(invoker.version)) {
action_args += [
"--version",
"${invoker.version}",
]
}
foreach(base, bases) {
action_args += [
"--base",
rebase_path(base, root_build_dir),
]
if (defined(invoker.version)) {
action_inputs += [ "$base/.hash" ]
}
}
action_deps = [ aidl_gen_target ]
if (defined(invoker.deps)) {
foreach(dep, invoker.deps) {
dep_gen_dir = get_label_info(dep, "target_gen_dir")
dep_dir = get_label_info(dep, "dir")
dep_name = get_label_info(dep, "name")
dep_dep_dir = "$dep_gen_dir/${dep_name}_aidl"
foreach(meta_file, meta_files) {
action_inputs += [ "$dep_dep_dir/$meta_file" ]
}
action_args += [
"--deps",
rebase_path(dep_dep_dir, root_build_dir),
]
action_deps += [ "$dep_dir:${dep_name}_aidl" ]
}
}
foreach(arg, raw_args) {
action_args += [
"--args",
arg,
]
}
compiled_action(target_name) {
deps = action_deps
if (defined(invoker.deps)) {
deps += invoker.deps
}
tool = "//src/lib/android/aidl:aidl_wrapper"
inputs = action_inputs
sources = action_sources
outputs = invoker.outputs
foreach(meta_file, meta_files) {
outputs += [ "$dependency_dir/$meta_file" ]
}
args = action_args
depfile = "$dependency_dir/deps.d"
}
}
# Generate AIDL binding for C++ using the ndk backend
#
# Parameters
#
# base (base or bases is required)
# Base path for the library.
# The last path component usually ends in a number, representing the
# version of the AIDL library.
#
# bases (base or bases is required)
# Base paths for the library.
# The last path component usually ends in a number, representing the
# version of the AIDL library.
#
# parcelables (optional)
# List of the sources of the parcelables defined by the library.
# Their directory relative to the base path should correspond to the
# AIDL package name, e.g. "android/hardware/health".
#
# interfaces (optional)
# List of the sources of the interfaces defined by the library.
# Their directory relative to the base path should correspond to the
# AIDL package name, e.g. "android/hardware/health".
#
# deps (optional)
# AIDL dependencies
#
# stability (optional)
# The stability requirement of this interface.
#
# structured (optional)
# Whether to use structured AIDL.
#
# version (optional)
# Which stable version; this being set also causes getInterfaceVersion code
# to be generated.
template("aidl_ndk") {
main_target_name = target_name
cpp_aidl_gen_dir = "$target_gen_dir/${main_target_name}_aidl"
aidl_cpp_outputs = []
if (defined(invoker.parcelables)) {
foreach(parcelable, invoker.parcelables) {
relative_path = rebase_path(parcelable, invoker.base)
object_name = get_path_info(relative_path, "name")
sub_directory = get_path_info(relative_path, "dir")
aidl_cpp_outputs += [
"$cpp_aidl_gen_dir/include/aidl/${sub_directory}/${object_name}.h",
"$cpp_aidl_gen_dir/include/aidl/${sub_directory}/Bn${object_name}.h",
"$cpp_aidl_gen_dir/include/aidl/${sub_directory}/Bp${object_name}.h",
"$cpp_aidl_gen_dir/src/${sub_directory}/${object_name}.cpp",
]
}
}
if (defined(invoker.interfaces)) {
foreach(interface, invoker.interfaces) {
relative_path = rebase_path(interface, invoker.base)
service = string_replace(get_path_info(relative_path, "name"), "I", "", 1)
sub_directory = get_path_info(relative_path, "dir")
aidl_cpp_outputs += [
"$cpp_aidl_gen_dir/include/aidl/${sub_directory}/I${service}.h",
"$cpp_aidl_gen_dir/include/aidl/${sub_directory}/Bn${service}.h",
"$cpp_aidl_gen_dir/include/aidl/${sub_directory}/Bp${service}.h",
"$cpp_aidl_gen_dir/src/${sub_directory}/I${service}.cpp",
]
}
}
aidl_args = [
"--lang=ndk",
"-o",
rebase_path("$cpp_aidl_gen_dir/src", root_build_dir),
"-h",
rebase_path("$cpp_aidl_gen_dir/include", root_build_dir),
]
_aidl_gen("${main_target_name}_aidl") {
forward_variables_from(invoker,
[
"base",
"bases",
"parcelables",
"interfaces",
"deps",
"stability",
"structured",
"version",
])
args = aidl_args
outputs = aidl_cpp_outputs
}
config("${main_target_name}_include") {
include_dirs = [ "$cpp_aidl_gen_dir/include" ]
defines = [ "BINDER_STABILITY_SUPPORT" ]
}
source_set(main_target_name) {
sources = aidl_cpp_outputs
deps = [ ":${main_target_name}_aidl" ]
# TODO: Remove this once https://issuetracker.google.com/153746485 is fixed.
configs += [ "//build/config:Wno-deprecated-anon-enum-enum-conversion" ]
public_deps = [
"//src/lib/android/binder",
"//src/lib/android/core",
"//src/lib/android/libbase",
]
if (defined(invoker.deps)) {
public_deps += invoker.deps
}
public_configs = [ ":${main_target_name}_include" ]
}
}
# Generate AIDL binding for C++ using the cpp backend
#
# Parameters
#
# base (base or bases is required)
# Base path for the library.
# The last path component usually ends in a number, representing the
# version of the AIDL library.
#
# bases (base or bases is required)
# Base paths for the library.
# The last path component usually ends in a number, representing the
# version of the AIDL library.
#
# parcelables (optional)
# List of the sources of the parcelables defined by the library
# Their directory relative to the base path should correspond to the
# AIDL package name, e.g. "android/hardware/health".
#
# interfaces (optional)
# List of the sources of the interfaces defined by the library
# Their directory relative to the base path should correspond to the
# AIDL package name, e.g. "android/hardware/health".
#
# deps (optional)
# AIDL dependencies
#
# stability (optional)
# The stability requirement of this interface.
#
# structured (optional)
# Whether to use structured AIDL.
#
# version (optional)
# Which stable version; this being set also causes getInterfaceVersion code
# to be generated.
#
# is_bootstrap (optional)
# Whether this is a bootstrap library, needed for building the aidl runtime
# library. In that case, no code is compiled, and the user is expected to
# include the generated code in the support library itself.
template("aidl_cpp") {
main_target_name = target_name
cpp_aidl_gen_dir = "$target_gen_dir/${main_target_name}_aidl"
aidl_cpp_outputs = []
if (defined(invoker.parcelables)) {
foreach(parcelable, invoker.parcelables) {
relative_path = rebase_path(parcelable, invoker.base)
object_name = get_path_info(relative_path, "name")
sub_directory = get_path_info(relative_path, "dir")
aidl_cpp_outputs += [
"$cpp_aidl_gen_dir/include/${sub_directory}/${object_name}.h",
"$cpp_aidl_gen_dir/include/${sub_directory}/Bn${object_name}.h",
"$cpp_aidl_gen_dir/include/${sub_directory}/Bp${object_name}.h",
"$cpp_aidl_gen_dir/src/${sub_directory}/${object_name}.cpp",
]
}
}
if (defined(invoker.interfaces)) {
foreach(interface, invoker.interfaces) {
relative_path = rebase_path(interface, invoker.base)
service = string_replace(get_path_info(relative_path, "name"), "I", "", 1)
sub_directory = get_path_info(relative_path, "dir")
aidl_cpp_outputs += [
"$cpp_aidl_gen_dir/include/${sub_directory}/I${service}.h",
"$cpp_aidl_gen_dir/include/${sub_directory}/Bn${service}.h",
"$cpp_aidl_gen_dir/include/${sub_directory}/Bp${service}.h",
"$cpp_aidl_gen_dir/src/${sub_directory}/I${service}.cpp",
]
}
}
aidl_args = [
"--lang=cpp",
"-o",
rebase_path("$cpp_aidl_gen_dir/src", root_build_dir),
"-h",
rebase_path("$cpp_aidl_gen_dir/include", root_build_dir),
]
_aidl_gen("${main_target_name}_aidl") {
forward_variables_from(invoker,
[
"base",
"bases",
"parcelables",
"interfaces",
"deps",
"stability",
"structured",
"version",
])
args = aidl_args
outputs = aidl_cpp_outputs
}
config("${main_target_name}_include") {
include_dirs = [ "$cpp_aidl_gen_dir/include" ]
}
if (defined(invoker.is_bootstrap) && invoker.is_bootstrap) {
group(main_target_name) {
public_deps = [ ":${main_target_name}_aidl" ]
}
} else {
source_set(main_target_name) {
sources = aidl_cpp_outputs
deps = [ ":${main_target_name}_aidl" ]
# TODO: Remove this once https://issuetracker.google.com/153746485 is fixed.
configs += [ "//build/config:Wno-deprecated-anon-enum-enum-conversion" ]
public_deps = [
"//src/lib/android/binder",
"//src/lib/android/core",
"//src/lib/android/libbase",
]
if (defined(invoker.deps)) {
public_deps += invoker.deps
}
public_configs = [ ":${main_target_name}_include" ]
}
}
}
# Generate AIDL binding for Rust
#
# Parameters
#
# base (base or bases is required)
# Base path for the library.
# The last path component usually ends in a number, representing the
# version of the AIDL library.
#
# bases (base or bases is required)
# Base paths for the library.
# The last path component usually ends in a number, representing the
# version of the AIDL library.
#
# parcelables (optional)
# List of the sources of the parcelables defined by the library.
# Their directory relative to the base path should correspond to the
# AIDL package name, e.g. "android/hardware/health".
#
# interfaces (optional)
# List of the sources of the interfaces defined by the library.
# Their directory relative to the base path should correspond to the
# AIDL package name, e.g. "android/hardware/health".
#
# deps (optional)
# AIDL dependencies
#
# stability (optional)
# The stability requirement of this interface.
#
# structured (optional)
# Whether to use structured AIDL.
#
# version (optional)
# Which stable version; this being set also causes getInterfaceVersion code
# to be generated.
#
# rust_crate_name (optional)
# Name of the generated Rust crate. If not set, derived from the directory path
# relative to the base.
template("aidl_rust") {
main_target_name = target_name
rust_aidl_gen_dir = "$target_gen_dir/${main_target_name}_aidl"
rust_glue_args =
"$target_gen_dir/${main_target_name}_aidl/aidl_rust_glue_args_main"
rust_glue_include_args =
"$target_gen_dir/${main_target_name}_aidl/aidl_rust_glue_args"
objects = []
if (defined(invoker.parcelables)) {
objects += invoker.parcelables
}
if (defined(invoker.interfaces)) {
objects += invoker.interfaces
}
package = ""
aidl_rust_outputs = []
invoker_bases = []
if (defined(invoker.bases)) {
invoker_bases = invoker.bases
}
if (defined(invoker.base)) {
invoker_bases += [ invoker.base ]
}
foreach(object, objects) {
foreach(base, invoker_bases) {
# Check whether the object is relative to base
split = []
split = string_split(string_replace(object, base, "_MARKER_ "))
if (split[0] == "_MARKER_") {
relative_path = rebase_path(object, base)
object_name = get_path_info(relative_path, "name")
sub_directory = get_path_info(relative_path, "dir")
if (package == "" ||
string_replace(package, sub_directory, "", 1) != "") {
package = sub_directory
}
aidl_rust_outputs +=
[ "$rust_aidl_gen_dir/${sub_directory}/${object_name}.rs" ]
}
}
}
name = ""
if (defined(invoker.rust_crate_name)) {
name = invoker.rust_crate_name
} else if (package == "." || package == "") {
message = "Failed to infer AIDL package name. The base path may not be set correctly. "
message += "The `.aidl` files should be located under a path like "
message += "\${base}/my/package/name/SomeFile.aidl."
assert(package != "." && package != "", message)
} else {
name = string_replace(package, "/", "_")
}
aidl_args = [
"--lang=rust",
"-o",
rebase_path(rust_aidl_gen_dir, root_build_dir),
]
_aidl_gen("${main_target_name}_aidl") {
forward_variables_from(invoker,
[
"base",
"bases",
"parcelables",
"interfaces",
"deps",
"stability",
"structured",
"version",
])
args = aidl_args
outputs = aidl_rust_outputs
}
root_rust_file = "$target_gen_dir/${main_target_name}_aidl_rust_glue.rs"
write_file(rust_glue_args, rebase_path(aidl_rust_outputs, root_build_dir))
python_action("${main_target_name}_aidl_rust_glue") {
binary_label = "//src/lib/android/aidl:aidl_rust_glue"
deps = [ ":${main_target_name}_aidl" ]
sources = aidl_rust_outputs + [
rust_glue_args,
rust_glue_include_args,
]
outputs = [ root_rust_file ]
args = [
rebase_path(root_rust_file, root_build_dir),
rebase_path(rust_aidl_gen_dir, root_build_dir),
"@" + rebase_path(rust_glue_args, root_build_dir),
"@" + rebase_path(rust_glue_include_args, root_build_dir),
]
}
rustc_library(main_target_name) {
edition = "2018"
sources = [ root_rust_file ]
name = name
deps = [
":${main_target_name}_aidl_rust_glue",
"//src/lib/android/binder/rust:binder",
"//third_party/rust_crates:async-trait",
"//third_party/rust_crates:static_assertions",
]
if (defined(invoker.deps)) {
deps += invoker.deps
}
source_root = root_rust_file
configs += [ "//src/lib/android:android_aidl_rust_config" ]
disable_clippy = true
}
}
# Generate AIDL bindings
#
# Parameters
#
# base (base or bases is required)
# Base path for the library.
# The last path component usually ends in a number, representing the
# version of the AIDL library.
#
# bases (base or bases is required)
# Base paths for the library.
# The last path component usually ends in a number, representing the
# version of the AIDL library.
#
# parcelables (optional)
# List of the sources of the parcelables defined by the library.
# Their directory relative to the base path should correspond to the
# AIDL package name, e.g. "android/hardware/health".
#
# interfaces (optional)
# List of the sources of the interfaces defined by the library.
# Their directory relative to the base path should correspond to the
# AIDL package name, e.g. "android/hardware/health".
#
# deps (optional)
# AIDL dependencies
#
# backends (optional)
# List of backends to generate bindings for. If not present, all backends are generated.
#
# stability (optional)
# The stability requirement of this interface.
#
# structured (optional)
# Whether to use structured AIDL.
#
# version (optional)
# Which stable version; this being set also causes getInterfaceVersion code
# to be generated.
#
# rust_crate_name (optional)
# Name of the generated Rust crate. If not set, derived from the directory path
# relative to the base. Only relevant for the "rust" backend.
template("aidl") {
if (defined(invoker.backends)) {
backends = invoker.backends
} else {
backends = [
"cpp",
"rust",
"ndk",
]
}
foreach(backend, backends) {
backend_target_name = "${target_name}_${backend}"
target("aidl_${backend}", backend_target_name) {
forward_variables_from(invoker,
"*",
[
"backends",
"deps",
"rust_crate_name",
])
deps = []
if (defined(invoker.deps)) {
foreach(dep, invoker.deps) {
dep_dir = get_label_info(dep, "dir")
dep_name = get_label_info(dep, "name")
deps += [ "$dep_dir:${dep_name}_${backend}" ]
}
}
if (backend == "rust" && defined(invoker.rust_crate_name)) {
rust_crate_name = invoker.rust_crate_name
}
}
}
}