#!/usr/bin/env python # Copyright (c) 2012 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. """Generator for C++ structs from api json files. The purpose of this tool is to remove the need for hand-written code that converts to and from base::Value types when receiving javascript api calls. Originally written for generating code for extension apis. Reference schemas are in chrome/common/extensions/api. Usage example: compiler.py --root /home/Work/src --namespace extensions windows.json tabs.json compiler.py --destdir gen --root /home/Work/src --namespace extensions windows.json tabs.json """ import cc_generator import cpp_type_generator import h_generator import idl_schema import json_schema import model import optparse import os.path import sys if __name__ == '__main__': parser = optparse.OptionParser( description='Generates a C++ model of an API from JSON schema', usage='usage: %prog [option]... schema') parser.add_option('-r', '--root', default='.', help='logical include root directory. Path to schema files from specified' 'dir will be the include path.') parser.add_option('-d', '--destdir', help='root directory to output generated files.') parser.add_option('-n', '--namespace', default='generated_api_schemas', help='C++ namespace for generated files. e.g extensions::api.') (opts, args) = parser.parse_args() if not args: sys.exit(parser.get_usage()) dest_dir = opts.destdir root_namespace = opts.namespace schema = os.path.normpath(args[0]) api_model = model.Model() # Actually generate for source file. schema_filename, schema_extension = os.path.splitext(schema) if schema_extension == '.json': api_defs = json_schema.Load(schema) elif schema_extension == '.idl': api_defs = idl_schema.Load(schema) else: sys.exit("Did not recognize file extension %s for schema %s" % (schema_extension, schema)) for target_namespace in api_defs: referenced_schemas = target_namespace.get('dependencies', []) # Load type dependencies into the model. # TODO(miket): do we need this in IDL? for referenced_schema in referenced_schemas: referenced_schema_path = os.path.join( os.path.dirname(schema), referenced_schema + '.json') referenced_api_defs = json_schema.Load(referenced_schema_path) for namespace in referenced_api_defs: api_model.AddNamespace(namespace, os.path.relpath(referenced_schema_path, opts.root)) # Gets the relative path from opts.root to the schema to correctly determine # the include path. relpath = os.path.relpath(schema, opts.root) namespace = api_model.AddNamespace(target_namespace, relpath) if not namespace: continue # The output filename must match the input filename for gyp to deal with it # properly. out_file = namespace.name type_generator = cpp_type_generator.CppTypeGenerator( root_namespace, namespace, namespace.unix_name) for referenced_namespace in api_model.namespaces.values(): type_generator.AddNamespace( referenced_namespace, referenced_namespace.unix_name) h_code = (h_generator.HGenerator(namespace, type_generator) .Generate().Render()) cc_code = (cc_generator.CCGenerator(namespace, type_generator) .Generate().Render()) if dest_dir: with open( os.path.join(dest_dir, namespace.source_file_dir, out_file + '.cc'), 'w') as cc_file: cc_file.write(cc_code) with open( os.path.join(dest_dir, namespace.source_file_dir, out_file + '.h'), 'w') as h_file: h_file.write(h_code) else: print '%s.h' % out_file print print h_code print print '%s.cc' % out_file print print cc_code