[M120 Migration] Implement ewk_view_is_video_playing api
[platform/framework/web/chromium-efl.git] / build / fuchsia / gen_build_defs.py
1 #!/usr/bin/env vpython3
2 # Copyright 2023 The Chromium Authors
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5 #
6 # Generates a single BUILD.gn file with build targets generated using the
7 # manifest files in the SDK.
8
9 import json
10 import logging
11 import os
12 import sys
13
14 sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),
15                                              'test')))
16
17 from common import DIR_SRC_ROOT, SDK_ROOT, get_host_os
18
19 # Inserted at the top of the generated BUILD.gn file.
20 _GENERATED_PREAMBLE = """# DO NOT EDIT! This file was generated by
21 # //build/fuchsia/gen_build_def.py.
22 # Any changes made to this file will be discarded.
23
24 import("//third_party/fuchsia-gn-sdk/src/fidl_library.gni")
25 import("//third_party/fuchsia-gn-sdk/src/fuchsia_sdk_pkg.gni")
26
27 """
28
29
30 def ReformatTargetName(dep_name):
31   """"Substitutes characters in |dep_name| which are not valid in GN target
32   names (e.g. dots become hyphens)."""
33   return dep_name
34
35
36 def FormatGNTarget(fields):
37   """Returns a GN target definition as a string.
38
39   |fields|: The GN fields to include in the target body.
40             'target_name' and 'type' are mandatory."""
41
42   output = '%s("%s") {\n' % (fields['type'], fields['target_name'])
43   del fields['target_name']
44   del fields['type']
45
46   # Ensure that fields with no ordering requirement are sorted.
47   for field in ['sources', 'public_deps']:
48     if field in fields:
49       fields[field].sort()
50
51   for key, val in fields.items():
52     if isinstance(val, str):
53       val_serialized = '\"%s\"' % val
54     elif isinstance(val, list):
55       # Serialize a list of strings in the prettiest possible manner.
56       if len(val) == 0:
57         val_serialized = '[]'
58       elif len(val) == 1:
59         val_serialized = '[ \"%s\" ]' % val[0]
60       else:
61         val_serialized = '[\n    ' + ',\n    '.join(['\"%s\"' % x
62                                                      for x in val]) + '\n  ]'
63     else:
64       raise Exception('Could not serialize %r' % val)
65
66     output += '  %s = %s\n' % (key, val_serialized)
67   output += '}'
68
69   return output
70
71
72 def MetaRootRelativePaths(sdk_relative_paths, meta_root):
73   return [os.path.relpath(path, meta_root) for path in sdk_relative_paths]
74
75
76 def ConvertCommonFields(json):
77   """Extracts fields from JSON manifest data which are used across all
78   target types. Note that FIDL packages do their own processing."""
79
80   meta_root = json['root']
81
82   converted = {'target_name': ReformatTargetName(json['name'])}
83
84   if 'deps' in json:
85     converted['public_deps'] = MetaRootRelativePaths(json['deps'],
86                                                      os.path.dirname(meta_root))
87
88   # FIDL bindings dependencies are relative to the "fidl" sub-directory.
89   if 'fidl_binding_deps' in json:
90     for entry in json['fidl_binding_deps']:
91       converted['public_deps'] += MetaRootRelativePaths([
92           'fidl/' + dep + ':' + os.path.basename(dep) + '_' +
93           entry['binding_type'] for dep in entry['deps']
94       ], meta_root)
95
96   return converted
97
98
99 def ConvertFidlLibrary(json):
100   """Converts a fidl_library manifest entry to a GN target.
101
102   Arguments:
103     json: The parsed manifest JSON.
104   Returns:
105     The GN target definition, represented as a string."""
106
107   meta_root = json['root']
108
109   converted = ConvertCommonFields(json)
110   converted['type'] = 'fidl_library'
111   converted['sources'] = MetaRootRelativePaths(json['sources'], meta_root)
112   converted['library_name'] = json['name']
113
114   return converted
115
116
117 def ConvertCcPrebuiltLibrary(json):
118   """Converts a cc_prebuilt_library manifest entry to a GN target.
119
120   Arguments:
121     json: The parsed manifest JSON.
122   Returns:
123     The GN target definition, represented as a string."""
124
125   meta_root = json['root']
126
127   converted = ConvertCommonFields(json)
128   converted['type'] = 'fuchsia_sdk_pkg'
129
130   converted['sources'] = MetaRootRelativePaths(json['headers'], meta_root)
131
132   converted['include_dirs'] = MetaRootRelativePaths([json['include_dir']],
133                                                     meta_root)
134
135   if json['format'] == 'shared':
136     converted['shared_libs'] = [json['name']]
137   else:
138     converted['static_libs'] = [json['name']]
139
140   return converted
141
142
143 def ConvertCcSourceLibrary(json):
144   """Converts a cc_source_library manifest entry to a GN target.
145
146   Arguments:
147     json: The parsed manifest JSON.
148   Returns:
149     The GN target definition, represented as a string."""
150
151   meta_root = json['root']
152
153   converted = ConvertCommonFields(json)
154   converted['type'] = 'fuchsia_sdk_pkg'
155
156   # Headers and source file paths can be scattered across "sources", "headers",
157   # and "files". Merge them together into one source list.
158   converted['sources'] = MetaRootRelativePaths(json['sources'], meta_root)
159   if 'headers' in json:
160     converted['sources'] += MetaRootRelativePaths(json['headers'], meta_root)
161   if 'files' in json:
162     converted['sources'] += MetaRootRelativePaths(json['files'], meta_root)
163   converted['sources'] = list(set(converted['sources']))
164
165   converted['include_dirs'] = MetaRootRelativePaths([json['include_dir']],
166                                                     meta_root)
167
168   return converted
169
170
171 def ConvertLoadableModule(json):
172   """Converts a loadable module manifest entry to GN targets.
173
174   Arguments:
175     json: The parsed manifest JSON.
176   Returns:
177     A list of GN target definitions."""
178
179   name = json['name']
180   if name != 'vulkan_layers':
181     raise RuntimeError('Unsupported loadable_module: %s' % name)
182
183   # Copy resources and binaries
184   resources = json['resources']
185
186   binaries = json['binaries']
187
188   def _filename_no_ext(name):
189     return os.path.splitext(os.path.basename(name))[0]
190
191   # Pair each json resource with its corresponding binary. Each such pair
192   # is a "layer". We only need to check one arch because each arch has the
193   # same list of binaries.
194   arch = next(iter(binaries))
195   binary_names = binaries[arch]
196   local_pkg = json['root']
197   vulkan_targets = []
198
199   for res in resources:
200     layer_name = _filename_no_ext(res)
201
202     # Filter binaries for a matching name.
203     filtered = [n for n in binary_names if _filename_no_ext(n) == layer_name]
204
205     if not filtered:
206       # If the binary could not be found then do not generate a
207       # target for this layer. The missing targets will cause a
208       # mismatch with the "golden" outputs.
209       continue
210
211     # Replace hardcoded arch in the found binary filename.
212     binary = filtered[0].replace('/' + arch + '/', "/${target_cpu}/")
213
214     target = {}
215     target['name'] = layer_name
216     target['config'] = os.path.relpath(res, start=local_pkg)
217     target['binary'] = os.path.relpath(binary, start=local_pkg)
218
219     vulkan_targets.append(target)
220
221   converted = []
222   all_target = {}
223   all_target['target_name'] = 'all'
224   all_target['type'] = 'group'
225   all_target['data_deps'] = []
226   for target in vulkan_targets:
227     config_target = {}
228     config_target['target_name'] = target['name'] + '_config'
229     config_target['type'] = 'copy'
230     config_target['sources'] = [target['config']]
231     config_target['outputs'] = ['${root_gen_dir}/' + target['config']]
232     converted.append(config_target)
233     lib_target = {}
234     lib_target['target_name'] = target['name'] + '_lib'
235     lib_target['type'] = 'copy'
236     lib_target['sources'] = [target['binary']]
237     lib_target['outputs'] = ['${root_out_dir}/lib/{{source_file_part}}']
238     converted.append(lib_target)
239     group_target = {}
240     group_target['target_name'] = target['name']
241     group_target['type'] = 'group'
242     group_target['data_deps'] = [
243         ':' + target['name'] + '_config', ':' + target['name'] + '_lib'
244     ]
245     converted.append(group_target)
246     all_target['data_deps'].append(':' + target['name'])
247   converted.append(all_target)
248   return converted
249
250
251 def ConvertNoOp(json):
252   """Null implementation of a conversion function. No output is generated."""
253
254   return None
255
256
257 """Maps manifest types to conversion functions."""
258 _CONVERSION_FUNCTION_MAP = {
259     'fidl_library': ConvertFidlLibrary,
260     'cc_source_library': ConvertCcSourceLibrary,
261     'cc_prebuilt_library': ConvertCcPrebuiltLibrary,
262     'loadable_module': ConvertLoadableModule,
263
264     # No need to build targets for these types yet.
265     'companion_host_tool': ConvertNoOp,
266     'component_manifest': ConvertNoOp,
267     'config': ConvertNoOp,
268     'dart_library': ConvertNoOp,
269     'data': ConvertNoOp,
270     'device_profile': ConvertNoOp,
271     'documentation': ConvertNoOp,
272     'ffx_tool': ConvertNoOp,
273     'host_tool': ConvertNoOp,
274     'image': ConvertNoOp,
275     'sysroot': ConvertNoOp,
276 }
277
278
279 def ConvertMeta(meta_path):
280   parsed = json.load(open(meta_path))
281   if 'type' not in parsed:
282     return
283
284   convert_function = _CONVERSION_FUNCTION_MAP.get(parsed['type'])
285   if convert_function is None:
286     logging.warning('Unexpected SDK artifact type %s in %s.' %
287                     (parsed['type'], meta_path))
288     return
289
290   converted = convert_function(parsed)
291   if not converted:
292     return
293   output_path = os.path.join(os.path.dirname(meta_path), 'BUILD.gn')
294   if os.path.exists(output_path):
295     os.unlink(output_path)
296   with open(output_path, 'w') as buildfile:
297     buildfile.write(_GENERATED_PREAMBLE)
298
299     # Loadable modules have multiple targets
300     if convert_function != ConvertLoadableModule:
301       buildfile.write(FormatGNTarget(converted) + '\n\n')
302     else:
303       for target in converted:
304         buildfile.write(FormatGNTarget(target) + '\n\n')
305
306
307 def ProcessSdkManifest():
308   toplevel_meta = json.load(
309       open(os.path.join(SDK_ROOT, 'meta', 'manifest.json')))
310
311   for part in toplevel_meta['parts']:
312     meta_path = os.path.join(SDK_ROOT, part['meta'])
313     ConvertMeta(meta_path)
314
315
316 def main():
317
318   # Exit if there's no Fuchsia support for this platform.
319   try:
320     get_host_os()
321   except:
322     logging.warning('Fuchsia SDK is not supported on this platform.')
323     return 0
324
325   # TODO(crbug/1432399): Remove this when links to these files inside the sdk
326   # directory have been redirected.
327   build_path = os.path.join(SDK_ROOT, 'build')
328   os.makedirs(build_path, exist_ok=True)
329   for gn_file in ['component.gni', 'package.gni']:
330     open(os.path.join(build_path, gn_file),
331          "w").write("""# DO NOT EDIT! This file was generated by
332 # //build/fuchsia/gen_build_def.py.
333 # Any changes made to this file will be discarded.
334
335 import("//third_party/fuchsia-gn-sdk/src/{}")
336       """.format(gn_file))
337
338   ProcessSdkManifest()
339
340
341 if __name__ == '__main__':
342   sys.exit(main())