Skip to content
Snippets Groups Projects
Select Git revision
  • a7916b14397b7e9116d514e7595a27d18a043afd
  • test default
2 results

cmake_transform.py

Blame
  • cmake_transform.py 6.12 KiB
    #!/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())