aboutsummaryrefslogtreecommitdiffstats
path: root/cmake_transform.py
diff options
context:
space:
mode:
authorErwin Jansen <jansene@google.com>2018-10-25 23:28:54 -0700
committerErwin Jansen <jansene@google.com>2018-10-26 09:01:25 -0700
commitf96db3c016ad5be5532d843758bb6cc7592fb68a (patch)
tree23206b24be6f934c4bf1e8edad407db8e9d4c4f1 /cmake_transform.py
parent023b3ca6ac518ef047b3ffbe9714276b293be116 (diff)
downloaddevice_generic_goldfish-opengl-f96db3c016ad5be5532d843758bb6cc7592fb68a.tar.gz
device_generic_goldfish-opengl-f96db3c016ad5be5532d843758bb6cc7592fb68a.tar.bz2
device_generic_goldfish-opengl-f96db3c016ad5be5532d843758bb6cc7592fb68a.zip
Autogenerate the CMake build
Adds a GNUMakefile that will generate the cmake files based upon the android makefiles. This will make it easier to keep the makefiles in sync. If the makefiles change, we will have to run make in this directory. It relies on the following: - The android.mk files are using the emugl dependency mechanism - You are in the emulator repo (as we need the emulator build.mk files) - We translate the emugl -> json representation. - We write the json representation to disk - We have a python script that transforms the json to cmake It is all driven by GNUmake, so all you have to do is type make to regenerate the files. SOONG does not use GNUMakefiles so we should be able to co-exist. Change-Id: I6f9ae22397bcf9987699b946aa14921b00fc94b0
Diffstat (limited to 'cmake_transform.py')
-rw-r--r--cmake_transform.py163
1 files changed, 163 insertions, 0 deletions
diff --git a/cmake_transform.py b/cmake_transform.py
new file mode 100644
index 00000000..f065488b
--- /dev/null
+++ b/cmake_transform.py
@@ -0,0 +1,163 @@
+#!/bin/python
+import argparse
+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 generate_module(module):
+ """Generates a cmake module."""
+ name = remove_lib_prefix(module['module'])
+ make = header()
+ make.append('set(%s_src %s)' % (name, ' '.join(module['src'])))
+ if module['type'] == 'SHARED_LIBRARY':
+ make.append('android_add_shared_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']]
+
+ # 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)))
+ 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')
+ cmake[root] = header()
+ cmake[root].append('set(GOLDFISH_DEVICE_ROOT ${CMAKE_CURRENT_SOURCE_DIR})')
+
+ # 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())