blob: 5ed7a135224f13231a6a079cc4f4254d6c277554 [file] [log] [blame]
# Copyright 2021 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/components/fuchsia_component.gni")
import("//build/dist/distribution_manifest.gni")
import("//build/drivers/driver_manifest.gni")
import("//tools/cmc/build/cmc.gni")
# Defines a Fuchsia driver component.
# A driver component is a normal component that launches a driver.
# For more information on components see:
# https://fuchsia.dev/fuchsia-src/development/components/build
#
# At the moment this template will generate the Component Manifest
# at build time. If you'd like to write your own Component Manifest,
# simply use the fuchsia_component build template.
#
# The component manifest is automatically generated that points to the
# correct driver library and bind file. If 'deps' includes more than
# one driver library or more than one bind file, this will cause a build-time
# error.
#
# Parameters
#
# manifest (optional)
# The component manifest. If this and `cm_label` are not present then this target will
# generate a component manifest for the driver.
# Type: path
# cm_label (optional)
# A `fuchsia_component_manifest` target label. If this and `manifest` are not present then this
# target will generate a component manifest for the driver.
# Type: GN label, e.g. `:my_manifest`
# is_v1_driver (optional)
# If this is true then the driver is a v1 driver and it will be placed in a
# compatibility shim when running in a DFv2 environment.
# Type: bool
# Default: true
# fallback (optional)
# If this is true then the driver is a fallback driver.
# Type: bool
# Default: false
# colocate
# If this is true, the driver will be put in the same DriverHost as its parent if possible. This
# is advisory, and the driver manager may still put the driver in a separate DriverHost, for
# instance if the parent device has MUST_ISOLATE set. In DFv1, a driver is always colocated if
# the parent device is a composite; isolation may still be enforced by setting MUST_ISOLATE on
# the primary fragment of the composite.
# Type: boolean
# root_resource (optional)
# If this is true, the driver will be given access to the root resource.
# This only affects drivers with automatically generated manifests.
# Type: bool
# Default: false
# uses_profiles (optional)
# If this is true, the driver will be given access to the profile provider service.
# Type: bool
# Default: false
# uses_sysmem (optional)
# If this is true, the driver will be given access to sysmem.
# Type: bool
# Default: false
# uses_boot_args (optional)
# If this is true, the driver will be given access to boot arguments service.
# Type: bool
# Default: false
# default_dispatcher_opts (optional)
# If this is set, then the default dispatcher for the driver will be
# created with these options.
# Type: array of strings
# Default: []
# default_dispatcher_scheduler_role (optional)
# If this is set, then the default dispatcher for the driver will be
# created with this scheduler role.
# Type: string
# Default: ""
# info (mandatory for //src and //zircon)
# Name of the file containing the driver information file.
# Type: file
# device_categories (optional)
# The device categories this driver is for. (The values must be from FHCP.json)
# This is a requirement for certification of the driver.
# Type: array of scopes
# deps
# testonly
# visibility
template("fuchsia_driver_component") {
if (current_toolchain == default_toolchain) {
generate_manifest = true
if (defined(invoker.manifest) || defined(invoker.cm_label)) {
generate_manifest = false
}
assert(!(defined(invoker.manifest) && defined(invoker.cm_label)),
"`manifest` and `cm_label` cannot be defined simultaneously")
is_v1_driver = true
if (defined(invoker.is_v1_driver)) {
is_v1_driver = invoker.is_v1_driver
}
if (generate_manifest) {
distribution_manifest_target = "${target_name}_distribution_manifest"
distribution_manifest_file =
"${target_gen_dir}/${target_name}.distribution_manifest"
distribution_manifest(distribution_manifest_target) {
visibility = [ ":*" ]
forward_variables_from(invoker,
[
"deps",
"testonly",
])
outputs = [ "${distribution_manifest_file}" ]
}
manifest_target = "${target_name}_manifest"
manifest_path = "${target_gen_dir}/meta/${target_name}.cml"
fallback = false
if (defined(invoker.fallback)) {
fallback = invoker.fallback
}
action(manifest_target) {
visibility = [ ":*" ]
forward_variables_from(invoker, [ "testonly" ])
deps = [ ":${distribution_manifest_target}" ]
script = "//build/drivers/create_component_manifest.py"
inputs = [ distribution_manifest_file ]
outputs = [ manifest_path ]
args = [
"--distribution_manifest",
rebase_path(distribution_manifest_file, root_build_dir),
"--output",
rebase_path(outputs[0], root_build_dir),
]
if (is_v1_driver) {
args += [ "--is_v1" ]
}
if (fallback) {
args += [ "--fallback" ]
}
if (invoker.colocate) {
args += [ "--colocate" ]
}
if (defined(invoker.root_resource) && invoker.root_resource) {
args += [ "--root_resource" ]
}
if (defined(invoker.uses_profiles) && invoker.uses_profiles) {
args += [ "--profile_provider" ]
}
if (defined(invoker.uses_sysmem) && invoker.uses_sysmem) {
args += [ "--sysmem" ]
}
if (defined(invoker.uses_boot_args) && invoker.uses_boot_args) {
args += [ "--boot_args" ]
}
if (defined(invoker.device_categories)) {
path = "${target_gen_dir}/device_categories.json"
write_file(path, invoker.device_categories, "json")
args += [
"--device_categories_file",
rebase_path(path, root_build_dir),
]
inputs += [ path ]
}
# TODO(fxbug.dev/99310): set allow_sync_calls for v1 drivers
# if they did not specify any opts.
if (defined(invoker.default_dispatcher_opts)) {
args += [ "--default_dispatcher_opts" ]
args += invoker.default_dispatcher_opts
}
if (defined(invoker.default_dispatcher_scheduler_role)) {
args += [
"--default_dispatcher_scheduler_role",
invoker.default_dispatcher_scheduler_role,
]
}
}
full_manifest_target = "${target_name}_full_manifest"
cmc_merge(full_manifest_target) {
visibility = [ ":*" ]
forward_variables_from(invoker, [ "testonly" ])
output_name = invoker.target_name + ".cml"
deps = [ ":${manifest_target}" ]
sources = []
foreach(dep, deps) {
sources += get_target_outputs(dep)
}
}
}
driver_path =
get_path_info(get_path_info(invoker.target_name, "abspath"), "dir")
splitted_path = string_split(driver_path, "/")
base_folder = splitted_path[2] # after removing "//"
create_driver_doc = false
if (base_folder == "src" || base_folder == "zircon") {
# Public drivers (defined as drivers in //src and //zircon) must provide an 'info' field with
# a driver information file.
assert(defined(invoker.info), "Must include driver info")
create_driver_doc = true
} else {
# Ignore info assignment if present, e.g. from //tools templates.
if (defined(invoker.info)) {
not_needed(invoker, [ "info" ])
}
}
if (create_driver_doc) {
doc_output = "${target_gen_dir}/${target_name}-doc.json"
doc_target = "${target_name}-driver-info"
name = invoker.target_name
if (defined(invoker.component_name)) {
name = invoker.component_name
}
doc_input = invoker.info
action(doc_target) {
visibility = [ ":*" ]
forward_variables_from(invoker, [ "testonly" ])
script = "//build/drivers/create_driver_doc.py"
inputs = [
driver_path,
doc_input,
]
outputs = [ "${doc_output}" ]
args = [
"--name",
name,
"--driver_path",
driver_path,
"--doc_input",
rebase_path(doc_input, root_build_dir),
"--doc_output",
rebase_path(outputs[0], root_build_dir),
]
}
}
fuchsia_component(target_name) {
# TODO(fxbug.dev/80980): Remove check_includes = false.
if (!defined(invoker.cm_label)) {
check_includes = false
}
forward_variables_from(invoker,
[
"cm_label",
"component_name",
"deps",
"manifest",
"manifest_deps",
"restricted_features",
"testonly",
"visibility",
])
if (generate_manifest) {
if (!defined(manifest_deps)) {
manifest_deps = []
}
manifest_deps += [ ":${full_manifest_target}" ]
manifest = get_target_outputs(":${full_manifest_target}")
manifest = manifest[0]
if (!defined(restricted_features)) {
restricted_features = []
}
}
if (!defined(deps)) {
deps = []
}
if (create_driver_doc) {
deps += [ ":${doc_target}" ]
not_needed(invoker, [ ":${doc_target}" ])
}
if (is_v1_driver) {
deps += [ "//src/devices/misc/drivers/compat:driver" ]
}
metadata = {
# Used by the assert_driver_components template.
driver_component_barrier = []
if (create_driver_doc) {
# Used by the create_all_drivers_doc template.
fuchsia_driver_doc_file = [ doc_output ]
}
component_catalog = [
{
has_driver = true
label = get_label_info(":$target_name", "label_with_toolchain")
},
]
}
}
} else {
group(target_name) {
forward_variables_from(invoker, [ "testonly" ])
deps = [ ":$target_name($default_toolchain)" ]
}
not_needed(invoker, "*")
}
}