Bug 1698238 add a GetUserMediaRequest variant for selectAudioOutput() r=jib,emilio
[gecko.git] / gfx / angle / update-angle.py
blobdc66bfc7f9ab515becea6fe3d4bedd003464b6f5
1 #! /usr/bin/env python3
2 # This Source Code Form is subject to the terms of the Mozilla Public
3 # License, v. 2.0. If a copy of the MPL was not distributed with this
4 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 assert __name__ == "__main__"
8 """
9 To update ANGLE in Gecko, use Windows with git-bash, and setup depot_tools, python2, and
10 python3. Because depot_tools expects `python` to be `python2` (shame!), python2 must come
11 before python3 in your path.
13 Upstream: https://chromium.googlesource.com/angle/angle
15 Our repo: https://github.com/mozilla/angle
16 It has branches like 'firefox-60' which is the branch we use for pulling into
17 Gecko with this script.
19 This script leaves a record of the merge-base and cherry-picks that we pull into
20 Gecko. (gfx/angle/cherries.log)
22 ANGLE<->Chrome version mappings are here: https://omahaproxy.appspot.com/
23 An easy choice is to grab Chrome's Beta's ANGLE branch.
25 ## Usage
27 Prepare your env:
29 ~~~
30 export PATH="$PATH:/path/to/depot_tools"
31 ~~~
33 If this is a new repo, don't forget:
35 ~~~
36 # In the angle repo:
37 ./scripts/bootstrap.py
38 gclient sync
39 ~~~
41 Update: (in the angle repo)
43 ~~~
44 # In the angle repo:
45 /path/to/gecko/gfx/angle/update-angle.py origin/chromium/XXXX
46 git push moz # Push the firefox-XX branch to github.com/mozilla/angle
47 ~~~~
49 """
51 import json
52 import os
53 import pathlib
54 import re
55 import shutil
56 import subprocess
57 import sys
58 from typing import * # mypy annotations
60 REPO_DIR = pathlib.Path.cwd()
61 GECKO_ANGLE_DIR = pathlib.Path(__file__).parent
63 OUT_DIR = pathlib.Path("out")
65 COMMON_HEADER = [
66 "# Generated by update-angle.py",
67 "",
68 'include("../../moz.build.common")',
71 ROOTS = ["//:translator", "//:libEGL", "//:libGLESv2"]
73 CHECK_ONLY = False
74 args = sys.argv[1:]
75 while True:
76 arg = args.pop(0)
77 if arg == "--check":
78 CHECK_ONLY = True
79 continue
80 args.insert(0, arg)
81 break
83 GN_ENV = dict(os.environ)
84 GN_ENV["DEPOT_TOOLS_WIN_TOOLCHAIN"] = "0"
86 (GIT_REMOTE,) = args # Not always 'origin'!
88 # ------------------------------------------------------------------------------
91 def run_checked(*args, **kwargs):
92 print(" ", args)
93 sys.stdout.flush()
94 return subprocess.run(args, check=True, **kwargs)
97 def sorted_items(x):
98 for k in sorted(x.keys()):
99 yield (k, x[k])
102 def collapse_dotdots(path):
103 split = path.split("/")
105 ret = []
106 for x in split:
107 if x == ".." and ret:
108 ret.pop()
109 continue
110 ret.append(x)
111 continue
113 return "/".join(ret)
116 def dag_traverse(root_keys: Sequence[str], pre_recurse_func: Callable[[str], list]):
117 visited_keys: Set[str] = set()
119 def recurse(key):
120 if key in visited_keys:
121 return
122 visited_keys.add(key)
124 t = pre_recurse_func(key)
125 try:
126 (next_keys, post_recurse_func) = t
127 except ValueError:
128 (next_keys,) = t
129 post_recurse_func = None
131 for x in next_keys:
132 recurse(x)
134 if post_recurse_func:
135 post_recurse_func(key)
136 return
138 for x in root_keys:
139 recurse(x)
140 return
143 # ------------------------------------------------------------------------------
145 print("Importing graph")
147 # shutil.rmtree(str(OUT_DIR), True)
148 OUT_DIR.mkdir(exist_ok=True)
150 GN_ARGS = b"""
151 # Build arguments go here.
152 # See "gn args <out_dir> --list" for available build arguments.
153 is_clang = true
154 is_debug = false
155 angle_build_all = false
156 angle_enable_abseil = false
157 angle_enable_gl = false
158 angle_enable_null = false
159 angle_enable_vulkan = false
160 use_custom_libcxx = false
161 """[
164 args_gn_path = OUT_DIR / "args.gn"
165 args_gn_path.write_bytes(GN_ARGS)
167 try:
168 run_checked("gn", "gen", str(OUT_DIR), shell=True, env=GN_ENV)
169 except subprocess.CalledProcessError:
170 sys.stderr.buffer.write(b"`gn` failed. Is depot_tools in your PATH?\n")
171 exit(1)
173 p = run_checked(
174 "py",
175 "scripts/export_targets.py",
176 str(OUT_DIR),
177 *ROOTS,
178 stdout=subprocess.PIPE,
179 shell=True,
180 env=GN_ENV,
185 print("\nProcessing graph")
186 libraries = json.loads(p.stdout.decode())
189 # HACKHACKHACK: Inject linux/mac sources instead of trying to merge graphs of different
190 # platforms.
191 # descs["//:angle_common"]["sources"] +=
192 EXTRA_ANGLE_COMMON_SOURCES = [
193 "//src/common/system_utils_linux.cpp",
194 "//src/common/system_utils_mac.cpp",
195 "//src/common/system_utils_posix.cpp",
198 angle_common = libraries["//:angle_common"]
199 angle_common["sources"] += EXTRA_ANGLE_COMMON_SOURCES
200 angle_common["sources"] = sorted(angle_common["sources"])
203 # Reuse our own zlib
205 del libraries["//third_party/zlib:zlib"]
209 if CHECK_ONLY:
210 print("\n--check complete.")
211 exit(0)
213 # ------------------------------------------------------------------------------
214 # Output to moz.builds
216 import vendor_from_git
218 print("")
219 vendor_from_git.record_cherry_picks(GECKO_ANGLE_DIR, GIT_REMOTE)
221 # --
224 def sortedi(x):
225 return sorted(x, key=str.lower)
228 def append_arr(dest, name, vals, indent=0):
229 if not vals:
230 return
232 dest.append("{}{} += [".format(" " * 4 * indent, name))
233 for x in sortedi(vals):
234 dest.append('{}"{}",'.format(" " * 4 * (indent + 1), x))
235 dest.append("{}]".format(" " * 4 * indent))
236 dest.append("")
237 return
240 REGISTERED_DEFINES = {
241 "ADLER32_SIMD_SSSE3": False,
242 "ANGLE_CAPTURE_ENABLED": True,
243 "ANGLE_EGL_LIBRARY_NAME": False,
244 "ANGLE_ENABLE_D3D11": True,
245 "ANGLE_ENABLE_D3D9": True,
246 "ANGLE_ENABLE_DEBUG_ANNOTATIONS": True,
247 "ANGLE_ENABLE_NULL": False,
248 "ANGLE_ENABLE_OPENGL": False,
249 "ANGLE_ENABLE_OPENGL_NULL": False,
250 "ANGLE_ENABLE_ESSL": True,
251 "ANGLE_ENABLE_GLSL": True,
252 "ANGLE_ENABLE_HLSL": True,
253 "ANGLE_GENERATE_SHADER_DEBUG_INFO": True,
254 "ANGLE_GLESV2_LIBRARY_NAME": True,
255 "ANGLE_IS_64_BIT_CPU": False,
256 "ANGLE_IS_WIN": False,
257 "ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES": False,
258 "ANGLE_USE_EGL_LOADER": True,
259 "CERT_CHAIN_PARA_HAS_EXTRA_FIELDS": False,
260 "CHROMIUM_BUILD": False,
261 "COMPONENT_BUILD": False,
262 "CRC32_SIMD_SSE42_PCLMUL": False,
263 "DEFLATE_FILL_WINDOW_SSE2": False,
264 "DYNAMIC_ANNOTATIONS_ENABLED": True,
265 "EGL_EGL_PROTOTYPES": True,
266 "EGL_EGLEXT_PROTOTYPES": True,
267 "EGLAPI": True,
268 "FIELDTRIAL_TESTING_ENABLED": False,
269 "FULL_SAFE_BROWSING": False,
270 "GL_API": True,
271 "GL_APICALL": True,
272 "GL_GLES_PROTOTYPES": True,
273 "GL_GLEXT_PROTOTYPES": True,
274 "GPU_INFO_USE_SETUPAPI": True,
275 "INFLATE_CHUNK_READ_64LE": False,
276 "INFLATE_CHUNK_SIMD_SSE2": False,
277 "LIBANGLE_IMPLEMENTATION": True,
278 "LIBEGL_IMPLEMENTATION": True,
279 "LIBGLESV2_IMPLEMENTATION": True,
280 "NOMINMAX": True,
281 "NO_TCMALLOC": False,
282 # Else: gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.cpp(89): error C2787: 'IDCompositionDevice': no GUID has been associated with this object
283 "NTDDI_VERSION": False,
284 "PSAPI_VERSION": False,
285 "SAFE_BROWSING_CSD": False,
286 "SAFE_BROWSING_DB_LOCAL": False,
287 "UNICODE": True,
288 "USE_AURA": False,
289 "V8_DEPRECATION_WARNINGS": False,
290 "VK_USE_PLATFORM_WIN32_KHR": False,
291 "WIN32": False,
292 "WIN32_LEAN_AND_MEAN": False,
293 "WINAPI_FAMILY": False,
294 "WINVER": True,
295 # Otherwise:
296 # gfx/angle/targets/libANGLE
297 # In file included from c:/dev/mozilla/gecko4/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/converged/CompositorNativeWindow11.cpp:10:
298 # In file included from c:/dev/mozilla/gecko4/gfx/angle/checkout/src\libANGLE/renderer/d3d/d3d11/converged/CompositorNativeWindow11.h:17:
299 # C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\winrt\Windows.ui.composition.interop.h(103,20): error: unknown type name 'POINTER_INFO'
300 # _In_ const POINTER_INFO& pointerInfo
302 "WTF_USE_DYNAMIC_ANNOTATIONS": False,
303 "X86_WINDOWS": False,
304 "ZLIB_IMPLEMENTATION": True,
305 "_ATL_NO_OPENGL": True,
306 "_CRT_NONSTDC_NO_DEPRECATE": True,
307 "_CRT_NONSTDC_NO_WARNINGS": True,
308 "_CRT_RAND_S": True,
309 "_CRT_SECURE_NO_DEPRECATE": True,
310 "_DEBUG": False,
311 "_HAS_EXCEPTIONS": True,
312 "_HAS_ITERATOR_DEBUGGING": False,
313 "_SCL_SECURE_NO_DEPRECATE": True,
314 "_SECURE_ATL": True,
315 "_UNICODE": True,
316 "_USING_V110_SDK71_": False,
317 "_WIN32_WINNT": False,
318 "_WINDOWS": False,
319 "__STD_C": False,
320 # clang specific
321 "CR_CLANG_REVISION": True,
322 "NDEBUG": False,
323 "NVALGRIND": False,
324 "_HAS_NODISCARD": False,
329 print("\nRun actions")
330 required_files: Set[str] = set()
332 run_checked("ninja", "-C", str(OUT_DIR), ":angle_commit_id")
333 required_files.add("//out/gen/angle/angle_commit.h")
337 # Export our targets
338 print("\nExport targets")
340 # Clear our dest directories
341 targets_dir = pathlib.Path(GECKO_ANGLE_DIR, "targets")
342 checkout_dir = pathlib.Path(GECKO_ANGLE_DIR, "checkout")
344 shutil.rmtree(targets_dir, True)
345 shutil.rmtree(checkout_dir, True)
346 targets_dir.mkdir(exist_ok=True)
347 checkout_dir.mkdir(exist_ok=True)
351 RE_TARGET_NAME = re.compile("//(.*):(.+)")
354 def export_target(target_full_name) -> Set[str]:
355 # print(' ', target_full_name)
356 descs = libraries
357 desc = descs[target_name]
358 flat = desc
360 m = RE_TARGET_NAME.match(target_name)
361 assert m, target_name
362 name = m.group(2)
364 required_files: Set[str] = set(flat["sources"])
366 # Create our manifest lines
367 target_dir = targets_dir / name
368 target_dir.mkdir(exist_ok=True)
370 lines = list(COMMON_HEADER)
371 lines.append("")
373 for x in sorted(set(desc["defines"])):
374 try:
375 (k, v) = x.split("=", 1)
376 if v.startswith('"'):
377 v = f"'{v}'"
378 else:
379 v = f'"{v}"'
380 except ValueError:
381 (k, v) = (x, "True")
383 line = f'DEFINES["{k}"] = {v}'
384 try:
385 if REGISTERED_DEFINES[k] == False:
386 line = "# " + line
387 except KeyError:
388 print(f"[{name}] Unrecognized define: {k}")
389 line = "# Unrecognized: " + line
390 lines.append(line)
391 lines.append("")
393 cxxflags = set(desc["cflags"] + desc["cflags_cc"])
395 def fixup_paths(listt):
396 for x in set(listt):
397 assert x.startswith("//"), x
398 yield "../../checkout/" + x[2:]
400 sources_by_config: Dict[str, List[str]] = {}
401 extras: Dict[str, str] = dict()
402 for x in fixup_paths(flat["sources"]):
403 # print(' '*5, x)
404 (b, e) = x.rsplit(".", 1)
405 if e in ["h", "hpp", "y", "l", "inc", "inl"]:
406 continue
407 elif e in ["cpp", "cc", "c"]:
408 if b.endswith("_win") or b.endswith("_win32"):
409 config = 'CONFIG["OS_ARCH"] == "WINNT"'
410 elif b.endswith("_linux"):
411 # Include these on BSDs too.
412 config = 'CONFIG["OS_ARCH"] not in ("Darwin", "WINNT")'
413 elif b.endswith("_mac"):
414 config = 'CONFIG["OS_ARCH"] == "Darwin"'
415 elif b.endswith("_posix"):
416 config = 'CONFIG["OS_ARCH"] != "WINNT"'
417 else:
418 config = "" # None can't compare against str.
420 sources_by_config.setdefault(config, []).append(x)
421 continue
422 elif e == "rc":
423 assert "RCFILE" not in extras, (target_name, extras["RCFILE"], x)
424 extras["RCFILE"] = f'"{x}"'
425 continue
426 elif e == "def":
427 assert "DEFFILE" not in extras, (target_name, extras["DEFFILE"], x)
428 extras["DEFFILE"] = f'"{x}"'
429 continue
430 else:
431 assert False, ("Unhandled ext:", x)
433 ldflags = set(desc["ldflags"])
434 DEF_PREFIX = "/DEF:"
435 for x in set(ldflags):
436 if x.startswith(DEF_PREFIX):
437 def_path = x[len(DEF_PREFIX) :]
438 required_files.add(def_path)
439 assert "DEFFILE" not in extras
440 ldflags.remove(x)
442 def_path = str(OUT_DIR) + "/" + def_path
443 def_path = "//" + collapse_dotdots(def_path)
445 def_rel_path = list(fixup_paths([def_path]))[0]
446 extras["DEFFILE"] = '"{}"'.format(def_rel_path)
448 os_libs = list(map(lambda x: x[: -len(".lib")], set(desc.get("libs", []))))
450 def append_arr_commented(dest, name, src):
451 lines = []
452 append_arr(lines, name, src)
454 def comment(x):
455 if x:
456 x = "# " + x
457 return x
459 lines = map(comment, lines)
460 dest += lines
462 append_arr(lines, "LOCAL_INCLUDES", fixup_paths(desc["include_dirs"]))
463 append_arr_commented(lines, "CXXFLAGS", cxxflags)
465 for (config, v) in sorted_items(sources_by_config):
466 indent = 0
467 if config:
468 lines.append("if {}:".format(config))
469 indent = 1
470 append_arr(lines, "SOURCES", v, indent=indent)
472 dep_libs: Set[str] = set()
473 for dep_full_name in set(flat["dep_libs"]):
474 assert dep_full_name.startswith("//"), dep_name
475 (_, dep_name) = dep_full_name.split(":")
476 dep_libs.add(dep_name)
478 dep_dirs = set(dep_libs)
479 dep_dirs.discard("zlib")
481 append_arr(lines, "USE_LIBS", dep_libs)
482 append_arr(lines, "DIRS", ["../" + x for x in dep_dirs])
483 append_arr(lines, "OS_LIBS", os_libs)
484 append_arr_commented(lines, "LDFLAGS", ldflags)
486 for (k, v) in sorted(extras.items()):
487 lines.append("{} = {}".format(k, v))
489 lib_type = desc["type"]
490 if lib_type == "shared_library":
491 lines.append(f'GeckoSharedLibrary("{name}", linkage=None)')
492 elif lib_type == "static_library":
493 lines.append(f'Library("{name}")')
494 else:
495 assert False, lib_type
497 lines.append("")
498 # EOF newline
500 # Write it out
502 mozbuild = target_dir / "moz.build"
503 print(" ", " ", f"Writing {mozbuild}")
504 data = b"\n".join((x.encode() for x in lines))
505 mozbuild.write_bytes(data)
507 return required_files
512 for target_name in libraries:
513 reqs = export_target(target_name)
514 required_files |= reqs
516 # Copy all the files
518 print("\nMigrate required files")
520 i = 0
521 for x in required_files:
522 i += 1
523 sys.stdout.write(f"\r Copying {i}/{len(required_files)}")
524 sys.stdout.flush()
525 assert x.startswith("//"), x
526 x = x[2:]
528 src = REPO_DIR / x
529 dest = checkout_dir / x
531 dest.parent.mkdir(parents=True, exist_ok=True)
532 data = src.read_bytes()
533 data = data.replace(b"\r\n", b"\n")
534 dest.write_bytes(data)
536 print("\n\nDone")