コード例 #1
0
 def testGetTypeIncludedRef(self):
   manager = CppTypeGenerator('', self.windows, self.windows.unix_name)
   manager.AddNamespace(self.tabs, self.tabs.unix_name)
   self.assertEquals(
       'std::vector<linked_ptr<tabs::Tab> >',
       manager.GetType(
           self.windows.types['windows.Window'].properties['tabs']))
コード例 #2
0
 def testGenerateIncludesAndForwardDeclarationsMultipleTypes(self):
   m = model.Model()
   self.tabs_json[0]['types'].append(self.permissions_json[0]['types'][0])
   self.windows_json[0]['functions'].append(
       self.permissions_json[0]['functions'][1])
   # Insert 'windows' before 'tabs' in order to test that they are sorted
   # properly.
   windows = m.AddNamespace(self.windows_json[0],
                            'path/to/windows.json')
   tabs_namespace = m.AddNamespace(self.tabs_json[0],
                                   'path/to/tabs.json')
   manager = CppTypeGenerator('', windows, self.windows.unix_name)
   manager.AddNamespace(tabs_namespace, self.tabs.unix_name)
   self.assertEquals('#include "path/to/tabs.h"\n'
                     '#include "base/string_number_conversions.h"\n'
                     '#include "base/json/json_writer.h"',
                     manager.GenerateIncludes().Render())
   self.assertEquals('namespace tabs {\n'
                     'struct Permissions;\n'
                     'struct Tab;\n'
                     '}\n'
                     'namespace windows {\n'
                     'struct Window;\n'
                     '}  // windows',
                     manager.GenerateForwardDeclarations().Render())
コード例 #3
0
 def testStringAsType(self):
   manager = CppTypeGenerator('', self.font_settings,
                              self.font_settings.unix_name)
   self.assertEquals(
       'std::string',
       manager.GetType(
           self.font_settings.types['fontSettings.FakeStringType']))
コード例 #4
0
 def testGetCppTypeLocalRef(self):
     manager = CppTypeGenerator(self.models.get('tabs'),
                                _FakeSchemaLoader(None))
     self.assertEquals(
         'Tab',
         manager.GetCppType(
             self.tabs.functions['get'].callback.params[0].type_))
コード例 #5
0
 def testArrayAsType(self):
     manager = CppTypeGenerator('', self.browser_action,
                                self.browser_action.unix_name)
     self.assertEquals(
         'std::vector<int>',
         manager.GetType(
             self.browser_action.types['browserAction.ColorArray']))
コード例 #6
0
 def testExpandParams(self):
   manager = CppTypeGenerator('extensions', self.tabs,
                              self.tabs.unix_name)
   props = self.tabs.functions['move'].params
   self.assertEquals(2, len(props))
   self.assertEquals(['move_properties', 'tab_ids_array', 'tab_ids_integer'],
       sorted([x.unix_name for x in manager.ExpandParams(props)])
   )
コード例 #7
0
 def testChoicesEnum(self):
   manager = CppTypeGenerator('', self.tabs, self.tabs.unix_name)
   prop = self.tabs.functions['move'].params[0]
   self.assertEquals('TAB_IDS_ARRAY',
       manager.GetEnumValue(prop, model.PropertyType.ARRAY.name))
   self.assertEquals('TAB_IDS_INTEGER',
       manager.GetEnumValue(prop, model.PropertyType.INTEGER.name))
   self.assertEquals('TabIdsType',
       manager.GetChoicesEnumType(prop))
コード例 #8
0
 def testGetCppTypeIncludedRef(self):
   m = model.Model()
   m.AddNamespace(self.windows_json[0], 'path/to/windows.json')
   m.AddNamespace(self.tabs_json[0], 'path/to/tabs.json')
   manager = CppTypeGenerator(m, _FakeSchemaLoader(m))
   self.assertEquals(
       'std::vector<linked_ptr<tabs::Tab> >',
       manager.GetCppType(
           self.windows.types['Window'].properties['tabs'].type_))
コード例 #9
0
 def testGetTypeSimple(self):
     manager = CppTypeGenerator('', self.tabs, self.tabs.unix_name)
     self.assertEquals(
         'int', manager.GetType(self.tabs.types['Tab'].properties['id']))
     self.assertEquals(
         'std::string',
         manager.GetType(self.tabs.types['Tab'].properties['status']))
     self.assertEquals(
         'bool',
         manager.GetType(self.tabs.types['Tab'].properties['selected']))
