Yilong Li | 837cb91 | 2022-01-04 00:23:24 -0800 | [diff] [blame] | 1 | #!/bin/python3 |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 2 | import argparse |
Erwin Jansen | a7916b1 | 2018-10-26 09:44:10 -0700 | [diff] [blame] | 3 | import hashlib |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 4 | import json |
| 5 | import logging |
| 6 | import os |
| 7 | import sys |
| 8 | |
| 9 | |
| 10 | def cleanup_json(data): |
| 11 | """Cleans up the json structure by removing empty "", and empty key value |
| 12 | pairs.""" |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 13 | if isinstance(data, str): |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 14 | copy = data.strip() |
| 15 | return None if len(copy) == 0 else copy |
| 16 | |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 17 | if isinstance(data, dict): |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 18 | copy = {} |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 19 | for key, value in data.items(): |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 20 | rem = cleanup_json(value) |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 21 | if rem is not None: |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 22 | copy[key] = rem |
| 23 | return None if len(copy) == 0 else copy |
| 24 | |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 25 | if isinstance(data, list): |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 26 | copy = [] |
| 27 | for elem in data: |
| 28 | rem = cleanup_json(elem) |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 29 | if rem is not None: |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 30 | if rem not in copy: |
| 31 | copy.append(rem) |
| 32 | |
| 33 | if len(copy) == 0: |
| 34 | return None |
| 35 | return copy |
| 36 | |
| 37 | |
| 38 | class AttrDict(dict): |
| 39 | def __init__(self, *args, **kwargs): |
| 40 | super(AttrDict, self).__init__(*args, **kwargs) |
| 41 | self.__dict__ = self |
| 42 | |
| 43 | def as_list(self, name): |
| 44 | v = self.get(name, []) |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 45 | if isinstance(v, list): |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 46 | return v |
| 47 | |
| 48 | return [v] |
| 49 | |
| 50 | |
| 51 | def remove_lib_prefix(module): |
| 52 | """Removes the lib prefix, as we are not using them in CMake.""" |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 53 | if module.startswith("lib"): |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 54 | return module[3:] |
| 55 | else: |
| 56 | return module |
| 57 | |
| 58 | |
| 59 | def escape(msg): |
| 60 | """Escapes the ".""" |
| 61 | return '"' + msg.replace('"', '\\"') + '"' |
| 62 | |
| 63 | |
| 64 | def header(): |
| 65 | """The auto generate header.""" |
| 66 | return [ |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 67 | "# This is an autogenerated file! Do not edit!", |
| 68 | "# instead run make from .../device/generic/goldfish-opengl", |
| 69 | "# which will re-generate this file.", |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 70 | ] |
| 71 | |
| 72 | |
Erwin Jansen | a7916b1 | 2018-10-26 09:44:10 -0700 | [diff] [blame] | 73 | def checksum(fname): |
| 74 | """Calculates a SHA256 digest of the given file name.""" |
| 75 | m = hashlib.sha256() |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 76 | with open(fname, "r", encoding="utf-8") as mk: |
| 77 | m.update(mk.read().encode("utf-8")) |
Erwin Jansen | a7916b1 | 2018-10-26 09:44:10 -0700 | [diff] [blame] | 78 | return m.hexdigest() |
| 79 | |
| 80 | |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 81 | def generate_module(module): |
| 82 | """Generates a cmake module.""" |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 83 | name = remove_lib_prefix(module["module"]) |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 84 | make = header() |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 85 | mkfile = os.path.join(module["path"], "Android.mk") |
Erwin Jansen | a7916b1 | 2018-10-26 09:44:10 -0700 | [diff] [blame] | 86 | sha256 = checksum(mkfile) |
| 87 | make.append( |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 88 | 'android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/%s" "%s")' % (mkfile, sha256) |
| 89 | ) |
| 90 | make.append("set(%s_src %s)" % (name, " ".join(module["src"]))) |
| 91 | if module["type"] == "SHARED_LIBRARY": |
| 92 | make.append( |
| 93 | "android_add_library(TARGET {} SHARED LICENSE Apache-2.0 SRC {})".format( |
| 94 | name, " ".join(module["src"]) |
| 95 | ) |
| 96 | ) |
| 97 | elif module["type"] == "STATIC_LIBRARY": |
| 98 | make.append( |
| 99 | "android_add_library(TARGET {} LICENSE Apache-2.0 SRC {})".format( |
| 100 | name, " ".join(module["src"]) |
| 101 | ) |
| 102 | ) |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 103 | else: |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 104 | raise ValueError("Unexpected module type: %s" % module["type"]) |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 105 | |
| 106 | # Fix up the includes. |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 107 | includes = ["${GOLDFISH_DEVICE_ROOT}/" + s for s in module["includes"]] |
| 108 | make.append( |
| 109 | "target_include_directories(%s PRIVATE %s)" % (name, " ".join(includes)) |
| 110 | ) |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 111 | |
| 112 | # filter out definitions |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 113 | defs = [escape(d) for d in module["cflags"] if d.startswith("-D")] |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 114 | |
| 115 | # And the remaining flags. |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 116 | flags = [escape(d) for d in module["cflags"] if not d.startswith("-D")] |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 117 | |
| 118 | # Make sure we remove the lib prefix from all our dependencies. |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 119 | libs = [remove_lib_prefix(l) for l in module.get("libs", [])] |
| 120 | staticlibs = [ |
| 121 | remove_lib_prefix(l) |
| 122 | for l in module.get("staticlibs", []) |
| 123 | if l != "libandroidemu" |
| 124 | ] |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 125 | |
| 126 | # Configure the target. |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 127 | make.append("target_compile_definitions(%s PRIVATE %s)" % (name, " ".join(defs))) |
| 128 | make.append("target_compile_options(%s PRIVATE %s)" % (name, " ".join(flags))) |
Lingfeng Yang | f4d77ef | 2018-11-02 23:21:37 -0700 | [diff] [blame] | 129 | |
| 130 | if len(staticlibs) > 0: |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 131 | make.append( |
| 132 | "target_link_libraries(%s PRIVATE %s PRIVATE %s)" |
| 133 | % (name, " ".join(libs), " ".join(staticlibs)) |
| 134 | ) |
Lingfeng Yang | f4d77ef | 2018-11-02 23:21:37 -0700 | [diff] [blame] | 135 | else: |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 136 | make.append("target_link_libraries(%s PRIVATE %s)" % (name, " ".join(libs))) |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 137 | return make |
| 138 | |
| 139 | |
| 140 | def main(argv=None): |
| 141 | parser = argparse.ArgumentParser( |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 142 | description="Generates a set of cmake files" |
| 143 | "based up the js representation." |
| 144 | "Use this to generate cmake files that can be consumed by the emulator build" |
| 145 | ) |
| 146 | parser.add_argument( |
| 147 | "-i", |
| 148 | "--input", |
| 149 | dest="input", |
| 150 | type=str, |
| 151 | required=True, |
| 152 | help="json file containing the build tree", |
| 153 | ) |
| 154 | parser.add_argument( |
| 155 | "-v", |
| 156 | "--verbose", |
| 157 | action="store_const", |
| 158 | dest="loglevel", |
| 159 | const=logging.INFO, |
| 160 | default=logging.ERROR, |
| 161 | help="Log what is happening", |
| 162 | ) |
| 163 | parser.add_argument( |
| 164 | "-o", |
| 165 | "--output", |
| 166 | dest="outdir", |
| 167 | type=str, |
| 168 | default=None, |
| 169 | help="Output directory for create CMakefile.txt", |
| 170 | ) |
| 171 | parser.add_argument( |
| 172 | "-c", |
| 173 | "--clean", |
| 174 | dest="output", |
| 175 | type=str, |
| 176 | default=None, |
| 177 | help="Write out the cleaned up js", |
| 178 | ) |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 179 | args = parser.parse_args() |
| 180 | |
| 181 | logging.basicConfig(level=args.loglevel) |
| 182 | |
| 183 | with open(args.input) as data_file: |
| 184 | data = json.load(data_file) |
| 185 | |
| 186 | modules = cleanup_json(data) |
| 187 | |
| 188 | # Write out cleaned up json, mainly useful for debugging etc. |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 189 | if args.output is not None: |
| 190 | with open(args.output, "w") as out_file: |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 191 | out_file.write(json.dumps(modules, indent=2)) |
| 192 | |
| 193 | # Location --> CMakeLists.txt |
| 194 | cmake = {} |
| 195 | |
| 196 | # The root, it will basically just include all the generated files. |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 197 | root = os.path.join(args.outdir, "CMakeLists.txt") |
| 198 | mkfile = os.path.join(args.outdir, "Android.mk") |
Erwin Jansen | a7916b1 | 2018-10-26 09:44:10 -0700 | [diff] [blame] | 199 | sha256 = checksum(mkfile) |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 200 | cmake[root] = header() |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 201 | cmake[root].append("set(GOLDFISH_DEVICE_ROOT ${CMAKE_CURRENT_SOURCE_DIR})") |
Erwin Jansen | a7916b1 | 2018-10-26 09:44:10 -0700 | [diff] [blame] | 202 | cmake[root].append( |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 203 | 'android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/%s" "%s")' % (mkfile, sha256) |
| 204 | ) |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 205 | |
| 206 | # Generate the modules. |
| 207 | for module in modules: |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 208 | location = os.path.join(args.outdir, module["path"], "CMakeLists.txt") |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 209 | |
| 210 | # Make sure we handle the case where we have >2 modules in the same dir. |
| 211 | if location not in cmake: |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 212 | cmake[root].append("add_subdirectory(%s)" % module["path"]) |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 213 | cmake[location] = [] |
| 214 | cmake[location].extend(generate_module(module)) |
| 215 | |
| 216 | # Write them to disk. |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 217 | for (loc, cmklist) in cmake.items(): |
| 218 | logging.info("Writing to %s", loc) |
| 219 | with open(loc, "w") as fn: |
| 220 | fn.write("\n".join(cmklist)) |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 221 | |
| 222 | |
Erwin Jansen | 5a6541c | 2021-12-07 12:12:25 -0800 | [diff] [blame] | 223 | if __name__ == "__main__": |
Erwin Jansen | f96db3c | 2018-10-25 23:28:54 -0700 | [diff] [blame] | 224 | sys.exit(main()) |