Commit 8f244ddf authored by Ken Rockot's avatar Ken Rockot Committed by Commit Bot

[SM] Generate C++ sources for all manifest targets

Changes the service_manifest target to emit C++ sources for that
specific Manifest definition. Previously we only generated sources
for catalog_cpp_source targets, which aggregated JSON data from
multiple service_manifest targets.

Every service_manifest GN template thus now emits two artifacts:
the same collated JSON as before (including packaged services and
overlays), since embedders use this to generate runtime
manifest resources; and a new source_set target which expresses the
same manifest in terms of C++ sources, with proper dependencies
on each dependency manifest's source_set.

The point of this is to make it possible for incremental migration away
from generated code and over to code that lives in the source tree.
For example, many implementations of ContentBrowserClient override
GetServiceManifestOverlay() and use parsed JSON resources at runtime
to construct a Manifest object. After this change, any of those
cases can be individually converted to use the generated source_set
instead of the generated JSON, and the JSON resource can be deleted.

Once this lands, catalog targets can also be eliminated and replaced by
helpers in the tree which return the same lists of manifests that the
catalog-generated code returns now. Finally, after all that, remaining
service manifests can be (mostly) independently pulled out of generated
code. The end result will be: no more JSON manifests anywhere, no more
catalog() or catalog_cpp_source() GN targets, and no more
service_manifest() GN targets.

TBR=sky@chromium.org

