| #!/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['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()) |