blob: 2e029544eddfceb1577845d8e485140de3d2fcf7 [file] [log] [blame] [edit]
#!/usr/bin/env python3
# Copyright 2021 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Generate mojo connectivity test code."""
import json
import os
from pathlib import Path
# pylint: disable=import-error, no-name-in-module
import jinja2
from generators import mojom_cpp_generator
from mojom.generate import generator as mojom_generator
from mojom.generate import module as mojom_module
# pylint: enable=import-error, no-name-in-module
from chromite.lib import commandline
TEMPLATES_PATH = Path(Path(os.path.realpath(__file__)).parent, "templates")
class Generator:
"""Generates bindings code for c++."""
def __init__(self, mojom, mojo_root, output_dir, generator_overrides):
self._output_dir = output_dir
self._mojom = os.path.relpath(mojom, mojo_root)
self._generator_overrides = generator_overrides
self._module = None
self._LoadModule()
self._env = None
self._SetUpEnv()
def _LoadModule(self):
module_path = Path(self._output_dir, f"{self._mojom}-module")
with module_path.open("rb") as f:
self._module = mojom_module.Module.Load(f)
self._module.Stylize(mojom_generator.Stylizer())
def _GetFullMojomNameForKind(self, kind):
return self._env.filters["get_full_mojom_name_for_kind"](kind)
def _IsGeneratorOverrideKind(self, kind):
return (
hasattr(kind, "name")
and self._GetFullMojomNameForKind(kind) in self._generator_overrides
)
def _GetGeneratorOverrideType(self, kind):
if not self._IsGeneratorOverrideKind(kind):
return None
return self._generator_overrides[self._GetFullMojomNameForKind(kind)][
"generator_typename"
]
def _SetUpEnv(self):
self._env = jinja2.Environment(
loader=jinja2.FileSystemLoader(TEMPLATES_PATH)
)
generator = mojom_cpp_generator.Generator(self._module)
self._env.filters.update(generator.GetFilters())
self._env.filters.update(
{
"generator_override_type": self._GetGeneratorOverrideType,
}
)
self._env.tests.update(
{
"PendingRemoteKind": mojom_module.IsPendingRemoteKind,
"PendingReceiverKind": mojom_module.IsPendingReceiverKind,
"StructKind": mojom_module.IsStructKind,
"UnionKind": mojom_module.IsUnionKind,
"EnumKind": mojom_module.IsEnumKind,
"ArrayKind": mojom_module.IsArrayKind,
"MapKind": mojom_module.IsMapKind,
"GenericHandleKind": mojom_module.IsGenericHandleKind,
"GeneratorOverrideKind": self._IsGeneratorOverrideKind,
}
)
def _GenerateFile(self, suffix, args):
data = self._env.get_template(f"{suffix}.j2").render(**args)
output_file = Path(self._output_dir, f"{self._mojom}-{suffix}")
output_file.write_text(data)
def Generate(self):
extra_headers = []
for override in self._generator_overrides.values():
extra_headers += override["generator_headers"]
args = {
"module": self._module,
"namespaces_as_array": self._module.mojom_namespace.split("."),
"extra_headers": extra_headers,
}
self._GenerateFile("connectivity-forward.h", args)
self._GenerateFile("connectivity.h", args)
self._GenerateFile("connectivity.cc", args)
def Generate(mojoms, mojo_root, output_dir, generator_overrides_files):
"""Parses arguments and generates bindings code for c++."""
generator_overrides = {}
for f in generator_overrides_files:
override = json.loads(Path(f).read_bytes())
generator_overrides.update(override.get("c++", {}))
for mojom in mojoms:
Generator(mojom, mojo_root, output_dir, generator_overrides).Generate()
def GetParser():
"""Returns an argument parser."""
parser = commandline.ArgumentParser(description=__doc__)
parser.add_argument(
"--mojo-root", required=True, help="Root of the mojo files."
)
parser.add_argument(
"--output-dir",
required=True,
help="Path for mojo generated code. "
"Must be the same as the mojo bindings output dir.",
)
parser.add_argument(
"--mojom-file-list", help="Mojom filenames passed as a file."
)
parser.add_argument(
"--mojoms", default=[], nargs="+", help="Mojom filenames."
)
parser.add_argument(
"--generator-overrides",
default=[],
nargs="+",
help="The json config of the generator overrides.",
)
return parser
def main(argv):
parser = GetParser()
opts = parser.parse_args(argv)
if opts.mojom_file_list:
opts.mojoms.extend(
Path(opts.mojom_file_list).read_text(encoding="utf-8").split()
)
opts.Freeze()
if not opts.mojoms:
raise parser.error(
"Must list at least one mojom file via --mojoms or "
"--mojom-file-list"
)
Generate(
opts.mojoms, opts.mojo_root, opts.output_dir, opts.generator_overrides
)
if __name__ == "__main__":
commandline.ScriptWrapperMain(lambda _: main)