| # Copyright 2020 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/dist/resource.gni") |
| import("//tools/cmc/build/cmc.gni") |
| import("//tools/cmc/build/cml.gni") |
| import("//tools/cmc/build/cmx.gni") |
| |
| # Defines a Fuchsia component's manifest. |
| # See: https://fuchsia.dev/fuchsia-src/development/components/build |
| # |
| # Parameters |
| # |
| # manifest (required) |
| # The component manifest. |
| # Type: path |
| # |
| # component_name (optional) |
| # The name of the component. |
| # Type: string |
| # Default: target_name |
| # |
| # check_includes (optional) |
| # Check against expect_includes() in deps. |
| # Warning: Do not disable this unless there is a good, documented reason. |
| # Type: boolean |
| # Default: true |
| # |
| # restricted_features (optional) |
| # The set of restricted CML features to allow. Only applicable to v2 components. |
| # The set of features is allowlisted here: //tools/cmc/build/restricted_features/BUILD.gn |
| # where each feature name is represented by a group of the same name. |
| # Type: list of strings |
| # Default: [] |
| # |
| # experimental_force_runner (optional) |
| # Set the --experimental-force-runner flag to the given value. |
| # This flag is experimental and may be removed without warning. |
| # Type: string |
| # |
| # data_deps |
| # deps |
| # testonly |
| # visibility |
| template("fuchsia_component_manifest") { |
| if (current_toolchain == default_toolchain) { |
| assert( |
| defined(invoker.manifest), |
| "A `manifest` argument was missing when calling fuchsia_component_manifest($target_name)") |
| |
| component_name = target_name |
| if (defined(invoker.component_name)) { |
| component_name = invoker.component_name |
| } |
| |
| # Handle different manifest versions |
| manifest_extension = get_path_info(invoker.manifest, "extension") |
| if (manifest_extension == "cml") { |
| manifest_processor = "cm" |
| manifest_name = "$component_name.cm" |
| } else if (manifest_extension == "cmx") { |
| manifest_processor = "cmx" |
| manifest_name = "$component_name.cmx" |
| } else { |
| assert( |
| false, |
| "Unknown manifest format for \"${invoker.manifest}\", must be \".cml\" or \".cmx\"") |
| } |
| |
| manifest_resource_target = "${target_name}_manifest_resource" |
| |
| # Process the manifest |
| target(manifest_processor, target_name) { |
| output_name = "$manifest_extension/$target_name/$manifest_name" |
| forward_variables_from(invoker, |
| [ |
| "deps", |
| "manifest", |
| "metadata", |
| "restricted_features", |
| "check_includes", |
| "testonly", |
| "visibility", |
| "experimental_force_runner", |
| ]) |
| |
| if (!defined(deps)) { |
| deps = [] |
| } |
| deps += [ ":$manifest_resource_target" ] |
| |
| if (manifest_extension == "cml") { |
| # NOTE: must be kept in sync with path in fuchsia_structured_config.gni |
| config_values_package_path = "meta/$component_name.cvf" |
| } |
| } |
| |
| # Add the manifest |
| resource(manifest_resource_target) { |
| forward_variables_from(invoker, [ "data_deps" ]) |
| sources = get_target_outputs(":${invoker.target_name}") |
| outputs = [ "meta/$manifest_name" ] |
| visibility = [ ":*" ] |
| } |
| } else { |
| group(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "visibility", |
| ]) |
| deps = [ ":$target_name($default_toolchain)" ] |
| } |
| not_needed(invoker, "*") |
| } |
| } |
| |
| # Defines a Fuchsia component. |
| # See: https://fuchsia.dev/fuchsia-src/development/components/build |
| # |
| # A component is defined by a component manifest. |
| # Component manifests typically reference files in the package that they are |
| # distributed in. Therefore a component can also have dependencies on |
| # `resource()`, such that any package that depends on the component # will |
| # also include that resource. |
| # |
| # A component is launched by a URL. |
| # See: https://fuchsia.dev/fuchsia-src/glossary#component_url |
| # |
| # A component's URL is a function of the name of a package that includes it, |
| # and the path within that package to the component's manifest. For instance if |
| # you defined the following: |
| # ``` |
| # executable("my_program") { |
| # ... |
| # } |
| # |
| # fuchsia_component("my-component") { |
| # manifest = "manifest.cml" |
| # deps = [ ":my_program" ] |
| # } |
| # |
| # fuchsia_package("my-package") { |
| # deps = [ ":my-component" ] |
| # } |
| # ``` |
| # The component above will have the following launch URL: |
| # `fuchsia-pkg://fuchsia.com/my-package#meta/my-component.cm` |
| # |
| # Since the component depends on the executable target, the binary produced by |
| # the executable will be packaged with the manifest. Therefore the manifest |
| # author can reference the path `bin/my_program`. |
| # |
| # Components may depend on any number of `resource()` targets to ensure that |
| # any `fuchsia_package()` that includes them will include the same resources. |
| # |
| # ``` |
| # resource("my_file") { |
| # sources = [ "my_file.txt" ] |
| # outputs = [ "data/{{source_file_part}}" ] |
| # } |
| # |
| # fuchsia_component("my-component") { |
| # deps = [ ":my_file" ] |
| # ... |
| # } |
| # ``` |
| # |
| # The component defined above will be able to read my_file.txt under the path |
| # "/pkg/data/my_file.txt" in its sandbox. |
| # |
| # Parameters |
| # |
| # manifest (required) |
| # The component manifest. |
| # Type: path |
| # |
| # component_name (optional) |
| # The name of the component. |
| # Type: string |
| # Default: target_name |
| # |
| # check_includes (optional) |
| # Check against expect_includes() in deps. |
| # Warning: Do not disable this unless there is a good, documented reason. |
| # Type: boolean |
| # Default: true |
| # |
| # check_references (optional) |
| # Check component manifest references (e.g. "program.binary") against |
| # package manifest. |
| # Type: boolean |
| # Default: true |
| # |
| # restricted_features (optional) |
| # The set of restricted CML features to allow. Only applicable to v2 components. |
| # The set of features is allowlisted here: //tools/cmc/build/restricted_features/BUILD.gn |
| # where each feature name is represented by a group of the same name. |
| # Type: list of strings |
| # Default: [] |
| # |
| # experimental_force_runner (optional) |
| # Set the --experimental-force-runner flag to the given value. |
| # This flag is experimental and may be removed without warning. |
| # Type: string |
| # |
| # cm_label (optional) |
| # Use label of a fuchsia_component_manifest target instead of supplying the manifest source. |
| # Type: string, GN label e.g. `:my-manifest` |
| # |
| # manifest_deps (optional) |
| # Dependencies for the component's manifest, in case it is generated by another target. |
| # Type: list of targets |
| # |
| # data_deps |
| # deps |
| # testonly |
| # visibility |
| template("fuchsia_component") { |
| if (current_toolchain == default_toolchain) { |
| _manifest_defined = defined(invoker.manifest) |
| _cm_label_defined = defined(invoker.cm_label) |
| assert( |
| (_manifest_defined && !_cm_label_defined) || |
| (!_manifest_defined && _cm_label_defined), |
| "Exactly one of `manifest` or `cm_label` argument must be specified when calling fuchsia_component($target_name)") |
| |
| if (defined(invoker.manifest)) { |
| # Compile the manifest from source |
| cm_target = "${target_name}_manifest_compile" |
| fuchsia_component_manifest(cm_target) { |
| forward_variables_from(invoker, |
| [ |
| "data_deps", |
| "deps", |
| "component_name", |
| "manifest", |
| "metadata", |
| "restricted_features", |
| "check_includes", |
| "testonly", |
| "visibility", |
| "experimental_force_runner", |
| ]) |
| if (!defined(component_name)) { |
| component_name = invoker.target_name |
| } |
| if (defined(invoker.manifest_deps)) { |
| if (!defined(deps)) { |
| deps = [] |
| } |
| deps += invoker.manifest_deps |
| } |
| } |
| cm_label = ":$cm_target" |
| } else { |
| cm_label = invoker.cm_label |
| } |
| |
| # Check that the files the manifest references are going to be packaged |
| check_references = true |
| if (defined(invoker.check_references)) { |
| check_references = invoker.check_references |
| } |
| |
| if (check_references) { |
| # Get the compiled manifest path |
| manifest_outputs = get_target_outputs(cm_label) |
| compiled_manifest = manifest_outputs[0] |
| |
| validate_target = "${target_name}_cmc_validate_references" |
| |
| cmc_validate_references(validate_target) { |
| forward_variables_from(invoker, |
| [ |
| "deps", |
| "testonly", |
| ]) |
| if (!defined(deps)) { |
| deps = [] |
| } |
| deps += [ cm_label ] |
| visibility = [ ":*" ] |
| component_manifest = compiled_manifest |
| label = get_label_info(":$target_name", "label_with_toolchain") |
| } |
| |
| validate_target = ":$validate_target" |
| } |
| |
| # We want to adopt the outputs of the cm_label, so we |
| # copy them to a new directory. |
| copy(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "data_deps", |
| "deps", |
| "testonly", |
| ]) |
| sources = get_target_outputs(cm_label) |
| outputs = [ "$target_out_dir/${target_name}_component_manifest/{{source_file_part}}" ] |
| |
| if (!defined(deps)) { |
| deps = [] |
| } |
| |
| deps += [ cm_label ] |
| |
| if (check_references) { |
| deps += [ validate_target ] |
| } |
| |
| metadata = { |
| if (defined(invoker.metadata)) { |
| forward_variables_from(invoker.metadata, "*") |
| } |
| |
| test_component_manifest_program_barrier = [] |
| test_component_manifest_barrier = [] |
| |
| # Don't collect expected includes via transitive deps of components |
| expect_includes_barrier = [] |
| } |
| } |
| } else { |
| group(target_name) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| deps = [ ":$target_name($default_toolchain)" ] |
| } |
| not_needed(invoker, "*") |
| } |
| } |