| # 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("configc.gni") |
| import("fidl_library.gni") |
| |
| # Defines a configuration value file for a Fuchsia component. |
| # |
| # A config value file is produced from a component manifest that contains a schema |
| # and a JSON5 file with concrete configuration values. |
| # |
| # For example, if a component manifest defines the `enable_foo` flag: |
| # |
| # ``` |
| # // ./meta/my_component.cml |
| # { |
| # // ... |
| # config: { |
| # enable_foo: { type: "bool" } |
| # } |
| # } |
| # ``` |
| # |
| # The definition file will need to contain an entry for it and any other fields |
| # in its manifest: |
| # |
| # ``` |
| # // ./config/my_component.json5 |
| # { |
| # enable_foo: true |
| # } |
| # ``` |
| # |
| # Building the config value file requires the compiled manifest: |
| # |
| # ``` |
| # # ./BUILD.gn |
| # fuchsia_component_manifest("my_component_manifest") { |
| # component = "my_component" |
| # manifest = "meta/my_component.cml" |
| # } |
| # |
| # fuchsia_component("my_component") { |
| # cm_label = ":my_component_manifest" |
| # deps = [ ... ] |
| # } |
| # |
| # fuchsia_structured_config_values("my_component_config") { |
| # cm_label = ":my_component_manifest" |
| # values = "config/my_component.json5" |
| # } |
| # ``` |
| # |
| # Finally, the package must include the value file alongside the manifest: |
| # |
| # ``` |
| # # ./BUILD.gn |
| # fuchsia_package("my_package") { |
| # deps = [ |
| # ":my_component", |
| # ":my_component_config", |
| # ] |
| # } |
| # ``` |
| # |
| # Parameters |
| # |
| # cm_label (required) |
| # The label of the fuchsia_component_manifest target for which the file will be generated. |
| # Type: GN label, e.g. `:my_component_manifest` |
| # |
| # values_source -or- values (required) |
| # values_source: The JSON5 file containing the concrete values for the generated file. |
| # values: A GN scope containing literal values for the generated file. |
| # TODO(https://fxbug.dev/87988) document this format properly. |
| # Type: path or scope |
| # |
| # data_deps (optional) |
| # deps (optional) |
| # testonly (optional) |
| # Standard GN meaning. |
| template("fuchsia_structured_config_values") { |
| assert( |
| defined(invoker.cm_label), |
| "must provide a component manifest label with a configuration declaration") |
| |
| _source_defined = defined(invoker.values_source) |
| _values_defined = defined(invoker.values) |
| assert( |
| (_source_defined || _values_defined) && |
| !(_source_defined && _values_defined), |
| "must provide either `values_source` (path to JSON5 file) or `values` (GN scope with literal values)") |
| |
| if (_values_defined) { |
| _generated_values_label = "${target_name}_generated_values" |
| _value_file_deps = [ ":$_generated_values_label" ] |
| _value_file = "$target_gen_dir/${target_name}_values_from_literal.json" |
| generated_file(_generated_values_label) { |
| output_conversion = "json" |
| contents = invoker.values |
| outputs = [ _value_file ] |
| } |
| } else { |
| _value_file_deps = [] |
| _value_file = invoker.values_source |
| } |
| |
| # make sure invoker.cm_label is in the same module, i.e. starts with ":". get_target_outputs depends on this condition |
| segments = string_split(invoker.cm_label, ":") |
| assert(segments[0] == "", "cm_label cannot be in a different module") |
| |
| # now we can call get_target_outputs without creating unactionable error messages |
| component_outputs = get_target_outputs(invoker.cm_label) |
| compiled_manifest = component_outputs[0] |
| |
| # compile the value file |
| cvf(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "data_deps", |
| "deps", |
| "testonly", |
| "visibility", |
| ]) |
| cm = compiled_manifest |
| value_file = _value_file |
| if (!defined(deps)) { |
| deps = [] |
| } |
| deps += [ "${invoker.cm_label}" ] + _value_file_deps |
| } |
| } |
| |
| # Defines a C++ configuration client library for a Fuchsia ELF component. |
| # |
| # A config client library is produced from a component manifest that contains a schema. |
| # |
| # For example, if a component manifest defines the `enable_foo` flag: |
| # |
| # ``` |
| # // ./meta/my_component.cml |
| # { |
| # // ... |
| # config: { |
| # enable_foo: { type: "bool" } |
| # } |
| # } |
| # ``` |
| # |
| # Building the config client library requires the compiled manifest: |
| # |
| # ``` |
| # # ./BUILD.gn |
| # fuchsia_component_manifest("my_component_manifest") { |
| # component = "my_component" |
| # manifest = "meta/my_component.cml" |
| # } |
| # |
| # fuchsia_component("my_component") { |
| # cm_label = ":my_component_manifest" |
| # deps = [ ... ] |
| # } |
| # |
| # fuchsia_structured_config_cpp_elf_lib("my_component_config_lib") { |
| # cm_label = ":my_component_manifest" |
| # } |
| # ``` |
| # |
| # Finally, a C++ binary can import this library for use |
| # |
| # ``` |
| # # ./BUILD.gn |
| # executable("my_binary") { |
| # ... |
| # deps = [ |
| # ":my_component_config_lib", |
| # ... |
| # ] |
| # } |
| # ``` |
| # |
| # And in my_binary source, it can be used like this |
| # |
| # ``` |
| # #include "path/to/target/dir/my_component_config_lib.h" |
| # |
| # int main(int argc, void** argv) { |
| # auto config = my_component_config_lib::Config::TakeFromStartupHandle(); |
| # DLOG(INFO) << "Is foo enabled = " << config.enable_foo(); |
| # } |
| # ``` |
| # |
| # Parameters |
| # |
| # cm_label (required) |
| # The label of the fuchsia_component_manifest target for which the file will be generated. |
| # Type: GN label, e.g. `:my_component_manifest` |
| # |
| # cpp_namespace (optional) |
| # Namespace used by the generated C++ library. If not specified, the target name is used. |
| # Type: string |
| # |
| # fidl_library_name (optional) |
| # Name for the generated FIDL library. If not specified, the default (cf.sc.internal) is used. |
| # Type: string |
| # |
| # testonly (optional) |
| # Standard GN meaning. |
| template("fuchsia_structured_config_cpp_elf_lib") { |
| if (!defined(invoker.cpp_namespace)) { |
| cpp_namespace = target_name |
| } else { |
| cpp_namespace = invoker.cpp_namespace |
| } |
| |
| # The library name is a string that is also used internally by configc when generating |
| # FIDL and C++ source files. It is not visible to the end user. |
| if (defined(invoker.fidl_library_name)) { |
| fidl_library_name = invoker.fidl_library_name |
| } else { |
| fidl_library_name = "cf.sc.internal" |
| } |
| |
| cpp_namespace = string_replace(cpp_namespace, ".", "_") |
| cpp_namespace = string_replace(cpp_namespace, "-", "_") |
| |
| fidl_source_target = "${target_name}_fidl_config_lib_source" |
| cpp_elf_source_target = "${target_name}_cpp_elf_config_lib_source" |
| |
| assert(defined(invoker.cm_label), "must provide a component manifest label") |
| |
| manifest_outputs = get_target_outputs(invoker.cm_label) |
| compiled_manifest = manifest_outputs[0] |
| |
| # generate the client library FIDL source |
| fidl_config_client_lib_source(fidl_source_target) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| name = fidl_library_name |
| compiled_manifest = compiled_manifest |
| deps = [ invoker.cm_label ] |
| } |
| |
| # generate the C++ source |
| cpp_config_client_lib_source(cpp_elf_source_target) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| namespace = cpp_namespace |
| fidl_library_name = fidl_library_name |
| compiled_manifest = compiled_manifest |
| flavor = "elf-hlcpp" |
| deps = [ invoker.cm_label ] |
| } |
| |
| # generate the FIDL library |
| fidl_library_target = "${target_name}_fidl_internal" |
| |
| fidl_library(fidl_library_target) { |
| library_name = fidl_library_name |
| forward_variables_from(invoker, [ "testonly" ]) |
| sources = get_target_outputs(":${fidl_source_target}") |
| non_fidl_deps = [ ":${fidl_source_target}" ] |
| } |
| |
| # generate the wrapper C++ library |
| source_set(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "visibility", |
| ]) |
| sources = get_target_outputs(":${cpp_elf_source_target}") |
| deps = [ |
| ":${fidl_library_target}", |
| "${fuchsia_sdk}/pkg/fidl", |
| "${fuchsia_sdk}/pkg/inspect_service_cpp", |
| ] |
| |
| public_deps = [ |
| ":${cpp_elf_source_target}($default_toolchain)", |
| "${fuchsia_sdk}/pkg/fidl", |
| "${fuchsia_sdk}/pkg/fidl_cpp", |
| "${fuchsia_sdk}/pkg/inspect_service_cpp", |
| ] |
| |
| # prevent manifest from getting into package this way |
| metadata = { |
| distribution_entries_barrier = [] |
| } |
| } |
| } |