Bug 1440849 - Add update-angle.py to facilitate updating Angle. - r=jrmuizel
authorJeff Gilbert <jgilbert@mozilla.com>
Thu, 22 Feb 2018 13:59:06 -0800
changeset 461429 f63d5bd89d787424c3eee518af5b65f580a8561b
parent 461428 d9f8ec82354d03faa5e0475004ffb8cc31bad8d6
child 461430 2479e330c5ea627e18cd520863dab04fff7b04c0
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1440849
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1440849 - Add update-angle.py to facilitate updating Angle. - r=jrmuizel MozReview-Commit-ID: 4aWcnb2UCmB
gfx/angle/moz.build
gfx/angle/moz.build.common
gfx/angle/update-angle.py
--- a/gfx/angle/moz.build
+++ b/gfx/angle/moz.build
@@ -1,206 +1,5 @@
-
-#
-# WARNING WARNING WARNING
-#
-# This file is generated by generate_mozbuild.py (from
-# https://github.com/mozilla/angle). Do not modify it without also modifying
-# generate_mozbuild.py.
-#
-# WARNING WARNING WARNING
-#
-UNIFIED_SOURCES += [
-    'src/common/angleutils.cpp',
-    'src/common/debug.cpp',
-    'src/common/Float16ToFloat32.cpp',
-    'src/common/mathutil.cpp',
-    'src/common/MemoryBuffer.cpp',
-    'src/common/string_utils.cpp',
-    'src/common/third_party/base/anglebase/sha1.cc',
-    'src/common/tls.cpp',
-    'src/common/uniform_type_info_autogen.cpp',
-    'src/common/utilities.cpp',
-    'src/compiler/preprocessor/DiagnosticsBase.cpp',
-    'src/compiler/preprocessor/DirectiveHandlerBase.cpp',
-    'src/compiler/preprocessor/DirectiveParser.cpp',
-    'src/compiler/preprocessor/ExpressionParser.cpp',
-    'src/compiler/preprocessor/Input.cpp',
-    'src/compiler/preprocessor/Lexer.cpp',
-    'src/compiler/preprocessor/Macro.cpp',
-    'src/compiler/preprocessor/MacroExpander.cpp',
-    'src/compiler/preprocessor/Preprocessor.cpp',
-    'src/compiler/preprocessor/Token.cpp',
-    'src/compiler/translator/AddAndTrueToLoopCondition.cpp',
-    'src/compiler/translator/AddDefaultReturnStatements.cpp',
-    'src/compiler/translator/ArrayReturnValueToOutParameter.cpp',
-    'src/compiler/translator/ASTMetadataHLSL.cpp',
-    'src/compiler/translator/blocklayout.cpp',
-    'src/compiler/translator/blocklayoutHLSL.cpp',
-    'src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp',
-    'src/compiler/translator/BuiltInFunctionEmulator.cpp',
-    'src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp',
-    'src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp',
-    'src/compiler/translator/Cache.cpp',
-    'src/compiler/translator/CallDAG.cpp',
-    'src/compiler/translator/ClampPointSize.cpp',
-    'src/compiler/translator/CodeGen.cpp',
-    'src/compiler/translator/CollectVariables.cpp',
-    'src/compiler/translator/Compiler.cpp',
-    'src/compiler/translator/ConstantUnion.cpp',
-    'src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp',
-    'src/compiler/translator/DeferGlobalInitializers.cpp',
-    'src/compiler/translator/Diagnostics.cpp',
-    'src/compiler/translator/DirectiveHandler.cpp',
-    'src/compiler/translator/emulated_builtin_functions_hlsl_autogen.cpp',
-    'src/compiler/translator/EmulatePrecision.cpp',
-    'src/compiler/translator/ExpandIntegerPowExpressions.cpp',
-    'src/compiler/translator/ExtensionBehavior.cpp',
-    'src/compiler/translator/ExtensionGLSL.cpp',
-    'src/compiler/translator/FindMain.cpp',
-    'src/compiler/translator/FindSymbolNode.cpp',
-    'src/compiler/translator/FlagStd140Structs.cpp',
-    'src/compiler/translator/HashNames.cpp',
-    'src/compiler/translator/InfoSink.cpp',
-    'src/compiler/translator/Initialize.cpp',
-    'src/compiler/translator/InitializeDll.cpp',
-    'src/compiler/translator/InitializeVariables.cpp',
-    'src/compiler/translator/IntermNode.cpp',
-    'src/compiler/translator/IntermNode_util.cpp',
-    'src/compiler/translator/IntermNodePatternMatcher.cpp',
-    'src/compiler/translator/IntermTraverse.cpp',
-    'src/compiler/translator/IsASTDepthBelowLimit.cpp',
-    'src/compiler/translator/Operator.cpp',
-    'src/compiler/translator/OutputESSL.cpp',
-    'src/compiler/translator/OutputGLSL.cpp',
-    'src/compiler/translator/OutputGLSLBase.cpp',
-    'src/compiler/translator/OutputHLSL.cpp',
-    'src/compiler/translator/OutputTree.cpp',
-    'src/compiler/translator/ParseContext.cpp',
-    'src/compiler/translator/PoolAlloc.cpp',
-    'src/compiler/translator/PruneEmptyDeclarations.cpp',
-    'src/compiler/translator/PrunePureLiteralStatements.cpp',
-    'src/compiler/translator/QualifierTypes.cpp',
-    'src/compiler/translator/RecordConstantPrecision.cpp',
-    'src/compiler/translator/RegenerateStructNames.cpp',
-    'src/compiler/translator/RemoveArrayLengthMethod.cpp',
-    'src/compiler/translator/RemoveDynamicIndexing.cpp',
-    'src/compiler/translator/RemoveInvariantDeclaration.cpp',
-    'src/compiler/translator/RemovePow.cpp',
-    'src/compiler/translator/RemoveSwitchFallThrough.cpp',
-    'src/compiler/translator/RewriteDoWhile.cpp',
-    'src/compiler/translator/RewriteElseBlocks.cpp',
-    'src/compiler/translator/RewriteUnaryMinusOperatorFloat.cpp',
-    'src/compiler/translator/RunAtTheEndOfShader.cpp',
-    'src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp',
-    'src/compiler/translator/SearchSymbol.cpp',
-    'src/compiler/translator/SeparateArrayInitialization.cpp',
-    'src/compiler/translator/SeparateDeclarations.cpp',
-    'src/compiler/translator/SeparateExpressionsReturningArrays.cpp',
-    'src/compiler/translator/ShaderVars.cpp',
-    'src/compiler/translator/SimplifyLoopConditions.cpp',
-    'src/compiler/translator/SplitSequenceOperator.cpp',
-    'src/compiler/translator/StructureHLSL.cpp',
-    'src/compiler/translator/SymbolTable.cpp',
-    'src/compiler/translator/TextureFunctionHLSL.cpp',
-    'src/compiler/translator/TranslatorESSL.cpp',
-    'src/compiler/translator/TranslatorGLSL.cpp',
-    'src/compiler/translator/TranslatorHLSL.cpp',
-    'src/compiler/translator/Types.cpp',
-    'src/compiler/translator/UnfoldShortCircuitAST.cpp',
-    'src/compiler/translator/UnfoldShortCircuitToIf.cpp',
-    'src/compiler/translator/UniformHLSL.cpp',
-    'src/compiler/translator/UseInterfaceBlockFields.cpp',
-    'src/compiler/translator/util.cpp',
-    'src/compiler/translator/UtilsHLSL.cpp',
-    'src/compiler/translator/ValidateGlobalInitializer.cpp',
-    'src/compiler/translator/ValidateLimitations.cpp',
-    'src/compiler/translator/ValidateMaxParameters.cpp',
-    'src/compiler/translator/ValidateSwitch.cpp',
-    'src/compiler/translator/ValidateVaryingLocations.cpp',
-    'src/compiler/translator/VariablePacker.cpp',
-    'src/compiler/translator/VersionGLSL.cpp',
-    'src/third_party/compiler/ArrayBoundsClamper.cpp',
-]
-SOURCES += [
-    'src/compiler/preprocessor/Tokenizer.cpp',
-    'src/compiler/translator/EmulateGLFragColorBroadcast.cpp',
-    'src/compiler/translator/glslang_lex.cpp',
-    'src/compiler/translator/glslang_tab.cpp',
-    'src/compiler/translator/RewriteTexelFetchOffset.cpp',
-    'src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp',
-    'src/compiler/translator/ShaderLang.cpp',
-    'src/compiler/translator/ValidateOutputs.cpp',
-]
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
-    UNIFIED_SOURCES += [
-        'src/common/system_utils_mac.cpp',
-    ]
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
-    UNIFIED_SOURCES += [
-        'src/common/system_utils_win.cpp',
-    ]
-
-
-if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
-    CXXFLAGS += [
-        '-Wno-attributes',
-        '-Wno-shadow',
-        '-Wno-sign-compare',
-        '-Wno-unknown-pragmas',
-        '-Wno-unreachable-code',
-    ]
-    if CONFIG['CC_TYPE'] == 'clang':
-        CXXFLAGS += [
-            '-Wno-implicit-fallthrough',
-            '-Wno-inconsistent-missing-override',
-            '-Wno-unused-private-field',
-        ]
-    else:
-        CXXFLAGS += [
-            '-Wno-shadow-compatible-local',
-            '-Wno-shadow-local',
-        ]
-
-if CONFIG['CC_TYPE'] in ('msvc', 'clang-cl'):
-    CXXFLAGS += ['-wd5038'] # C5038: initializer list order warnings
-
-if CONFIG['MOZ_DIRECTX_SDK_PATH'] and not CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
-    LOCAL_INCLUDES += ['%' + '%s/include/' % CONFIG['MOZ_DIRECTX_SDK_PATH']]
-
-DEFINES['_CRT_SECURE_NO_DEPRECATE'] = True
-DEFINES['_HAS_EXCEPTIONS'] = 0
-
-if not CONFIG['MOZ_DEBUG']:
-    DEFINES['_SECURE_SCL'] = 0
-
-DEFINES['ANGLE_SKIP_DXGI_1_2_CHECK'] = True
-if CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
-    DEFINES['ANGLE_ENABLE_D3D9'] = True
-    DEFINES['ANGLE_ENABLE_D3D11'] = True
-
-DEFINES['ANGLE_COMPILE_OPTIMIZATION_LEVEL'] = 'D3DCOMPILE_OPTIMIZATION_LEVEL1'
-DEFINES['ANGLE_NO_EXCEPTIONS'] = True
-
-# We need these defined to nothing so that we don't get bogus dllimport declspecs
-DEFINES['GL_APICALL'] = ""
-DEFINES['GL_GLEXT_PROTOTYPES'] = ""
-DEFINES['EGLAPI'] = ""
-
+DIRS += [ 'targets/translator' ]
 
 # Only build libEGL/libGLESv2 on Windows
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
-    DIRS += [ 'src/libANGLE', 'src/libGLESv2', 'src/libEGL' ]
-
-DEFINES['ANGLE_ENABLE_HLSL'] = "1"
-DEFINES['ANGLE_ENABLE_GLSL'] = "1"
-DEFINES['ANGLE_ENABLE_ESSL'] = "1"
-DEFINES['ANGLE_ENABLE_KEYEDMUTEX'] = "1"
-
-EXPORTS.angle += [ 'include/GLSLANG/ShaderLang.h', 'include/GLSLANG/ShaderVars.h', 'include/platform/Platform.h' ]
-EXPORTS.angle.KHR += [ 'include/KHR/khrplatform.h' ]
-
-LOCAL_INCLUDES += [ 'include', 'src', 'src/common/third_party/base']
-
-# We allow warnings for third-party code that can be updated from upstream.
-AllowCompilerWarnings()
-
-FINAL_LIBRARY = 'gkmedias'
+    DIRS += [ 'targets/libEGL', 'targets/libGLESv2' ]
new file mode 100644
--- /dev/null
+++ b/gfx/angle/moz.build.common
@@ -0,0 +1,6 @@
+AllowCompilerWarnings()
+
+CXXFLAGS += CONFIG['SSE2_FLAGS']
+DEFINES['__NDK_FPABI__'] = ''
+DEFINES['constexpr14'] = ''
+DEFINES['ANGLE_SKIP_DXGI_1_2_CHECK'] = True
new file mode 100644
--- /dev/null
+++ b/gfx/angle/update-angle.py
@@ -0,0 +1,520 @@
+#!/bin/python3
+assert __name__ == '__main__'
+
+'''
+To update ANGLE in Gecko, use Windows with git-bash, and setup depot_tools and
+python3.
+
+Upstream: https://chromium.googlesource.com/angle/angle
+
+Our repo: https://github.com/mozilla/angle
+It has branches like 'firefox-60' which is the branch we use for pulling into
+Gecko with this script.
+
+This script leaves a record of the merge-base and cherry-picks that we pull into
+Gecko. (gfx/angle/cherries.log)
+'''
+
+import json
+import os
+from pathlib import *
+import re
+import shutil
+import subprocess
+import sys
+
+REPO_DIR = Path.cwd()
+GECKO_ANGLE_DIR = Path(__file__).parent
+GECKO_DIR = GECKO_ANGLE_DIR.parent.parent
+
+OUT_DIR = 'out'
+
+COMMON_HEADER = [
+    '# Generated by update-angle.py',
+    '',
+    "include('../../moz.build.common')",
+]
+
+# --
+
+def print_now(*args):
+    print(*args)
+    sys.stdout.flush()
+
+
+def run_checked(*args, **kwargs):
+    print_now(' ', args)
+    return subprocess.run(args, check=True, shell=True, **kwargs)
+
+
+def sorted_items(x):
+    for k in sorted(x.keys()):
+        yield (k, x[k])
+
+# --
+
+CHERRIES_PATH = Path(GECKO_ANGLE_DIR, 'cherries.log')
+print_now('Logging cherries ({})'.format(CHERRIES_PATH))
+
+MERGE_BASE = sys.argv[1]
+MERGE_BASE = run_checked('git', 'merge-base', 'HEAD', MERGE_BASE,
+                         stdout=subprocess.PIPE).stdout.decode().strip()
+
+mb_info = run_checked('git', 'log', '{}~1..{}'.format(MERGE_BASE, MERGE_BASE),
+                      stdout=subprocess.PIPE).stdout
+cherries = run_checked('git', 'log', MERGE_BASE + '..', stdout=subprocess.PIPE).stdout
+
+with open(CHERRIES_PATH, 'wb') as f:
+    f.write(cherries)
+    f.write(b'\nCherries picked')
+    f.write(b'\n' + (b'=' * 80))
+    f.write(b'\nMerge base')
+    f.write(b'\n\n')
+    f.write(mb_info)
+
+# --
+
+print_now('Importing graph')
+
+shutil.rmtree(OUT_DIR, True)
+
+run_checked('gn', 'gen', OUT_DIR)
+
+GN_ARGS = '''
+# Build arguments go here.
+# See "gn args <out_dir> --list" for available build arguments.
+is_clang = false
+angle_enable_gl = false
+angle_enable_gl_null = false
+angle_enable_null = false
+angle_enable_vulkan = false
+'''[1:]
+with open(OUT_DIR + '/args.gn', 'wb') as f:
+    f.write(GN_ARGS.encode())
+
+# --
+
+p = run_checked('gn', 'desc', '--format=json', OUT_DIR, '*', stdout=subprocess.PIPE)
+
+print_now('Processing graph')
+descs = json.loads(p.stdout.decode())
+
+# HACKHACKHACK
+common = descs['//:angle_common']
+common['sources'] += [
+    '//src/common/system_utils_linux.cpp',
+    '//src/common/system_utils_mac.cpp',
+]
+
+# --
+
+# Inject node key and child links into desc dicts
+for (k, v) in descs.items():
+    v['target_name'] = k
+    v['dep_children'] = [descs[x] for x in v['deps']]
+    assert v['public'] == '*', k
+
+    v['includes'] = []
+    v['just_sources'] = []
+
+    def fn(x):
+        (_, e) = x.rsplit('.', 1)
+        if e in ['h', 'inl']:
+            v['includes'].append(x)
+            return
+        elif e in ['cc', 'cpp']:
+            v['just_sources'].append(x)
+            return
+
+    list(map(fn, v.get('sources', [])))
+    if v['type'] == 'action':
+        list(map(fn, v['outputs']))
+
+# --
+# Ready to traverse
+
+def traverse(roots, pre_recurse_func, key_func=None):
+    visited = set()
+
+    def identity(x):
+        return x
+
+    if not key_func:
+        key_func = identity
+
+    def recurse(cur):
+        key = key_func(cur)
+        if key in visited:
+            return
+        visited.add(key)
+
+        t = pre_recurse_func(cur)
+        post_recurse_func = None
+        try:
+            (children, post_recurse_func) = t
+        except ValueError:
+            (children,) = t
+
+        for x in children:
+            recurse(x)
+
+        if post_recurse_func:
+            post_recurse_func(cur)
+        return
+
+    for x in roots:
+        recurse(x)
+    return
+
+ROOTS = ['//:translator', '//:libEGL', '//:libGLESv2']
+ROOTS = list(map(descs.get, ROOTS))
+
+# Gather real targets:
+real_targets = []
+
+def desc_key(x):
+    return x['target_name']
+
+def gather_includable_includes_post(x):
+    x['includable_includes'] = x['includes']
+    x['includable_sources'] = x['just_sources']
+    x['all_include_dirs'] = x.get('include_dirs', [])
+    for y in x['dep_children']:
+        x['includable_includes'] += y['includable_includes']
+        x['all_include_dirs'] += y['all_include_dirs']
+        if y['type'] == 'source_set':
+            x['includable_sources'] += y['includable_sources']
+
+def gather_real_targets(cur):
+    print_now('  ' + cur['type'], cur['target_name'])
+    if cur['type'] in ['shared_library', 'static_library']:
+        real_targets.append(cur)
+
+    return (cur['dep_children'], gather_includable_includes_post)
+
+traverse(ROOTS, gather_real_targets, desc_key)
+
+# --
+
+print_now('Running required actions')
+
+# Build the ':commit_id' 'action' target to generate 'commit.h'.
+run_checked('ninja', '-C', OUT_DIR, ':commit_id')
+
+# --
+
+print_now('Export targets')
+
+# Clear our dest directories
+targets_dir = Path(GECKO_ANGLE_DIR, 'targets')
+checkout_dir = Path(GECKO_ANGLE_DIR, 'checkout')
+shutil.rmtree(targets_dir, True)
+shutil.rmtree(checkout_dir, True)
+targets_dir.mkdir(exist_ok=True)
+checkout_dir.mkdir(exist_ok=True)
+
+# Export our targets
+
+def sortedi(x):
+    return sorted(x, key=str.lower)
+
+def append_arr(dest, name, vals):
+    if not vals:
+        return
+
+    dest.append('')
+    dest.append('{} += ['.format(name))
+    for x in sortedi(vals):
+        dest.append("    '{}',".format(x))
+    dest.append(']')
+    return
+
+INCLUDE_REGEX = re.compile('# *include *"(.+)"')
+
+IGNORED_INCLUDES = {
+    'compiler/translator/TranslatorVulkan.h',
+    'libANGLE/renderer/d3d/d3d11/winrt/NativeWindow11WinRT.h',
+    'libANGLE/renderer/gl/glx/DisplayGLX.h',
+    'libANGLE/renderer/gl/cgl/DisplayCGL.h',
+    'libANGLE/renderer/gl/egl/ozone/DisplayOzone.h',
+    'libANGLE/renderer/gl/egl/android/DisplayAndroid.h',
+    'libANGLE/renderer/vulkan/win32/DisplayVkWin32.h',
+    'libANGLE/renderer/vulkan/xcb/DisplayVkXcb.h',
+}
+
+REGISTERED_DEFINES = {
+    'ANGLE_ENABLE_D3D11': True,
+    'ANGLE_ENABLE_D3D9': True,
+    'ANGLE_ENABLE_DEBUG_ANNOTATIONS': True,
+    'ANGLE_ENABLE_NULL': False,
+    'ANGLE_ENABLE_OPENGL': False,
+    'ANGLE_ENABLE_OPENGL_NULL': False,
+    'ANGLE_ENABLE_ESSL': True,
+    'ANGLE_ENABLE_GLSL': True,
+    'ANGLE_ENABLE_HLSL': True,
+    'ANGLE_GENERATE_SHADER_DEBUG_INFO': True,
+    'ANGLE_IS_64_BIT_CPU': False,
+    'ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES': False,
+    'CERT_CHAIN_PARA_HAS_EXTRA_FIELDS': False,
+    'CHROMIUM_BUILD': False,
+    'COMPONENT_BUILD': False,
+    'constexpr14': False,
+    'DYNAMIC_ANNOTATIONS_ENABLED': True,
+    'EGL_EGLEXT_PROTOTYPES': True,
+    'EGLAPI': True,
+    'FIELDTRIAL_TESTING_ENABLED': False,
+    'FULL_SAFE_BROWSING': False,
+    'GL_API': True,
+    'GL_APICALL': True,
+    'GL_GLEXT_PROTOTYPES': True,
+    'GPU_INFO_USE_SETUPAPI': True,
+    'LIBANGLE_IMPLEMENTATION': True,
+    'LIBEGL_IMPLEMENTATION': True,
+    'LIBGLESV2_IMPLEMENTATION': True,
+    'NOMINMAX': True,
+    'NO_TCMALLOC': False,
+
+    # Else: gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow11Win32.cpp(89): error C2787: 'IDCompositionDevice': no GUID has been associated with this object
+    'NTDDI_VERSION': True,
+
+    'PSAPI_VERSION': False,
+    'SAFE_BROWSING_CSD': False,
+    'SAFE_BROWSING_DB_LOCAL': False,
+    'UNICODE': True,
+    'USE_AURA': False,
+    'V8_DEPRECATION_WARNINGS': False,
+    'WIN32': False,
+    'WIN32_LEAN_AND_MEAN': False,
+    'WINVER': False,
+    'WTF_USE_DYNAMIC_ANNOTATIONS': False,
+    '_ATL_NO_OPENGL': True,
+    '_CRT_RAND_S': True,
+    '_CRT_SECURE_NO_DEPRECATE': True,
+    '_DEBUG': False,
+    '_HAS_EXCEPTIONS': True,
+    '_SCL_SECURE_NO_DEPRECATE': True,
+    '_SECURE_ATL': True,
+    '_UNICODE': True,
+    '_USING_V110_SDK71_': False,
+    '_WIN32_WINNT': False,
+    '_WINDOWS': False,
+    '__STD_C': False,
+}
+
+def is_used_file_name(x):
+    (_, e) = x.rsplit('.', 1)
+    if e in ['h', 'cc', 'cpp', 'inl']:
+        return True
+    return False
+
+def check_includes(target_name, cur, avail_files, include_dirs):
+    assert cur.startswith('//'), cur
+    cur = cur[2:]
+
+    if not is_used_file_name(cur):
+        return
+
+    (cur_dir, _) = os.path.split(cur)
+    include_dirs = [
+        '//',
+        '//' + cur_dir + '/',
+    ] + list(include_dirs)
+
+    def is_valid_include(inc):
+        if inc in IGNORED_INCLUDES:
+            return True
+
+        for inc_dir in include_dirs:
+            inc_path = inc_dir + inc
+            if inc_path in avail_files:
+                return True
+
+        return False
+
+    line_num = 0
+    with open(cur, 'rb') as f:
+        for line in f:
+            line = line.decode()
+            line_num += 1
+            m = INCLUDE_REGEX.match(line)
+            if not m:
+                continue
+            inc = m.group(1)
+            if not is_valid_include(inc):
+                print('Warning in {}: {}:{}: Invalid include: {}'.format(target_name, cur, line_num, inc))
+
+
+total_used_files = set()
+
+def export_target(root):
+    name = root['target_name']
+    assert name.startswith('//:')
+    name = name[3:]
+
+    accum_desc = dict(root)
+    use_libs = set()
+
+    checkable_sources = set()
+
+    target_includable_files = set()
+
+    def pre(cur):
+        assert cur.get('allow_circular_includes_from', []) == [], cur['target_name']
+        children = cur['dep_children']
+
+        if cur != root:
+            if cur['type'] in ['shared_library', 'static_library']:
+                children = []
+
+                name = cur['target_name']
+                assert name.startswith('//:')
+                name = name[3:]
+                use_libs.add(name)
+            elif cur['type'] in ('source_set', 'group', 'action'):
+                for (k,v) in cur.items():
+                    if type(v) == list:
+                        vs = accum_desc.setdefault(k, [])
+                        vs += v
+                    else:
+                        accum_desc.setdefault(k, v)
+
+        return (children,)
+
+    traverse([root], pre, desc_key)
+
+    # Check includes, since `gn check` seems to be broken
+    includable = set(root['includable_sources'] + root['includable_includes'])
+    for x in includable:
+        check_includes(name, x, includable, set(accum_desc['all_include_dirs']))
+
+    total_used_files.update(includable, root['sources']) # With 'sources' to get rc/defs.
+
+    # --
+
+    target_dir = Path(targets_dir, name)
+    target_dir.mkdir(exist_ok=True)
+
+    lines = COMMON_HEADER[:]
+
+    lines.append('')
+    for x in sorted(set(accum_desc['defines'])):
+        try:
+            (k, v) = x.split('=', 1)
+            v = "'{}'".format(v)
+        except ValueError:
+            (k, v) = (x, 'True')
+        try:
+            line = "DEFINES['{}'] = {}".format(k, v)
+            if REGISTERED_DEFINES[k] == False:
+                line = '#' + line
+            lines.append(line)
+        except KeyError:
+            print('[{}] Unrecognized define: {}'.format(name, k))
+
+    cxxflags = set(accum_desc['cflags'] + accum_desc['cflags_cc'])
+
+    def fixup_paths(listt):
+        for x in set(listt):
+            assert x.startswith('//'), x
+            yield '../../checkout/' + x[2:]
+
+    sources = []
+    sources_by_os_arch = {}
+    extras = dict()
+    for x in fixup_paths(accum_desc['sources']):
+        (b, e) = x.rsplit('.', 1)
+        if e in ['h', 'y', 'l', 'inl']:
+            continue
+        elif e in ['cpp', 'cc']:
+            if b.endswith('_win'):
+                sources_by_os_arch.setdefault('WINNT', []).append(x)
+            elif b.endswith('_linux'):
+                sources_by_os_arch.setdefault('Linux', []).append(x)
+            elif b.endswith('_mac'):
+                sources_by_os_arch.setdefault('Darwin', []).append(x)
+            else:
+                sources.append(x)
+            continue
+        elif e == 'rc':
+            assert 'RCFILE' not in extras
+            extras['RCFILE'] = "'{}'".format(x)
+            continue
+        elif e == 'def':
+            assert 'DEFFILE' not in extras
+            extras['DEFFILE'] = "SRCDIR + '/{}'".format(x)
+            continue
+        else:
+            assert False, x
+
+    ldflags = filter(lambda x: not x.startswith('/DEF:'), set(accum_desc['ldflags']))
+    os_libs = list(map( lambda x: x[:-len('.lib')], set(accum_desc.get('libs', [])) ))
+
+    def append_arr_commented(dest, name, src):
+        lines = []
+        append_arr(lines, name, src)
+        lines = map(lambda x: '#' + x, lines)
+        dest += lines
+
+    append_arr(lines, 'LOCAL_INCLUDES', fixup_paths(accum_desc['include_dirs']))
+    append_arr_commented(lines, 'CXXFLAGS', cxxflags)
+    append_arr(lines, 'SOURCES', sources)
+
+    for (os_arch,v) in sorted_items(sources_by_os_arch):
+        lines += [
+            "if CONFIG['OS_ARCH'] == '{}':".format(os_arch),
+            "    SOURCES += [",
+        ]
+        lines += ("{}'{}',".format(' '*8, x) for x in sorted(set(v)))
+        lines += ["    ]"]
+
+    append_arr(lines, 'USE_LIBS', use_libs)
+    append_arr(lines, 'DIRS', ['../' + x for x in use_libs])
+    append_arr(lines, 'OS_LIBS', os_libs)
+    append_arr_commented(lines, 'LDFLAGS', ldflags)
+
+    for (k,v) in sorted(extras.items()):
+        lines.append('{} = {}'.format(k, v))
+
+    lib_type = root['type']
+    if lib_type == 'shared_library':
+        lines.append("\nGeckoSharedLibrary('{}', linkage=None)".format(name))
+    elif lib_type == 'static_library':
+        lines.append("\nLibrary('{}')".format(name))
+    else:
+        assert False, lib_type
+
+    # Write it out
+
+    mozbuild = Path(target_dir, 'moz.build')
+    print_now('  Writing {}'.format(mozbuild))
+    with mozbuild.open('w', newline='\n') as f:
+        for x in lines:
+            f.write(x + '\n')
+
+    return
+
+
+for x in real_targets:
+    export_target(x)
+
+# Copy all the files
+
+print_now('Migrate files')
+
+total_used_files = sorted(set(total_used_files))
+i = 0
+for x in total_used_files:
+    i += 1
+    sys.stdout.write('\r  Copying {}/{}'.format(i, len(total_used_files)))
+    sys.stdout.flush()
+    assert x.startswith('//'), x
+    x = x[2:]
+
+    src = Path(REPO_DIR, x)
+    dest = Path(checkout_dir, x)
+    dest.parent.mkdir(parents=True, exist_ok=True)
+    data = src.read_bytes()
+    data = data.replace(b'\r\n', b'\n')
+    dest.write_bytes(data)
+
+print('\nDone')