コード例 #10
0
 def testGetTypeWithPadForGeneric(self):
   manager = CppTypeGenerator('', self.permissions, self.permissions.unix_name)
   self.assertEquals('std::vector<std::string> ',
       manager.GetType(
       self.permissions.types['Permissions'].properties['origins'],
       pad_for_generics=True))
   self.assertEquals('bool',
       manager.GetType(
       self.permissions.functions['contains'].callback.params[0],
       pad_for_generics=True))
コード例 #11
0
 def testGetCppTypeSimple(self):
   manager = CppTypeGenerator(self.models.get('tabs'), _FakeSchemaLoader(None))
   self.assertEquals(
       'int',
       manager.GetCppType(self.tabs.types['Tab'].properties['id'].type_))
   self.assertEquals(
       'std::string',
       manager.GetCppType(self.tabs.types['Tab'].properties['status'].type_))
   self.assertEquals(
       'bool',
       manager.GetCppType(self.tabs.types['Tab'].properties['selected'].type_))
コード例 #12
0
 def testGetCppTypeIncludedRef(self):
     m = model.Model()
     m.AddNamespace(self.windows_json[0],
                    'path/to/windows.json',
                    environment=CppNamespaceEnvironment('%(namespace)s'))
     m.AddNamespace(self.tabs_json[0],
                    'path/to/tabs.json',
                    environment=CppNamespaceEnvironment('%(namespace)s'))
     manager = CppTypeGenerator(m, _FakeSchemaLoader(m))
     self.assertEqual(
         'std::vector<tabs::Tab>',
         manager.GetCppType(
             self.windows.types['Window'].properties['tabs'].type_))
コード例 #13
0
 def testGetCppTypeWithPadForGeneric(self):
   manager = CppTypeGenerator(self.models.get('permissions'),
                              _FakeSchemaLoader(None))
   self.assertEquals('std::vector<std::string>',
       manager.GetCppType(
           self.permissions.types['Permissions'].properties['origins'].type_,
           is_in_container=False))
   self.assertEquals('linked_ptr<std::vector<std::string> >',
       manager.GetCppType(
           self.permissions.types['Permissions'].properties['origins'].type_,
           is_in_container=True))
   self.assertEquals('bool',
       manager.GetCppType(
           self.permissions.functions['contains'].callback.params[0].type_,
       is_in_container=True))
コード例 #14
0
 def testGenerateIncludesAndForwardDeclarationsDependencies(self):
   m = model.Model()
   # Insert 'font_settings' before 'browser_action' in order to test that
   # CppTypeGenerator sorts them properly.
   m.AddNamespace(self.font_settings_json[0], 'path/to/font_settings.json')
   m.AddNamespace(self.browser_action_json[0], 'path/to/browser_action.json')
   dependency_tester = m.AddNamespace(self.dependency_tester_json[0],
                                      'path/to/dependency_tester.json')
   manager = CppTypeGenerator(m,
                              _FakeSchemaLoader(m),
                              default_namespace=dependency_tester)
   self.assertEquals('#include "path/to/browser_action.h"\n'
                     '#include "path/to/font_settings.h"',
                     manager.GenerateIncludes().Render())
   self.assertEquals('', manager.GenerateForwardDeclarations().Render())
コード例 #15
0
    def testHardIncludesForEnumArrays(self):
        """Tests that enums in arrays generate hard includes. Note that it's
    important to use a separate file (cross_enums_array) here to isolate the
    test case so that other types don't cause the hard-dependency.
    """
        m = model.Model()
        m.AddNamespace(self.crossref_enums_json[0],
                       'path/to/crossref_enums_array.json',
                       environment=CppNamespaceEnvironment('%(namespace)s'))
        m.AddNamespace(self.simple_api_json[0],
                       'path/to/simple_api.json',
                       environment=CppNamespaceEnvironment('%(namespace)s'))
        manager = CppTypeGenerator(self.models.get('crossref_enums_array'),
                                   _FakeSchemaLoader(m))

        self.assertEquals('#include "path/to/simple_api.h"',
                          manager.GenerateIncludes().Render())
コード例 #16
0
 def testGetAllPossibleParameterLists(self):
   manager = CppTypeGenerator('extensions', self.tabs,
                              self.tabs.unix_name)
   props = self.forbidden.functions['forbiddenParameters'].params
   self.assertEquals(4, len(props))
   param_lists = manager.GetAllPossibleParameterLists(props)
   expected_lists = [
       ['first_choice_array', 'first_string',
        'second_choice_array', 'second_string'],
       ['first_choice_array', 'first_string',
        'second_choice_integer', 'second_string'],
       ['first_choice_integer', 'first_string',
        'second_choice_array', 'second_string'],
       ['first_choice_integer', 'first_string',
        'second_choice_integer', 'second_string']]
   result_lists = sorted([[param.unix_name for param in param_list]
                          for param_list in param_lists])
   self.assertEquals(expected_lists, result_lists)
コード例 #17
0
 def testGenerateIncludesAndForwardDeclarationsMultipleTypes(self):
     m = model.Model()
     self.tabs_json[0]['types'].append(self.permissions_json[0]['types'][0])
     tabs_namespace = m.AddNamespace(self.tabs_json[0], 'path/to/tabs.json')
     self.windows_json[0]['functions'].append(
         self.permissions_json[0]['functions'][1])
     windows = m.AddNamespace(self.windows_json[0], 'path/to/windows.json')
     manager = CppTypeGenerator('', windows, self.windows.unix_name)
     manager.AddNamespace(tabs_namespace, self.tabs.unix_name)
     self.assertEquals('#include "path/to/tabs.h"',
                       manager.GenerateIncludes().Render())
     self.assertEquals(
         'namespace tabs {\n'
         'struct Tab;\n'
         'struct Permissions;\n'
         '}\n'
         'namespace windows {\n'
         'struct Window;\n'
         '}  // windows',
         manager.GenerateForwardDeclarations().Render())
コード例 #18
0
 def testGenerateIncludesAndForwardDeclarationsDependencies(self):
     m = model.Model()
     browser_action_namespace = m.AddNamespace(
         self.browser_action_json[0], 'path/to/browserAction.json')
     font_settings_namespace = m.AddNamespace(self.font_settings_json[0],
                                              'path/to/fontSettings.json')
     manager = CppTypeGenerator('', self.dependency_tester,
                                self.dependency_tester.unix_name)
     manager.AddNamespace(browser_action_namespace,
                          self.browser_action.unix_name)
     manager.AddNamespace(font_settings_namespace,
                          self.font_settings.unix_name)
     self.assertEquals(
         '#include "path/to/browser_action.h"\n'
         '#include "path/to/font_settings.h"',
         manager.GenerateIncludes().Render())
     self.assertEquals(
         'namespace browserAction {\n'
         'typedef std::vector<int> ColorArray;\n'
         '}\n'
         'namespace fontSettings {\n'
         'typedef std::string ScriptCode;\n'
         '}\n'
         'namespace dependency_tester {\n'
         '}  // dependency_tester',
         manager.GenerateForwardDeclarations().Render())
コード例 #19
0
 def testGenerateIncludesAndForwardDeclarationsDependencies(self):
   m = model.Model()
   # Insert 'font_settings' before 'browser_action' in order to test that
   # CppTypeGenerator sorts them properly.
   font_settings_namespace = m.AddNamespace(self.font_settings_json[0],
                                            'path/to/font_settings.json')
   browser_action_namespace = m.AddNamespace(self.browser_action_json[0],
                                             'path/to/browser_action.json')
   manager = CppTypeGenerator('', self.dependency_tester,
                              self.dependency_tester.unix_name)
   manager.AddNamespace(font_settings_namespace,
                        self.font_settings.unix_name)
   manager.AddNamespace(browser_action_namespace,
                        self.browser_action.unix_name)
   self.assertEquals('#include "path/to/browser_action.h"\n'
                     '#include "path/to/font_settings.h"\n'
                     '#include "base/string_number_conversions.h"',
                     manager.GenerateIncludes().Render())
   self.assertEquals('namespace browserAction {\n'
                     'typedef std::vector<int> ColorArray;\n'
                     '}\n'
                     'namespace fontSettings {\n'
                     'typedef std::string FakeStringType;\n'
                     '}\n'
                     'namespace dependency_tester {\n'
                     '}  // dependency_tester',
                     manager.GenerateForwardDeclarations().Render())
コード例 #20
0
 def testGetTypeArray(self):
   manager = CppTypeGenerator('', self.windows, self.windows.unix_name)
   self.assertEquals(
       'std::vector<linked_ptr<Window> >',
       manager.GetType(self.windows.functions['getAll'].callback.params[0]))
   manager = CppTypeGenerator('', self.permissions, self.permissions.unix_name)
   self.assertEquals('std::vector<std::string>', manager.GetType(
     self.permissions.types['permissions.Permissions'].properties['origins']))
コード例 #21
0
 def testGenerateIncludesAndForwardDeclarations(self):
   manager = CppTypeGenerator('', self.windows, self.windows.unix_name)
   manager.AddNamespace(self.tabs, self.tabs.unix_name)
   self.assertEquals('#include "path/to/tabs.h"',
       manager.GenerateIncludes().Render())
   self.assertEquals(
       'namespace tabs {\n'
       'struct Tab;\n'
       '}\n'
       'namespace windows {\n'
       'struct Window;\n'
       '}  // windows',
       manager.GenerateForwardDeclarations().Render())
   manager = CppTypeGenerator('', self.permissions, self.permissions.unix_name)
   self.assertEquals('', manager.GenerateIncludes().Render())
   self.assertEquals('namespace permissions {\n'
                     'struct Permissions;\n'
                     '}  // permissions',
                     manager.GenerateForwardDeclarations().Render())
コード例 #22
0
  def testNamespaceDeclaration(self):
    manager = CppTypeGenerator('extensions', self.permissions,
                               self.permissions.unix_name)
    self.assertEquals('namespace extensions {',
                      manager.GetRootNamespaceStart().Render())

    manager = CppTypeGenerator('extensions::gen::api', self.permissions,
                               self.permissions.unix_name)
    self.assertEquals('namespace permissions {',
                      manager.GetNamespaceStart().Render())
    self.assertEquals('}  // permissions',
                      manager.GetNamespaceEnd().Render())
    self.assertEquals('namespace extensions {\n'
                      'namespace gen {\n'
                      'namespace api {',
                      manager.GetRootNamespaceStart().Render())
    self.assertEquals('}  // api\n'
                      '}  // gen\n'
                      '}  // extensions',
                      manager.GetRootNamespaceEnd().Render())
コード例 #23
0
    def testGetCppTypeArray(self):
        manager = CppTypeGenerator(self.models.get('windows'),
                                   _FakeSchemaLoader(None))
        self.assertEquals(
            'std::vector<Window>',
            manager.GetCppType(
                self.windows.functions['getAll'].callback.params[0].type_))
        manager = CppTypeGenerator(self.models.get('permissions'),
                                   _FakeSchemaLoader(None))
        self.assertEquals(
            'std::vector<std::string>',
            manager.GetCppType(self.permissions.types['Permissions'].
                               properties['origins'].type_))

        manager = CppTypeGenerator(self.models.get('objects_movable'),
                                   _FakeSchemaLoader(None))
        self.assertEquals(
            'std::vector<MovablePod>',
            manager.GetCppType(self.objects_movable.types['MovableParent'].
                               properties['pods'].type_))
コード例 #24
0
    def testGenerateIncludesAndForwardDeclarations(self):
        m = model.Model()
        m.AddNamespace(self.windows_json[0],
                       'path/to/windows.json',
                       environment=CppNamespaceEnvironment('%(namespace)s'))
        m.AddNamespace(self.tabs_json[0],
                       'path/to/tabs.json',
                       environment=CppNamespaceEnvironment('%(namespace)s'))
        manager = CppTypeGenerator(m, _FakeSchemaLoader(m))

        self.assertEquals('', manager.GenerateIncludes().Render())
        self.assertEquals('#include "path/to/tabs.h"',
                          manager.GenerateIncludes(include_soft=True).Render())
        self.assertEquals(
            'namespace tabs {\n'
            'struct Tab;\n'
            '}  // namespace tabs',
            manager.GenerateForwardDeclarations().Render())

        m = model.Model()
        m.AddNamespace(
            self.windows_json[0],
            'path/to/windows.json',
            environment=CppNamespaceEnvironment('foo::bar::%(namespace)s'))
        m.AddNamespace(
            self.tabs_json[0],
            'path/to/tabs.json',
            environment=CppNamespaceEnvironment('foo::bar::%(namespace)s'))
        manager = CppTypeGenerator(m, _FakeSchemaLoader(m))
        self.assertEquals(
            'namespace foo {\n'
            'namespace bar {\n'
            'namespace tabs {\n'
            'struct Tab;\n'
            '}  // namespace tabs\n'
            '}  // namespace bar\n'
            '}  // namespace foo',
            manager.GenerateForwardDeclarations().Render())
        manager = CppTypeGenerator(self.models.get('permissions'),
                                   _FakeSchemaLoader(m))
        self.assertEquals('', manager.GenerateIncludes().Render())
        self.assertEquals('', manager.GenerateIncludes().Render())
        self.assertEquals('', manager.GenerateForwardDeclarations().Render())
        manager = CppTypeGenerator(self.models.get('content_settings'),
                                   _FakeSchemaLoader(m))
        self.assertEquals('', manager.GenerateIncludes().Render())
コード例 #25
0
 def testGetTypeNotimplemented(self):
   prop = self.windows.types['Window'].properties['tabs'].item_type
   prop.type_ = 10
   manager = CppTypeGenerator('', self.windows, self.windows.unix_name)
   self.assertRaises(NotImplementedError, manager.GetType, prop)
コード例 #26
0
 def testArrayAsType(self):
     manager = CppTypeGenerator(self.models.get('browser_action'),
                                _FakeSchemaLoader(None))
     self.assertEquals(
         'std::vector<int>',
         manager.GetCppType(self.browser_action.types['ColorArray']))
コード例 #27
0
 def testStringAsType(self):
     manager = CppTypeGenerator(self.models.get('font_settings'),
                                _FakeSchemaLoader(None))
     self.assertEquals(
         'std::string',
         manager.GetCppType(self.font_settings.types['FakeStringType']))
コード例 #28
0
def GenerateSchema(generator, filenames, root, destdir, root_namespace,
                   dart_overrides_dir, impl_dir):
    # Merge the source files into a single list of schemas.
    api_defs = []
    for filename in filenames:
        schema = os.path.normpath(filename)
        schema_loader = SchemaLoader(
            os.path.dirname(os.path.relpath(os.path.normpath(filename), root)),
            os.path.dirname(filename))
        api_def = schema_loader.LoadSchema(os.path.split(schema)[1])

        # If compiling the C++ model code, delete 'nocompile' nodes.
        if generator == 'cpp':
            api_def = json_schema.DeleteNodes(api_def, 'nocompile')
        api_defs.extend(api_def)

    api_model = Model()

    # For single-schema compilation make sure that the first (i.e. only) schema
    # is the default one.
    default_namespace = None

    # If we have files from multiple source paths, we'll use the common parent
    # path as the source directory.
    src_path = None

    # Load the actual namespaces into the model.
    for target_namespace, schema_filename in zip(api_defs, filenames):
        relpath = os.path.relpath(os.path.normpath(schema_filename), root)
        namespace = api_model.AddNamespace(target_namespace,
                                           relpath,
                                           include_compiler_options=True)

        if default_namespace is None:
            default_namespace = namespace

        if src_path is None:
            src_path = namespace.source_file_dir
        else:
            src_path = os.path.commonprefix(
                (src_path, namespace.source_file_dir))

        path, filename = os.path.split(schema_filename)
        short_filename, extension = os.path.splitext(filename)

    # Construct the type generator with all the namespaces in this model.
    type_generator = CppTypeGenerator(api_model,
                                      schema_loader,
                                      default_namespace=default_namespace)
    if generator == 'cpp-bundle':
        cpp_bundle_generator = CppBundleGenerator(root, api_model, api_defs,
                                                  type_generator,
                                                  root_namespace, src_path,
                                                  impl_dir)
        generators = [
            ('generated_api.cc', cpp_bundle_generator.api_cc_generator),
            ('generated_api.h', cpp_bundle_generator.api_h_generator),
            ('generated_schemas.cc',
             cpp_bundle_generator.schemas_cc_generator),
            ('generated_schemas.h', cpp_bundle_generator.schemas_h_generator)
        ]
    elif generator == 'cpp':
        cpp_generator = CppGenerator(type_generator, root_namespace)
        generators = [('%s.h' % short_filename, cpp_generator.h_generator),
                      ('%s.cc' % short_filename, cpp_generator.cc_generator)]
    elif generator == 'dart':
        generators = [('%s.dart' % namespace.unix_name,
                       DartGenerator(dart_overrides_dir))]
    elif generator == 'ppapi':
        generator = PpapiGenerator()
        generators = [
            (os.path.join('api', 'ppb_%s.idl' % namespace.unix_name),
             generator.idl_generator),
        ]
    else:
        raise Exception('Unrecognised generator %s' % generator)

    output_code = []
    for filename, generator in generators:
        code = generator.Generate(namespace).Render()
        if destdir:
            output_dir = os.path.join(destdir, src_path)
            if not os.path.exists(output_dir):
                os.makedirs(output_dir)
            with open(os.path.join(output_dir, filename), 'w') as f:
                f.write(code)
        output_code += [filename, '', code, '']

    return '\n'.join(output_code)
コード例 #29
0
ファイル: compiler.py プロジェクト: bbmjja8123/chromium-1
def GenerateSchema(generator, filenames, root, destdir, root_namespace,
                   dart_overrides_dir):
    schema_loader = SchemaLoader(
        os.path.dirname(os.path.relpath(os.path.normpath(filenames[0]), root)),
        os.path.dirname(filenames[0]))
    # Merge the source files into a single list of schemas.
    api_defs = []
    for filename in filenames:
        schema = os.path.normpath(filename)
        api_def = schema_loader.LoadSchema(os.path.split(schema)[1])

        # If compiling the C++ model code, delete 'nocompile' nodes.
        if generator == 'cpp':
            api_def = json_schema.DeleteNodes(api_def, 'nocompile')
        api_defs.extend(api_def)

    api_model = Model()

    # For single-schema compilation make sure that the first (i.e. only) schema
    # is the default one.
    default_namespace = None

    # Load the actual namespaces into the model.
    for target_namespace, schema_filename in zip(api_defs, filenames):
        relpath = os.path.relpath(os.path.normpath(schema_filename), root)
        namespace = api_model.AddNamespace(target_namespace,
                                           relpath,
                                           include_compiler_options=True)
        if default_namespace is None:
            default_namespace = namespace

        path, filename = os.path.split(schema_filename)
        short_filename, extension = os.path.splitext(filename)

        # Filenames are checked against the unix_names of the namespaces they
        # generate because the gyp uses the names of the JSON files to generate
        # the names of the .cc and .h files. We want these to be using unix_names.
        if namespace.unix_name != short_filename:
            sys.exit(
                "Filename %s is illegal. Name files using unix_hacker style." %
                schema_filename)

    # Construct the type generator with all the namespaces in this model.
    type_generator = CppTypeGenerator(api_model,
                                      schema_loader,
                                      default_namespace=default_namespace)

    if generator == 'cpp-bundle':
        cpp_bundle_generator = CppBundleGenerator(root, api_model, api_defs,
                                                  type_generator,
                                                  root_namespace)
        generators = [
            ('generated_api.cc', cpp_bundle_generator.api_cc_generator),
            ('generated_api.h', cpp_bundle_generator.api_h_generator),
            ('generated_schemas.cc',
             cpp_bundle_generator.schemas_cc_generator),
            ('generated_schemas.h', cpp_bundle_generator.schemas_h_generator)
        ]
    elif generator == 'cpp':
        cpp_generator = CppGenerator(type_generator, root_namespace)
        generators = [
            ('%s.h' % namespace.unix_name, cpp_generator.h_generator),
            ('%s.cc' % namespace.unix_name, cpp_generator.cc_generator)
        ]
    elif generator == 'dart':
        generators = [('%s.dart' % namespace.unix_name,
                       DartGenerator(dart_overrides_dir))]
    else:
        raise Exception('Unrecognised generator %s' % generator)

    output_code = []
    for filename, generator in generators:
        code = generator.Generate(namespace).Render()
        if destdir:
            with open(
                    os.path.join(destdir, namespace.source_file_dir, filename),
                    'w') as f:
                f.write(code)
        output_code += [filename, '', code, '']

    return '\n'.join(output_code)
コード例 #30
0
ファイル: compiler.py プロジェクト: sokolovp/BraveMining
def GenerateSchema(generator_name,
                   file_paths,
                   root,
                   destdir,
                   cpp_namespace_pattern,
                   bundle_name,
                   impl_dir,
                   include_rules):
  # Merge the source files into a single list of schemas.
  api_defs = []
  for file_path in file_paths:
    schema = os.path.relpath(file_path, root)
    api_def = SchemaLoader(root).LoadSchema(schema)

    # If compiling the C++ model code, delete 'nocompile' nodes.
    if generator_name == 'cpp':
      api_def = json_schema.DeleteNodes(api_def, 'nocompile')

    # Delete all 'nodefine' nodes. They are only for documentation.
    api_def = json_schema.DeleteNodes(api_def, 'nodefine')

    api_defs.extend(api_def)

  api_model = Model(allow_inline_enums=False)

  # For single-schema compilation make sure that the first (i.e. only) schema
  # is the default one.
  default_namespace = None

  # If we have files from multiple source paths, we'll use the common parent
  # path as the source directory.
  src_path = None

  # Load the actual namespaces into the model.
  for target_namespace, file_path in zip(api_defs, file_paths):
    relpath = os.path.relpath(os.path.normpath(file_path), root)
    namespace = api_model.AddNamespace(target_namespace,
                                       relpath,
                                       include_compiler_options=True,
                                       environment=CppNamespaceEnvironment(
                                           cpp_namespace_pattern))

    if default_namespace is None:
      default_namespace = namespace

    if src_path is None:
      src_path = namespace.source_file_dir
    else:
      src_path = os.path.commonprefix((src_path, namespace.source_file_dir))

    _, filename = os.path.split(file_path)
    filename_base, _ = os.path.splitext(filename)

  # Construct the type generator with all the namespaces in this model.
  schema_dir = os.path.dirname(os.path.relpath(file_paths[0], root))
  namespace_resolver = NamespaceResolver(root, schema_dir,
                                         include_rules, cpp_namespace_pattern)
  type_generator = CppTypeGenerator(api_model,
                                    namespace_resolver,
                                    default_namespace)
  if generator_name in ('cpp-bundle-registration', 'cpp-bundle-schema'):
    cpp_bundle_generator = CppBundleGenerator(root,
                                              api_model,
                                              api_defs,
                                              type_generator,
                                              cpp_namespace_pattern,
                                              bundle_name,
                                              src_path,
                                              impl_dir)
    if generator_name == 'cpp-bundle-registration':
      generators = [
        ('generated_api_registration.cc',
         cpp_bundle_generator.api_cc_generator),
        ('generated_api_registration.h', cpp_bundle_generator.api_h_generator),
      ]
    elif generator_name == 'cpp-bundle-schema':
      generators = [
        ('generated_schemas.cc', cpp_bundle_generator.schemas_cc_generator),
        ('generated_schemas.h', cpp_bundle_generator.schemas_h_generator)
      ]
  elif generator_name == 'cpp':
    cpp_generator = CppGenerator(type_generator)
    generators = [
      ('%s.h' % filename_base, cpp_generator.h_generator),
      ('%s.cc' % filename_base, cpp_generator.cc_generator)
    ]
  elif generator_name == 'externs':
    generators = [
      ('%s_externs.js' % namespace.unix_name, JsExternsGenerator())
    ]
  elif generator_name == 'interface':
    generators = [
      ('%s_interface.js' % namespace.unix_name, JsInterfaceGenerator())
    ]
  else:
    raise Exception('Unrecognised generator %s' % generator_name)

  output_code = []
  for filename, generator in generators:
    code = generator.Generate(namespace).Render()
    if destdir:
      if generator_name == 'cpp-bundle-registration':
        # Function registrations must be output to impl_dir, since they link in
        # API implementations.
        output_dir = os.path.join(destdir, impl_dir)
      else:
        output_dir = os.path.join(destdir, src_path)
      if not os.path.exists(output_dir):
        os.makedirs(output_dir)
      with open(os.path.join(output_dir, filename), 'w') as f:
        f.write(code)
    # If multiple files are being output, add the filename for each file.
    if len(generators) > 1:
      output_code += [filename, '', code, '']
    else:
      output_code += [code]

  return '\n'.join(output_code)