Bug: 895616
Change-Id: Ie3d53a96ac79952383e473f23d390583306be2fa
Reviewed-on: https://chromium-review.googlesource.com/c/1388158
Commit-Queue: Ken Rockot <rockot@google.com>
Reviewed-by: default avatarKen Rockot <rockot@google.com>
Reviewed-by: default avatarOksana Zhuravlova <oksamyt@chromium.org>
Reviewed-by: default avatarDirk Pranke <dpranke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#618718}
parent d9b0450c
......@@ -1184,10 +1184,7 @@ if (!is_ios && !is_android && !is_chromecast && !is_fuchsia) {
]
}
if (enable_ipc_fuzzer && !is_component_build) {
deps += [
"//chrome/app:service_manifests",
"//tools/ipc_fuzzer:ipc_fuzzer_all",
]
deps += [ "//tools/ipc_fuzzer:ipc_fuzzer_all" ]
}
if (!is_chromeos) {
deps += [
......
......@@ -123,9 +123,6 @@ if (!is_android && !is_mac) {
public_deps += [ ":reorder_imports" ]
data_deps += [ ":reorder_imports" ]
}
if (use_aura && (is_win || is_linux)) {
data_deps += [ "//chrome/app:service_manifests" ]
}
if (is_chromeos) {
data_deps += [ "//sandbox/linux:chrome_sandbox" ]
}
......@@ -1228,13 +1225,9 @@ if (is_win) {
]
if (is_chrome_branded) {
framework_contents += [
"Default Apps",
]
framework_contents += [ "Default Apps" ]
if (enable_keystone_registration_framework) {
framework_contents += [
"Frameworks", # For KeystoneRegistration.framework.
]
framework_contents += [ "Frameworks" ] # For KeystoneRegistration.framework.
}
}
......
......@@ -519,70 +519,3 @@ group("chrome_content_manifest_overlays") {
":chrome_content_utility_manifest_overlay",
]
}
if (use_aura || enable_ipc_fuzzer) {
# NOTE: These rules generate compiled versions of the content service
# manifests with Chrome's overlays applied. These are only used at run-time,
# and only when running Chrome inside the Mash environment. In production
# Chrome, the content manifests and Chrome's overlays are baked into browser
# resources and merged at runtime.
service_manifest("chrome_content_packaged_services_manifest") {
source_manifest = "//content/public/app:packaged_services_manifest"
overlays = [ ":chrome_content_packaged_services_manifest_overlay" ]
}
service_manifest("chrome_content_browser_manifest") {
source_manifest = "//content/public/app:browser_manifest"
overlays = [ ":chrome_content_browser_manifest_overlay" ]
}
service_manifest("chrome_test_browser_manifest") {
source_manifest = ":chrome_content_browser_manifest"
overlays = [ ":chrome_test_browser_overlay" ]
}
service_manifest("chrome_content_gpu_manifest") {
source_manifest = "//content/public/app:gpu_manifest"
overlays = [ ":chrome_content_gpu_manifest_overlay" ]
}
service_manifest("chrome_content_plugin_manifest") {
source_manifest = "//content/public/app:plugin_manifest"
overlays = [ ":chrome_content_plugin_manifest_overlay" ]
}
service_manifest("chrome_content_renderer_manifest") {
source_manifest = "//content/public/app:renderer_manifest"
overlays = [ ":chrome_content_renderer_manifest_overlay" ]
}
service_manifest("chrome_content_utility_manifest") {
source_manifest = "//content/public/app:utility_manifest"
overlays = [ ":chrome_content_utility_manifest_overlay" ]
}
group("service_manifests") {
deps = [
":chrome_content_browser_manifest",
":chrome_content_gpu_manifest",
":chrome_content_plugin_manifest",
":chrome_content_renderer_manifest",
":chrome_content_utility_manifest",
]
}
chrome_embedded_services = [
":chrome_content_browser_manifest",
":chrome_content_gpu_manifest",
":chrome_content_plugin_manifest",
":chrome_content_renderer_manifest",
":chrome_content_utility_manifest",
":chrome_renderer_manifest",
]
catalog("catalog") {
embedded_services = chrome_embedded_services +
[ ":chrome_content_packaged_services_manifest" ]
}
}
......@@ -2,9 +2,9 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//tools/grit/grit_rule.gni")
import("//build/config/nacl/config.gni")
import("//ppapi/buildflags/buildflags.gni")
import("//tools/grit/grit_rule.gni")
# Applied by targets internal to content.
config("content_implementation") {
......@@ -128,7 +128,6 @@ grit("resources") {
"//content/public/app:plugin_manifest",
"//content/public/app:renderer_manifest",
"//content/public/app:utility_manifest",
"//services/catalog:manifest",
]
}
......
......@@ -56,7 +56,6 @@
#include "mojo/public/cpp/system/invitation.h"
#include "services/audio/public/mojom/constants.mojom.h"
#include "services/audio/service_factory.h"
#include "services/catalog/public/mojom/constants.mojom.h"
#include "services/data_decoder/public/mojom/constants.mojom.h"
#include "services/device/device_service.h"
#include "services/device/public/mojom/constants.mojom.h"
......@@ -562,7 +561,6 @@ ServiceManagerContext::ServiceManagerContext(
{mojom::kPluginServiceName, IDR_MOJO_CONTENT_PLUGIN_MANIFEST},
{mojom::kRendererServiceName, IDR_MOJO_CONTENT_RENDERER_MANIFEST},
{mojom::kUtilityServiceName, IDR_MOJO_CONTENT_UTILITY_MANIFEST},
{catalog::mojom::kServiceName, IDR_MOJO_CATALOG_MANIFEST},
};
std::vector<service_manager::Manifest> manifests;
for (const auto& manifest_info : kManifestInfo) {
......
......@@ -26,7 +26,6 @@
<include name="IDR_INDEXED_DB_INTERNALS_CSS" file="browser/resources/indexed_db/indexeddb_internals.css" flattenhtml="true" compress="gzip" type="BINDATA" />
<include name="IDR_MEDIA_INTERNALS_HTML" file="browser/resources/media/media_internals.html" flattenhtml="true" allowexternalscript="true" compress="gzip" type="BINDATA" />
<include name="IDR_MEDIA_INTERNALS_JS" file="browser/resources/media/media_internals.js" flattenhtml="true" compress="gzip" type="BINDATA" />
<include name="IDR_MOJO_CATALOG_MANIFEST" file="../services/catalog/manifest.json" type="BINDATA" />
<include name="IDR_MOJO_CONTENT_BROWSER_MANIFEST" file="${root_gen_dir}/content/public/app/browser_manifest.json" use_base_dir="false" type="BINDATA" />
<include name="IDR_MOJO_CONTENT_GPU_MANIFEST" file="${root_gen_dir}/content/public/app/gpu_manifest.json" use_base_dir="false" type="BINDATA" />
<include name="IDR_MOJO_CONTENT_PACKAGED_SERVICES_MANIFEST" file="${root_gen_dir}/content/public/app/packaged_services_manifest.json" use_base_dir="false" type="BINDATA" />
......
......@@ -35,16 +35,14 @@ catalog("catalog") {
standalone_services = [
"//components/services/leveldb:manifest",
"//mash/catalog_viewer:manifest",
"//mash/example/views_examples:manifest",
"//mash/example/window_type_launcher:manifest",
"//mash/session:manifest",
"//mash/task_viewer:manifest",
"//services/ws/ime/test_ime_driver:manifest",
"//services/viz:manifest",
]
executable_overrides = [ "content_packaged_services:@EXE_DIR/chrome" ]
catalog_deps = [ "//mash/example:catalog" ]
if (is_chromeos) {
standalone_services += [
"//ash:manifest",
......
......@@ -18,10 +18,3 @@ group("example") {
deps += [ "//ash:ash_service" ]
}
}
catalog("catalog") {
standalone_services = [
"//mash/example/views_examples:manifest",
"//mash/example/window_type_launcher:manifest",
]
}
......@@ -223,6 +223,7 @@ if (standalone_supported) {
service_manifest("standalone_unittest_manifest") {
name = "audio_unittests"
source = "test/service_unittest_manifest.json"
generated_namespace = "standalone_audio_unittest"
}
catalog("standalone_unittest_catalog") {
......
......@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//services/service_manager/public/service_manifest.gni")
import("//testing/test.gni")
group("catalog") {
......@@ -54,8 +53,3 @@ component("lib") {
defines = [ "IS_CATALOG_IMPL" ]
}
service_manifest("manifest") {
name = "catalog"
source = "manifest.json"
}
{
"name": "catalog",
"display_name": "Application Resolver",
"options" : {
"instance_sharing" : "shared_instance_across_users"
},
"interface_provider_specs": {
// NOTE: This manifest is for documentation purposes only. Relevant
// capability spec is defined inline in the ServiceManager implementation.
//
// TODO(rockot): Fix this. We can bake this file into ServiceManager at
// build time or something. Same with service:service_manager.
"service_manager:connector": {
"provides": {
"directory": [ "filesystem.mojom.Directory" ],
"control": [ "catalog.mojom.CatalogControl" ]
}
}
}
}
......@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This is a generated file. Please see the "catalog_cpp_source" template in
// src/services/catalog/public/tools/catalog.gni for more details.
// This is a generated file. Please see the "service_manifest" template in
// src/services/service_manager/public/service_manifest.gni for more details.
#include "{{path}}.h"
......@@ -13,8 +13,15 @@
#include "base/no_destructor.h"
#include "build/build_config.h"
#include "services/service_manager/public/cpp/manifest_builder.h"
{% for info in packaged_services %}
#include "{{info.header}}"
{%- endfor %}
{% for info in overlays %}
#include "{{info.header}}"
{%- endfor %}
{%- macro generate_manifest_builder(manifest) -%}
{%- macro generate_manifest_builder(manifest, packaged_services=[],
overlays=[]) -%}
service_manager::ManifestBuilder()
.WithServiceName("{{manifest['name']}}")
{%- if 'display_name' in manifest %}
......@@ -101,22 +108,37 @@ service_manager::ManifestBuilder()
{%- for packaged_service_manifest in manifest.get('services', []) %}
.PackageService(
{{generate_manifest_builder(packaged_service_manifest)|indent(8)}})
{%- endfor %}
{%- for info in packaged_services %}
.PackageService({{info.namespace}}::GetManifest())
{%- endfor %}
.Build()
{%- for info in overlays %}
.Amend({{info.namespace}}::GetManifest())
{%- endfor %}
{%- endmacro %}
{% for namespace in namespaces %}
namespace {{namespace}} {
{%- endfor %}
{% if root_manifest %}
const service_manager::Manifest& {{function_name}}() {
static base::NoDestructor<service_manager::Manifest> manifest{
{{generate_manifest_builder(root_manifest,
packaged_services=packaged_services, overlays=overlays)
|indent(6)}} };
return *manifest;
}
{% else %}
const std::vector<service_manager::Manifest>& {{function_name}}() {
static base::NoDestructor<std::vector<service_manager::Manifest>> catalog{ {
{%- for entry in catalog['services'].itervalues() %}
{{generate_manifest_builder(entry['manifest'])|indent(6)}}
{%- if not loop.last %},{% endif %}
{%- endfor %} } };
return *catalog;
static base::NoDestructor<std::vector<service_manager::Manifest>> manifests{ {
{%- for info in packaged_services %}
{{info.namespace}}::GetManifest(){%- if not loop.last %},{%- endif %}
{%- endfor -%} }};
return *manifests;
}
{% endif %}
{%- for namespace in namespaces|reverse %}
} // namespace {{namespace}}
......
......@@ -4,173 +4,53 @@
import("//build/config/dcheck_always_on.gni")
# Generates a static catalog manifest to be loaded at runtime. This manifest
# contains the union of all individual service manifests specified by the
# template parameters.
# Generates code to produce a list service_manager::Manifest objects given a set
# of service_manager targets to include in the list.
#
# The output of a catalog rule is always a file named:
#
# ${target_gen_dir}/${target_name}.json
#
# A Service Manager embedder uses a catalog manifest as its singular source of
# truth regarding available services in the system.
#
# Parameters:
#
# embedded_services (optional)
# A list of service manifest targets whose outputs correspond to services
# embedded by the Service Manager embedder's binary. Outputs of targets
# listed here will be embedded in the catalog within its
# "embedded_services" list.
#
# standalone_services (optional)
# A list of service manifest targets whose outputs correspond to services
# with standalone binaries which must be available to the Service Manager
# at runtime. Outputs of targets listed here will be embedded in the
# catalog within its "standalone_services" list.
#
# Typically a standalone service binary is expected to live next to
# the Service Manager embedder's binary, with the name
# "${service_name}.service", with an additional ".exe" suffix on Windows.
# Binaries following this naming scheme are typically output by
# service_executable targets. See
# //services/service_manager/public/cpp/service_executable.gni.
#
# executable_overrides (optional)
# A list of overrides to apply in catalog metadata for individual
# services. An override string must be of the form
#
# "<service_name>:<executable_path>"
#
# The special token @EXE_DIR may be used in |executable_path| to denote
# a path relative to the Service Manager embedder's binary, substituted
# at runtime. For example:
#
# "content_browser:@EXE_DIR/chrome"
#
# would indicate to the Service Manager embedder that the
# "content_browser" service can be started by running the "chrome"
# executable in the embedder's own directory.
#
# This overrides the default binary name expectation described in
# |standalone_services| above.
#
# catalog_deps (optional)
# A list of other catalog targets whose outputs will be included within
# this catalog. Targets in this list
# This is a temporary helper to transition away from JSON manifests. The catalog
# target always has a companion catalog_cpp_source target, which yields a
# source_set defining the generated function.
#
# No new uses of these targets should be introduced.
template("catalog") {
output_filename = "$target_gen_dir/${target_name}.json"
action(target_name) {
group(target_name) {
testonly = defined(invoker.testonly) && invoker.testonly
}
script = "//services/catalog/public/tools/generate_manifest.py"
inputs = []
outputs = [
output_filename,
]
args = [ "--output=" + rebase_path(output_filename, root_build_dir) ]
if (is_debug || dcheck_always_on) {
args += [ "--pretty" ]
}
deps = []
if (defined(invoker.deps)) {
deps += invoker.deps
}
if (defined(invoker.embedded_services)) {
args += [ "--embedded-services" ]
foreach(manifest_target, invoker.embedded_services) {
manifest_target_dir = get_label_info(manifest_target, "target_gen_dir")
manifest_target_name = get_label_info(manifest_target, "name")
manifest_filename = "$manifest_target_dir/${manifest_target_name}.json"
inputs += [ "$manifest_filename" ]
deps += [ manifest_target ]
args += [ rebase_path(manifest_filename, root_build_dir) ]
# Ensure that each entry does in fact reference a service manifest rule.
label_no_toolchain =
get_label_info(manifest_target, "label_no_toolchain")
toolchain = get_label_info(manifest_target, "toolchain")
deps += [ "${label_no_toolchain}__is_service_manifest(${toolchain})" ]
}
}
if (defined(invoker.standalone_services)) {
args += [ "--standalone-services" ]
foreach(manifest_target, invoker.standalone_services) {
manifest_target_dir = get_label_info(manifest_target, "target_gen_dir")
manifest_target_name = get_label_info(manifest_target, "name")
manifest_filename = "$manifest_target_dir/${manifest_target_name}.json"
inputs += [ "$manifest_filename" ]
deps += [ manifest_target ]
args += [ rebase_path(manifest_filename, root_build_dir) ]
# Ensure that each entry does in fact reference a service manifest rule.
label_no_toolchain =
get_label_info(manifest_target, "label_no_toolchain")
toolchain = get_label_info(manifest_target, "toolchain")
deps += [ "${label_no_toolchain}__is_service_manifest(${toolchain})" ]
}
}
if (defined(invoker.executable_overrides)) {
args +=
[ "--override-service-executables" ] + invoker.executable_overrides
}
if (defined(invoker.catalog_deps)) {
args += [ "--include-catalogs" ]
foreach(catalog_target, invoker.catalog_deps) {
catalog_target_dir = get_label_info(catalog_target, "target_gen_dir")
catalog_target_name = get_label_info(catalog_target, "name")
catalog_filename = "$catalog_target_dir/${catalog_target_name}.json"
inputs += [ "$catalog_filename" ]
deps += [ catalog_target ]
args += [ rebase_path(catalog_filename, root_build_dir) ]
}
}
# NOTE: There is no longer a practical difference between embedded and
# standalone services in terms of manifest data. Some targets use one or the
# other or both.
submanifests = []
if (defined(invoker.embedded_services)) {
submanifests += invoker.embedded_services
}
if (defined(invoker.standalone_services)) {
submanifests += invoker.standalone_services
}
write_file("$target_gen_dir/${target_name}.submanifests", submanifests)
}
# Generates a source_set target which defines a single string constant
# containing the contents of a compiled catalog manifest.
#
# Parameters:
#
# catalog
# The catalog target whose output should be stringified.
#
# generated_function_name
# The fully qualified symbol name of the C++ string constant to define in
# the generate source_set.
#
template("catalog_cpp_source") {
assert(defined(invoker.catalog), "catalog is required")
assert(defined(invoker.generated_function_name),
"generated_function_name is required")
generator_target_name = "${target_name}__generator"
generated_filename_base = "${target_gen_dir}/${target_name}"
catalog_target = invoker.catalog
catalog_target_dir = get_label_info(catalog_target, "target_gen_dir")
catalog_target_name = get_label_info(catalog_target, "name")
catalog_filename = "$catalog_target_dir/${catalog_target_name}.json"
generator_target_name = "${target_name}__generator"
generated_filename_base = "${target_gen_dir}/${target_name}"
submanifests =
read_file("$catalog_target_dir/${catalog_target_name}.submanifests",
"list lines")
action(generator_target_name) {
testonly = defined(invoker.testonly) && invoker.testonly
script = "//services/catalog/public/tools/sourcify_manifest.py"
inputs = [
catalog_filename,
"//services/catalog/public/tools/catalog.cc.tmpl",
"//services/catalog/public/tools/catalog.h.tmpl",
]
......@@ -178,28 +58,42 @@ template("catalog_cpp_source") {
"${generated_filename_base}.cc",
"${generated_filename_base}.h",
]
submanifest_info = []
foreach(submanifest, submanifests) {
manifest_dir = get_label_info(submanifest, "target_gen_dir")
manifest_target_name = get_label_info(submanifest, "name")
manifest_namespace_input =
"$manifest_dir/${manifest_target_name}.namespace"
manifest_namespace_path =
rebase_path(manifest_namespace_input, root_build_dir)
manifest_header_base =
rebase_path(manifest_dir, root_gen_dir) + "/${manifest_target_name}"
submanifest_info +=
[ "packaged@$manifest_namespace_path@$manifest_header_base" ]
}
submanifest_info_file =
"$target_gen_dir/${invoker.target_name}.submanifest_info"
write_file(submanifest_info_file, submanifest_info)
args = [
"--input=" + rebase_path(catalog_filename, root_build_dir),
"--submanifest-info=" +
rebase_path(submanifest_info_file, root_build_dir),
"--output-filename-base=" +
rebase_path(generated_filename_base, root_build_dir),
"--output-function-name=" + invoker.generated_function_name,
"--module-path=" + rebase_path(generated_filename_base, root_gen_dir),
]
if (is_debug || dcheck_always_on) {
args += [ "--pretty" ]
}
deps = [
catalog_target,
]
}
source_set(target_name) {
testonly = defined(invoker.testonly) && invoker.testonly
sources = get_target_outputs(":$generator_target_name")
deps = [
":$generator_target_name",
"//base",
"//services/service_manager/public/cpp",
]
":$generator_target_name",
"//base",
"//services/service_manager/public/cpp",
] + submanifests
}
}
......@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This is a generated file. Please see the "catalog_cpp_source" template in
// src/services/catalog/public/tools/catalog.gni for more details.
// This is a generated file. Please see the "service_manifest" template in
// src/services/service_manager/public/service_manifest.gni for more details.
{%- set header_guard = "%s_H_"|format(path)|upper|replace("/", "_")|
replace(".", "_")|replace("-", "_") %}
......@@ -18,7 +19,11 @@
namespace {{namespace}} {
{%- endfor %}
{% if root_manifest -%}
const service_manager::Manifest& {{function_name}}();
{% else -%}
const std::vector<service_manager::Manifest>& {{function_name}}();
{%- endif %}
{% for namespace in namespaces|reverse %}
} // namespace {{namespace}}
......
......@@ -18,10 +18,20 @@ sys.path.append(os.path.join(
"build", "android", "gyp"))
from util import build_utils
_H_FILE_TEMPLATE = "catalog.h.tmpl"
_CC_FILE_TEMPLATE = "catalog.cc.tmpl"
eater_relative = "../../../../../tools/json_comment_eater"
eater_relative = os.path.join(os.path.abspath(__file__), eater_relative)
sys.path.insert(0, os.path.normpath(eater_relative))
try:
import json_comment_eater
finally:
sys.path.pop(0)
# Disable lint check for finding modules:
# pylint: disable=F0401
......@@ -44,49 +54,38 @@ import jinja2
def ApplyTemplate(path_to_template, output_path, global_vars, **kwargs):
def make_ascii(maybe_unicode):
if type(maybe_unicode) is str:
return maybe_unicode
assert type(maybe_unicode) is unicode
return maybe_unicode.encode("ascii", "ignore")
with build_utils.AtomicOutput(output_path) as output_file:
jinja_env = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
keep_trailing_newline=True, **kwargs)
jinja_env.globals.update(global_vars)
jinja_env.filters.update({
"is_dict": lambda x : type(x) is dict,
"is_list": lambda x : type(x) is list,
"is_number": lambda x : type(x) is int or type(x) is float,
"is_bool": lambda x: type(x) is bool,
"is_string": lambda x: type(x) is str,
"is_unicode": lambda x: type(x) is unicode,
"make_ascii": make_ascii,
})
output_file.write(jinja_env.get_template(path_to_template).render())
def main():
parser = argparse.ArgumentParser(
description="Generates a C++ constant containing a catalog manifest.")
parser.add_argument("--input")
parser.add_argument("--root-manifest")
parser.add_argument("--submanifest-info")
parser.add_argument("--output-filename-base")
parser.add_argument("--output-function-name")
parser.add_argument("--module-path")
args, _ = parser.parse_known_args()
if args.input is None:
raise Exception("--input is required")
if args.submanifest_info is None:
raise Exception("--submanifest-info required")
if args.output_filename_base is None:
raise Exception("--output-filename-base is required")
if args.output_function_name is None:
raise Exception("--output-function-name is required")
if args.module_path is None:
raise Exception("--module-path is required")
args.module_path = args.output_filename_base
with open(args.input, "r") as input_file:
catalog = json.load(input_file)
if args.root_manifest:
with open(args.root_manifest, "r") as input_file:
root_manifest = json.loads(json_comment_eater.Nom(input_file.read()))
else:
root_manifest = None
qualified_function_name = args.output_function_name.split("::")
namespaces = qualified_function_name[0:-1]
......@@ -95,8 +94,23 @@ def main():
def raise_error(error, value):
raise Exception(error)
overlays = []
packaged_services = []
with open(args.submanifest_info, "r") as info_file:
for line in info_file.readlines():
submanifest_type, namespace_file, header_base = line.strip().split("@", 3)
with open(namespace_file, "r") as namespace_file:
namespace = namespace_file.readline().strip()
info = { "namespace": namespace, "header": header_base + ".h" }
if submanifest_type == "overlay":
overlays.append(info)
else:
packaged_services.append(info)
global_vars = {
"catalog": catalog,
"root_manifest": root_manifest,
"overlays": overlays,
"packaged_services": packaged_services,
"function_name": function_name,
"namespaces": namespaces,
"path": args.module_path,
......
......@@ -230,7 +230,7 @@ Manifest Manifest::FromValueDeprecated(std::unique_ptr<base::Value> value_ptr) {
return manifest;
}
void Manifest::Amend(Manifest other) {
Manifest& Manifest::Amend(Manifest other) {
for (auto& other_capability : other.exposed_capabilities) {
auto it = std::find_if(
exposed_capabilities.begin(), exposed_capabilities.end(),
......@@ -272,6 +272,8 @@ void Manifest::Amend(Manifest other) {
packaged_services.emplace_back(std::move(manifest));
for (auto& file_info : other.preloaded_files)
preloaded_files.emplace_back(std::move(file_info));
return *this;
}
} // namespace service_manager
......@@ -267,7 +267,7 @@ struct COMPONENT_EXPORT(SERVICE_MANAGER_CPP) Manifest {
// Amends this Manifest with a subset of |other|. Namely, exposed and required
// capabilities, exposed and required interface filter capabilities, packaged
// services, and preloaded files are all added from |other| if present.
void Amend(Manifest other);
Manifest& Amend(Manifest other);
std::string service_name;
DisplayName display_name;
......
......@@ -4,65 +4,129 @@
import("//build/config/dcheck_always_on.gni")
# Used to produce a Service Manifest for a Service.
# Generates code to produce a compiled service_manager::Manifest from a JSON
# description at build time.
#
# Service manifests may be subsequently aggregated into one or more catalog
# manifests (see //services/catalog/public/tools/catalog.gni). A catalog
# manifest provides the Service Manager at runtime with a static service layout
# configuration to dictate which services are supported by the runtime
# environment as well as how individual services may be launched and
# interconnected.
# This is a temporary helper for the transition away from JSON manifests. Do not
# introduce new service_manifest targets.
#
# Note that this target may be used to produce partial manifests, and partial
# manifests may be aggregated by using one service_manifest target as the
# |source_manifest| of another (see below.)
#
# Parameters:
#
# source (optional**)
# The manifest template for this service. Must be the name of a valid JSON
# file.
#
# source_manifest (optional**)
# The manifest template for this service. Must be the name of another
# service_manifest target.
#
# ** NOTE: Either |source| OR |source_manifest| MUST be specified.
#
# name (optional)
# The name of the service whose manifest is to be generated. A script
# validates that the value of this parameter matches the name set in the
# source manifest and raises an error if it does not match.
#
# overlays (optional)
# A list of other manifest targets whose outputs should be overlayed onto
# the source manifest before emitting the final output. Overlays are
# applied in-order as the last step of output generation, after any
# |packaged_services| manifests are embedded.
#
# packaged_services (optional)
# A list of other manifest targets whose outputs should be packaged
# within this output manifest, specifically within a toplevel "services"
# list.
#
# testonly (optional)
#
# Outputs:
#
# An instantiation of this template produces a meta manifest from the source
# template and the output manifests of all its |overlay| and
# |packaged_services|dependencies. The output file is always
# "$target_gen_dir/${target_name}.json".
# This template yields a source_set target which defines a symbol named
# "${name}::GetManifest()" where ${name} is the service name given in the
# target.
#
# All service_manifest targets should be replaced with in-tree C++ sources.
template("service_manifest") {
assert(
defined(invoker.source) || defined(invoker.source_manifest),
"\"source\" or \"source_manifest\" must be defined for the $target_name target")
assert(
!defined(invoker.source) || !defined(invoker.source_manifest),
"Only one of \"source\" or \"source_manifest\" must be defined for the $target_name target")
action(target_name) {
assert(defined(invoker.source),
"\"source\" must be defined for the $target_name target")
generator_target_name = "${target_name}__generator"
generated_sources = [
"$target_gen_dir/${target_name}.cc",
"$target_gen_dir/${target_name}.h",
]
# We prefer to use |name| for the generated function's namespace if a
# |generated_namespace| isn't explicitly defined. It turns out that we also
# have a few targets which don't specify a |name| though; they all have unique
# target names, so we fall back on that if necessary. The important detail is
# that all generated GetManifest() functions should live in their own
# namespace, and with the current (and final) set of service_manifest targets
# in the tree, these rules accomplish that.
if (defined(invoker.generated_namespace)) {
output_namespace = invoker.generated_namespace
} else if (defined(invoker.name)) {
output_namespace = invoker.name
} else {
output_namespace = invoker.target_name
}
write_file("$target_gen_dir/${target_name}.namespace", output_namespace)
source_set(target_name) {
testonly = defined(invoker.testonly) && invoker.testonly
sources = generated_sources
public_deps = [
":$generator_target_name",
]
deps = []
if (defined(invoker.packaged_services)) {
deps += invoker.packaged_services
}
if (defined(invoker.overlays)) {
deps += invoker.overlays
}
}
collator_target_name = "${target_name}__collator"
action(generator_target_name) {
testonly = defined(invoker.testonly) && invoker.testonly
script = "//services/catalog/public/tools/sourcify_manifest.py"
inputs = [
"//services/catalog/public/tools/catalog.cc.tmpl",
"//services/catalog/public/tools/catalog.h.tmpl",
invoker.source,
]
outputs = generated_sources
submanifest_info = []
if (defined(invoker.packaged_services)) {
foreach(submanifest, invoker.packaged_services) {
manifest_dir = get_label_info(submanifest, "target_gen_dir")
manifest_target_name = get_label_info(submanifest, "name")
manifest_namespace_input =
"$manifest_dir/${manifest_target_name}.namespace"
manifest_namespace_path =
rebase_path(manifest_namespace_input, root_build_dir)
manifest_header_base =
rebase_path(manifest_dir, root_gen_dir) + "/${manifest_target_name}"
submanifest_info +=
[ "packaged@$manifest_namespace_path@$manifest_header_base" ]
}
}
if (defined(invoker.overlays)) {
foreach(submanifest, invoker.overlays) {
manifest_dir = get_label_info(submanifest, "target_gen_dir")
manifest_target_name = get_label_info(submanifest, "name")
manifest_namespace_input =
"$manifest_dir/${manifest_target_name}.namespace"
manifest_namespace_path =
rebase_path(manifest_namespace_input, root_build_dir)
manifest_header_base =
rebase_path(manifest_dir, root_gen_dir) + "/${manifest_target_name}"
submanifest_info +=
[ "overlay@$manifest_namespace_path@$manifest_header_base" ]
}
}
submanifest_info_file =
"${target_gen_dir}/${invoker.target_name}.submanifest_info"
write_file(submanifest_info_file, submanifest_info)
args = [
"--root-manifest=" + rebase_path(invoker.source, root_build_dir),
"--submanifest-info=" +
rebase_path(submanifest_info_file, root_build_dir),
"--output-function-name=${output_namespace}::GetManifest",
"--output-filename-base=" +
rebase_path("$target_gen_dir/${invoker.target_name}", root_build_dir),
"--module-path=" +
rebase_path("$target_gen_dir/${invoker.target_name}", root_gen_dir),
]
# We inherit a public dependency on the collator because service_manifest
# dependents still expect to use its generated JSON output. We don't
# actually depend on the collated JSON at all here, since packaged services
# and overlays are added in the generated C++ code by referring to other
# generated C++ code.
public_deps = [
":$collator_target_name",
]
}
action(collator_target_name) {
testonly = defined(invoker.testonly) && invoker.testonly
script =
......@@ -73,25 +137,16 @@ template("service_manifest") {
deps += invoker.deps
}
if (defined(invoker.source)) {
source = invoker.source
} else {
source_target_dir =
get_label_info(invoker.source_manifest, "target_gen_dir")
source_target_name = get_label_info(invoker.source_manifest, "name")
source = "$source_target_dir/${source_target_name}.json"
deps += [ invoker.source_manifest ]
}
inputs = [
source,
invoker.source,
]
output = "$target_gen_dir/${target_name}.json"
output = "$target_gen_dir/${invoker.target_name}.json"
outputs = [
output,
]
rebase_parent = rebase_path(source, root_build_dir)
rebase_parent = rebase_path(invoker.source, root_build_dir)
rebase_output = rebase_path(output, root_build_dir)
args = [
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment