| #!/bin/python | 
 | import argparse | 
 | import hashlib | 
 | import json | 
 | import logging | 
 | import os | 
 | import sys | 
 |  | 
 |  | 
 | def cleanup_json(data): | 
 |     """Cleans up the json structure by removing empty "", and empty key value | 
 |     pairs.""" | 
 |     if (isinstance(data, unicode)): | 
 |         copy = data.strip() | 
 |         return None if len(copy) == 0 else copy | 
 |  | 
 |     if (isinstance(data, dict)): | 
 |         copy = {} | 
 |         for key, value in data.iteritems(): | 
 |             rem = cleanup_json(value) | 
 |             if (rem is not None): | 
 |                 copy[key] = rem | 
 |         return None if len(copy) == 0 else copy | 
 |  | 
 |     if (isinstance(data, list)): | 
 |         copy = [] | 
 |         for elem in data: | 
 |             rem = cleanup_json(elem) | 
 |             if (rem is not None): | 
 |                 if rem not in copy: | 
 |                     copy.append(rem) | 
 |  | 
 |         if len(copy) == 0: | 
 |             return None | 
 |         return copy | 
 |  | 
 |  | 
 | class AttrDict(dict): | 
 |     def __init__(self, *args, **kwargs): | 
 |         super(AttrDict, self).__init__(*args, **kwargs) | 
 |         self.__dict__ = self | 
 |  | 
 |     def as_list(self, name): | 
 |         v = self.get(name, []) | 
 |         if (isinstance(v, list)): | 
 |             return v | 
 |  | 
 |         return [v] | 
 |  | 
 |  | 
 | def remove_lib_prefix(module): | 
 |     """Removes the lib prefix, as we are not using them in CMake.""" | 
 |     if module.startswith('lib'): | 
 |         return module[3:] | 
 |     else: | 
 |         return module | 
 |  | 
 |  | 
 | def escape(msg): | 
 |     """Escapes the ".""" | 
 |     return '"' + msg.replace('"', '\\"') + '"' | 
 |  | 
 |  | 
 | def header(): | 
 |     """The auto generate header.""" | 
 |     return [ | 
 |         '# This is an autogenerated file! Do not edit!', | 
 |         '# instead run make from .../device/generic/goldfish-opengl', | 
 |         '# which will re-generate this file.' | 
 |     ] | 
 |  | 
 |  | 
 | def checksum(fname): | 
 |     """Calculates a SHA256 digest of the given file name.""" | 
 |     m = hashlib.sha256() | 
 |     with open(fname, 'r') as mk: | 
 |         m.update(mk.read()) | 
 |     return m.hexdigest() | 
 |  | 
 |  | 
 | def generate_module(module): | 
 |     """Generates a cmake module.""" | 
 |     name = remove_lib_prefix(module['module']) | 
 |     make = header() | 
 |     mkfile = os.path.join(module['path'], 'Android.mk') | 
 |     sha256 = checksum(mkfile) | 
 |     make.append( | 
 |         'android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/%s" "%s")' % (mkfile, sha256)) | 
 |     make.append('set(%s_src %s)' % (name, ' '.join(module['src']))) | 
 |     if module['type'] == 'SHARED_LIBRARY': | 
 |         make.append('android_add_shared_library(%s)' % name) | 
 |     elif module['type'] == 'STATIC_LIBRARY': | 
 |         make.append('android_add_library(%s)' % name) | 
 |     else: | 
 |         raise ValueError('Unexpected module type: %s' % module['type']) | 
 |  | 
 |     # Fix up the includes. | 
 |     includes = ['${GOLDFISH_DEVICE_ROOT}/' + s for s in module['includes']] | 
 |     make.append('target_include_directories(%s PRIVATE %s)' % | 
 |                 (name, ' '.join(includes))) | 
 |  | 
 |     # filter out definitions | 
 |     defs = [escape(d) for d in module['cflags'] if d.startswith('-D')] | 
 |  | 
 |     #  And the remaining flags. | 
 |     flags = [escape(d) for d in module['cflags'] if not d.startswith('-D')] | 
 |  | 
 |     # Make sure we remove the lib prefix from all our dependencies. | 
 |     libs = [remove_lib_prefix(l) for l in module['libs']] | 
 |     staticlibs = [remove_lib_prefix(l) for l in | 
 |                       module.get('staticlibs', []) | 
 |                       if l != "libandroidemu"] | 
 |  | 
 |     # Configure the target. | 
 |     make.append('target_compile_definitions(%s PRIVATE %s)' % | 
 |                 (name, ' '.join(defs))) | 
 |     make.append('target_compile_options(%s PRIVATE %s)' % | 
 |                 (name, ' '.join(flags))) | 
 |  | 
 |     if len(staticlibs) > 0: | 
 |         make.append('target_link_libraries(%s PRIVATE %s PRIVATE %s)' % | 
 |                     (name, ' '.join(libs), " ".join(staticlibs))) | 
 |     else: | 
 |         make.append('target_link_libraries(%s PRIVATE %s)' % | 
 |                     (name, ' '.join(libs))) | 
 |     return make | 
 |  | 
 |  | 
 | def main(argv=None): | 
 |     parser = argparse.ArgumentParser( | 
 |         description='Generates a set of cmake files' | 
 |         'based up the js representation.' | 
 |         'Use this to generate cmake files that can be consumed by the emulator build') | 
 |     parser.add_argument('-i', '--input', dest='input', type=str, required=True, | 
 |                         help='json file containing the build tree') | 
 |     parser.add_argument('-v', '--verbose', | 
 |                         action='store_const', dest='loglevel', | 
 |                         const=logging.INFO, default=logging.ERROR, | 
 |                         help='Log what is happening') | 
 |     parser.add_argument('-o', '--output', | 
 |                         dest='outdir', type=str, default=None, | 
 |                         help='Output directory for create CMakefile.txt') | 
 |     parser.add_argument('-c', '--clean', dest='output', type=str, | 
 |                         default=None, | 
 |                         help='Write out the cleaned up js') | 
 |     args = parser.parse_args() | 
 |  | 
 |     logging.basicConfig(level=args.loglevel) | 
 |  | 
 |     with open(args.input) as data_file: | 
 |         data = json.load(data_file) | 
 |  | 
 |     modules = cleanup_json(data) | 
 |  | 
 |     # Write out cleaned up json, mainly useful for debugging etc. | 
 |     if (args.output is not None): | 
 |         with open(args.output, 'w') as out_file: | 
 |             out_file.write(json.dumps(modules, indent=2)) | 
 |  | 
 |     # Location --> CMakeLists.txt | 
 |     cmake = {} | 
 |  | 
 |     # The root, it will basically just include all the generated files. | 
 |     root = os.path.join(args.outdir, 'CMakeLists.txt') | 
 |     mkfile = os.path.join(args.outdir, 'Android.mk') | 
 |     sha256 = checksum(mkfile) | 
 |     cmake[root] = header() | 
 |     cmake[root].append('set(GOLDFISH_DEVICE_ROOT ${CMAKE_CURRENT_SOURCE_DIR})') | 
 |     cmake[root].append( | 
 |         'android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/%s" "%s")' % (mkfile, sha256)) | 
 |  | 
 |     # Generate the modules. | 
 |     for module in modules: | 
 |         location = os.path.join(args.outdir, module['path'], 'CMakeLists.txt') | 
 |  | 
 |         # Make sure we handle the case where we have >2 modules in the same dir. | 
 |         if location not in cmake: | 
 |             cmake[root].append('add_subdirectory(%s)' % module['path']) | 
 |             cmake[location] = [] | 
 |         cmake[location].extend(generate_module(module)) | 
 |  | 
 |     # Write them to disk. | 
 |     for (loc, cmklist) in cmake.iteritems(): | 
 |         logging.info('Writing to %s', loc) | 
 |         with open(loc, 'w') as fn: | 
 |             fn.write('\n'.join(cmklist)) | 
 |  | 
 |  | 
 | if __name__ == '__main__': | 
 |     sys.exit(main()) |