Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/angle
Path: blob/main_old/scripts/export_targets.py
1693 views
1
#! /usr/bin/env python3
2
assert __name__ == '__main__'
3
4
'''
5
To update ANGLE in Gecko, use Windows with git-bash, and setup depot_tools, python2, and
6
python3. Because depot_tools expects `python` to be `python2` (shame!), python2 must come
7
before python3 in your path.
8
9
Upstream: https://chromium.googlesource.com/angle/angle
10
11
Our repo: https://github.com/mozilla/angle
12
It has branches like 'firefox-60' which is the branch we use for pulling into
13
Gecko with this script.
14
15
This script leaves a record of the merge-base and cherry-picks that we pull into
16
Gecko. (gfx/angle/cherries.log)
17
18
ANGLE<->Chrome version mappings are here: https://omahaproxy.appspot.com/
19
An easy choice is to grab Chrome's Beta's ANGLE branch.
20
21
## Usage
22
23
Prepare your env:
24
25
~~~
26
export PATH="$PATH:/path/to/depot_tools"
27
~~~
28
29
If this is a new repo, don't forget:
30
31
~~~
32
# In the angle repo:
33
./scripts/bootstrap.py
34
gclient sync
35
~~~
36
37
Update: (in the angle repo)
38
39
~~~
40
# In the angle repo:
41
/path/to/gecko/gfx/angle/update-angle.py origin/chromium/XXXX
42
git push moz # Push the firefox-XX branch to github.com/mozilla/angle
43
~~~~
44
45
'''
46
47
import json
48
import os
49
import pathlib
50
import re
51
import shutil
52
import subprocess
53
import sys
54
from typing import * # mypy annotations
55
56
REPO_DIR = pathlib.Path.cwd()
57
58
GN_ENV = dict(os.environ)
59
# We need to set DEPOT_TOOLS_WIN_TOOLCHAIN to 0 for non-Googlers, but otherwise
60
# leave it unset since vs_toolchain.py assumes that the user is a Googler with
61
# the Visual Studio files in depot_tools if DEPOT_TOOLS_WIN_TOOLCHAIN is not
62
# explicitly set to 0.
63
vs_found = False
64
for directory in os.environ['PATH'].split(os.pathsep):
65
vs_dir = os.path.join(directory, 'win_toolchain', 'vs_files')
66
if os.path.exists(vs_dir):
67
vs_found = True
68
break
69
if not vs_found:
70
GN_ENV['DEPOT_TOOLS_WIN_TOOLCHAIN'] = '0'
71
72
if len(sys.argv) < 3:
73
sys.exit('Usage: export_targets.py OUT_DIR ROOTS...')
74
75
(OUT_DIR, *ROOTS) = sys.argv[1:]
76
for x in ROOTS:
77
assert x.startswith('//:')
78
79
# ------------------------------------------------------------------------------
80
81
def run_checked(*args, **kwargs):
82
print(' ', args, file=sys.stderr)
83
sys.stderr.flush()
84
return subprocess.run(args, check=True, **kwargs)
85
86
87
def sortedi(x):
88
return sorted(x, key=str.lower)
89
90
91
def dag_traverse(root_keys: Sequence[str], pre_recurse_func: Callable[[str], list]):
92
visited_keys: Set[str] = set()
93
94
def recurse(key):
95
if key in visited_keys:
96
return
97
visited_keys.add(key)
98
99
t = pre_recurse_func(key)
100
try:
101
(next_keys, post_recurse_func) = t
102
except ValueError:
103
(next_keys,) = t
104
post_recurse_func = None
105
106
for x in next_keys:
107
recurse(x)
108
109
if post_recurse_func:
110
post_recurse_func(key)
111
return
112
113
for x in root_keys:
114
recurse(x)
115
return
116
117
# ------------------------------------------------------------------------------
118
119
print('Importing graph', file=sys.stderr)
120
121
try:
122
p = run_checked('gn', 'desc', '--format=json', str(OUT_DIR), '*', stdout=subprocess.PIPE,
123
env=GN_ENV, shell=(True if sys.platform == 'win32' else False))
124
except subprocess.CalledProcessError:
125
sys.stderr.buffer.write(b'"gn desc" failed. Is depot_tools in your PATH?\n')
126
exit(1)
127
128
# -
129
130
print('\nProcessing graph', file=sys.stderr)
131
descs = json.loads(p.stdout.decode())
132
133
# Ready to traverse
134
# ------------------------------------------------------------------------------
135
136
LIBRARY_TYPES = ('shared_library', 'static_library')
137
138
def flattened_target(target_name: str, descs: dict, stop_at_lib: bool =True) -> dict:
139
flattened = dict(descs[target_name])
140
141
EXPECTED_TYPES = LIBRARY_TYPES + ('source_set', 'group', 'action')
142
143
def pre(k):
144
dep = descs[k]
145
146
dep_type = dep['type']
147
deps = dep['deps']
148
if stop_at_lib and dep_type in LIBRARY_TYPES:
149
return ((),)
150
151
if dep_type == 'copy':
152
assert not deps, (target_name, dep['deps'])
153
else:
154
assert dep_type in EXPECTED_TYPES, (k, dep_type)
155
for (k,v) in dep.items():
156
if type(v) in (list, tuple, set):
157
# This is a workaround for
158
# https://bugs.chromium.org/p/gn/issues/detail?id=196, where
159
# the value of "public" can be a string instead of a list.
160
existing = flattened.get(k, [])
161
if isinstance(existing, str):
162
existing = [existing]
163
flattened[k] = sortedi(set(existing + v))
164
else:
165
#flattened.setdefault(k, v)
166
pass
167
return (deps,)
168
169
dag_traverse(descs[target_name]['deps'], pre)
170
return flattened
171
172
# ------------------------------------------------------------------------------
173
# Check that includes are valid. (gn's version of this check doesn't seem to work!)
174
175
INCLUDE_REGEX = re.compile(b'(?:^|\\n) *# *include +([<"])([^>"]+)[>"]')
176
assert INCLUDE_REGEX.match(b'#include "foo"')
177
assert INCLUDE_REGEX.match(b'\n#include "foo"')
178
179
# Most of these are ignored because this script does not currently handle
180
# #includes in #ifdefs properly, so they will erroneously be marked as being
181
# included, but not part of the source list.
182
IGNORED_INCLUDES = {
183
b'absl/container/flat_hash_map.h',
184
b'absl/container/flat_hash_set.h',
185
b'compiler/translator/TranslatorESSL.h',
186
b'compiler/translator/TranslatorGLSL.h',
187
b'compiler/translator/TranslatorHLSL.h',
188
b'compiler/translator/TranslatorMetal.h',
189
b'compiler/translator/TranslatorMetalDirect.h',
190
b'compiler/translator/TranslatorVulkan.h',
191
b'contrib/optimizations/slide_hash_neon.h',
192
b'dirent_on_windows.h',
193
b'dlopen_fuchsia.h',
194
b'kernel/image.h',
195
b'libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h',
196
b'libANGLE/renderer/d3d/DeviceD3D.h',
197
b'libANGLE/renderer/d3d/DisplayD3D.h',
198
b'libANGLE/renderer/d3d/RenderTargetD3D.h',
199
b'libANGLE/renderer/gl/apple/DisplayApple_api.h',
200
b'libANGLE/renderer/gl/cgl/DisplayCGL.h',
201
b'libANGLE/renderer/gl/eagl/DisplayEAGL.h',
202
b'libANGLE/renderer/gl/egl/android/DisplayAndroid.h',
203
b'libANGLE/renderer/gl/egl/DisplayEGL.h',
204
b'libANGLE/renderer/gl/egl/gbm/DisplayGbm.h',
205
b'libANGLE/renderer/gl/glx/DisplayGLX.h',
206
b'libANGLE/renderer/gl/wgl/DisplayWGL.h',
207
b'libANGLE/renderer/metal/DisplayMtl_api.h',
208
b'libANGLE/renderer/null/DisplayNULL.h',
209
b'libANGLE/renderer/vulkan/android/AHBFunctions.h',
210
b'libANGLE/renderer/vulkan/android/DisplayVkAndroid.h',
211
b'libANGLE/renderer/vulkan/DisplayVk_api.h',
212
b'libANGLE/renderer/vulkan/fuchsia/DisplayVkFuchsia.h',
213
b'libANGLE/renderer/vulkan/ggp/DisplayVkGGP.h',
214
b'libANGLE/renderer/vulkan/mac/DisplayVkMac.h',
215
b'libANGLE/renderer/vulkan/win32/DisplayVkWin32.h',
216
b'libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h',
217
b'loader_cmake_config.h',
218
b'optick.h',
219
b'spirv-tools/libspirv.h',
220
b'third_party/volk/volk.h',
221
b'vk_loader_extensions.c',
222
b'vk_snippets.h',
223
b'vulkan_android.h',
224
b'vulkan_beta.h',
225
b'vulkan_directfb.h',
226
b'vulkan_fuchsia.h',
227
b'vulkan_ggp.h',
228
b'vulkan_ios.h',
229
b'vulkan_macos.h',
230
b'vulkan_metal.h',
231
b'vulkan_vi.h',
232
b'vulkan_wayland.h',
233
b'vulkan_win32.h',
234
b'vulkan_xcb.h',
235
b'vulkan_xlib.h',
236
b'vulkan_xlib_xrandr.h',
237
# rapidjson adds these include stubs into their documentation
238
# comments. Since the script doesn't skip comments they are
239
# erroneously marked as valid includes
240
b'rapidjson/...',
241
# Validation layers support building with robin hood hashing, but we are not enabling that
242
# See http://anglebug.com/5791
243
b'robin_hood.h',
244
}
245
246
IGNORED_INCLUDE_PREFIXES = {
247
b'android',
248
b'Carbon',
249
b'CoreFoundation',
250
b'CoreServices',
251
b'IOSurface',
252
b'mach',
253
b'mach-o',
254
b'OpenGL',
255
b'pci',
256
b'sys',
257
b'wrl',
258
b'X11',
259
}
260
261
IGNORED_DIRECTORIES = {
262
'//buildtools/third_party/libc++',
263
'//third_party/abseil-cpp',
264
'//third_party/SwiftShader',
265
}
266
267
def has_all_includes(target_name: str, descs: dict) -> bool:
268
for ignored_directory in IGNORED_DIRECTORIES:
269
if target_name.startswith(ignored_directory):
270
return True
271
272
flat = flattened_target(target_name, descs, stop_at_lib=False)
273
acceptable_sources = flat.get('sources', []) + flat.get('outputs', [])
274
acceptable_sources = {x.rsplit('/', 1)[-1].encode() for x in acceptable_sources}
275
276
ret = True
277
desc = descs[target_name]
278
for cur_file in desc.get('sources', []):
279
assert cur_file.startswith('/'), cur_file
280
if not cur_file.startswith('//'):
281
continue
282
cur_file = pathlib.Path(cur_file[2:])
283
text = cur_file.read_bytes()
284
for m in INCLUDE_REGEX.finditer(text):
285
if m.group(1) == b'<':
286
continue
287
include = m.group(2)
288
if include in IGNORED_INCLUDES:
289
continue
290
try:
291
(prefix, _) = include.split(b'/', 1)
292
if prefix in IGNORED_INCLUDE_PREFIXES:
293
continue
294
except ValueError:
295
pass
296
297
include_file = include.rsplit(b'/', 1)[-1]
298
if include_file not in acceptable_sources:
299
#print(' acceptable_sources:')
300
#for x in sorted(acceptable_sources):
301
# print(' ', x)
302
print('Warning in {}: {}: Invalid include: {}'.format(target_name, cur_file, include), file=sys.stderr)
303
ret = False
304
#print('Looks valid:', m.group())
305
continue
306
307
return ret
308
309
# -
310
# Gather real targets:
311
312
def gather_libraries(roots: Sequence[str], descs: dict) -> Set[str]:
313
libraries = set()
314
def fn(target_name):
315
cur = descs[target_name]
316
print(' ' + cur['type'], target_name, file=sys.stderr)
317
assert has_all_includes(target_name, descs), target_name
318
319
if cur['type'] in ('shared_library', 'static_library'):
320
libraries.add(target_name)
321
return (cur['deps'], )
322
323
dag_traverse(roots, fn)
324
return libraries
325
326
# -
327
328
libraries = gather_libraries(ROOTS, descs)
329
print(f'\n{len(libraries)} libraries:', file=sys.stderr)
330
for k in libraries:
331
print(f' {k}', file=sys.stderr)
332
print('\nstdout begins:', file=sys.stderr)
333
sys.stderr.flush()
334
335
# ------------------------------------------------------------------------------
336
# Output
337
338
out = {k: flattened_target(k, descs) for k in libraries}
339
340
for (k,desc) in out.items():
341
dep_libs: Set[str] = set()
342
for dep_name in set(desc['deps']):
343
dep = descs[dep_name]
344
if dep['type'] in LIBRARY_TYPES:
345
dep_libs.add(dep_name)
346
desc['dep_libs'] = sortedi(dep_libs)
347
348
json.dump(out, sys.stdout, indent=' ')
349
exit(0)
350
351