summaryrefslogtreecommitdiff
path: root/utils/ipc/mojo/public/tools/bindings
diff options
context:
space:
mode:
authorPaul Elder <paul.elder@ideasonboard.com>2020-09-08 20:47:19 +0900
committerPaul Elder <paul.elder@ideasonboard.com>2020-11-11 19:22:37 +0900
commit82ba73535c0966e8ae8fb50db1ea23534d827717 (patch)
treef75b0d7f3933369872157105f1e467b71430e8cf /utils/ipc/mojo/public/tools/bindings
parent3d624b745b31383dbcd94d96246fab865820085f (diff)
utils: ipc: import mojo
Import mojo from the Chromium repository, so that we can use it for generating code for the IPC mechanism. The commit from which this was taken is: a079161ec8c6907b883f9cb84fc8c4e7896cb1d0 "Add PPAPI constructs for sending focus object to PdfAccessibilityTree" This tree has been pruned to remove directories that didn't have any necessary code: - mojo/* except for mojo/public - mojo core, docs, and misc files - mojo/public/* except for mojo/public/{tools,LICENSE} - language bindings for IPC, tests, and some mojo internals - mojo/public/tools/{fuzzers,chrome_ipc} - mojo/public/tools/bindings/generators - code generation for other languages No files were modified. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> Acked-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Diffstat (limited to 'utils/ipc/mojo/public/tools/bindings')
-rw-r--r--utils/ipc/mojo/public/tools/bindings/BUILD.gn108
-rw-r--r--utils/ipc/mojo/public/tools/bindings/README.md816
-rw-r--r--utils/ipc/mojo/public/tools/bindings/chromium_bindings_configuration.gni51
-rw-r--r--utils/ipc/mojo/public/tools/bindings/compile_typescript.py27
-rwxr-xr-xutils/ipc/mojo/public/tools/bindings/concatenate-files.py54
-rwxr-xr-xutils/ipc/mojo/public/tools/bindings/concatenate_and_replace_closure_exports.py73
-rwxr-xr-xutils/ipc/mojo/public/tools/bindings/format_typemap_generator_args.py36
-rw-r--r--utils/ipc/mojo/public/tools/bindings/gen_data_files_list.py52
-rwxr-xr-xutils/ipc/mojo/public/tools/bindings/generate_type_mappings.py187
-rw-r--r--utils/ipc/mojo/public/tools/bindings/mojom.gni1941
-rwxr-xr-xutils/ipc/mojo/public/tools/bindings/mojom_bindings_generator.py390
-rw-r--r--utils/ipc/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py62
-rwxr-xr-xutils/ipc/mojo/public/tools/bindings/mojom_types_downgrader.py119
-rwxr-xr-xutils/ipc/mojo/public/tools/bindings/validate_typemap_config.py57
14 files changed, 3973 insertions, 0 deletions
diff --git a/utils/ipc/mojo/public/tools/bindings/BUILD.gn b/utils/ipc/mojo/public/tools/bindings/BUILD.gn
new file mode 100644
index 00000000..8ba6e922
--- /dev/null
+++ b/utils/ipc/mojo/public/tools/bindings/BUILD.gn
@@ -0,0 +1,108 @@
+# Copyright 2016 The Chromium 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("//mojo/public/tools/bindings/mojom.gni")
+import("//third_party/jinja2/jinja2.gni")
+
+action("precompile_templates") {
+ sources = mojom_generator_sources
+ sources += [
+ "$mojom_generator_root/generators/cpp_templates/enum_macros.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/enum_serialization_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/interface_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/interface_definition.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/interface_macros.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/interface_proxy_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/interface_request_validator_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/interface_response_validator_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/interface_stub_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/module-forward.h.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/module-import-headers.h.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/module-params-data.h.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/module-shared-internal.h.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/module-shared-message-ids.h.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/module-shared.cc.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/module-shared.h.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/module-test-utils.cc.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/module-test-utils.h.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/module.cc.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/module.h.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/struct_data_view_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/struct_data_view_definition.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/struct_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/struct_definition.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/struct_macros.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/struct_serialization_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/struct_traits_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/struct_traits_definition.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/struct_unserialized_message_context.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/union_data_view_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/union_data_view_definition.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/union_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/union_definition.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/union_serialization_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/union_traits_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/union_traits_definition.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/validation_macros.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/wrapper_class_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/wrapper_class_definition.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/wrapper_class_template_definition.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/wrapper_union_class_declaration.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/wrapper_union_class_definition.tmpl",
+ "$mojom_generator_root/generators/cpp_templates/wrapper_union_class_template_definition.tmpl",
+ "$mojom_generator_root/generators/java_templates/constant_definition.tmpl",
+ "$mojom_generator_root/generators/java_templates/constants.java.tmpl",
+ "$mojom_generator_root/generators/java_templates/data_types_definition.tmpl",
+ "$mojom_generator_root/generators/java_templates/enum.java.tmpl",
+ "$mojom_generator_root/generators/java_templates/enum_definition.tmpl",
+ "$mojom_generator_root/generators/java_templates/header.java.tmpl",
+ "$mojom_generator_root/generators/java_templates/interface.java.tmpl",
+ "$mojom_generator_root/generators/java_templates/interface_definition.tmpl",
+ "$mojom_generator_root/generators/java_templates/interface_internal.java.tmpl",
+ "$mojom_generator_root/generators/java_templates/struct.java.tmpl",
+ "$mojom_generator_root/generators/java_templates/union.java.tmpl",
+ "$mojom_generator_root/generators/js_templates/enum_definition.tmpl",
+ "$mojom_generator_root/generators/js_templates/externs/interface_definition.tmpl",
+ "$mojom_generator_root/generators/js_templates/externs/module.externs.tmpl",
+ "$mojom_generator_root/generators/js_templates/externs/struct_definition.tmpl",
+ "$mojom_generator_root/generators/js_templates/fuzzing.tmpl",
+ "$mojom_generator_root/generators/js_templates/interface_definition.tmpl",
+ "$mojom_generator_root/generators/js_templates/lite/enum_definition.tmpl",
+ "$mojom_generator_root/generators/js_templates/lite/interface_definition.tmpl",
+ "$mojom_generator_root/generators/js_templates/lite/module_definition.tmpl",
+ "$mojom_generator_root/generators/js_templates/lite/mojom-lite.js.tmpl",
+ "$mojom_generator_root/generators/js_templates/lite/struct_definition.tmpl",
+ "$mojom_generator_root/generators/js_templates/lite/union_definition.tmpl",
+ "$mojom_generator_root/generators/js_templates/module.amd.tmpl",
+ "$mojom_generator_root/generators/js_templates/module_definition.tmpl",
+ "$mojom_generator_root/generators/js_templates/struct_definition.tmpl",
+ "$mojom_generator_root/generators/js_templates/union_definition.tmpl",
+ "$mojom_generator_root/generators/js_templates/validation_macros.tmpl",
+ "$mojom_generator_root/generators/mojolpm_templates/mojolpm.cc.tmpl",
+ "$mojom_generator_root/generators/mojolpm_templates/mojolpm.h.tmpl",
+ "$mojom_generator_root/generators/mojolpm_templates/mojolpm.proto.tmpl",
+ "$mojom_generator_root/generators/mojolpm_templates/mojolpm_from_proto_macros.tmpl",
+ "$mojom_generator_root/generators/mojolpm_templates/mojolpm_macros.tmpl",
+ "$mojom_generator_root/generators/mojolpm_templates/mojolpm_to_proto_macros.tmpl",
+ "$mojom_generator_root/generators/mojolpm_templates/mojolpm_traits_specialization_macros.tmpl",
+ "$mojom_generator_root/generators/ts_templates/module_definition.tmpl",
+ "$mojom_generator_root/generators/ts_templates/mojom.tmpl",
+ ]
+ script = mojom_generator_script
+
+ inputs = jinja2_sources
+ outputs = [
+ "$target_gen_dir/cpp_templates.zip",
+ "$target_gen_dir/java_templates.zip",
+ "$target_gen_dir/mojolpm_templates.zip",
+ "$target_gen_dir/js_templates.zip",
+ "$target_gen_dir/ts_templates.zip",
+ ]
+ args = [
+ "-o",
+ rebase_path(target_gen_dir, root_build_dir),
+ "--use_bundled_pylibs",
+ "precompile",
+ ]
+}
diff --git a/utils/ipc/mojo/public/tools/bindings/README.md b/utils/ipc/mojo/public/tools/bindings/README.md
new file mode 100644
index 00000000..1a3d5c58
--- /dev/null
+++ b/utils/ipc/mojo/public/tools/bindings/README.md
@@ -0,0 +1,816 @@
+# Mojom Interface Definition Language (IDL)
+This document is a subset of the [Mojo documentation](/mojo/README.md).
+
+[TOC]
+
+## Overview
+
+Mojom is the IDL for Mojo interfaces. Given a `.mojom` file, the
+[bindings
+generator](https://cs.chromium.org/chromium/src/mojo/public/tools/bindings/) can
+output bindings for any supported language: **C++**, **JavaScript**, or
+**Java**.
+
+For a trivial example consider the following hypothetical Mojom file we write to
+`//services/widget/public/mojom/frobinator.mojom`:
+
+```
+module widget.mojom;
+
+interface Frobinator {
+ Frobinate();
+};
+```
+
+This defines a single [interface](#Interfaces) named `Frobinator` in a
+[module](#Modules) named `widget.mojom` (and thus fully qualified in Mojom as
+`widget.mojom.Frobinator`.) Note that many interfaces and/or other types of
+definitions (structs, enums, *etc.*) may be included in a single Mojom file.
+
+If we add a corresponding GN target to
+`//services/widget/public/mojom/BUILD.gn`:
+
+```
+import("mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojom") {
+ sources = [
+ "frobinator.mojom",
+ ]
+}
+```
+
+and then build this target:
+
+```
+ninja -C out/r services/widget/public/mojom
+```
+
+we'll find several generated sources in our output directory:
+
+```
+out/r/gen/services/widget/public/mojom/frobinator.mojom.cc
+out/r/gen/services/widget/public/mojom/frobinator.mojom.h
+out/r/gen/services/widget/public/mojom/frobinator.mojom-shared.h
+etc...
+```
+
+Each of these generated source modules includes a set of definitions
+representing the Mojom contents in C++. You can also build or depend on suffixed
+target names to get bindings for other languages. For example,
+
+```
+ninja -C out/r services/widget/public/mojom:mojom_js
+ninja -C out/r services/widget/public/mojom:mojom_java
+```
+
+would generate JavaScript and Java bindings respectively, in the same generated
+output directory.
+
+For more details regarding the generated
+outputs please see
+[documentation for individual target languages](#Generated-Code-For-Target-Languages).
+
+## Mojom Syntax
+
+Mojom IDL allows developers to define **structs**, **unions**, **interfaces**,
+**constants**, and **enums**, all within the context of a **module**. These
+definitions are used to generate code in the supported target languages at build
+time.
+
+Mojom files may **import** other Mojom files in order to reference their
+definitions.
+
+### Primitive Types
+Mojom supports a few basic data types which may be composed into structs or used
+for message parameters.
+
+| Type | Description
+|-------------------------------|-------------------------------------------------------|
+| `bool` | Boolean type (`true` or `false`.)
+| `int8`, `uint8` | Signed or unsigned 8-bit integer.
+| `int16`, `uint16` | Signed or unsigned 16-bit integer.
+| `int32`, `uint32` | Signed or unsigned 32-bit integer.
+| `int64`, `uint64` | Signed or unsigned 64-bit integer.
+| `float`, `double` | 32- or 64-bit floating point number.
+| `string` | UTF-8 encoded string.
+| `array<T>` | Array of any Mojom type *T*; for example, `array<uint8>` or `array<array<string>>`.
+| `array<T, N>` | Fixed-length array of any Mojom type *T*. The parameter *N* must be an integral constant.
+| `map<S, T>` | Associated array maping values of type *S* to values of type *T*. *S* may be a `string`, `enum`, or numeric type.
+| `handle` | Generic Mojo handle. May be any type of handle, including a wrapped native platform handle.
+| `handle<message_pipe>` | Generic message pipe handle.
+| `handle<shared_buffer>` | Shared buffer handle.
+| `handle<data_pipe_producer>` | Data pipe producer handle.
+| `handle<data_pipe_consumer>` | Data pipe consumer handle.
+| `handle<platform>` | A native platform/OS handle.
+| *`pending_remote<InterfaceType>`* | Any user-defined Mojom interface type. This is sugar for a strongly-typed message pipe handle which should eventually be used to make outgoing calls on the interface.
+| *`pending_receiver<InterfaceType>`* | A pending receiver for any user-defined Mojom interface type. This is sugar for a more strongly-typed message pipe handle which is expected to receive request messages and should therefore eventually be bound to an implementation of the interface.
+| *`pending_associated_remote<InterfaceType>`* | An associated interface handle. See [Associated Interfaces](#Associated-Interfaces)
+| *`pending_associated_receiver<InterfaceType>`* | A pending associated receiver. See [Associated Interfaces](#Associated-Interfaces)
+| *T*? | An optional (nullable) value. Primitive numeric types (integers, floats, booleans, and enums) are not nullable. All other types are nullable.
+
+### Modules
+
+Every Mojom file may optionally specify a single **module** to which it belongs.
+
+This is used strictly for aggregaging all defined symbols therein within a
+common Mojom namespace. The specific impact this has on generated binidngs code
+varies for each target language. For example, if the following Mojom is used to
+generate bindings:
+
+```
+module business.stuff;
+
+interface MoneyGenerator {
+ GenerateMoney();
+};
+```
+
+Generated C++ bindings will define a class interface `MoneyGenerator` in the
+`business::stuff` namespace, while Java bindings will define an interface
+`MoneyGenerator` in the `org.chromium.business.stuff` package. JavaScript
+bindings at this time are unaffected by module declarations.
+
+**NOTE:** By convention in the Chromium codebase, **all** Mojom files should
+declare a module name with at least (and preferrably exactly) one top-level name
+as well as an inner `mojom` module suffix. *e.g.*, `chrome.mojom`,
+`business.mojom`, *etc.*
+
+This convention makes it easy to tell which symbols are generated by Mojom when
+reading non-Mojom code, and it also avoids namespace collisions in the fairly
+common scenario where you have a real C++ or Java `Foo` along with a
+corresponding Mojom `Foo` for its serialized representation.
+
+### Imports
+
+If your Mojom references definitions from other Mojom files, you must **import**
+those files. Import syntax is as follows:
+
+```
+import "services/widget/public/mojom/frobinator.mojom";
+```
+
+Import paths are always relative to the top-level directory.
+
+Note that circular imports are **not** supported.
+
+### Structs
+
+Structs are defined using the **struct** keyword, and they provide a way to
+group related fields together:
+
+``` cpp
+struct StringPair {
+ string first;
+ string second;
+};
+```
+
+Struct fields may be comprised of any of the types listed above in the
+[Primitive Types](#Primitive-Types) section.
+
+Default values may be specified as long as they are constant:
+
+``` cpp
+struct Request {
+ int32 id = -1;
+ string details;
+};
+```
+
+What follows is a fairly
+comprehensive example using the supported field types:
+
+``` cpp
+struct StringPair {
+ string first;
+ string second;
+};
+
+enum AnEnum {
+ YES,
+ NO
+};
+
+interface SampleInterface {
+ DoStuff();
+};
+
+struct AllTheThings {
+ // Note that these types can never be marked nullable!
+ bool boolean_value;
+ int8 signed_8bit_value = 42;
+ uint8 unsigned_8bit_value;
+ int16 signed_16bit_value;
+ uint16 unsigned_16bit_value;
+ int32 signed_32bit_value;
+ uint32 unsigned_32bit_value;
+ int64 signed_64bit_value;
+ uint64 unsigned_64bit_value;
+ float float_value_32bit;
+ double float_value_64bit;
+ AnEnum enum_value = AnEnum.YES;
+
+ // Strings may be nullable.
+ string? maybe_a_string_maybe_not;
+
+ // Structs may contain other structs. These may also be nullable.
+ StringPair some_strings;
+ StringPair? maybe_some_more_strings;
+
+ // In fact structs can also be nested, though in practice you must always make
+ // such fields nullable -- otherwise messages would need to be infinitely long
+ // in order to pass validation!
+ AllTheThings? more_things;
+
+ // Arrays may be templated over any Mojom type, and are always nullable:
+ array<int32> numbers;
+ array<int32>? maybe_more_numbers;
+
+ // Arrays of arrays of arrays... are fine.
+ array<array<array<AnEnum>>> this_works_but_really_plz_stop;
+
+ // The element type may be nullable if it's a type which is allowed to be
+ // nullable.
+ array<AllTheThings?> more_maybe_things;
+
+ // Fixed-size arrays get some extra validation on the receiving end to ensure
+ // that the correct number of elements is always received.
+ array<uint64, 2> uuid;
+
+ // Maps follow many of the same rules as arrays. Key types may be any
+ // non-handle, non-collection type, and value types may be any supported
+ // struct field type. Maps may also be nullable.
+ map<string, int32> one_map;
+ map<AnEnum, string>? maybe_another_map;
+ map<StringPair, AllTheThings?>? maybe_a_pretty_weird_but_valid_map;
+ map<StringPair, map<int32, array<map<string, string>?>?>?> ridiculous;
+
+ // And finally, all handle types are valid as struct fields and may be
+ // nullable. Note that interfaces and interface requests (the "Foo" and
+ // "Foo&" type syntax respectively) are just strongly-typed message pipe
+ // handles.
+ handle generic_handle;
+ handle<data_pipe_consumer> reader;
+ handle<data_pipe_producer>? maybe_writer;
+ handle<shared_buffer> dumping_ground;
+ handle<message_pipe> raw_message_pipe;
+ pending_remote<SampleInterface>? maybe_a_sample_interface_client_pipe;
+ pending_receiver<SampleInterface> non_nullable_sample_pending_receiver;
+ pending_receiver<SampleInterface>? nullable_sample_pending_receiver;
+ pending_associated_remote<SampleInterface> associated_interface_client;
+ pending_associated_receiver<SampleInterface> associated_pending_receiver;
+ pending_associated_receiver<SampleInterface>? maybe_another_pending_receiver;
+};
+```
+
+For details on how all of these different types translate to usable generated
+code, see
+[documentation for individual target languages](#Generated-Code-For-Target-Languages).
+
+### Unions
+
+Mojom supports tagged unions using the **union** keyword. A union is a
+collection of fields which may taken the value of any single one of those fields
+at a time. Thus they provide a way to represent a variant value type while
+minimizing storage requirements.
+
+Union fields may be of any type supported by [struct](#Structs) fields. For
+example:
+
+```cpp
+union ExampleUnion {
+ string str;
+ StringPair pair;
+ int64 id;
+ array<uint64, 2> guid;
+ SampleInterface iface;
+};
+```
+
+For details on how unions like this translate to generated bindings code, see
+[documentation for individual target languages](#Generated-Code-For-Target-Languages).
+
+### Enumeration Types
+
+Enumeration types may be defined using the **enum** keyword either directly
+within a module or nested within the namespace of some struct or interface:
+
+```
+module business.mojom;
+
+enum Department {
+ SALES = 0,
+ DEV,
+};
+
+struct Employee {
+ enum Type {
+ FULL_TIME,
+ PART_TIME,
+ };
+
+ Type type;
+ // ...
+};
+```
+
+Similar to C-style enums, individual values may be explicitly assigned within an
+enum definition. By default, values are based at zero and increment by
+1 sequentially.
+
+The effect of nested definitions on generated bindings varies depending on the
+target language. See [documentation for individual target languages](#Generated-Code-For-Target-Languages)
+
+### Constants
+
+Constants may be defined using the **const** keyword either directly within a
+module or nested within the namespace of some struct or interface:
+
+```
+module business.mojom;
+
+const string kServiceName = "business";
+
+struct Employee {
+ const uint64 kInvalidId = 0;
+
+ enum Type {
+ FULL_TIME,
+ PART_TIME,
+ };
+
+ uint64 id = kInvalidId;
+ Type type;
+};
+```
+
+The effect of nested definitions on generated bindings varies depending on the
+target language. See [documentation for individual target languages](#Generated-Code-For-Target-Languages)
+
+### Interfaces
+
+An **interface** is a logical bundle of parameterized request messages. Each
+request message may optionally define a parameterized response message. Here's
+an example to define an interface `Foo` with various kinds of requests:
+
+```
+interface Foo {
+ // A request which takes no arguments and expects no response.
+ MyMessage();
+
+ // A request which has some arguments and expects no response.
+ MyOtherMessage(string name, array<uint8> bytes);
+
+ // A request which expects a single-argument response.
+ MyMessageWithResponse(string command) => (bool success);
+
+ // A request which expects a response with multiple arguments.
+ MyMessageWithMoarResponse(string a, string b) => (int8 c, int8 d);
+};
+```
+
+Anything which is a valid struct field type (see [Structs](#Structs)) is also a
+valid request or response argument type. The type notation is the same for both.
+
+### Attributes
+
+Mojom definitions may have their meaning altered by **attributes**, specified
+with a syntax similar to Java or C# attributes. There are a handle of
+interesting attributes supported today.
+
+**`[Sync]`**
+: The `Sync` attribute may be specified for any interface method which expects
+ a response. This makes it so that callers of the method can wait
+ synchronously for a response. See
+ [Synchronous Calls](/mojo/public/cpp/bindings/README.md#Synchronous-Calls)
+ in the C++ bindings documentation. Note that sync methods are only actually
+ synchronous when called from C++.
+
+**`[Extensible]`**
+: The `Extensible` attribute may be specified for any enum definition. This
+ essentially disables builtin range validation when receiving values of the
+ enum type in a message, allowing older bindings to tolerate unrecognized
+ values from newer versions of the enum.
+
+**`[Native]`**
+: The `Native` attribute may be specified for an empty struct declaration to
+ provide a nominal bridge between Mojo IPC and legacy `IPC::ParamTraits` or
+ `IPC_STRUCT_TRAITS*` macros.
+ See
+ [Repurposing Legacy IPC Traits](/docs/mojo_ipc_conversion.md#repurposing-and-invocations)
+ for more details. Note support for this attribute is strictly limited to C++
+ bindings generation.
+
+**`[MinVersion=N]`**
+: The `MinVersion` attribute is used to specify the version at which a given
+ field, enum value, interface method, or method parameter was introduced.
+ See [Versioning](#Versioning) for more details.
+
+**`[Stable]`**
+: The `Stable` attribute specifies that a given mojom type or interface
+ definition can be considered stable over time, meaning it is safe to use for
+ things like persistent storage or communication between independent
+ version-skewed binaries. Stable definitions may only depend on builtin mojom
+ types or other stable definitions, and changes to such definitions MUST
+ preserve backward-compatibility through appropriate use of versioning.
+ Backward-compatibility of changes is enforced in the Chromium tree using a
+ strict presubmit check. See [Versioning](#Versioning) for more details on
+ backward-compatibility constraints.
+
+**`[EnableIf=value]`**
+: The `EnableIf` attribute is used to conditionally enable definitions when
+ the mojom is parsed. If the `mojom` target in the GN file does not include
+ the matching `value` in the list of `enabled_features`, the definition
+ will be disabled. This is useful for mojom definitions that only make
+ sense on one platform. Note that the `EnableIf` attribute can only be set
+ once per definition.
+
+## Generated Code For Target Languages
+
+When the bindings generator successfully processes an input Mojom file, it emits
+corresponding code for each supported target language. For more details on how
+Mojom concepts translate to a given target langauge, please refer to the
+bindings API documentation for that language:
+
+* [C++ Bindings](/mojo/public/cpp/bindings/README.md)
+* [JavaScript Bindings](/mojo/public/js/README.md)
+* [Java Bindings](/mojo/public/java/bindings/README.md)
+
+## Message Validation
+
+Regardless of target language, all interface messages are validated during
+deserialization before they are dispatched to a receiving implementation of the
+interface. This helps to ensure consitent validation across interfaces without
+leaving the burden to developers and security reviewers every time a new message
+is added.
+
+If a message fails validation, it is never dispatched. Instead a **connection
+error** is raised on the binding object (see
+[C++ Connection Errors](/mojo/public/cpp/bindings/README.md#Connection-Errors),
+[Java Connection Errors](/mojo/public/java/bindings/README.md#Connection-Errors),
+or
+[JavaScript Connection Errors](/mojo/public/js/README.md#Connection-Errors) for
+details.)
+
+Some baseline level of validation is done automatically for primitive Mojom
+types.
+
+### Non-Nullable Objects
+
+Mojom fields or parameter values (*e.g.*, structs, interfaces, arrays, *etc.*)
+may be marked nullable in Mojom definitions (see
+[Primitive Types](#Primitive-Types).) If a field or parameter is **not** marked
+nullable but a message is received with a null value in its place, that message
+will fail validation.
+
+### Enums
+
+Enums declared in Mojom are automatically validated against the range of legal
+values. For example if a Mojom declares the enum:
+
+``` cpp
+enum AdvancedBoolean {
+ TRUE = 0,
+ FALSE = 1,
+ FILE_NOT_FOUND = 2,
+};
+```
+
+and a message is received with the integral value 3 (or anything other than 0,
+1, or 2) in place of some `AdvancedBoolean` field or parameter, the message will
+fail validation.
+
+*** note
+NOTE: It's possible to avoid this type of validation error by explicitly marking
+an enum as [Extensible](#Attributes) if you anticipate your enum being exchanged
+between two different versions of the binding interface. See
+[Versioning](#Versioning).
+***
+
+### Other failures
+
+There are a host of internal validation errors that may occur when a malformed
+message is received, but developers should not be concerned with these
+specifically; in general they can only result from internal bindings bugs,
+compromised processes, or some remote endpoint making a dubious effort to
+manually encode their own bindings messages.
+
+### Custom Validation
+
+It's also possible for developers to define custom validation logic for specific
+Mojom struct types by exploiting the
+[type mapping](/mojo/public/cpp/bindings/README.md#Type-Mapping) system for C++
+bindings. Messages rejected by custom validation logic trigger the same
+validation failure behavior as the built-in type validation routines.
+
+## Associated Interfaces
+
+As mentioned in the [Primitive Types](#Primitive-Types) section above, pending_remote
+and pending_receiver fields and parameters may be marked as `associated`. This
+essentially means that they are piggy-backed on some other interface's message
+pipe.
+
+Because individual interface message pipes operate independently there can be no
+relative ordering guarantees among them. Associated interfaces are useful when
+one interface needs to guarantee strict FIFO ordering with respect to one or
+more other interfaces, as they allow interfaces to share a single pipe.
+
+Currently associated interfaces are only supported in generated C++ bindings.
+See the documentation for
+[C++ Associated Interfaces](/mojo/public/cpp/bindings/README.md#Associated-Interfaces).
+
+## Versioning
+
+### Overview
+
+*** note
+**NOTE:** You don't need to worry about versioning if you don't care about
+backwards compatibility. Specifically, all parts of Chrome are updated
+atomically today and there is not yet any possibility of any two Chrome
+processes communicating with two different versions of any given Mojom
+interface.
+***
+
+Services extend their interfaces to support new features over time, and clients
+want to use those new features when they are available. If services and clients
+are not updated at the same time, it's important for them to be able to
+communicate with each other using different snapshots (versions) of their
+interfaces.
+
+This document shows how to extend Mojom interfaces in a backwards-compatible
+way. Changing interfaces in a non-backwards-compatible way is not discussed,
+because in that case communication between different interface versions is
+impossible anyway.
+
+### Versioned Structs
+
+You can use the `MinVersion` [attribute](#Attributes) to indicate from which
+version a struct field is introduced. Assume you have the following struct:
+
+``` cpp
+struct Employee {
+ uint64 employee_id;
+ string name;
+};
+```
+
+and you would like to add a birthday field. You can do:
+
+``` cpp
+struct Employee {
+ uint64 employee_id;
+ string name;
+ [MinVersion=1] Date? birthday;
+};
+```
+
+By default, fields belong to version 0. New fields must be appended to the
+struct definition (*i.e*., existing fields must not change **ordinal value**)
+with the `MinVersion` attribute set to a number greater than any previous
+existing versions.
+
+*** note
+**NOTE:** do not change existing fields in versioned structs, as this is
+not backwards-compatible. Instead, rename the old field to make its
+deprecation clear and add a new field with the new version number.
+***
+
+**Ordinal value** refers to the relative positional layout of a struct's fields
+(and an interface's methods) when encoded in a message. Implicitly, ordinal
+numbers are assigned to fields according to lexical position. In the example
+above, `employee_id` has an ordinal value of 0 and `name` has an ordinal value
+of 1.
+
+Ordinal values can be specified explicitly using `**@**` notation, subject to
+the following hard constraints:
+
+* For any given struct or interface, if any field or method explicitly specifies
+ an ordinal value, all fields or methods must explicitly specify an ordinal
+ value.
+* For an *N*-field struct or *N*-method interface, the set of explicitly
+ assigned ordinal values must be limited to the range *[0, N-1]*. Interfaces
+ should include placeholder methods to fill the ordinal positions of removed
+ methods (for example "Unused_Message_7@7()" or "RemovedMessage@42()", etc).
+
+You may reorder fields, but you must ensure that the ordinal values of existing
+fields remain unchanged. For example, the following struct remains
+backwards-compatible:
+
+``` cpp
+struct Employee {
+ uint64 employee_id@0;
+ [MinVersion=1] Date? birthday@2;
+ string name@1;
+};
+```
+
+*** note
+**NOTE:** Newly added fields of Mojo object or handle types MUST be nullable.
+See [Primitive Types](#Primitive-Types).
+***
+
+### Versioned Interfaces
+
+There are two dimensions on which an interface can be extended
+
+**Appending New Parameters To Existing Methods**
+: Parameter lists are treated as structs internally, so all the rules of
+ versioned structs apply to method parameter lists. The only difference is
+ that the version number is scoped to the whole interface rather than to any
+ individual parameter list.
+
+ Please note that adding a response to a message which did not previously
+ expect a response is a not a backwards-compatible change.
+
+**Appending New Methods**
+: Similarly, you can reorder methods with explicit ordinal values as long as
+ the ordinal values of existing methods are unchanged.
+
+For example:
+
+``` cpp
+// Old version:
+interface HumanResourceDatabase {
+ AddEmployee(Employee employee) => (bool success);
+ QueryEmployee(uint64 id) => (Employee? employee);
+};
+
+// New version:
+interface HumanResourceDatabase {
+ AddEmployee(Employee employee) => (bool success);
+
+ QueryEmployee(uint64 id, [MinVersion=1] bool retrieve_finger_print)
+ => (Employee? employee,
+ [MinVersion=1] array<uint8>? finger_print);
+
+ [MinVersion=1]
+ AttachFingerPrint(uint64 id, array<uint8> finger_print)
+ => (bool success);
+};
+```
+
+Similar to [versioned structs](#Versioned-Structs), when you pass the parameter
+list of a request or response method to a destination using an older version of
+an interface, unrecognized fields are silently discarded. However, if the method
+call itself is not recognized, it is considered a validation error and the
+receiver will close its end of the interface pipe. For example, if a client on
+version 1 of the above interface sends an `AttachFingerPrint` request to an
+implementation of version 0, the client will be disconnected.
+
+Bindings target languages that support versioning expose means to query or
+assert the remote version from a client handle (*e.g.*, an
+`mojo::Remote<T>` in C++ bindings.)
+
+See
+[C++ Versioning Considerations](/mojo/public/cpp/bindings/README.md#Versioning-Considerations)
+and
+[Java Versioning Considerations](/mojo/public/java/bindings/README.md#Versioning-Considerations)
+
+### Versioned Enums
+
+**By default, enums are non-extensible**, which means that generated message
+validation code does not expect to see new values in the future. When an unknown
+value is seen for a non-extensible enum field or parameter, a validation error
+is raised.
+
+If you want an enum to be extensible in the future, you can apply the
+`[Extensible]` [attribute](#Attributes):
+
+``` cpp
+[Extensible]
+enum Department {
+ SALES,
+ DEV,
+};
+```
+
+And later you can extend this enum without breaking backwards compatibility:
+
+``` cpp
+[Extensible]
+enum Department {
+ SALES,
+ DEV,
+ [MinVersion=1] RESEARCH,
+};
+```
+
+*** note
+**NOTE:** For versioned enum definitions, the use of a `[MinVersion]` attribute
+is strictly for documentation purposes. It has no impact on the generated code.
+***
+
+With extensible enums, bound interface implementations may receive unknown enum
+values and will need to deal with them gracefully. See
+[C++ Versioning Considerations](/mojo/public/cpp/bindings/README.md#Versioning-Considerations)
+for details.
+
+## Grammar Reference
+
+Below is the (BNF-ish) context-free grammar of the Mojom language:
+
+```
+MojomFile = StatementList
+StatementList = Statement StatementList | Statement
+Statement = ModuleStatement | ImportStatement | Definition
+
+ModuleStatement = AttributeSection "module" Identifier ";"
+ImportStatement = "import" StringLiteral ";"
+Definition = Struct Union Interface Enum Const
+
+AttributeSection = <empty> | "[" AttributeList "]"
+AttributeList = <empty> | NonEmptyAttributeList
+NonEmptyAttributeList = Attribute
+ | Attribute "," NonEmptyAttributeList
+Attribute = Name
+ | Name "=" Name
+ | Name "=" Literal
+
+Struct = AttributeSection "struct" Name "{" StructBody "}" ";"
+ | AttributeSection "struct" Name ";"
+StructBody = <empty>
+ | StructBody Const
+ | StructBody Enum
+ | StructBody StructField
+StructField = AttributeSection TypeSpec Name Ordinal Default ";"
+
+Union = AttributeSection "union" Name "{" UnionBody "}" ";"
+UnionBody = <empty> | UnionBody UnionField
+UnionField = AttributeSection TypeSpec Name Ordinal ";"
+
+Interface = AttributeSection "interface" Name "{" InterfaceBody "}" ";"
+InterfaceBody = <empty>
+ | InterfaceBody Const
+ | InterfaceBody Enum
+ | InterfaceBody Method
+Method = AttributeSection Name Ordinal "(" ParamterList ")" Response ";"
+ParameterList = <empty> | NonEmptyParameterList
+NonEmptyParameterList = Parameter
+ | Parameter "," NonEmptyParameterList
+Parameter = AttributeSection TypeSpec Name Ordinal
+Response = <empty> | "=>" "(" ParameterList ")"
+
+TypeSpec = TypeName "?" | TypeName
+TypeName = BasicTypeName
+ | Array
+ | FixedArray
+ | Map
+ | InterfaceRequest
+BasicTypeName = Identifier | "associated" Identifier | HandleType | NumericType
+NumericType = "bool" | "int8" | "uint8" | "int16" | "uint16" | "int32"
+ | "uint32" | "int64" | "uint64" | "float" | "double"
+HandleType = "handle" | "handle" "<" SpecificHandleType ">"
+SpecificHandleType = "message_pipe"
+ | "shared_buffer"
+ | "data_pipe_consumer"
+ | "data_pipe_producer"
+ | "platform"
+Array = "array" "<" TypeSpec ">"
+FixedArray = "array" "<" TypeSpec "," IntConstDec ">"
+Map = "map" "<" Identifier "," TypeSpec ">"
+InterfaceRequest = Identifier "&" | "associated" Identifier "&"
+
+Ordinal = <empty> | OrdinalValue
+
+Default = <empty> | "=" Constant
+
+Enum = AttributeSection "enum" Name "{" NonEmptyEnumValueList "}" ";"
+ | AttributeSection "enum" Name "{" NonEmptyEnumValueList "," "}" ";"
+NonEmptyEnumValueList = EnumValue | NonEmptyEnumValueList "," EnumValue
+EnumValue = AttributeSection Name
+ | AttributeSection Name "=" Integer
+ | AttributeSection Name "=" Identifier
+
+Const = "const" TypeSpec Name "=" Constant ";"
+
+Constant = Literal | Identifier ";"
+
+Identifier = Name | Name "." Identifier
+
+Literal = Integer | Float | "true" | "false" | "default" | StringLiteral
+
+Integer = IntConst | "+" IntConst | "-" IntConst
+IntConst = IntConstDec | IntConstHex
+
+Float = FloatConst | "+" FloatConst | "-" FloatConst
+
+; The rules below are for tokens matched strictly according to the given regexes
+
+Identifier = /[a-zA-Z_][0-9a-zA-Z_]*/
+IntConstDec = /0|(1-9[0-9]*)/
+IntConstHex = /0[xX][0-9a-fA-F]+/
+OrdinalValue = /@(0|(1-9[0-9]*))/
+FloatConst = ... # Imagine it's close enough to C-style float syntax.
+StringLiteral = ... # Imagine it's close enough to C-style string literals, including escapes.
+```
+
+## Additional Documentation
+
+[Mojom Message Format](https://docs.google.com/document/d/13pv9cFh5YKuBggDBQ1-AL8VReF-IYpFOFpRfvWFrwio/edit)
+: Describes the wire format used by Mojo bindings interfaces over message
+ pipes.
+
+[Input Format of Mojom Message Validation Tests](https://docs.google.com/document/d/1-y-2IYctyX2NPaLxJjpJfzVNWCC2SR2MJAD9MpIytHQ/edit)
+: Describes a text format used to facilitate bindings message validation
+ tests.
diff --git a/utils/ipc/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/utils/ipc/mojo/public/tools/bindings/chromium_bindings_configuration.gni
new file mode 100644
index 00000000..d8a13874
--- /dev/null
+++ b/utils/ipc/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -0,0 +1,51 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+_typemap_imports = [
+ "//chrome/chrome_cleaner/mojom/typemaps/typemaps.gni",
+ "//chrome/common/importer/typemaps.gni",
+ "//chrome/common/media_router/mojom/typemaps.gni",
+ "//chrome/typemaps.gni",
+ "//chromecast/typemaps.gni",
+ "//chromeos/typemaps.gni",
+ "//chromeos/components/multidevice/mojom/typemaps.gni",
+ "//chromeos/services/cros_healthd/public/mojom/typemaps.gni",
+ "//chromeos/services/device_sync/public/mojom/typemaps.gni",
+ "//chromeos/services/network_config/public/mojom/typemaps.gni",
+ "//chromeos/services/secure_channel/public/mojom/typemaps.gni",
+ "//components/arc/mojom/typemaps.gni",
+ "//components/chromeos_camera/common/typemaps.gni",
+ "//components/services/storage/public/cpp/filesystem/typemaps.gni",
+ "//components/sync/mojom/typemaps.gni",
+ "//components/typemaps.gni",
+ "//content/browser/typemaps.gni",
+ "//content/public/common/typemaps.gni",
+ "//sandbox/mac/mojom/typemaps.gni",
+ "//services/media_session/public/cpp/typemaps.gni",
+ "//services/proxy_resolver/public/cpp/typemaps.gni",
+ "//services/resource_coordinator/public/cpp/typemaps.gni",
+ "//services/service_manager/public/cpp/typemaps.gni",
+ "//services/tracing/public/mojom/typemaps.gni",
+]
+
+_typemaps = []
+foreach(typemap_import, _typemap_imports) {
+ # Avoid reassignment error by assigning to empty scope first.
+ _imported = {
+ }
+ _imported = read_file(typemap_import, "scope")
+ _typemaps += _imported.typemaps
+}
+
+typemaps = []
+foreach(typemap, _typemaps) {
+ typemaps += [
+ {
+ filename = typemap
+ config = read_file(typemap, "scope")
+ },
+ ]
+}
+
+component_macro_suffix = ""
diff --git a/utils/ipc/mojo/public/tools/bindings/compile_typescript.py b/utils/ipc/mojo/public/tools/bindings/compile_typescript.py
new file mode 100644
index 00000000..a978901b
--- /dev/null
+++ b/utils/ipc/mojo/public/tools/bindings/compile_typescript.py
@@ -0,0 +1,27 @@
+# Copyright 2019 The Chromium 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 os
+import sys
+import argparse
+
+_HERE_PATH = os.path.dirname(__file__)
+_SRC_PATH = os.path.normpath(os.path.join(_HERE_PATH, '..', '..', '..', '..'))
+
+sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'node'))
+import node
+import node_modules
+
+def main(argv):
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--tsconfig_path', required=True)
+ args = parser.parse_args(argv)
+
+ result = node.RunNode([node_modules.PathToTypescript()] +
+ ['--project', args.tsconfig_path])
+ if len(result) != 0:
+ raise RuntimeError('Failed to compile Typescript: \n%s' % result)
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/utils/ipc/mojo/public/tools/bindings/concatenate-files.py b/utils/ipc/mojo/public/tools/bindings/concatenate-files.py
new file mode 100755
index 00000000..48bc66fd
--- /dev/null
+++ b/utils/ipc/mojo/public/tools/bindings/concatenate-files.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# This utility concatenates several files into one. On Unix-like systems
+# it is equivalent to:
+# cat file1 file2 file3 ...files... > target
+#
+# The reason for writing a separate utility is that 'cat' is not available
+# on all supported build platforms, but Python is, and hence this provides
+# us with an easy and uniform way of doing this on all platforms.
+
+# for py2/py3 compatibility
+from __future__ import print_function
+
+import optparse
+
+
+def Concatenate(filenames):
+ """Concatenate files.
+
+ Args:
+ files: Array of file names.
+ The last name is the target; all earlier ones are sources.
+
+ Returns:
+ True, if the operation was successful.
+ """
+ if len(filenames) < 2:
+ print("An error occurred generating %s:\nNothing to do." % filenames[-1])
+ return False
+
+ try:
+ with open(filenames[-1], "wb") as target:
+ for filename in filenames[:-1]:
+ with open(filename, "rb") as current:
+ target.write(current.read())
+ return True
+ except IOError as e:
+ print("An error occurred when writing %s:\n%s" % (filenames[-1], e))
+ return False
+
+
+def main():
+ parser = optparse.OptionParser()
+ parser.set_usage("""Concatenate several files into one.
+ Equivalent to: cat file1 ... > target.""")
+ (_options, args) = parser.parse_args()
+ exit(0 if Concatenate(args) else 1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/utils/ipc/mojo/public/tools/bindings/concatenate_and_replace_closure_exports.py b/utils/ipc/mojo/public/tools/bindings/concatenate_and_replace_closure_exports.py
new file mode 100755
index 00000000..be8985ce
--- /dev/null
+++ b/utils/ipc/mojo/public/tools/bindings/concatenate_and_replace_closure_exports.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Simple utility which concatenates a set of files into a single output file
+while also stripping any goog.provide or goog.require lines. This allows us to
+provide a very primitive sort of "compilation" without any extra toolchain
+support and without having to modify otherwise compilable sources in the tree
+which use these directives.
+
+goog.provide lines are replaced with an equivalent invocation of
+mojo.internal.exportModule, which accomplishes essentially the same thing in an
+uncompiled context. A singular exception is made for the 'mojo.internal' export,
+which is instead replaced with an inlined assignment to initialize the
+namespace.
+"""
+
+from __future__ import print_function
+
+import optparse
+import re
+
+
+_MOJO_INTERNAL_MODULE_NAME = "mojo.internal"
+_MOJO_EXPORT_MODULE_SYMBOL = "mojo.internal.exportModule"
+
+
+def FilterLine(filename, line, output):
+ if line.startswith("goog.require"):
+ return
+
+ if line.startswith("goog.provide"):
+ match = re.match("goog.provide\('([^']+)'\);", line)
+ if not match:
+ print("Invalid goog.provide line in %s:\n%s" % (filename, line))
+ exit(1)
+
+ module_name = match.group(1)
+ if module_name == _MOJO_INTERNAL_MODULE_NAME:
+ output.write("self.mojo = { internal: {} };")
+ else:
+ output.write("%s('%s');\n" % (_MOJO_EXPORT_MODULE_SYMBOL, module_name))
+ return
+
+ output.write(line)
+
+def ConcatenateAndReplaceExports(filenames):
+ if (len(filenames) < 2):
+ print("At least two filenames (one input and the output) are required.")
+ return False
+
+ try:
+ with open(filenames[-1], "w") as target:
+ for filename in filenames[:-1]:
+ with open(filename, "r") as current:
+ for line in current.readlines():
+ FilterLine(filename, line, target)
+ return True
+ except IOError as e:
+ print("Error generating %s\n: %s" % (filenames[-1], e))
+ return False
+
+def main():
+ parser = optparse.OptionParser()
+ parser.set_usage("""file1 [file2...] outfile
+ Concatenate several files into one, stripping Closure provide and
+ require directives along the way.""")
+ (_, args) = parser.parse_args()
+ exit(0 if ConcatenateAndReplaceExports(args) else 1)
+
+if __name__ == "__main__":
+ main()
diff --git a/utils/ipc/mojo/public/tools/bindings/format_typemap_generator_args.py b/utils/ipc/mojo/public/tools/bindings/format_typemap_generator_args.py
new file mode 100755
index 00000000..7ac4af5f
--- /dev/null
+++ b/utils/ipc/mojo/public/tools/bindings/format_typemap_generator_args.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from __future__ import print_function
+
+import sys
+
+# This utility converts mojom dependencies into their corresponding typemap
+# paths and formats them to be consumed by generate_type_mappings.py.
+
+
+def FormatTypemap(typemap_filename):
+ # A simple typemap is valid Python with a minor alteration.
+ with open(typemap_filename) as f:
+ typemap_content = f.read().replace('=\n', '=')
+ typemap = {}
+ exec typemap_content in typemap
+
+ for header in typemap.get('public_headers', []):
+ yield 'public_headers=%s' % header
+ for header in typemap.get('traits_headers', []):
+ yield 'traits_headers=%s' % header
+ for header in typemap.get('type_mappings', []):
+ yield 'type_mappings=%s' % header
+
+
+def main():
+ typemaps = sys.argv[1:]
+ print(' '.join('--start-typemap %s' % ' '.join(FormatTypemap(typemap))
+ for typemap in typemaps))
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/utils/ipc/mojo/public/tools/bindings/gen_data_files_list.py b/utils/ipc/mojo/public/tools/bindings/gen_data_files_list.py
new file mode 100644
index 00000000..79c9e50e
--- /dev/null
+++ b/utils/ipc/mojo/public/tools/bindings/gen_data_files_list.py
@@ -0,0 +1,52 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Generates a list of all files in a directory.
+
+This script takes in a directory and an output file name as input.
+It then reads the directory and creates a list of all file names
+in that directory. The list is written to the output file.
+There is also an option to pass in '-p' or '--pattern'
+which will check each file name against a regular expression
+pattern that is passed in. Only files which match the regex
+will be written to the list.
+"""
+
+from __future__ import print_function
+
+import os
+import re
+import sys
+
+from cStringIO import StringIO
+from optparse import OptionParser
+
+sys.path.insert(
+ 0,
+ os.path.join(
+ os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "mojom"))
+
+from mojom.generate.generator import WriteFile
+
+
+def main():
+ parser = OptionParser()
+ parser.add_option('-d', '--directory', help='Read files from DIRECTORY')
+ parser.add_option('-o', '--output', help='Write list to FILE')
+ parser.add_option('-p',
+ '--pattern',
+ help='Only reads files that name matches PATTERN',
+ default=".")
+ (options, _) = parser.parse_args()
+ pattern = re.compile(options.pattern)
+ files = [f for f in os.listdir(options.directory) if pattern.match(f)]
+
+ stream = StringIO()
+ for f in files:
+ print(f, file=stream)
+
+ WriteFile(stream.getvalue(), options.output)
+ stream.close()
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/utils/ipc/mojo/public/tools/bindings/generate_type_mappings.py b/utils/ipc/mojo/public/tools/bindings/generate_type_mappings.py
new file mode 100755
index 00000000..64ca048f
--- /dev/null
+++ b/utils/ipc/mojo/public/tools/bindings/generate_type_mappings.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Generates a JSON typemap from its command-line arguments and dependencies.
+
+Each typemap should be specified in an command-line argument of the form
+key=value, with an argument of "--start-typemap" preceding each typemap.
+
+For example,
+generate_type_mappings.py --output=foo.typemap --start-typemap \\
+ public_headers=foo.h traits_headers=foo_traits.h \\
+ type_mappings=mojom.Foo=FooImpl
+
+generates a foo.typemap containing
+{
+ "c++": {
+ "mojom.Foo": {
+ "typename": "FooImpl",
+ "traits_headers": [
+ "foo_traits.h"
+ ],
+ "public_headers": [
+ "foo.h"
+ ]
+ }
+ }
+}
+
+Then,
+generate_type_mappings.py --dependency foo.typemap --output=bar.typemap \\
+ --start-typemap public_headers=bar.h traits_headers=bar_traits.h \\
+ type_mappings=mojom.Bar=BarImpl
+
+generates a bar.typemap containing
+{
+ "c++": {
+ "mojom.Bar": {
+ "typename": "BarImpl",
+ "traits_headers": [
+ "bar_traits.h"
+ ],
+ "public_headers": [
+ "bar.h"
+ ]
+ },
+ "mojom.Foo": {
+ "typename": "FooImpl",
+ "traits_headers": [
+ "foo_traits.h"
+ ],
+ "public_headers": [
+ "foo.h"
+ ]
+ }
+ }
+}
+"""
+
+import argparse
+import json
+import os
+import re
+import sys
+
+sys.path.insert(
+ 0,
+ os.path.join(
+ os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "mojom"))
+
+from mojom.generate.generator import WriteFile
+
+def ReadTypemap(path):
+ with open(path) as f:
+ return json.load(f)['c++']
+
+
+def ParseTypemapArgs(args):
+ typemaps = [s for s in '\n'.join(args).split('--start-typemap\n') if s]
+ result = {}
+ for typemap in typemaps:
+ result.update(ParseTypemap(typemap))
+ return result
+
+
+def LoadCppTypemapConfig(path):
+ configs = {}
+ with open(path) as f:
+ for config in json.load(f):
+ for entry in config['types']:
+ configs[entry['mojom']] = {
+ 'typename': entry['cpp'],
+ 'public_headers': config.get('traits_headers', []),
+ 'traits_headers': config.get('traits_private_headers', []),
+ 'copyable_pass_by_value': entry.get('copyable_pass_by_value',
+ False),
+ 'force_serialize': entry.get('force_serialize', False),
+ 'hashable': entry.get('hashable', False),
+ 'move_only': entry.get('move_only', False),
+ 'nullable_is_same_type': entry.get('nullable_is_same_type', False),
+ 'non_copyable_non_movable': False,
+ }
+ return configs
+
+
+def ParseTypemap(typemap):
+ values = {'type_mappings': [], 'public_headers': [], 'traits_headers': []}
+ for line in typemap.split('\n'):
+ if not line:
+ continue
+ key, _, value = line.partition('=')
+ values[key].append(value.lstrip('/'))
+ result = {}
+ mapping_pattern = \
+ re.compile(r"""^([^=]+) # mojom type
+ =
+ ([^[]+) # native type
+ (?:\[([^]]+)\])?$ # optional attribute in square brackets
+ """, re.X)
+ for typename in values['type_mappings']:
+ match_result = mapping_pattern.match(typename)
+ assert match_result, (
+ "Cannot parse entry in the \"type_mappings\" section: %s" % typename)
+
+ mojom_type = match_result.group(1)
+ native_type = match_result.group(2)
+ attributes = []
+ if match_result.group(3):
+ attributes = match_result.group(3).split(',')
+
+ assert mojom_type not in result, (
+ "Cannot map multiple native types (%s, %s) to the same mojom type: %s" %
+ (result[mojom_type]['typename'], native_type, mojom_type))
+
+ result[mojom_type] = {
+ 'public_headers': values['public_headers'],
+ 'traits_headers': values['traits_headers'],
+ 'typename': native_type,
+
+ # Attributes supported for individual mappings.
+ 'copyable_pass_by_value': 'copyable_pass_by_value' in attributes,
+ 'force_serialize': 'force_serialize' in attributes,
+ 'hashable': 'hashable' in attributes,
+ 'move_only': 'move_only' in attributes,
+ 'non_copyable_non_movable': 'non_copyable_non_movable' in attributes,
+ 'nullable_is_same_type': 'nullable_is_same_type' in attributes,
+ }
+ return result
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+ parser.add_argument(
+ '--dependency',
+ type=str,
+ action='append',
+ default=[],
+ help=('A path to another JSON typemap to merge into the output. '
+ 'This may be repeated to merge multiple typemaps.'))
+ parser.add_argument(
+ '--cpp-typemap-config',
+ type=str,
+ action='store',
+ dest='cpp_config_path',
+ help=('A path to a single JSON-formatted typemap config as emitted by'
+ 'GN when processing a mojom_cpp_typemap build rule.'))
+ parser.add_argument('--output',
+ type=str,
+ required=True,
+ help='The path to which to write the generated JSON.')
+ params, typemap_params = parser.parse_known_args()
+ typemaps = ParseTypemapArgs(typemap_params)
+ if params.cpp_config_path:
+ typemaps.update(LoadCppTypemapConfig(params.cpp_config_path))
+ missing = [path for path in params.dependency if not os.path.exists(path)]
+ if missing:
+ raise IOError('Missing dependencies: %s' % ', '.join(missing))
+ for path in params.dependency:
+ typemaps.update(ReadTypemap(path))
+
+ WriteFile(json.dumps({'c++': typemaps}, indent=2), params.output)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/utils/ipc/mojo/public/tools/bindings/mojom.gni b/utils/ipc/mojo/public/tools/bindings/mojom.gni
new file mode 100644
index 00000000..a739fa6e
--- /dev/null
+++ b/utils/ipc/mojo/public/tools/bindings/mojom.gni
@@ -0,0 +1,1941 @@
+# Copyright 2014 The Chromium 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/config/jumbo.gni")
+import("//third_party/closure_compiler/closure_args.gni")
+import("//third_party/closure_compiler/compile_js.gni")
+import("//third_party/protobuf/proto_library.gni")
+import("//ui/webui/webui_features.gni")
+
+# TODO(rockot): Maybe we can factor these dependencies out of //mojo. They're
+# used to conditionally enable message ID scrambling in a way which is
+# consistent across toolchains and which is affected by branded vs non-branded
+# Chrome builds. Ideally we could create some generic knobs here that could be
+# flipped elsewhere though.
+import("//build/config/chrome_build.gni")
+import("//build/config/chromecast_build.gni")
+import("//build/config/chromeos/ui_mode.gni")
+import("//build/config/nacl/config.gni")
+import("//build/toolchain/kythe.gni")
+import("//components/nacl/features.gni")
+import("//third_party/jinja2/jinja2.gni")
+import("//tools/ipc_fuzzer/ipc_fuzzer.gni")
+declare_args() {
+ # Indicates whether typemapping should be supported in this build
+ # configuration. This may be disabled when building external projects which
+ # depend on //mojo but which do not need/want all of the Chromium tree
+ # dependencies that come with typemapping.
+ #
+ # Note that (perhaps obviously) a huge amount of Chromium code will not build
+ # with typemapping disabled, so it is never valid to set this to |false| in
+ # any Chromium build configuration.
+ enable_mojom_typemapping = true
+
+ # Controls message ID scrambling behavior. If |true|, message IDs are
+ # scrambled (i.e. randomized based on the contents of //chrome/VERSION) on
+ # non-Chrome OS desktop platforms. Set to |false| to disable message ID
+ # scrambling on all platforms.
+ enable_mojom_message_id_scrambling = true
+
+ # Enables Closure compilation of generated JS lite bindings. In environments
+ # where compilation is supported, any mojom target "foo" will also have a
+ # corresponding "foo_js_library_for_compile" target generated.
+ enable_mojom_closure_compile = enable_js_type_check && optimize_webui
+
+ # Enables generating Typescript bindings and compiling them to JS bindings.
+ enable_typescript_bindings = false
+
+ # Enables generating javascript fuzzing-related code and the bindings for the
+ # MojoLPM fuzzer targets. Off by default.
+ enable_mojom_fuzzer = false
+}
+
+# NOTE: We would like to avoid scrambling message IDs where it doesn't add
+# value, so we limit the behavior to desktop builds for now. There is some
+# redundancy in the conditions here, but it is tolerated for clarity:
+# We're explicit about Mac, Windows, and Linux desktop support, but it's
+# also necessary to ensure that bindings in alternate toolchains (e.g.
+# NaCl IRT) are always consistent with the default toolchain; for that
+# reason we always enable scrambling within NaCl toolchains when possible,
+# as well as within the default toolchain when NaCl is enabled.
+#
+# Finally, because we *cannot* enable scrambling on Chrome OS (it would break
+# ARC) we have to explicitly opt out there even when NaCl is enabled (and
+# consequently also when building for NaCl toolchains.) For this reason we
+# check |target_os| explicitly, as it's consistent across all toolchains.
+enable_scrambled_message_ids =
+ enable_mojom_message_id_scrambling &&
+ (is_mac || is_win || (is_linux && !is_chromeos && !is_chromecast &&
+ !chromeos_is_browser_only) ||
+ ((enable_nacl || is_nacl || is_nacl_nonsfi) &&
+ (target_os != "chromeos" && !chromeos_is_browser_only)))
+
+_mojom_tools_root = "//mojo/public/tools"
+_mojom_library_root = "$_mojom_tools_root/mojom/mojom"
+mojom_parser_script = "$_mojom_tools_root/mojom/mojom_parser.py"
+mojom_parser_sources = [
+ "$_mojom_library_root/__init__.py",
+ "$_mojom_library_root/error.py",
+ "$_mojom_library_root/generate/__init__.py",
+ "$_mojom_library_root/generate/constant_resolver.py",
+ "$_mojom_library_root/generate/generator.py",
+ "$_mojom_library_root/generate/module.py",
+ "$_mojom_library_root/generate/pack.py",
+ "$_mojom_library_root/generate/template_expander.py",
+ "$_mojom_library_root/generate/translate.py",
+ "$_mojom_library_root/parse/__init__.py",
+ "$_mojom_library_root/parse/ast.py",
+ "$_mojom_library_root/parse/lexer.py",
+ "$_mojom_library_root/parse/parser.py",
+]
+
+mojom_generator_root = "$_mojom_tools_root/bindings"
+mojom_generator_script = "$mojom_generator_root/mojom_bindings_generator.py"
+mojom_generator_sources =
+ mojom_parser_sources + [
+ "$mojom_generator_root/generators/mojom_cpp_generator.py",
+ "$mojom_generator_root/generators/mojom_java_generator.py",
+ "$mojom_generator_root/generators/mojom_mojolpm_generator.py",
+ "$mojom_generator_root/generators/mojom_js_generator.py",
+ "$mojom_generator_root/generators/mojom_ts_generator.py",
+ "$mojom_generator_script",
+ ]
+
+if (enable_scrambled_message_ids) {
+ declare_args() {
+ # The path to a file whose contents can be used as the basis for a message
+ # ID scrambling salt.
+ mojom_message_id_salt_path = "//chrome/VERSION"
+
+ # The path to a file whose contents will be concatenated to the contents of
+ # the file at |mojom_message_id_salt_path| to form a complete salt for
+ # message ID scrambling. May be the empty string, in which case the contents
+ # of the above file alone are used as the complete salt.
+ if (is_chrome_branded) {
+ mojom_message_id_salt_suffix_path =
+ "//mojo/internal/chrome-message-id-salt-suffix"
+ } else {
+ mojom_message_id_salt_suffix_path = ""
+ }
+ }
+
+ assert(mojom_message_id_salt_path != "")
+ message_scrambling_args = [
+ "--scrambled_message_id_salt_path",
+ rebase_path(mojom_message_id_salt_path, root_build_dir),
+ ]
+ message_scrambling_inputs = [ mojom_message_id_salt_path ]
+
+ if (mojom_message_id_salt_suffix_path != "") {
+ message_scrambling_args += [
+ "--scrambled_message_id_salt_path",
+ rebase_path(mojom_message_id_salt_suffix_path, root_build_dir),
+ ]
+ message_scrambling_inputs += [ mojom_message_id_salt_suffix_path ]
+ }
+} else {
+ message_scrambling_args = []
+ message_scrambling_inputs = []
+}
+
+if (enable_mojom_typemapping) {
+ _bindings_configuration_files =
+ [ "//mojo/public/tools/bindings/chromium_bindings_configuration.gni" ]
+ _bindings_configurations = []
+ foreach(config_file, _bindings_configuration_files) {
+ _bindings_configurations += [ read_file(config_file, "scope") ]
+ }
+ foreach(configuration, _bindings_configurations) {
+ # Check that the mojom field of each typemap refers to a mojom that exists.
+ foreach(typemap, configuration.typemaps) {
+ _typemap_config = {
+ }
+ _typemap_config = typemap.config
+ read_file(_typemap_config.mojom, "")
+ }
+ }
+} else {
+ _bindings_configuration_files = []
+ _bindings_configurations = [
+ {
+ typemaps = []
+ component_macro_suffix = ""
+ },
+ ]
+}
+
+if (!is_ios) {
+ _bindings_configurations += [
+ {
+ variant = "blink"
+ component_macro_suffix = "_BLINK"
+ for_blink = true
+ typemaps = []
+ },
+ ]
+}
+
+# Generates targets for building C++, JavaScript and Java bindings from mojom
+# files. The output files will go under the generated file directory tree with
+# the same path as each input file.
+#
+# Other targets should depend on one of these generated targets (where "foo"
+# is the target name):
+#
+# foo
+# C++ bindings.
+#
+# foo_blink
+# C++ bindings using Blink standard types.
+#
+# foo_java
+# Java bindings.
+#
+# foo_js
+# JavaScript bindings; used as compile-time dependency.
+#
+# foo_js_data_deps
+# JavaScript bindings; used as run-time dependency.
+#
+# Parameters:
+#
+# sources (optional if one of the deps sets listed below is present)
+# List of source .mojom files to compile.
+#
+# deps (optional)
+# Note: this can contain only other mojom targets.
+#
+# DEPRECATED: This is synonymous with public_deps because all mojom
+# dependencies must be public by design. Please use public_deps.
+#
+# public_deps (optional)
+# Note: this can contain only other mojom targets.
+#
+# parser_deps (optional)
+# List of non-mojom targets required for the mojom sources to be parsed.
+#
+# import_dirs (optional)
+# List of import directories that will get added when processing sources.
+#
+# testonly (optional)
+#
+# visibility (optional)
+#
+# visibility_blink (optional)
+# The value to use for visibility for the blink variant. If unset,
+# |visibility| is used.
+#
+# cpp_only (optional)
+# If set to true, only the C++ bindings targets will be generated.
+#
+# NOTE: If the global |enable_mojom_fuzzer| build arg is true, JS bindings
+# will still be generated even when |cpp_only| is set to |true|, unless
+# you also set |enable_fuzzing| to |false| in your mojom target.
+#
+# cpp_typemaps (optional)
+# A list of typemaps to be applied to the generated C++ bindings for this
+# mojom target. Note that this only applies to the non-Blink variant of
+# generated C++ bindings.
+#
+# Every typemap is a GN scope describing how one or more mojom types maps
+# to a non-mojom C++ type, including necessary deps and headers required
+# for the mapping to work. See the Typemaps section below.
+#
+# blink_cpp_typemaps (optional)
+# Same as above, but for the Blink variant of generated C++ bindings.
+#
+# generate_java (optional)
+# If set to true, Java bindings are generated for Android builds. If
+# |cpp_only| is set to true, it overrides this to prevent generation of
+# Java bindings.
+#
+# enable_fuzzing (optional)
+# Enables generation of fuzzing sources for the target if the global build
+# arg |enable_mojom_fuzzer| is also set to |true|. Defaults to |true|. If
+# fuzzing generation is enabled for a target, the target will always
+# generate JS bindings even if |cpp_only| is set to |true|. See note
+# above.
+#
+# support_lazy_serialization (optional)
+# If set to |true|, generated C++ bindings will effectively prefer to
+# transmit messages in an unserialized form when going between endpoints
+# in the same process. This avoids the runtime cost of serialization,
+# deserialization, and validation logic at the expensive of increased
+# code size. Defaults to |false|.
+#
+# disable_variants (optional)
+# If |true|, no variant sources will be generated for the target. Defaults
+# to |false|.
+#
+# disallow_native_types (optional)
+# If set to |true|, mojoms in this target may not apply the [Native]
+# attribute to struct or enum declarations. This avoids emitting code
+# which depends on legacy IPC serialization. Default is |false|, meaning
+# [Native] types are allowed.
+#
+# disallow_interfaces (optional)
+# If set to |true|, mojoms in this target may not define interfaces.
+# Generates bindings with a smaller set of dependencies. Defaults to
+# |false|.
+#
+# scramble_message_ids (optional)
+# If set to |true| (the default), generated mojom interfaces will use
+# scrambled ordinal identifiers in encoded messages.
+#
+# component_output_prefix (optional)
+# The prefix to use for the output_name of any component library emitted
+# for generated C++ bindings. If this is omitted, C++ bindings targets are
+# emitted as source_sets instead. Because this controls the name of the
+# output shared library binary in the root output directory, it must be
+# unique across the entire build configuration.
+#
+# This is required if |component_macro_prefix| is specified.
+#
+# component_macro_prefix (optional)
+# This specifies a macro prefix to use for component export macros and
+# should therefore be globally unique in the project. For example if this
+# is "FOO_BAR", then the generated C++ sources will be built with
+# IS_FOO_BAR_{suffix}_IMPL defined, and the generated public headers will
+# annotate public symbol definitions with
+# COMPONENT_EXPORT(FOO_BAR_{suffix}). "suffix" in this case depends on
+# which internal subtarget is generating the code (e.g. "SHARED", or a
+# variant name like "BLINK").
+#
+# enabled_features (optional)
+# Definitions in a mojom file can be guarded by an EnableIf attribute. If
+# the value specified by the attribute does not match any items in the
+# list of enabled_features, the definition will be disabled, with no code
+# emitted for it.
+#
+# generate_closure_exports (optional)
+# Generates JS lite bindings will use goog.provide and goog.require
+# annotations to export its symbols and import core Mojo bindings support
+# and other mojom dependency modules. Use this if you plan to compile your
+# bindings into a larger JS binary. Defaults to |false|, instead
+# generating JS lite bindings which assume they will be manually loaded in
+# correct dependency order. Note that this only has an effect if
+# the |enable_mojom_closure_compile| global arg is set to |true| as well.
+#
+# use_typescript_sources (optional)
+# Uses the Typescript generator to generate JavaScript bindings.
+#
+# js_generate_struct_deserializers (optional)
+# Generates JS deerialize methods for structs.
+#
+# extra_cpp_template_paths (optional)
+# List of extra C++ templates that are used to generate additional source
+# and/or header files. The templates should end with extension ".tmpl".
+#
+# The following parameters are used to support the component build. They are
+# needed so that bindings which are linked with a component can use the same
+# export settings for classes. The first three are for the chromium variant, and
+# the last three are for the blink variant. These parameters can also override
+# |component_macro_prefix| for a specific variant, allowing e.g. one variant
+# to be linked into a larger non-mojom component target, while all other
+# variants get their own unique component target.
+# export_class_attribute (optional)
+# The attribute to add to the class declaration. e.g. "CONTENT_EXPORT"
+# export_define (optional)
+# A define to be added to the source_set which is needed by the export
+# header. e.g. "CONTENT_IMPLEMENTATION=1"
+# export_header (optional)
+# A header to be added to the generated bindings to support the component
+# build. e.g. "content/common/content_export.h"
+# export_class_attribute_blink (optional)
+# export_define_blink (optional)
+# export_header_blink (optional)
+# These three parameters are the blink variants of the previous 3.
+#
+# The following parameters are used to correct component build dependencies.
+# They are needed so mojom-mojom dependencies follow the rule that dependencies
+# on a source set in another component are replaced by a dependency on the
+# containing component. The first two are for the chromium variant; the other
+# two are for the blink variant.
+# overridden_deps (optional)
+# The list of mojom deps to be overridden.
+# component_deps (optional)
+# The list of component deps to add to replace overridden_deps.
+# overridden_deps_blink (optional)
+# component_deps_blink (optional)
+# These two parameters are the blink variants of the previous two.
+#
+# check_includes_blink (optional)
+# Overrides the check_includes variable for the blink variant.
+# If check_includes_blink is not defined, the check_includes variable
+# retains its original value.
+#
+# Typemaps
+# ========
+# The cpp_typemaps and blink_cpp_typemaps each specify an optional list of
+# typemapping configurations. Each configuration is a GN scope with metadata
+# describing what and how to map.
+#
+# Typemap scope parameters:
+# types
+# A list of type specifications for this typemap. Each type specification
+# is a nested GN scope which can be expressed with the following syntax:
+#
+# {
+# mojom = "foo.mojom.Bar"
+# cpp = "::foo::LegitBar"
+# move_only = true
+# # etc...
+# }
+#
+# Each type specification supports the following values:
+#
+# mojom (required)
+# The fully qualified name of a mojom type to be mapped. This is a
+# string like "foo.mojom.Bar".
+#
+# cpp (required)
+# The fully qualified name of the C++ type to which the mojom type
+# should be mapped in generated bindings. This is a string like
+# "::base::Value" or "std::vector<::base::Value>".
+#
+# move_only (optional)
+# A boolean value (default false) which indicates whether the C++
+# type is move-only. If true, generated bindings will pass the type
+# by value and use std::move() at call sites.
+#
+# copyable_pass_by_value (optional)
+# A boolean value (default false) which effectively indicates
+# whether the C++ type is very cheap to copy. If so, generated
+# bindings will pass by value but not use std::move() at call sites.
+#
+# nullable_is_same_type (optional)
+# A boolean value (default false) which indicates that the C++ type
+# has some baked-in semantic notion of a "null" state. If true, the
+# traits for the type must define IsNull and SetToNull methods.
+#
+# When false, nullable fields are represented by wrapping the C++
+# type with base::Optional, and null values are simply
+# base::nullopt.
+#
+# hashable (optional)
+# A boolean value (default false) indicating whether the C++ type is
+# hashable. Set to true if true AND needed (i.e. you need to use the
+# type as the key of a mojom map).
+#
+# force_serialize (optional)
+# A boolean value (default false) which disables lazy serialization
+# of the typemapped type if lazy serialization is enabled for the
+# mojom target applying this typemap.
+#
+# Additional typemap scope parameters:
+#
+# traits_headers (optional)
+# Headers which must be included in the generated mojom in order for
+# serialization to be possible. This generally means including at least
+# the header for the corresponding mojom traits definitions.
+#
+# traits_private_headers (optional)
+# Headers which must be included in generated C++ serialization code for
+# a mojom using the typemap. This should be used only when including a
+# header in |traits_headers| is problematic for compilation, as is
+# sometimes the case with legacy IPC message headers.
+#
+# traits_sources (optional)
+# The references to the source files (typically a single .cc and .h file)
+# defining an appropriate set of EnumTraits or StructTraits, etc for the
+# the type-mapping. Using this will cause the listed sources to be
+# integrated directly into the dependent mojom's generated type-mapping
+# targets.
+#
+# Prefer using |traits_public_deps| over inlined |traits_sources|, as this
+# will generally lead to easier build maintenance over time.
+#
+# NOTE: If a typemap is shared by Blink and non-Blink bindings, you cannot
+# use this and MUST use |traits_public_deps| to reference traits built
+# within a separate target.
+#
+# traits_deps / traits_public_deps (optional)
+# Any dependencies of sources in |traits_headers| or |traits_sources| must
+# be listed here.
+#
+template("mojom") {
+ assert(
+ defined(invoker.sources) || defined(invoker.deps) ||
+ defined(invoker.public_deps),
+ "\"sources\" or \"deps\" must be defined for the $target_name template.")
+
+ if (defined(invoker.export_class_attribute) ||
+ defined(invoker.export_define) || defined(invoker.export_header)) {
+ assert(defined(invoker.export_class_attribute))
+ assert(defined(invoker.export_define))
+ assert(defined(invoker.export_header))
+ }
+ if (defined(invoker.export_class_attribute_blink) ||
+ defined(invoker.export_define_blink) ||
+ defined(invoker.export_header_blink)) {
+ assert(defined(invoker.export_class_attribute_blink))
+ assert(defined(invoker.export_define_blink))
+ assert(defined(invoker.export_header_blink))
+
+ # Not all platforms use the Blink variant, so make sure GN doesn't complain
+ # about these values being inconsequential.
+ not_needed(invoker,
+ [
+ "export_class_attribute_blink",
+ "export_define_blink",
+ "export_header_blink",
+ ])
+ }
+ if (defined(invoker.overridden_deps) || defined(invoker.component_deps)) {
+ assert(defined(invoker.overridden_deps))
+ assert(defined(invoker.component_deps))
+ }
+
+ if (defined(invoker.overridden_deps_blink) ||
+ defined(invoker.component_deps_blink)) {
+ assert(defined(invoker.overridden_deps_blink))
+ assert(defined(invoker.component_deps_blink))
+ }
+
+ # Type-mapping may be disabled or we may not generate C++ bindings.
+ not_needed(invoker,
+ [
+ "cpp_typemaps",
+ "blink_cpp_typemaps",
+ ])
+
+ require_full_cpp_deps =
+ !defined(invoker.disallow_native_types) ||
+ !invoker.disallow_native_types || !defined(invoker.disallow_interfaces) ||
+ !invoker.disallow_interfaces
+
+ all_deps = []
+ if (defined(invoker.deps)) {
+ all_deps += invoker.deps
+ }
+ if (defined(invoker.public_deps)) {
+ all_deps += invoker.public_deps
+ }
+
+ if (defined(invoker.component_macro_prefix)) {
+ assert(defined(invoker.component_output_prefix))
+ }
+
+ group("${target_name}__is_mojom") {
+ }
+
+ # Explicitly ensure that all dependencies (invoker.deps and
+ # invoker.public_deps) are mojom targets.
+ group("${target_name}__check_deps_are_all_mojom") {
+ deps = []
+ foreach(d, all_deps) {
+ name = get_label_info(d, "label_no_toolchain")
+ toolchain = get_label_info(d, "toolchain")
+ deps += [ "${name}__is_mojom(${toolchain})" ]
+ }
+ }
+
+ sources_list = []
+ if (defined(invoker.sources)) {
+ sources_list = invoker.sources
+ }
+
+ # Reset sources_assignment_filter for the BUILD.gn file to prevent
+ # regression during the migration of Chromium away from the feature.
+ # See docs/no_sources_assignment_filter.md for more information.
+ # TODO(crbug.com/1018739): remove this when migration is done.
+ set_sources_assignment_filter([])
+
+ # Listed sources may be relative to the current target dir, or they may be
+ # absolute paths, including paths to generated mojom files. While those are
+ # fine as-is for input references, deriving output paths can be more subtle.
+ #
+ # Here we rewrite all source paths to be relative to the root build dir and
+ # strip any root_gen_dir prefixes.
+ #
+ # So for a target in //foo/bar with:
+ #
+ # sources = [
+ # "a.mojom",
+ # "b/c.mojom",
+ # "//baz/d.mojom",
+ # "$target_gen_dir/e.mojom",
+ # ]
+ #
+ # output_file_base_paths will be:
+ #
+ # [
+ # "foo/bar/a.mojom",
+ # "foo/bar/b/c.mojom",
+ # "baz/d.mojom",
+ # "foo/bar/e.mojom",
+ # ]
+ #
+ # This result is essentially a list of base filename paths which are suitable
+ # for the naming of any generated output files derived from their
+ # corresponding input mojoms. These paths are always considered to be relative
+ # to root_gen_dir.
+ source_abspaths = rebase_path(sources_list, "//")
+ output_file_base_paths = []
+ foreach(path, source_abspaths) {
+ output_file_base_paths +=
+ [ string_replace(path, rebase_path(root_gen_dir, "//") + "/", "") ]
+ }
+
+ # Sanity check that either all input files have a .mojom extension, or
+ # all input files have a .test-mojom extension AND |testonly| is |true|.
+ sources_list_filenames =
+ process_file_template(sources_list, "{{source_file_part}}")
+ sources_list_filenames_with_mojom_extension =
+ process_file_template(sources_list, "{{source_name_part}}.mojom")
+ if (sources_list_filenames != sources_list_filenames_with_mojom_extension) {
+ sources_list_filenames_with_test_mojom_extension =
+ process_file_template(sources_list, "{{source_name_part}}.test-mojom")
+ if (sources_list_filenames ==
+ sources_list_filenames_with_test_mojom_extension) {
+ assert(
+ defined(invoker.testonly) && invoker.testonly,
+ "mojom targets for .test-mojom files must set |testonly| to |true|")
+ } else {
+ assert(
+ false,
+ "One or more mojom files has an invalid extension. The only " +
+ "allowed extensions are .mojom and .test-mojom, and any given " +
+ "mojom target must use one or the other exclusively.")
+ }
+ }
+
+ build_metadata_filename = "$target_gen_dir/$target_name.build_metadata"
+ build_metadata = {
+ }
+ build_metadata.sources = rebase_path(sources_list)
+ build_metadata.deps = []
+ foreach(dep, all_deps) {
+ dep_target_gen_dir = get_label_info(dep, "target_gen_dir")
+ dep_name = get_label_info(dep, "name")
+ build_metadata.deps +=
+ [ rebase_path("$dep_target_gen_dir/$dep_name.build_metadata") ]
+ }
+ write_file(build_metadata_filename, build_metadata, "json")
+
+ generate_fuzzing =
+ (!defined(invoker.enable_fuzzing) || invoker.enable_fuzzing) &&
+ enable_mojom_fuzzer && (!defined(invoker.testonly) || !invoker.testonly)
+
+ parser_target_name = "${target_name}__parser"
+ parser_deps = []
+ foreach(dep, all_deps) {
+ _label = get_label_info(dep, "label_no_toolchain")
+ parser_deps += [ "${_label}__parser" ]
+ }
+ if (defined(invoker.parser_deps)) {
+ parser_deps += invoker.parser_deps
+ }
+ if (sources_list == []) {
+ # Even without sources we generate a parser target to at least forward
+ # other parser dependencies.
+ group(parser_target_name) {
+ public_deps = parser_deps
+ }
+ } else {
+ enabled_features = []
+ if (defined(invoker.enabled_features)) {
+ enabled_features += invoker.enabled_features
+ }
+ if (is_posix) {
+ enabled_features += [ "is_posix" ]
+ }
+ if (is_android) {
+ enabled_features += [ "is_android" ]
+ } else if (is_chromeos) {
+ enabled_features += [ "is_chromeos" ]
+ } else if (is_fuchsia) {
+ enabled_features += [ "is_fuchsia" ]
+ } else if (is_ios) {
+ enabled_features += [ "is_ios" ]
+ } else if (is_linux) {
+ enabled_features += [ "is_linux" ]
+ } else if (is_mac) {
+ enabled_features += [ "is_mac" ]
+ } else if (is_win) {
+ enabled_features += [ "is_win" ]
+ }
+
+ action(parser_target_name) {
+ script = mojom_parser_script
+ inputs = mojom_parser_sources + [ build_metadata_filename ]
+ sources = sources_list
+ deps = parser_deps
+ outputs = []
+ foreach(base_path, output_file_base_paths) {
+ filename = get_path_info(base_path, "file")
+ dirname = get_path_info(base_path, "dir")
+ outputs += [ "$root_gen_dir/$dirname/${filename}-module" ]
+ }
+
+ filelist = []
+ foreach(source, sources_list) {
+ filelist += [ rebase_path(source) ]
+ }
+ response_file_contents = filelist
+
+ args = [
+ # Resolve relative input mojom paths against both the root src dir and
+ # the root gen dir.
+ "--input-root",
+ rebase_path("//"),
+ "--input-root",
+ rebase_path(root_gen_dir),
+
+ "--output-root",
+ rebase_path(root_gen_dir),
+
+ "--mojom-file-list={{response_file_name}}",
+
+ "--check-imports",
+ rebase_path(build_metadata_filename),
+ ]
+
+ foreach(enabled_feature, enabled_features) {
+ args += [
+ "--enable-feature",
+ enabled_feature,
+ ]
+ }
+ }
+ }
+
+ generator_cpp_message_ids_target_name = "${target_name}__generate_message_ids"
+
+ # Generate code that is shared by different variants.
+ if (sources_list != []) {
+ common_generator_args = [
+ "--use_bundled_pylibs",
+ "-o",
+ rebase_path(root_gen_dir, root_build_dir),
+ "generate",
+ "-d",
+ rebase_path("//", root_build_dir),
+ "-I",
+ rebase_path("//", root_build_dir),
+ "--bytecode_path",
+ rebase_path("$root_gen_dir/mojo/public/tools/bindings", root_build_dir),
+ ]
+
+ if (defined(invoker.disallow_native_types) &&
+ invoker.disallow_native_types) {
+ common_generator_args += [ "--disallow_native_types" ]
+ }
+
+ if (defined(invoker.disallow_interfaces) && invoker.disallow_interfaces) {
+ common_generator_args += [ "--disallow_interfaces" ]
+ }
+
+ if (defined(invoker.import_dirs)) {
+ foreach(import_dir, invoker.import_dirs) {
+ common_generator_args += [
+ "-I",
+ rebase_path(import_dir, root_build_dir),
+ ]
+ }
+ }
+
+ if (defined(invoker.component_macro_prefix)) {
+ shared_component_export_macro =
+ "COMPONENT_EXPORT(${invoker.component_macro_prefix}_SHARED)"
+ shared_component_impl_macro =
+ "IS_${invoker.component_macro_prefix}_SHARED_IMPL"
+ shared_component_output_name = "${invoker.component_output_prefix}_shared"
+ } else if (defined(invoker.export_class_attribute_shared) ||
+ defined(invoker.export_class_attribute)) {
+ if (defined(invoker.export_class_attribute_shared)) {
+ assert(defined(invoker.export_header_shared))
+ shared_component_export_macro = invoker.export_class_attribute_shared
+ shared_component_impl_macro = invoker.export_define_shared
+ } else {
+ assert(!defined(invoker.export_header_shared))
+
+ # If no explicit shared attribute/define was provided by the invoker,
+ # we derive some reasonable settings frorm the default variant.
+ shared_component_export_macro = "COMPONENT_EXPORT(MOJOM_SHARED_" +
+ invoker.export_class_attribute + ")"
+ shared_component_impl_macro =
+ "IS_MOJOM_SHARED_" + invoker.export_class_attribute + "_IMPL"
+ }
+
+ if (defined(invoker.component_output_prefix)) {
+ shared_component_output_name =
+ "${invoker.component_output_prefix}_shared"
+ } else {
+ shared_component_output_name = "${target_name}_shared"
+ }
+ }
+
+ action(generator_cpp_message_ids_target_name) {
+ script = mojom_generator_script
+ inputs = mojom_generator_sources + jinja2_sources
+ sources = sources_list
+ deps = [
+ ":$parser_target_name",
+ "//mojo/public/tools/bindings:precompile_templates",
+ ]
+ if (defined(invoker.parser_deps)) {
+ deps += invoker.parser_deps
+ }
+ outputs = []
+ args = common_generator_args
+ filelist = []
+ foreach(source, sources_list) {
+ filelist += [ rebase_path("$source", root_build_dir) ]
+ }
+ foreach(base_path, output_file_base_paths) {
+ outputs += [ "$root_gen_dir/$base_path-shared-message-ids.h" ]
+ }
+
+ response_file_contents = filelist
+
+ args += [
+ "--filelist={{response_file_name}}",
+ "--generate_non_variant_code",
+ "--generate_message_ids",
+ "-g",
+ "c++",
+ ]
+
+ if (!defined(invoker.scramble_message_ids) ||
+ invoker.scramble_message_ids) {
+ inputs += message_scrambling_inputs
+ args += message_scrambling_args
+ }
+ }
+
+ generator_shared_target_name = "${target_name}_shared__generator"
+ action(generator_shared_target_name) {
+ visibility = [ ":*" ]
+ script = mojom_generator_script
+ inputs = mojom_generator_sources + jinja2_sources
+ sources = sources_list
+ deps = [
+ ":$parser_target_name",
+ "//mojo/public/tools/bindings:precompile_templates",
+ ]
+ if (defined(invoker.parser_deps)) {
+ deps += invoker.parser_deps
+ }
+
+ outputs = []
+ args = common_generator_args
+ filelist = []
+ foreach(source, sources_list) {
+ filelist += [ rebase_path("$source", root_build_dir) ]
+ }
+ foreach(base_path, output_file_base_paths) {
+ outputs += [
+ "$root_gen_dir/$base_path-params-data.h",
+ "$root_gen_dir/$base_path-shared-internal.h",
+ "$root_gen_dir/$base_path-shared.cc",
+ "$root_gen_dir/$base_path-shared.h",
+ ]
+ }
+
+ response_file_contents = filelist
+
+ args += [
+ "--filelist={{response_file_name}}",
+ "--generate_non_variant_code",
+ "-g",
+ "c++",
+ ]
+
+ if (defined(shared_component_export_macro)) {
+ args += [
+ "--export_attribute",
+ shared_component_export_macro,
+ "--export_header",
+ "base/component_export.h",
+ ]
+ }
+
+ # Enable adding annotations to generated C++ headers that are used for
+ # cross-references in CodeSearch.
+ if (enable_kythe_annotations) {
+ args += [ "--enable_kythe_annotations" ]
+ }
+ }
+ } else {
+ group(generator_cpp_message_ids_target_name) {
+ }
+ }
+
+ shared_cpp_sources_target_name = "${target_name}_shared_cpp_sources"
+ jumbo_source_set(shared_cpp_sources_target_name) {
+ if (defined(invoker.testonly)) {
+ testonly = invoker.testonly
+ }
+ deps = []
+ public_deps = []
+ if (output_file_base_paths != []) {
+ sources = []
+ foreach(base_path, output_file_base_paths) {
+ sources += [
+ "$root_gen_dir/$base_path-params-data.h",
+ "$root_gen_dir/$base_path-shared-internal.h",
+ "$root_gen_dir/$base_path-shared.cc",
+ "$root_gen_dir/$base_path-shared.h",
+ ]
+ }
+ public_deps += [ ":$generator_shared_target_name" ]
+ }
+ if (require_full_cpp_deps) {
+ public_deps += [ "//mojo/public/cpp/bindings" ]
+ } else {
+ public_deps += [ "//mojo/public/cpp/bindings:bindings_base" ]
+ }
+ foreach(d, all_deps) {
+ # Resolve the name, so that a target //mojo/something becomes
+ # //mojo/something:something and we can append shared_cpp_sources_suffix
+ # to get the cpp dependency name.
+ full_name = get_label_info("$d", "label_no_toolchain")
+ public_deps += [ "${full_name}_shared" ]
+ }
+ if (defined(shared_component_impl_macro)) {
+ defines = [ shared_component_impl_macro ]
+ }
+ }
+
+ shared_cpp_library_target_name = "${target_name}_shared"
+ if (defined(shared_component_output_name)) {
+ component(shared_cpp_library_target_name) {
+ if (defined(invoker.testonly)) {
+ testonly = invoker.testonly
+ }
+ output_name = "$shared_component_output_name"
+ public_deps = [ ":$shared_cpp_sources_target_name" ]
+ }
+ } else {
+ group(shared_cpp_library_target_name) {
+ if (defined(invoker.testonly)) {
+ testonly = invoker.testonly
+ }
+ public_deps = [ ":$shared_cpp_sources_target_name" ]
+ }
+ }
+
+ if (generate_fuzzing) {
+ # This block generates the proto files used for the MojoLPM fuzzer,
+ # and the corresponding proto targets that will be linked in the fuzzer
+ # targets. These are independent of the typemappings, and can be done
+ # separately here.
+
+ generator_mojolpm_proto_target_name =
+ "${target_name}_mojolpm_proto_generator"
+ action(generator_mojolpm_proto_target_name) {
+ script = mojom_generator_script
+ inputs = mojom_generator_sources + jinja2_sources
+ sources = invoker.sources
+ deps = [
+ ":$parser_target_name",
+ "//mojo/public/tools/bindings:precompile_templates",
+ ]
+
+ outputs = []
+ args = common_generator_args
+ filelist = []
+ foreach(source, invoker.sources) {
+ filelist += [ rebase_path("$source", root_build_dir) ]
+ outputs += [ "$target_gen_dir/$source.mojolpm.proto" ]
+ }
+
+ response_file_contents = filelist
+
+ args += [
+ "--filelist={{response_file_name}}",
+ "--generate_non_variant_code",
+ "-g",
+ "mojolpm",
+ ]
+ }
+
+ mojolpm_proto_target_name = "${target_name}_mojolpm_proto"
+ if (defined(invoker.sources)) {
+ proto_library(mojolpm_proto_target_name) {
+ testonly = true
+ generate_python = false
+ sources = process_file_template(
+ invoker.sources,
+ [ "{{source_gen_dir}}/{{source_file_part}}.mojolpm.proto" ])
+ import_dirs = [ "${root_gen_dir}" ]
+ proto_in_dir = "${root_gen_dir}"
+ proto_out_dir = "."
+ proto_deps = [ "//mojo/public/tools/fuzzers:mojolpm_proto_copy" ]
+ proto_deps += [ ":$generator_mojolpm_proto_target_name" ]
+ link_deps = [ "//mojo/public/tools/fuzzers:mojolpm_proto" ]
+
+ foreach(d, all_deps) {
+ # Resolve the name, so that a target //mojo/something becomes
+ # //mojo/something:something and we can append mojolpm_proto_suffix
+ # to get the proto dependency name.
+ full_name = get_label_info("$d", "label_no_toolchain")
+ proto_deps += [ "${full_name}_mojolpm_proto" ]
+ link_deps += [ "${full_name}_mojolpm_proto" ]
+ }
+ }
+ } else {
+ group(mojolpm_proto_target_name) {
+ testonly = true
+ public_deps = [ "//mojo/public/tools/fuzzers:mojolpm_proto" ]
+ if (defined(generator_shared_target_name)) {
+ public_deps += [ ":$generator_shared_target_name" ]
+ }
+ foreach(d, all_deps) {
+ # Resolve the name, so that a target //mojo/something becomes
+ # //mojo/something:something and we can append #mojolpm_proto_suffix
+ # to get the proto dependency name.
+ full_name = get_label_info("$d", "label_no_toolchain")
+ public_deps += [ "${full_name}_mojolpm_proto" ]
+ }
+ }
+ }
+ }
+
+ # Generate code for variants.
+ if (!defined(invoker.disable_variants) || !invoker.disable_variants) {
+ enabled_configurations = _bindings_configurations
+ } else {
+ first_config = _bindings_configurations[0]
+ assert(!defined(first_config.variant))
+ enabled_configurations = [ first_config ]
+ }
+ foreach(bindings_configuration, enabled_configurations) {
+ cpp_only = false
+ if (defined(invoker.cpp_only)) {
+ cpp_only = invoker.cpp_only
+ }
+ variant_suffix = ""
+ if (defined(bindings_configuration.variant)) {
+ variant = bindings_configuration.variant
+ variant_suffix = "_${variant}"
+ cpp_only = true
+ }
+
+ cpp_typemap_configs = []
+ export_defines = []
+ export_defines_overridden = false
+ force_source_set = false
+ if (defined(bindings_configuration.for_blink) &&
+ bindings_configuration.for_blink) {
+ if (defined(invoker.blink_cpp_typemaps)) {
+ cpp_typemap_configs = invoker.blink_cpp_typemaps
+ }
+ if (defined(invoker.export_define_blink)) {
+ export_defines_overridden = true
+ export_defines = [ invoker.export_define_blink ]
+ force_source_set = true
+ }
+ } else {
+ if (defined(invoker.cpp_typemaps)) {
+ cpp_typemap_configs = invoker.cpp_typemaps
+ }
+
+ if (defined(invoker.export_define)) {
+ export_defines_overridden = true
+ export_defines = [ invoker.export_define ]
+ force_source_set = true
+ }
+ }
+ not_needed([ "cpp_typemap_configs" ])
+
+ if (!export_defines_overridden && defined(invoker.component_macro_prefix)) {
+ output_name_override =
+ "${invoker.component_output_prefix}${variant_suffix}"
+ export_defines =
+ [ "IS_${invoker.component_macro_prefix}" +
+ "${bindings_configuration.component_macro_suffix}_IMPL" ]
+ }
+
+ export_args = []
+ export_args_overridden = false
+ if (defined(bindings_configuration.for_blink) &&
+ bindings_configuration.for_blink) {
+ if (defined(invoker.export_class_attribute_blink)) {
+ export_args_overridden = true
+ export_args += [
+ "--export_attribute",
+ invoker.export_class_attribute_blink,
+ "--export_header",
+ invoker.export_header_blink,
+ ]
+ }
+ } else if (defined(invoker.export_class_attribute)) {
+ export_args_overridden = true
+ export_args += [
+ "--export_attribute",
+ invoker.export_class_attribute,
+ "--export_header",
+ invoker.export_header,
+ ]
+ }
+
+ if (!export_args_overridden && defined(invoker.component_macro_prefix)) {
+ export_args += [
+ "--export_attribute",
+ "COMPONENT_EXPORT(${invoker.component_macro_prefix}" +
+ "${bindings_configuration.component_macro_suffix})",
+ "--export_header",
+ "base/component_export.h",
+ ]
+ }
+
+ generate_java = false
+ if (!cpp_only && defined(invoker.generate_java)) {
+ generate_java = invoker.generate_java
+ }
+ type_mappings_target_name = "${target_name}${variant_suffix}__type_mappings"
+ type_mappings_path =
+ "$target_gen_dir/${target_name}${variant_suffix}__type_mappings"
+ active_typemaps = []
+ if (sources_list != []) {
+ generator_cpp_output_suffixes = []
+ variant_dash_suffix = ""
+ if (defined(variant)) {
+ variant_dash_suffix = "-${variant}"
+ }
+ generator_cpp_output_suffixes += [
+ "${variant_dash_suffix}-forward.h",
+ "${variant_dash_suffix}-import-headers.h",
+ "${variant_dash_suffix}-test-utils.cc",
+ "${variant_dash_suffix}-test-utils.h",
+ "${variant_dash_suffix}.cc",
+ "${variant_dash_suffix}.h",
+ ]
+ foreach(source, sources_list) {
+ # TODO(sammc): Use a map instead of a linear scan when GN supports maps.
+ foreach(typemap, bindings_configuration.typemaps) {
+ _typemap_config = {
+ }
+ _typemap_config = typemap.config
+ if (get_path_info(source, "abspath") == _typemap_config.mojom) {
+ active_typemaps += [ typemap ]
+ }
+ }
+ }
+
+ generator_target_name = "${target_name}${variant_suffix}__generator"
+ action(generator_target_name) {
+ visibility = [ ":*" ]
+ script = mojom_generator_script
+ inputs = mojom_generator_sources + jinja2_sources
+ sources = sources_list
+ deps = [
+ ":$parser_target_name",
+ ":$type_mappings_target_name",
+ "//mojo/public/tools/bindings:precompile_templates",
+ ]
+ if (defined(invoker.parser_deps)) {
+ deps += invoker.parser_deps
+ }
+ outputs = []
+ args = common_generator_args + export_args
+ filelist = []
+ foreach(source, sources_list) {
+ filelist += [ rebase_path("$source", root_build_dir) ]
+ }
+ foreach(base_path, output_file_base_paths) {
+ outputs += [
+ "$root_gen_dir/${base_path}${variant_dash_suffix}-forward.h",
+ "$root_gen_dir/${base_path}${variant_dash_suffix}-import-headers.h",
+ "$root_gen_dir/${base_path}${variant_dash_suffix}-test-utils.cc",
+ "$root_gen_dir/${base_path}${variant_dash_suffix}-test-utils.h",
+ "$root_gen_dir/${base_path}${variant_dash_suffix}.cc",
+ "$root_gen_dir/${base_path}${variant_dash_suffix}.h",
+ ]
+ if (generate_fuzzing && !defined(bindings_configuration.variant)) {
+ outputs += [
+ "$root_gen_dir/${base_path}${variant_dash_suffix}-mojolpm.cc",
+ "$root_gen_dir/${base_path}${variant_dash_suffix}-mojolpm.h",
+ ]
+ }
+ }
+
+ response_file_contents = filelist
+
+ args += [
+ "--filelist={{response_file_name}}",
+ "-g",
+ ]
+
+ if (generate_fuzzing && !defined(bindings_configuration.variant)) {
+ args += [ "c++,mojolpm" ]
+ } else {
+ args += [ "c++" ]
+ }
+
+ if (defined(bindings_configuration.variant)) {
+ args += [
+ "--variant",
+ bindings_configuration.variant,
+ ]
+ }
+
+ args += [
+ "--typemap",
+ rebase_path(type_mappings_path, root_build_dir),
+ ]
+
+ if (defined(bindings_configuration.for_blink) &&
+ bindings_configuration.for_blink) {
+ args += [ "--for_blink" ]
+ }
+
+ if (defined(invoker.support_lazy_serialization) &&
+ invoker.support_lazy_serialization) {
+ args += [ "--support_lazy_serialization" ]
+ }
+
+ if (enable_kythe_annotations) {
+ args += [ "--enable_kythe_annotations" ]
+ }
+
+ if (!defined(invoker.scramble_message_ids) ||
+ invoker.scramble_message_ids) {
+ inputs += message_scrambling_inputs
+ args += message_scrambling_args
+ }
+
+ if (defined(invoker.extra_cpp_template_paths)) {
+ foreach(extra_cpp_template, invoker.extra_cpp_template_paths) {
+ args += [
+ "--extra_cpp_template_paths",
+ rebase_path(extra_cpp_template, root_build_dir),
+ ]
+ assert(
+ get_path_info(extra_cpp_template, "extension") == "tmpl",
+ "--extra_cpp_template_paths only accepts template files ending in extension .tmpl")
+ foreach(base_path, output_file_base_paths) {
+ template_file_name = get_path_info("$extra_cpp_template", "name")
+ outputs += [ "$root_gen_dir/${base_path}${variant_dash_suffix}-${template_file_name}" ]
+ }
+ }
+ }
+ }
+ }
+
+ if (generate_fuzzing && !defined(variant)) {
+ # This block contains the C++ targets for the MojoLPM fuzzer, we need to
+ # do this here so that we can use the typemap configuration for the
+ # empty-variant Mojo target.
+
+ mojolpm_target_name = "${target_name}_mojolpm"
+ mojolpm_generator_target_name = "${target_name}__generator"
+ source_set(mojolpm_target_name) {
+ # There are still a few missing header dependencies between mojo targets
+ # with typemaps and the dependencies of their typemap headers. It would
+ # be good to enable include checking for these in the future though.
+ check_includes = false
+ testonly = true
+ if (defined(invoker.sources)) {
+ sources = process_file_template(
+ invoker.sources,
+ [
+ "{{source_gen_dir}}/{{source_file_part}}-mojolpm.cc",
+ "{{source_gen_dir}}/{{source_file_part}}-mojolpm.h",
+ ])
+ deps = []
+ } else {
+ sources = []
+ deps = []
+ }
+
+ public_deps = [
+ ":$generator_shared_target_name",
+
+ # NB: hardcoded dependency on the no-variant variant generator, since
+ # mojolpm only uses the no-variant type.
+ ":$mojolpm_generator_target_name",
+ ":$mojolpm_proto_target_name",
+ "//mojo/public/tools/fuzzers:mojolpm",
+ ]
+
+ foreach(d, all_deps) {
+ # Resolve the name, so that a target //mojo/something becomes
+ # //mojo/something:something and we can append variant_suffix to
+ # get the cpp dependency name.
+ full_name = get_label_info("$d", "label_no_toolchain")
+ public_deps += [ "${full_name}_mojolpm" ]
+ }
+
+ foreach(typemap, active_typemaps) {
+ _typemap_config = {
+ }
+ _typemap_config = typemap.config
+
+ if (defined(_typemap_config.deps)) {
+ deps += _typemap_config.deps
+ }
+ if (defined(_typemap_config.public_deps)) {
+ public_deps += _typemap_config.public_deps
+ }
+ }
+ foreach(config, cpp_typemap_configs) {
+ if (defined(config.traits_deps)) {
+ deps += config.traits_deps
+ }
+ if (defined(config.traits_public_deps)) {
+ public_deps += config.traits_public_deps
+ }
+ }
+ }
+ }
+
+ # Write the typemapping configuration for this target out to a file to be
+ # validated by a Python script. This helps catch mistakes that can't
+ # be caught by logic in GN.
+ _typemap_config_filename =
+ "$target_gen_dir/${target_name}${variant_suffix}.typemap_config"
+ _typemap_stamp_filename = "${_typemap_config_filename}.validated"
+ _typemap_validator_target_name = "${type_mappings_target_name}__validator"
+ _rebased_typemap_configs = []
+ foreach(config, cpp_typemap_configs) {
+ _rebased_config = {
+ }
+ _rebased_config = config
+ if (defined(config.traits_headers)) {
+ _rebased_config.traits_headers = []
+ _rebased_config.traits_headers =
+ rebase_path(config.traits_headers, "//")
+ }
+ if (defined(config.traits_private_headers)) {
+ _rebased_config.traits_private_headers = []
+ _rebased_config.traits_private_headers =
+ rebase_path(config.traits_private_headers, "//")
+ }
+ _rebased_typemap_configs += [ _rebased_config ]
+ }
+ write_file(_typemap_config_filename, _rebased_typemap_configs, "json")
+ _mojom_target_name = target_name
+ action(_typemap_validator_target_name) {
+ script = "$mojom_generator_root/validate_typemap_config.py"
+ inputs = [ _typemap_config_filename ]
+ outputs = [ _typemap_stamp_filename ]
+ args = [
+ get_label_info(_mojom_target_name, "label_no_toolchain"),
+ rebase_path(_typemap_config_filename),
+ rebase_path(_typemap_stamp_filename),
+ ]
+ }
+
+ action(type_mappings_target_name) {
+ inputs = _bindings_configuration_files + mojom_generator_sources +
+ jinja2_sources + [ _typemap_stamp_filename ]
+ outputs = [ type_mappings_path ]
+ script = "$mojom_generator_root/generate_type_mappings.py"
+ deps = [ ":$_typemap_validator_target_name" ]
+ args = [
+ "--output",
+ rebase_path(type_mappings_path, root_build_dir),
+ ]
+
+ foreach(d, all_deps) {
+ name = get_label_info(d, "label_no_toolchain")
+ toolchain = get_label_info(d, "toolchain")
+ dependency_output = "${name}${variant_suffix}__type_mappings"
+ dependency_target = "${dependency_output}(${toolchain})"
+ deps += [ dependency_target ]
+ dependency_output_dir =
+ get_label_info(dependency_output, "target_gen_dir")
+ dependency_name = get_label_info(dependency_output, "name")
+ dependency_path =
+ rebase_path("$dependency_output_dir/${dependency_name}",
+ root_build_dir)
+ args += [
+ "--dependency",
+ dependency_path,
+ ]
+ }
+
+ if (sources_list != []) {
+ # TODO(sammc): Pass the typemap description in a file to avoid command
+ # line length limitations.
+ typemap_description = []
+ foreach(typemap, active_typemaps) {
+ _typemap_config = {
+ }
+ _typemap_config = typemap.config
+
+ typemap_description += [ "--start-typemap" ]
+ if (defined(_typemap_config.public_headers)) {
+ foreach(value, _typemap_config.public_headers) {
+ typemap_description += [ "public_headers=$value" ]
+ }
+ }
+ if (defined(_typemap_config.traits_headers)) {
+ foreach(value, _typemap_config.traits_headers) {
+ typemap_description += [ "traits_headers=$value" ]
+ }
+ }
+ foreach(value, _typemap_config.type_mappings) {
+ typemap_description += [ "type_mappings=$value" ]
+ }
+
+ # The typemap configuration files are not actually used as inputs here
+ # but this establishes a necessary build dependency to ensure that
+ # typemap changes force a rebuild of affected targets.
+ if (defined(typemap.filename)) {
+ inputs += [ typemap.filename ]
+ }
+ }
+ args += typemap_description
+
+ # Newer GN-based typemaps are aggregated into a single config.
+ inputs += [ _typemap_config_filename ]
+ args += [
+ "--cpp-typemap-config",
+ rebase_path(_typemap_config_filename, root_build_dir),
+ ]
+ }
+ }
+
+ group("${target_name}${variant_suffix}_headers") {
+ public_deps = []
+ if (sources_list != []) {
+ public_deps += [
+ ":$generator_cpp_message_ids_target_name",
+ ":$generator_shared_target_name",
+ ":$generator_target_name",
+ ]
+ }
+ foreach(d, all_deps) {
+ full_name = get_label_info("$d", "label_no_toolchain")
+ public_deps += [ "${full_name}${variant_suffix}_headers" ]
+ }
+ }
+
+ if (!force_source_set && defined(invoker.component_macro_prefix)) {
+ output_target_type = "component"
+ } else {
+ output_target_type = "source_set"
+ }
+
+ js_data_deps_target_name = target_name + "_js_data_deps"
+ not_needed([ "js_data_deps_target_name" ])
+
+ target("jumbo_" + output_target_type, "${target_name}${variant_suffix}") {
+ if (defined(output_name_override)) {
+ output_name = output_name_override
+ }
+ if (defined(bindings_configuration.for_blink) &&
+ bindings_configuration.for_blink &&
+ defined(invoker.visibility_blink)) {
+ visibility = invoker.visibility_blink
+ } else if (defined(invoker.visibility)) {
+ visibility = invoker.visibility
+ }
+ if (defined(invoker.testonly)) {
+ testonly = invoker.testonly
+ }
+ defines = export_defines
+ if (output_file_base_paths != []) {
+ sources = []
+ foreach(base_path, output_file_base_paths) {
+ foreach(suffix, generator_cpp_output_suffixes) {
+ sources += [ "$root_gen_dir/${base_path}$suffix" ]
+ }
+ }
+ }
+ deps = [
+ ":$generator_cpp_message_ids_target_name",
+ "//mojo/public/cpp/bindings:struct_traits",
+ "//mojo/public/interfaces/bindings:bindings_headers",
+ ]
+ public_deps = [
+ ":$shared_cpp_library_target_name",
+ "//base",
+ ]
+ if (require_full_cpp_deps) {
+ public_deps += [ "//mojo/public/cpp/bindings" ]
+ } else {
+ public_deps += [ "//mojo/public/cpp/bindings:bindings_base" ]
+ }
+
+ if (sources_list != []) {
+ public_deps += [ ":$generator_target_name" ]
+ }
+ foreach(d, all_deps) {
+ # Resolve the name, so that a target //mojo/something becomes
+ # //mojo/something:something and we can append variant_suffix to
+ # get the cpp dependency name.
+ full_name = get_label_info("$d", "label_no_toolchain")
+ public_deps += [ "${full_name}${variant_suffix}" ]
+ }
+ if (defined(bindings_configuration.for_blink) &&
+ bindings_configuration.for_blink) {
+ if (defined(invoker.overridden_deps_blink)) {
+ foreach(d, invoker.overridden_deps_blink) {
+ # Resolve the name, so that a target //mojo/something becomes
+ # //mojo/something:something and we can append variant_suffix
+ # to get the cpp dependency name.
+ full_name = get_label_info("$d", "label_no_toolchain")
+ public_deps -= [ "${full_name}${variant_suffix}" ]
+ }
+ public_deps += invoker.component_deps_blink
+ }
+ if (defined(invoker.check_includes_blink)) {
+ check_includes = invoker.check_includes_blink
+ }
+ } else {
+ if (defined(invoker.check_includes_blink)) {
+ not_needed(invoker, [ "check_includes_blink" ])
+ }
+ if (defined(invoker.overridden_deps)) {
+ foreach(d, invoker.overridden_deps) {
+ # Resolve the name, so that a target //mojo/something becomes
+ # //mojo/something:something and we can append variant_suffix
+ # to get the cpp dependency name.
+ full_name = get_label_info("$d", "label_no_toolchain")
+ public_deps -= [ "${full_name}${variant_suffix}" ]
+ }
+ public_deps += invoker.component_deps
+ }
+ }
+ foreach(typemap, active_typemaps) {
+ _typemap_config = {
+ }
+ _typemap_config = typemap.config
+ if (defined(_typemap_config.sources)) {
+ sources += _typemap_config.sources
+ }
+ if (defined(_typemap_config.public_deps)) {
+ public_deps += _typemap_config.public_deps
+ }
+ if (defined(_typemap_config.deps)) {
+ deps += _typemap_config.deps
+ }
+ }
+ foreach(config, cpp_typemap_configs) {
+ if (defined(config.traits_sources)) {
+ sources += config.traits_sources
+ }
+ if (defined(config.traits_deps)) {
+ deps += config.traits_deps
+ }
+ if (defined(config.traits_public_deps)) {
+ public_deps += config.traits_public_deps
+ }
+ }
+ if (defined(invoker.export_header)) {
+ sources += [ "//" + invoker.export_header ]
+ }
+ if (defined(bindings_configuration.for_blink) &&
+ bindings_configuration.for_blink) {
+ public_deps += [ "//mojo/public/cpp/bindings:wtf_support" ]
+ }
+
+ if (generate_fuzzing) {
+ # Generate JS bindings by default if IPC fuzzer is enabled.
+ public_deps += [ ":$js_data_deps_target_name" ]
+ }
+ }
+
+ if (generate_java && is_android) {
+ import("//build/config/android/rules.gni")
+
+ java_generator_target_name = target_name + "_java__generator"
+ if (sources_list != []) {
+ action(java_generator_target_name) {
+ script = mojom_generator_script
+ inputs = mojom_generator_sources + jinja2_sources
+ sources = sources_list
+ deps = [
+ ":$parser_target_name",
+ ":$type_mappings_target_name",
+ "//mojo/public/tools/bindings:precompile_templates",
+ ]
+ outputs = []
+ args = common_generator_args
+ filelist = []
+ foreach(source, sources_list) {
+ filelist += [ rebase_path("$source", root_build_dir) ]
+ }
+ foreach(base_path, output_file_base_paths) {
+ outputs += [ "$root_gen_dir/$base_path.srcjar" ]
+ }
+
+ response_file_contents = filelist
+
+ args += [
+ "--filelist={{response_file_name}}",
+ "-g",
+ "java",
+ ]
+
+ if (!defined(invoker.scramble_message_ids) ||
+ invoker.scramble_message_ids) {
+ inputs += message_scrambling_inputs
+ args += message_scrambling_args
+ }
+ }
+ } else {
+ group(java_generator_target_name) {
+ }
+ }
+
+ java_srcjar_target_name = target_name + "_java_sources"
+ action(java_srcjar_target_name) {
+ script = "//build/android/gyp/zip.py"
+ inputs = []
+ if (output_file_base_paths != []) {
+ foreach(base_path, output_file_base_paths) {
+ inputs += [ "$root_gen_dir/${base_path}.srcjar" ]
+ }
+ }
+ output = "$target_gen_dir/$target_name.srcjar"
+ outputs = [ output ]
+ rebase_inputs = rebase_path(inputs, root_build_dir)
+ rebase_output = rebase_path(output, root_build_dir)
+ args = [
+ "--input-zips=$rebase_inputs",
+ "--output=$rebase_output",
+ ]
+ deps = []
+ if (sources_list != []) {
+ deps = [ ":$java_generator_target_name" ]
+ }
+ }
+
+ java_target_name = target_name + "_java"
+ android_library(java_target_name) {
+ forward_variables_from(invoker, [ "enable_bytecode_checks" ])
+ deps = [
+ "//base:base_java",
+ "//mojo/public/java:bindings_java",
+ "//mojo/public/java:system_java",
+ ]
+
+ # Disable warnings/checks on these generated files.
+ chromium_code = false
+
+ foreach(d, all_deps) {
+ # Resolve the name, so that a target //mojo/something becomes
+ # //mojo/something:something and we can append "_java" to get the java
+ # dependency name.
+ full_name = get_label_info(d, "label_no_toolchain")
+ deps += [ "${full_name}_java" ]
+ }
+
+ srcjar_deps = [ ":$java_srcjar_target_name" ]
+ }
+ }
+ }
+
+ use_typescript_for_target =
+ enable_typescript_bindings && defined(invoker.use_typescript_sources) &&
+ invoker.use_typescript_sources
+
+ if (!use_typescript_for_target && defined(invoker.use_typescript_sources)) {
+ not_needed(invoker, [ "use_typescript_sources" ])
+ }
+
+ if ((generate_fuzzing || !defined(invoker.cpp_only) || !invoker.cpp_only) &&
+ !use_typescript_for_target) {
+ if (sources_list != []) {
+ generator_js_target_name = "${target_name}_js__generator"
+ action(generator_js_target_name) {
+ script = mojom_generator_script
+ inputs = mojom_generator_sources + jinja2_sources
+ sources = sources_list
+ deps = [
+ ":$parser_target_name",
+ "//mojo/public/tools/bindings:precompile_templates",
+ ]
+ if (defined(invoker.parser_deps)) {
+ deps += invoker.parser_deps
+ }
+ outputs = []
+ args = common_generator_args
+ filelist = []
+ foreach(source, sources_list) {
+ filelist += [ rebase_path("$source", root_build_dir) ]
+ }
+ foreach(base_path, output_file_base_paths) {
+ outputs += [
+ "$root_gen_dir/$base_path.js",
+ "$root_gen_dir/$base_path.externs.js",
+ "$root_gen_dir/$base_path-lite.js",
+ "$root_gen_dir/$base_path.html",
+ "$root_gen_dir/$base_path-lite-for-compile.js",
+ ]
+ }
+
+ response_file_contents = filelist
+
+ args += [
+ "--filelist={{response_file_name}}",
+ "-g",
+ "javascript",
+ "--js_bindings_mode=new",
+ ]
+
+ if (defined(invoker.js_generate_struct_deserializers) &&
+ invoker.js_generate_struct_deserializers) {
+ args += [ "--js_generate_struct_deserializers" ]
+ }
+
+ if (!defined(invoker.scramble_message_ids) ||
+ invoker.scramble_message_ids) {
+ inputs += message_scrambling_inputs
+ args += message_scrambling_args
+ }
+
+ if (generate_fuzzing) {
+ args += [ "--generate_fuzzing" ]
+ }
+ }
+ }
+
+ js_target_name = target_name + "_js"
+ group(js_target_name) {
+ public_deps = []
+ if (sources_list != []) {
+ public_deps += [ ":$generator_js_target_name" ]
+ }
+
+ foreach(d, all_deps) {
+ full_name = get_label_info(d, "label_no_toolchain")
+ public_deps += [ "${full_name}_js" ]
+ }
+ }
+
+ group(js_data_deps_target_name) {
+ deps = []
+ if (sources_list != []) {
+ data = []
+ foreach(base_path, output_file_base_paths) {
+ data += [
+ "$root_gen_dir/${base_path}.js",
+ "$root_gen_dir/${base_path}-lite.js",
+ ]
+ }
+ deps += [ ":$generator_js_target_name" ]
+ }
+
+ data_deps = []
+ foreach(d, all_deps) {
+ full_name = get_label_info(d, "label_no_toolchain")
+ data_deps += [ "${full_name}_js_data_deps" ]
+ }
+ }
+
+ js_library_target_name = "${target_name}_js_library"
+ if (sources_list != []) {
+ js_library(js_library_target_name) {
+ extra_public_deps = [ ":$generator_js_target_name" ]
+ sources = []
+ foreach(base_path, output_file_base_paths) {
+ sources += [ "$root_gen_dir/${base_path}-lite.js" ]
+ }
+ externs_list = [
+ "${externs_path}/mojo_core.js",
+ "${externs_path}/pending.js",
+ ]
+
+ deps = []
+ foreach(d, all_deps) {
+ full_name = get_label_info(d, "label_no_toolchain")
+ deps += [ "${full_name}_js_library" ]
+ }
+ }
+ } else {
+ group(js_library_target_name) {
+ }
+ }
+
+ js_library_for_compile_target_name = "${target_name}_js_library_for_compile"
+ if (sources_list != []) {
+ js_library(js_library_for_compile_target_name) {
+ extra_public_deps = [ ":$generator_js_target_name" ]
+ sources = []
+ foreach(base_path, output_file_base_paths) {
+ sources += [ "$root_gen_dir/${base_path}-lite-for-compile.js" ]
+ }
+ externs_list = [
+ "${externs_path}/mojo_core.js",
+ "${externs_path}/pending.js",
+ ]
+ deps = []
+ if (!defined(invoker.disallow_native_types)) {
+ deps += [ "//mojo/public/js:bindings_lite_sources" ]
+ }
+ foreach(d, all_deps) {
+ full_name = get_label_info(d, "label_no_toolchain")
+ deps += [ "${full_name}_js_library_for_compile" ]
+ }
+ }
+ } else {
+ group(js_library_for_compile_target_name) {
+ }
+ }
+ }
+ if ((generate_fuzzing || !defined(invoker.cpp_only) || !invoker.cpp_only) &&
+ use_typescript_for_target) {
+ generator_js_target_names = []
+ source_filelist = []
+ foreach(source, sources_list) {
+ source_filelist += [ rebase_path("$source", root_build_dir) ]
+ }
+
+ dependency_types = [
+ {
+ name = "regular"
+ ts_extension = ".ts"
+ js_extension = ".js"
+ },
+ {
+ name = "es_modules"
+ ts_extension = ".m.ts"
+ js_extension = ".m.js"
+ },
+ ]
+
+ foreach(dependency_type, dependency_types) {
+ ts_outputs = []
+ js_outputs = []
+
+ foreach(base_path, output_file_base_paths) {
+ ts_outputs +=
+ [ "$root_gen_dir/$base_path-lite${dependency_type.ts_extension}" ]
+ js_outputs +=
+ [ "$root_gen_dir/$base_path-lite${dependency_type.js_extension}" ]
+ }
+
+ # Generate Typescript bindings.
+ generator_ts_target_name =
+ "${target_name}_${dependency_type.name}__ts__generator"
+ action(generator_ts_target_name) {
+ script = mojom_generator_script
+ inputs = mojom_generator_sources + jinja2_sources
+ sources = sources_list
+ deps = [
+ ":$parser_target_name",
+ "//mojo/public/tools/bindings:precompile_templates",
+ ]
+
+ outputs = ts_outputs
+ args = common_generator_args
+ response_file_contents = source_filelist
+
+ args += [
+ "--filelist={{response_file_name}}",
+ "-g",
+ "typescript",
+ ]
+
+ if (dependency_type.name == "es_modules") {
+ args += [ "--ts_use_es_modules" ]
+ }
+
+ # TODO(crbug.com/1007587): Support scramble_message_ids.
+ # TODO(crbug.com/1007591): Support generate_fuzzing.
+ }
+
+ # Create tsconfig.json for the generated Typescript.
+ tsconfig_filename =
+ "$target_gen_dir/$target_name-${dependency_type.name}-tsconfig.json"
+ tsconfig = {
+ }
+ tsconfig.compilerOptions = {
+ composite = true
+ target = "es6"
+ module = "es6"
+ lib = [
+ "es6",
+ "esnext.bigint",
+ ]
+ strict = true
+ }
+ tsconfig.files = []
+ foreach(base_path, output_file_base_paths) {
+ tsconfig.files += [ rebase_path(
+ "$root_gen_dir/$base_path-lite${dependency_type.ts_extension}",
+ target_gen_dir,
+ root_gen_dir) ]
+ }
+ tsconfig.references = []
+
+ # Get tsconfigs for deps.
+ foreach(d, all_deps) {
+ dep_target_gen_dir = rebase_path(get_label_info(d, "target_gen_dir"))
+ dep_name = get_label_info(d, "name")
+ reference = {
+ }
+ reference.path = "$dep_target_gen_dir/$dep_name-${dependency_type.name}-tsconfig.json"
+ tsconfig.references += [ reference ]
+ }
+ write_file(tsconfig_filename, tsconfig, "json")
+
+ # Compile previously generated Typescript to Javascript.
+ generator_js_target_name =
+ "${target_name}_${dependency_type.name}__js__generator"
+ generator_js_target_names += [ generator_js_target_name ]
+
+ action(generator_js_target_name) {
+ script = "$mojom_generator_root/compile_typescript.py"
+ sources = ts_outputs
+ outputs = js_outputs
+ public_deps = [ ":$generator_ts_target_name" ]
+ foreach(d, all_deps) {
+ full_name = get_label_info(d, "label_no_toolchain")
+ public_deps +=
+ [ "${full_name}_${dependency_type.name}__js__generator" ]
+ }
+
+ absolute_tsconfig_path =
+ rebase_path(tsconfig_filename, "", target_gen_dir)
+ args = [ "--tsconfig_path=$absolute_tsconfig_path" ]
+ }
+ }
+
+ js_target_name = target_name + "_js"
+ group(js_target_name) {
+ public_deps = []
+ if (sources_list != []) {
+ foreach(generator_js_target_name, generator_js_target_names) {
+ public_deps += [ ":$generator_js_target_name" ]
+ }
+ }
+
+ foreach(d, all_deps) {
+ full_name = get_label_info(d, "label_no_toolchain")
+ public_deps += [ "${full_name}_js" ]
+ }
+ }
+
+ group(js_data_deps_target_name) {
+ data = js_outputs
+ deps = []
+ foreach(generator_js_target_name, generator_js_target_names) {
+ deps += [ ":$generator_js_target_name" ]
+ }
+ data_deps = []
+ foreach(d, all_deps) {
+ full_name = get_label_info(d, "label_no_toolchain")
+ data_deps += [ "${full_name}_js_data_deps" ]
+ }
+ }
+ }
+}
+
+# A helper for the mojom() template above when component libraries are desired
+# for generated C++ bindings units. Supports all the same arguments as mojom()
+# except for the optional |component_output_prefix| and |component_macro_prefix|
+# arguments. These are instead shortened to |output_prefix| and |macro_prefix|
+# and are *required*.
+template("mojom_component") {
+ assert(defined(invoker.output_prefix) && defined(invoker.macro_prefix))
+
+ mojom(target_name) {
+ forward_variables_from(invoker,
+ "*",
+ [
+ "output_prefix",
+ "macro_prefix",
+ ])
+ component_output_prefix = invoker.output_prefix
+ component_macro_prefix = invoker.macro_prefix
+ }
+}
diff --git a/utils/ipc/mojo/public/tools/bindings/mojom_bindings_generator.py b/utils/ipc/mojo/public/tools/bindings/mojom_bindings_generator.py
new file mode 100755
index 00000000..da9efc71
--- /dev/null
+++ b/utils/ipc/mojo/public/tools/bindings/mojom_bindings_generator.py
@@ -0,0 +1,390 @@
+#!/usr/bin/env python
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""The frontend for the Mojo bindings system."""
+
+from __future__ import print_function
+
+import argparse
+
+import hashlib
+import importlib
+import json
+import os
+import pprint
+import re
+import struct
+import sys
+
+# Disable lint check for finding modules:
+# pylint: disable=F0401
+
+def _GetDirAbove(dirname):
+ """Returns the directory "above" this file containing |dirname| (which must
+ also be "above" this file)."""
+ path = os.path.abspath(__file__)
+ while True:
+ path, tail = os.path.split(path)
+ assert tail
+ if tail == dirname:
+ return path
+
+
+sys.path.insert(
+ 0,
+ os.path.join(
+ os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "mojom"))
+
+from mojom.error import Error
+import mojom.fileutil as fileutil
+from mojom.generate.module import Module
+from mojom.generate import template_expander
+from mojom.generate import translate
+from mojom.generate.generator import WriteFile
+
+sys.path.append(
+ os.path.join(_GetDirAbove("mojo"), "tools", "diagnosis"))
+import crbug_1001171
+
+
+_BUILTIN_GENERATORS = {
+ "c++": "mojom_cpp_generator",
+ "javascript": "mojom_js_generator",
+ "java": "mojom_java_generator",
+ "mojolpm": "mojom_mojolpm_generator",
+ "typescript": "mojom_ts_generator",
+}
+
+
+def LoadGenerators(generators_string):
+ if not generators_string:
+ return [] # No generators.
+
+ generators = {}
+ for generator_name in [s.strip() for s in generators_string.split(",")]:
+ language = generator_name.lower()
+ if language not in _BUILTIN_GENERATORS:
+ print("Unknown generator name %s" % generator_name)
+ sys.exit(1)
+ generator_module = importlib.import_module(
+ "generators.%s" % _BUILTIN_GENERATORS[language])
+ generators[language] = generator_module
+ return generators
+
+
+def MakeImportStackMessage(imported_filename_stack):
+ """Make a (human-readable) message listing a chain of imports. (Returned
+ string begins with a newline (if nonempty) and does not end with one.)"""
+ return ''.join(
+ reversed(["\n %s was imported by %s" % (a, b) for (a, b) in \
+ zip(imported_filename_stack[1:], imported_filename_stack)]))
+
+
+class RelativePath(object):
+ """Represents a path relative to the source tree or generated output dir."""
+
+ def __init__(self, path, source_root, output_dir):
+ self.path = path
+ if path.startswith(source_root):
+ self.root = source_root
+ elif path.startswith(output_dir):
+ self.root = output_dir
+ else:
+ raise Exception("Invalid input path %s" % path)
+
+ def relative_path(self):
+ return os.path.relpath(
+ os.path.abspath(self.path), os.path.abspath(self.root))
+
+
+def _GetModulePath(path, output_dir):
+ return os.path.join(output_dir, path.relative_path() + '-module')
+
+
+def ScrambleMethodOrdinals(interfaces, salt):
+ already_generated = set()
+ for interface in interfaces:
+ i = 0
+ already_generated.clear()
+ for method in interface.methods:
+ if method.explicit_ordinal is not None:
+ continue
+ while True:
+ i = i + 1
+ if i == 1000000:
+ raise Exception("Could not generate %d method ordinals for %s" %
+ (len(interface.methods), interface.mojom_name))
+ # Generate a scrambled method.ordinal value. The algorithm doesn't have
+ # to be very strong, cryptographically. It just needs to be non-trivial
+ # to guess the results without the secret salt, in order to make it
+ # harder for a compromised process to send fake Mojo messages.
+ sha256 = hashlib.sha256(salt)
+ sha256.update(interface.mojom_name.encode('utf-8'))
+ sha256.update(str(i).encode('utf-8'))
+ # Take the first 4 bytes as a little-endian uint32.
+ ordinal = struct.unpack('<L', sha256.digest()[:4])[0]
+ # Trim to 31 bits, so it always fits into a Java (signed) int.
+ ordinal = ordinal & 0x7fffffff
+ if ordinal in already_generated:
+ continue
+ already_generated.add(ordinal)
+ method.ordinal = ordinal
+ method.ordinal_comment = (
+ 'The %s value is based on sha256(salt + "%s%d").' %
+ (ordinal, interface.mojom_name, i))
+ break
+
+
+def ReadFileContents(filename):
+ with open(filename, 'rb') as f:
+ return f.read()
+
+
+class MojomProcessor(object):
+ """Takes parsed mojom modules and generates language bindings from them.
+
+ Attributes:
+ _processed_files: {Dict[str, mojom.generate.module.Module]} Mapping from
+ relative mojom filename paths to the module AST for that mojom file.
+ """
+ def __init__(self, should_generate):
+ self._should_generate = should_generate
+ self._processed_files = {}
+ self._typemap = {}
+
+ def LoadTypemaps(self, typemaps):
+ # Support some very simple single-line comments in typemap JSON.
+ comment_expr = r"^\s*//.*$"
+ def no_comments(line):
+ return not re.match(comment_expr, line)
+ for filename in typemaps:
+ with open(filename) as f:
+ typemaps = json.loads("".join(filter(no_comments, f.readlines())))
+ for language, typemap in typemaps.items():
+ language_map = self._typemap.get(language, {})
+ language_map.update(typemap)
+ self._typemap[language] = language_map
+ if 'c++' in self._typemap:
+ self._typemap['mojolpm'] = self._typemap['c++']
+
+ def _GenerateModule(self, args, remaining_args, generator_modules,
+ rel_filename, imported_filename_stack):
+ # Return the already-generated module.
+ if rel_filename.path in self._processed_files:
+ return self._processed_files[rel_filename.path]
+
+ if rel_filename.path in imported_filename_stack:
+ print("%s: Error: Circular dependency" % rel_filename.path + \
+ MakeImportStackMessage(imported_filename_stack + [rel_filename.path]))
+ sys.exit(1)
+
+ module_path = _GetModulePath(rel_filename, args.output_dir)
+ with open(module_path, 'rb') as f:
+ module = Module.Load(f)
+
+ if args.scrambled_message_id_salt_paths:
+ salt = b''.join(
+ map(ReadFileContents, args.scrambled_message_id_salt_paths))
+ ScrambleMethodOrdinals(module.interfaces, salt)
+
+ if self._should_generate(rel_filename.path):
+ for language, generator_module in generator_modules.items():
+ generator = generator_module.Generator(
+ module, args.output_dir, typemap=self._typemap.get(language, {}),
+ variant=args.variant, bytecode_path=args.bytecode_path,
+ for_blink=args.for_blink,
+ js_bindings_mode=args.js_bindings_mode,
+ js_generate_struct_deserializers=\
+ args.js_generate_struct_deserializers,
+ export_attribute=args.export_attribute,
+ export_header=args.export_header,
+ generate_non_variant_code=args.generate_non_variant_code,
+ support_lazy_serialization=args.support_lazy_serialization,
+ disallow_native_types=args.disallow_native_types,
+ disallow_interfaces=args.disallow_interfaces,
+ generate_message_ids=args.generate_message_ids,
+ generate_fuzzing=args.generate_fuzzing,
+ enable_kythe_annotations=args.enable_kythe_annotations,
+ extra_cpp_template_paths=args.extra_cpp_template_paths,
+ generate_extra_cpp_only=args.generate_extra_cpp_only)
+ filtered_args = []
+ if hasattr(generator_module, 'GENERATOR_PREFIX'):
+ prefix = '--' + generator_module.GENERATOR_PREFIX + '_'
+ filtered_args = [arg for arg in remaining_args
+ if arg.startswith(prefix)]
+ generator.GenerateFiles(filtered_args)
+
+ # Save result.
+ self._processed_files[rel_filename.path] = module
+ return module
+
+
+def _Generate(args, remaining_args):
+ if args.variant == "none":
+ args.variant = None
+
+ for idx, import_dir in enumerate(args.import_directories):
+ tokens = import_dir.split(":")
+ if len(tokens) >= 2:
+ args.import_directories[idx] = RelativePath(tokens[0], tokens[1],
+ args.output_dir)
+ else:
+ args.import_directories[idx] = RelativePath(tokens[0], args.depth,
+ args.output_dir)
+ generator_modules = LoadGenerators(args.generators_string)
+
+ fileutil.EnsureDirectoryExists(args.output_dir)
+
+ processor = MojomProcessor(lambda filename: filename in args.filename)
+ processor.LoadTypemaps(set(args.typemaps))
+
+ if args.filelist:
+ with open(args.filelist) as f:
+ args.filename.extend(f.read().split())
+
+ for filename in args.filename:
+ processor._GenerateModule(
+ args, remaining_args, generator_modules,
+ RelativePath(filename, args.depth, args.output_dir), [])
+
+ return 0
+
+
+def _Precompile(args, _):
+ generator_modules = LoadGenerators(",".join(_BUILTIN_GENERATORS.keys()))
+
+ template_expander.PrecompileTemplates(generator_modules, args.output_dir)
+ return 0
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="Generate bindings from mojom files.")
+ parser.add_argument("--use_bundled_pylibs", action="store_true",
+ help="use Python modules bundled in the SDK")
+ parser.add_argument(
+ "-o",
+ "--output_dir",
+ dest="output_dir",
+ default=".",
+ help="output directory for generated files")
+
+ subparsers = parser.add_subparsers()
+
+ generate_parser = subparsers.add_parser(
+ "generate", description="Generate bindings from mojom files.")
+ generate_parser.add_argument("filename", nargs="*",
+ help="mojom input file")
+ generate_parser.add_argument("--filelist", help="mojom input file list")
+ generate_parser.add_argument("-d", "--depth", dest="depth", default=".",
+ help="depth from source root")
+ generate_parser.add_argument("-g",
+ "--generators",
+ dest="generators_string",
+ metavar="GENERATORS",
+ default="c++,javascript,java,mojolpm",
+ help="comma-separated list of generators")
+ generate_parser.add_argument(
+ "--gen_dir", dest="gen_directories", action="append", metavar="directory",
+ default=[], help="add a directory to be searched for the syntax trees.")
+ generate_parser.add_argument(
+ "-I", dest="import_directories", action="append", metavar="directory",
+ default=[],
+ help="add a directory to be searched for import files. The depth from "
+ "source root can be specified for each import by appending it after "
+ "a colon")
+ generate_parser.add_argument("--typemap", action="append", metavar="TYPEMAP",
+ default=[], dest="typemaps",
+ help="apply TYPEMAP to generated output")
+ generate_parser.add_argument("--variant", dest="variant", default=None,
+ help="output a named variant of the bindings")
+ generate_parser.add_argument(
+ "--bytecode_path", required=True, help=(
+ "the path from which to load template bytecode; to generate template "
+ "bytecode, run %s precompile BYTECODE_PATH" % os.path.basename(
+ sys.argv[0])))
+ generate_parser.add_argument("--for_blink", action="store_true",
+ help="Use WTF types as generated types for mojo "
+ "string/array/map.")
+ generate_parser.add_argument(
+ "--js_bindings_mode", choices=["new", "old"], default="old",
+ help="This option only affects the JavaScript bindings. The value could "
+ "be \"new\" to generate new-style lite JS bindings in addition to the "
+ "old, or \"old\" to only generate old bindings.")
+ generate_parser.add_argument(
+ "--js_generate_struct_deserializers", action="store_true",
+ help="Generate javascript deserialize methods for structs in "
+ "mojom-lite.js file")
+ generate_parser.add_argument(
+ "--export_attribute", default="",
+ help="Optional attribute to specify on class declaration to export it "
+ "for the component build.")
+ generate_parser.add_argument(
+ "--export_header", default="",
+ help="Optional header to include in the generated headers to support the "
+ "component build.")
+ generate_parser.add_argument(
+ "--generate_non_variant_code", action="store_true",
+ help="Generate code that is shared by different variants.")
+ generate_parser.add_argument(
+ "--scrambled_message_id_salt_path",
+ dest="scrambled_message_id_salt_paths",
+ help="If non-empty, the path to a file whose contents should be used as"
+ "a salt for generating scrambled message IDs. If this switch is specified"
+ "more than once, the contents of all salt files are concatenated to form"
+ "the salt value.", default=[], action="append")
+ generate_parser.add_argument(
+ "--support_lazy_serialization",
+ help="If set, generated bindings will serialize lazily when possible.",
+ action="store_true")
+ generate_parser.add_argument(
+ "--extra_cpp_template_paths",
+ dest="extra_cpp_template_paths",
+ action="append",
+ metavar="path_to_template",
+ default=[],
+ help="Provide a path to a new template (.tmpl) that is used to generate "
+ "additional C++ source/header files ")
+ generate_parser.add_argument(
+ "--generate_extra_cpp_only",
+ help="If set and extra_cpp_template_paths provided, will only generate"
+ "extra_cpp_template related C++ bindings",
+ action="store_true")
+ generate_parser.add_argument(
+ "--disallow_native_types",
+ help="Disallows the [Native] attribute to be specified on structs or "
+ "enums within the mojom file.", action="store_true")
+ generate_parser.add_argument(
+ "--disallow_interfaces",
+ help="Disallows interface definitions within the mojom file. It is an "
+ "error to specify this flag when processing a mojom file which defines "
+ "any interface.", action="store_true")
+ generate_parser.add_argument(
+ "--generate_message_ids",
+ help="Generates only the message IDs header for C++ bindings. Note that "
+ "this flag only matters if --generate_non_variant_code is also "
+ "specified.", action="store_true")
+ generate_parser.add_argument(
+ "--generate_fuzzing",
+ action="store_true",
+ help="Generates additional bindings for fuzzing in JS.")
+ generate_parser.add_argument(
+ "--enable_kythe_annotations",
+ action="store_true",
+ help="Adds annotations for kythe metadata generation.")
+
+ generate_parser.set_defaults(func=_Generate)
+
+ precompile_parser = subparsers.add_parser("precompile",
+ description="Precompile templates for the mojom bindings generator.")
+ precompile_parser.set_defaults(func=_Precompile)
+
+ args, remaining_args = parser.parse_known_args()
+ return args.func(args, remaining_args)
+
+
+if __name__ == "__main__":
+ with crbug_1001171.DumpStateOnLookupError():
+ sys.exit(main())
diff --git a/utils/ipc/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py b/utils/ipc/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py
new file mode 100644
index 00000000..bddbe3f4
--- /dev/null
+++ b/utils/ipc/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py
@@ -0,0 +1,62 @@
+# Copyright 2014 The Chromium 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 unittest
+
+from mojom_bindings_generator import MakeImportStackMessage
+from mojom_bindings_generator import ScrambleMethodOrdinals
+
+
+class FakeIface(object):
+ def __init__(self):
+ self.mojom_name = None
+ self.methods = None
+
+
+class FakeMethod(object):
+ def __init__(self, explicit_ordinal=None):
+ self.explicit_ordinal = explicit_ordinal
+ self.ordinal = explicit_ordinal
+ self.ordinal_comment = None
+
+
+class MojoBindingsGeneratorTest(unittest.TestCase):
+ """Tests mojo_bindings_generator."""
+
+ def testMakeImportStackMessage(self):
+ """Tests MakeImportStackMessage()."""
+ self.assertEqual(MakeImportStackMessage(["x"]), "")
+ self.assertEqual(MakeImportStackMessage(["x", "y"]),
+ "\n y was imported by x")
+ self.assertEqual(MakeImportStackMessage(["x", "y", "z"]),
+ "\n z was imported by y\n y was imported by x")
+
+ def testScrambleMethodOrdinals(self):
+ """Tests ScrambleMethodOrdinals()."""
+ interface = FakeIface()
+ interface.mojom_name = 'RendererConfiguration'
+ interface.methods = [
+ FakeMethod(),
+ FakeMethod(),
+ FakeMethod(),
+ FakeMethod(explicit_ordinal=42)
+ ]
+ ScrambleMethodOrdinals([interface], "foo".encode('utf-8'))
+ # These next three values are hard-coded. If the generation algorithm
+ # changes from being based on sha256(seed + interface.name + str(i)) then
+ # these numbers will obviously need to change too.
+ #
+ # Note that hashlib.sha256('fooRendererConfiguration1').digest()[:4] is
+ # '\xa5\xbc\xf9\xca' and that hex(1257880741) = '0x4af9bca5'. The
+ # difference in 0x4a vs 0xca is because we only take 31 bits.
+ self.assertEqual(interface.methods[0].ordinal, 1257880741)
+ self.assertEqual(interface.methods[1].ordinal, 631133653)
+ self.assertEqual(interface.methods[2].ordinal, 549336076)
+
+ # Explicit method ordinals should not be scrambled.
+ self.assertEqual(interface.methods[3].ordinal, 42)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/utils/ipc/mojo/public/tools/bindings/mojom_types_downgrader.py b/utils/ipc/mojo/public/tools/bindings/mojom_types_downgrader.py
new file mode 100755
index 00000000..15f0e3ba
--- /dev/null
+++ b/utils/ipc/mojo/public/tools/bindings/mojom_types_downgrader.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Downgrades *.mojom files to the old mojo types for remotes and receivers."""
+
+import argparse
+import fnmatch
+import os
+import re
+import shutil
+import sys
+import tempfile
+
+# List of patterns and replacements to match and use against the contents of a
+# mojo file. Each replacement string will be used with Python string's format()
+# function, so the '{}' substring is used to mark where the mojo type should go.
+_MOJO_REPLACEMENTS = {
+ r'pending_remote': r'{}',
+ r'pending_receiver': r'{}&',
+ r'pending_associated_remote': r'associated {}',
+ r'pending_associated_receiver': r'associated {}&',
+}
+
+# Pre-compiled regular expression that matches against any of the replacements.
+_REGEXP_PATTERN = re.compile(
+ r'|'.join(
+ ['{}\s*<\s*(.*?)\s*>'.format(k) for k in _MOJO_REPLACEMENTS.keys()]),
+ flags=re.DOTALL)
+
+
+def ReplaceFunction(match_object):
+ """Returns the right replacement for the string matched against the regexp."""
+ for index, (match, repl) in enumerate(_MOJO_REPLACEMENTS.items(), 1):
+ if match_object.group(0).startswith(match):
+ return repl.format(match_object.group(index))
+
+
+def DowngradeFile(path, output_dir=None):
+ """Downgrades the mojom file specified by |path| to the old mojo types.
+
+ Optionally pass |output_dir| to place the result under a separate output
+ directory, preserving the relative path to the file included in |path|.
+ """
+ # Use a temporary file to dump the new contents after replacing the patterns.
+ with open(path) as src_mojo_file:
+ with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp_mojo_file:
+ tmp_contents = _REGEXP_PATTERN.sub(ReplaceFunction, src_mojo_file.read())
+ tmp_mojo_file.write(tmp_contents)
+
+ # Files should be placed in the desired output directory
+ if output_dir:
+ output_filepath = os.path.join(output_dir, os.path.basename(path))
+ if not os.path.exists(output_dir):
+ os.makedirs(output_dir)
+ else:
+ output_filepath = path
+
+ # Write the new contents preserving the original file's attributes.
+ shutil.copystat(path, tmp_mojo_file.name)
+ shutil.move(tmp_mojo_file.name, output_filepath)
+
+ # Make sure to "touch" the new file so that access, modify and change times
+ # are always newer than the source file's, otherwise Modify time will be kept
+ # as per the call to shutil.copystat(), causing unnecessary generations of the
+ # output file in subsequent builds due to ninja considering it dirty.
+ os.utime(output_filepath, None)
+
+
+def DowngradeDirectory(path, output_dir=None):
+ """Downgrades mojom files inside directory |path| to the old mojo types.
+
+ Optionally pass |output_dir| to place the result under a separate output
+ directory, preserving the relative path to the file included in |path|.
+ """
+ # We don't have recursive glob.glob() nor pathlib.Path.rglob() in Python 2.7
+ mojom_filepaths = []
+ for dir_path, _, filenames in os.walk(path):
+ for filename in fnmatch.filter(filenames, "*mojom"):
+ mojom_filepaths.append(os.path.join(dir_path, filename))
+
+ for path in mojom_filepaths:
+ absolute_dirpath = os.path.dirname(os.path.abspath(path))
+ if output_dir:
+ dest_dirpath = output_dir + absolute_dirpath
+ else:
+ dest_dirpath = absolute_dirpath
+ DowngradeFile(path, dest_dirpath)
+
+
+def DowngradePath(src_path, output_dir=None):
+ """Downgrades the mojom files pointed by |src_path| to the old mojo types.
+
+ Optionally pass |output_dir| to place the result under a separate output
+ directory, preserving the relative path to the file included in |path|.
+ """
+ if os.path.isdir(src_path):
+ DowngradeDirectory(src_path, output_dir)
+ elif os.path.isfile(src_path):
+ DowngradeFile(src_path, output_dir)
+ else:
+ print(">>> {} not pointing to a valid file or directory".format(src_path))
+ sys.exit(1)
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="Downgrade *.mojom files to use the old mojo types.")
+ parser.add_argument(
+ "srcpath", help="path to the file or directory to apply the conversion")
+ parser.add_argument(
+ "--outdir", help="the directory to place the converted file(s) under")
+ args = parser.parse_args()
+
+ DowngradePath(args.srcpath, args.outdir)
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/utils/ipc/mojo/public/tools/bindings/validate_typemap_config.py b/utils/ipc/mojo/public/tools/bindings/validate_typemap_config.py
new file mode 100755
index 00000000..f1783d59
--- /dev/null
+++ b/utils/ipc/mojo/public/tools/bindings/validate_typemap_config.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+# Copyright 2020 The Chromium 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 argparse
+import json
+import os
+import re
+import sys
+
+
+def CheckCppTypemapConfigs(target_name, config_filename, out_filename):
+ _SUPPORTED_CONFIG_KEYS = set([
+ 'types', 'traits_headers', 'traits_private_headers', 'traits_sources',
+ 'traits_deps', 'traits_public_deps'
+ ])
+ _SUPPORTED_TYPE_KEYS = set([
+ 'mojom', 'cpp', 'copyable_pass_by_value', 'force_serialize', 'hashable',
+ 'move_only', 'nullable_is_same_type'
+ ])
+ with open(config_filename, 'r') as f:
+ for config in json.load(f):
+ for key in config.keys():
+ if key not in _SUPPORTED_CONFIG_KEYS:
+ raise ValueError('Invalid typemap property "%s" when processing %s' %
+ (key, target_name))
+
+ types = config.get('types')
+ if not types:
+ raise ValueError('Typemap for %s must specify at least one type to map'
+ % target_name)
+
+ for entry in types:
+ for key in entry.keys():
+ if key not in _SUPPORTED_TYPE_KEYS:
+ raise IOError(
+ 'Invalid type property "%s" in typemap for "%s" on target %s' %
+ (key, entry.get('mojom', '(unknown)'), target_name))
+
+ with open(out_filename, 'w') as f:
+ f.truncate(0)
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ _, args = parser.parse_known_args()
+ if len(args) != 3:
+ print('Usage: validate_typemap_config.py target_name config_filename '
+ 'stamp_filename')
+ sys.exit(1)
+
+ CheckCppTypemapConfigs(args[0], args[1], args[2])
+
+
+if __name__ == '__main__':
+ main()