blob: b93b1a0ce32223c0a1692f56be5dab7ebe10669d [file] [log] [blame]
Yilong Li837cb912022-01-04 00:23:24 -08001#!/bin/python3
Erwin Jansenf96db3c2018-10-25 23:28:54 -07002import argparse
Erwin Jansena7916b12018-10-26 09:44:10 -07003import hashlib
Erwin Jansenf96db3c2018-10-25 23:28:54 -07004import json
5import logging
6import os
7import sys
8
9
10def cleanup_json(data):
11 """Cleans up the json structure by removing empty "", and empty key value
12 pairs."""
Erwin Jansen5a6541c2021-12-07 12:12:25 -080013 if isinstance(data, str):
Erwin Jansenf96db3c2018-10-25 23:28:54 -070014 copy = data.strip()
15 return None if len(copy) == 0 else copy
16
Erwin Jansen5a6541c2021-12-07 12:12:25 -080017 if isinstance(data, dict):
Erwin Jansenf96db3c2018-10-25 23:28:54 -070018 copy = {}
Erwin Jansen5a6541c2021-12-07 12:12:25 -080019 for key, value in data.items():
Erwin Jansenf96db3c2018-10-25 23:28:54 -070020 rem = cleanup_json(value)
Erwin Jansen5a6541c2021-12-07 12:12:25 -080021 if rem is not None:
Erwin Jansenf96db3c2018-10-25 23:28:54 -070022 copy[key] = rem
23 return None if len(copy) == 0 else copy
24
Erwin Jansen5a6541c2021-12-07 12:12:25 -080025 if isinstance(data, list):
Erwin Jansenf96db3c2018-10-25 23:28:54 -070026 copy = []
27 for elem in data:
28 rem = cleanup_json(elem)
Erwin Jansen5a6541c2021-12-07 12:12:25 -080029 if rem is not None:
Erwin Jansenf96db3c2018-10-25 23:28:54 -070030 if rem not in copy:
31 copy.append(rem)
32
33 if len(copy) == 0:
34 return None
35 return copy
36
37
38class 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 Jansen5a6541c2021-12-07 12:12:25 -080045 if isinstance(v, list):
Erwin Jansenf96db3c2018-10-25 23:28:54 -070046 return v
47
48 return [v]
49
50
51def remove_lib_prefix(module):
52 """Removes the lib prefix, as we are not using them in CMake."""
Erwin Jansen5a6541c2021-12-07 12:12:25 -080053 if module.startswith("lib"):
Erwin Jansenf96db3c2018-10-25 23:28:54 -070054 return module[3:]
55 else:
56 return module
57
58
59def escape(msg):
60 """Escapes the "."""
61 return '"' + msg.replace('"', '\\"') + '"'
62
63
64def header():
65 """The auto generate header."""
66 return [
Erwin Jansen5a6541c2021-12-07 12:12:25 -080067 "# 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 Jansenf96db3c2018-10-25 23:28:54 -070070 ]
71
72
Erwin Jansena7916b12018-10-26 09:44:10 -070073def checksum(fname):
74 """Calculates a SHA256 digest of the given file name."""
75 m = hashlib.sha256()
Erwin Jansen5a6541c2021-12-07 12:12:25 -080076 with open(fname, "r", encoding="utf-8") as mk:
77 m.update(mk.read().encode("utf-8"))
Erwin Jansena7916b12018-10-26 09:44:10 -070078 return m.hexdigest()
79
80
Erwin Jansenf96db3c2018-10-25 23:28:54 -070081def generate_module(module):
82 """Generates a cmake module."""
Erwin Jansen5a6541c2021-12-07 12:12:25 -080083 name = remove_lib_prefix(module["module"])
Erwin Jansenf96db3c2018-10-25 23:28:54 -070084 make = header()
Erwin Jansen5a6541c2021-12-07 12:12:25 -080085 mkfile = os.path.join(module["path"], "Android.mk")
Erwin Jansena7916b12018-10-26 09:44:10 -070086 sha256 = checksum(mkfile)
87 make.append(
Erwin Jansen5a6541c2021-12-07 12:12:25 -080088 '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 Jansenf96db3c2018-10-25 23:28:54 -0700103 else:
Erwin Jansen5a6541c2021-12-07 12:12:25 -0800104 raise ValueError("Unexpected module type: %s" % module["type"])
Erwin Jansenf96db3c2018-10-25 23:28:54 -0700105
106 # Fix up the includes.
Erwin Jansen5a6541c2021-12-07 12:12:25 -0800107 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 Jansenf96db3c2018-10-25 23:28:54 -0700111
112 # filter out definitions
Erwin Jansen5a6541c2021-12-07 12:12:25 -0800113 defs = [escape(d) for d in module["cflags"] if d.startswith("-D")]
Erwin Jansenf96db3c2018-10-25 23:28:54 -0700114
115 # And the remaining flags.
Erwin Jansen5a6541c2021-12-07 12:12:25 -0800116 flags = [escape(d) for d in module["cflags"] if not d.startswith("-D")]
Erwin Jansenf96db3c2018-10-25 23:28:54 -0700117
118 # Make sure we remove the lib prefix from all our dependencies.
Erwin Jansen5a6541c2021-12-07 12:12:25 -0800119 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 Jansenf96db3c2018-10-25 23:28:54 -0700125
126 # Configure the target.
Erwin Jansen5a6541c2021-12-07 12:12:25 -0800127 make.append("target_compile_definitions(%s PRIVATE %s)" % (name, " ".join(defs)))
128 make.append("target_compile_options(%s PRIVATE %s)" % (name, " ".join(flags)))
Lingfeng Yangf4d77ef2018-11-02 23:21:37 -0700129
130 if len(staticlibs) > 0:
Erwin Jansen5a6541c2021-12-07 12:12:25 -0800131 make.append(
132 "target_link_libraries(%s PRIVATE %s PRIVATE %s)"
133 % (name, " ".join(libs), " ".join(staticlibs))
134 )
Lingfeng Yangf4d77ef2018-11-02 23:21:37 -0700135 else:
Erwin Jansen5a6541c2021-12-07 12:12:25 -0800136 make.append("target_link_libraries(%s PRIVATE %s)" % (name, " ".join(libs)))
Erwin Jansenf96db3c2018-10-25 23:28:54 -0700137 return make
138
139
140def main(argv=None):
141 parser = argparse.ArgumentParser(
Erwin Jansen5a6541c2021-12-07 12:12:25 -0800142 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 Jansenf96db3c2018-10-25 23:28:54 -0700179 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 Jansen5a6541c2021-12-07 12:12:25 -0800189 if args.output is not None:
190 with open(args.output, "w") as out_file:
Erwin Jansenf96db3c2018-10-25 23:28:54 -0700191 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 Jansen5a6541c2021-12-07 12:12:25 -0800197 root = os.path.join(args.outdir, "CMakeLists.txt")
198 mkfile = os.path.join(args.outdir, "Android.mk")
Erwin Jansena7916b12018-10-26 09:44:10 -0700199 sha256 = checksum(mkfile)
Erwin Jansenf96db3c2018-10-25 23:28:54 -0700200 cmake[root] = header()
Erwin Jansen5a6541c2021-12-07 12:12:25 -0800201 cmake[root].append("set(GOLDFISH_DEVICE_ROOT ${CMAKE_CURRENT_SOURCE_DIR})")
Erwin Jansena7916b12018-10-26 09:44:10 -0700202 cmake[root].append(
Erwin Jansen5a6541c2021-12-07 12:12:25 -0800203 'android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/%s" "%s")' % (mkfile, sha256)
204 )
Erwin Jansenf96db3c2018-10-25 23:28:54 -0700205
206 # Generate the modules.
207 for module in modules:
Erwin Jansen5a6541c2021-12-07 12:12:25 -0800208 location = os.path.join(args.outdir, module["path"], "CMakeLists.txt")
Erwin Jansenf96db3c2018-10-25 23:28:54 -0700209
210 # Make sure we handle the case where we have >2 modules in the same dir.
211 if location not in cmake:
Erwin Jansen5a6541c2021-12-07 12:12:25 -0800212 cmake[root].append("add_subdirectory(%s)" % module["path"])
Erwin Jansenf96db3c2018-10-25 23:28:54 -0700213 cmake[location] = []
214 cmake[location].extend(generate_module(module))
215
216 # Write them to disk.
Erwin Jansen5a6541c2021-12-07 12:12:25 -0800217 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 Jansenf96db3c2018-10-25 23:28:54 -0700221
222
Erwin Jansen5a6541c2021-12-07 12:12:25 -0800223if __name__ == "__main__":
Erwin Jansenf96db3c2018-10-25 23:28:54 -0700224 sys.exit(main())