| #!/usr/bin/env python |
| # Copyright 2015 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 script accepts the output of version 2 of the mojom parser and uses that |
| # data to invoke the code generators. |
| |
| import argparse |
| import imp |
| import os |
| import sys |
| |
| |
| def _ParseCLIArgs(): |
| """Parses the command line arguments. |
| |
| Returns: |
| tuple<Namespace, list<str>> The first value of the tuple is a Namespace |
| holding the value of the optional args. The second value of the tuple is |
| a list of the remaining arguments. |
| """ |
| parser = argparse.ArgumentParser( |
| description='Generate bindings from mojom parser output.') |
| parser.add_argument('filenames', nargs='*', |
| help='Filter on the set of .mojom files for which code ' |
| 'will be generated.') |
| parser.add_argument('-f', '--file-graph', dest='file_graph', |
| help='Location of the parser output. "-" for stdin. ' |
| '(default "-")', default='-') |
| parser.add_argument('-p', '--python-sdk-dir', dest='python_sdk_dir', |
| default=None, |
| help='Location of the compiled python bindings') |
| parser.add_argument("-o", "--output-dir", dest="output_dir", default=".", |
| help="output directory for generated files") |
| parser.add_argument("-g", "--generators", dest="generators_string", |
| metavar="GENERATORS", |
| default="c++,dart,go,javascript,java,python", |
| help="comma-separated list of generators") |
| parser.add_argument("-d", "--depth", dest="depth", default=".", |
| help="relative path to the root of the source tree.") |
| parser.add_argument("--no-gen-imports", action="store_true", |
| help="Generate code only for the files that are " |
| "specified on the command line. By default, code " |
| "is generated for all specified files and their " |
| "transitive imports.") |
| parser.add_argument("--generate-type-info", dest="generate_type_info", |
| action="store_true", |
| help="generate mojom type descriptors") |
| parser.add_argument("--no-generate-type-info", dest="generate_type_info", |
| action="store_false", |
| help="do not generate mojom type descriptors") |
| parser.set_defaults(generate_type_info=True) |
| |
| return parser.parse_known_args() |
| |
| # We assume this script is located in the Mojo SDK in tools/bindings. |
| THIS_DIR = os.path.abspath(os.path.dirname(__file__)) |
| SDK_ROOT = os.path.abspath(os.path.join(THIS_DIR, os.pardir, os.pardir)) |
| PYTHON_SDK_DIR = os.path.abspath(os.path.join(SDK_ROOT, "python")) |
| |
| def _FixPath(): |
| # We parse command line args before imports in case the caller wishes to |
| # specify an alternative location for the Mojo Python SDK. |
| # TODO(rudominer) Consider removing this flexibility as I can think of |
| # no good reason for it. |
| args, _ = _ParseCLIArgs() |
| python_sdk_dir = args.python_sdk_dir |
| if not python_sdk_dir: |
| python_sdk_dir = PYTHON_SDK_DIR |
| sys.path.insert(0, python_sdk_dir) |
| # In order to use mojom_files_mojom we need to make sure the dummy mojo_system |
| # can be found on the python path. |
| sys.path.insert(0, os.path.join(python_sdk_dir, "dummy_mojo_system")) |
| |
| sys.path.insert(0, os.path.join(THIS_DIR, "pylib")) |
| |
| |
| _FixPath() |
| |
| |
| from mojom.generate.generated import mojom_files_mojom |
| from mojom.generate import mojom_translator |
| from mojo_bindings import serialization |
| |
| |
| def LoadGenerators(generators_string): |
| if not generators_string: |
| return [] # No generators. |
| |
| script_dir = os.path.dirname(os.path.abspath(__file__)) |
| generators = [] |
| for generator_name in [s.strip() for s in generators_string.split(",")]: |
| # "Built-in" generators: |
| if generator_name.lower() == "c++": |
| generator_name = os.path.join(script_dir, "generators", |
| "mojom_cpp_generator.py") |
| elif generator_name.lower() == "dart": |
| generator_name = os.path.join(script_dir, "generators", |
| "mojom_dart_generator.py") |
| elif generator_name.lower() == "go": |
| generator_name = os.path.join(script_dir, "generators", |
| "mojom_go_generator.py") |
| elif generator_name.lower() == "javascript": |
| generator_name = os.path.join(script_dir, "generators", |
| "mojom_js_generator.py") |
| elif generator_name.lower() == "java": |
| generator_name = os.path.join(script_dir, "generators", |
| "mojom_java_generator.py") |
| elif generator_name.lower() == "python": |
| generator_name = os.path.join(script_dir, "generators", |
| "mojom_python_generator.py") |
| # Specified generator python module: |
| elif generator_name.endswith(".py"): |
| pass |
| else: |
| print "Unknown generator name %s" % generator_name |
| sys.exit(1) |
| generator_module = imp.load_source(os.path.basename(generator_name)[:-3], |
| generator_name) |
| generators.append(generator_module) |
| return generators |
| |
| |
| def ReadMojomFileGraphFromFile(fp): |
| """Reads a mojom_files_mojom.MojomFileGraph from a file. |
| |
| Args: |
| fp: A file pointer from which a serialized mojom_fileS_mojom.MojomFileGraph |
| can be read. |
| |
| Returns: |
| The mojom_files_mojom.MojomFileGraph that was deserialized from the file. |
| """ |
| data = bytearray(fp.read()) |
| context = serialization.RootDeserializationContext(data, []) |
| return mojom_files_mojom.MojomFileGraph.Deserialize(context) |
| |
| |
| def FixModulePath(module, src_root_path): |
| """Fix the path attribute of the provided module and its imports. |
| |
| The path provided for the various modules is the absolute path to the mojom |
| file which the module represents. But the generators expect the path to be |
| relative to the root of the source tree. |
| |
| Args: |
| module: {module.Module} whose path is to be updated. |
| abs_root: {str} absolute path to the root of the source tree. |
| """ |
| module.path = os.path.relpath(module.path, src_root_path) |
| if not hasattr(module, 'imports'): |
| return |
| for import_dict in module.imports: |
| FixModulePath(import_dict['module'], src_root_path) |
| |
| |
| def main(): |
| args, remaining_args = _ParseCLIArgs() |
| |
| if args.file_graph == '-': |
| fp = sys.stdin |
| else: |
| fp = open(args.file_graph) |
| |
| mojom_file_graph = ReadMojomFileGraphFromFile(fp) |
| modules = mojom_translator.TranslateFileGraph(mojom_file_graph) |
| |
| generator_modules = LoadGenerators(args.generators_string) |
| filenames = set(os.path.basename(filename) for filename in args.filenames) |
| |
| for _, module in modules.iteritems(): |
| # If filenames are specified on the command line, only generate code for |
| # the specified mojom files. |
| # TODO(azani): This is not as robust as we would like since files with the |
| # same name but different paths or files resolved through links might not |
| # be correctly identified by module.name. |
| if args.no_gen_imports and filenames and module.name not in filenames: |
| continue |
| FixModulePath(module, os.path.abspath(args.depth)) |
| for generator_module in generator_modules: |
| generator = generator_module.Generator(module, args.output_dir) |
| |
| # Look at unparsed args for generator-specific args. |
| 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)] |
| if args.generate_type_info: |
| filtered_args.append("--generate_type_info") |
| |
| generator.GenerateFiles(filtered_args) |
| |
| |
| if __name__ == "__main__": |
| sys.exit(main()) |