#!/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_library(TARGET {} SHARED LICENSE Apache-2.0 SRC {})'.format(name, ' '.join(module['src']))) elif module['type'] == 'STATIC_LIBRARY': make.append('android_add_library(TARGET {} LICENSE Apache-2.0 SRC {})'.format(name, ' '.join(module['src']))) 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.get('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())