xref: /aosp_15_r20/external/angle/scripts/run_code_generation.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker#!/usr/bin/python3
2*8975f5c5SAndroid Build Coastguard Worker#
3*8975f5c5SAndroid Build Coastguard Worker# Copyright 2017 The ANGLE Project Authors. All rights reserved.
4*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
5*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file.
6*8975f5c5SAndroid Build Coastguard Worker#
7*8975f5c5SAndroid Build Coastguard Worker# run_code_generation.py:
8*8975f5c5SAndroid Build Coastguard Worker#   Runs ANGLE format table and other script code generation scripts.
9*8975f5c5SAndroid Build Coastguard Worker
10*8975f5c5SAndroid Build Coastguard Workerimport argparse
11*8975f5c5SAndroid Build Coastguard Workerfrom concurrent import futures
12*8975f5c5SAndroid Build Coastguard Workerimport hashlib
13*8975f5c5SAndroid Build Coastguard Workerimport json
14*8975f5c5SAndroid Build Coastguard Workerimport os
15*8975f5c5SAndroid Build Coastguard Workerimport subprocess
16*8975f5c5SAndroid Build Coastguard Workerimport sys
17*8975f5c5SAndroid Build Coastguard Workerimport platform
18*8975f5c5SAndroid Build Coastguard Worker
19*8975f5c5SAndroid Build Coastguard Workerscript_dir = sys.path[0]
20*8975f5c5SAndroid Build Coastguard Workerroot_dir = os.path.abspath(os.path.join(script_dir, '..'))
21*8975f5c5SAndroid Build Coastguard Worker
22*8975f5c5SAndroid Build Coastguard Workerhash_dir = os.path.join(script_dir, 'code_generation_hashes')
23*8975f5c5SAndroid Build Coastguard Worker
24*8975f5c5SAndroid Build Coastguard Worker
25*8975f5c5SAndroid Build Coastguard Workerdef get_child_script_dirname(script):
26*8975f5c5SAndroid Build Coastguard Worker    # All script names are relative to ANGLE's root
27*8975f5c5SAndroid Build Coastguard Worker    return os.path.dirname(os.path.abspath(os.path.join(root_dir, script)))
28*8975f5c5SAndroid Build Coastguard Worker
29*8975f5c5SAndroid Build Coastguard Worker
30*8975f5c5SAndroid Build Coastguard Workerdef get_executable_name(script):
31*8975f5c5SAndroid Build Coastguard Worker    with open(script, 'r') as f:
32*8975f5c5SAndroid Build Coastguard Worker        # Check shebang
33*8975f5c5SAndroid Build Coastguard Worker        binary = os.path.basename(f.readline().strip().replace(' ', '/'))
34*8975f5c5SAndroid Build Coastguard Worker        assert binary in ['python3', 'vpython3']
35*8975f5c5SAndroid Build Coastguard Worker        if platform.system() == 'Windows':
36*8975f5c5SAndroid Build Coastguard Worker            return binary + '.bat'
37*8975f5c5SAndroid Build Coastguard Worker        else:
38*8975f5c5SAndroid Build Coastguard Worker            return binary
39*8975f5c5SAndroid Build Coastguard Worker
40*8975f5c5SAndroid Build Coastguard Worker
41*8975f5c5SAndroid Build Coastguard Workerdef paths_from_auto_script(script, param):
42*8975f5c5SAndroid Build Coastguard Worker    script_dir = get_child_script_dirname(script)
43*8975f5c5SAndroid Build Coastguard Worker    # python3 (not vpython3) to get inputs/outputs faster
44*8975f5c5SAndroid Build Coastguard Worker    exe = 'python3'
45*8975f5c5SAndroid Build Coastguard Worker    try:
46*8975f5c5SAndroid Build Coastguard Worker        res = subprocess.check_output([exe, os.path.basename(script), param],
47*8975f5c5SAndroid Build Coastguard Worker                                      cwd=script_dir).decode().strip()
48*8975f5c5SAndroid Build Coastguard Worker    except Exception:
49*8975f5c5SAndroid Build Coastguard Worker        print('Error with auto_script %s: %s, executable %s' % (param, script, exe))
50*8975f5c5SAndroid Build Coastguard Worker        raise
51*8975f5c5SAndroid Build Coastguard Worker    if res == '':
52*8975f5c5SAndroid Build Coastguard Worker        return []
53*8975f5c5SAndroid Build Coastguard Worker    return [
54*8975f5c5SAndroid Build Coastguard Worker        os.path.relpath(os.path.join(script_dir, path), root_dir).replace("\\", "/")
55*8975f5c5SAndroid Build Coastguard Worker        for path in res.split(',')
56*8975f5c5SAndroid Build Coastguard Worker    ]
57*8975f5c5SAndroid Build Coastguard Worker
58*8975f5c5SAndroid Build Coastguard Worker
59*8975f5c5SAndroid Build Coastguard Worker# auto_script is a standard way for scripts to return their inputs and outputs.
60*8975f5c5SAndroid Build Coastguard Workerdef auto_script(script):
61*8975f5c5SAndroid Build Coastguard Worker    info = {
62*8975f5c5SAndroid Build Coastguard Worker        'inputs': paths_from_auto_script(script, 'inputs'),
63*8975f5c5SAndroid Build Coastguard Worker        'outputs': paths_from_auto_script(script, 'outputs')
64*8975f5c5SAndroid Build Coastguard Worker    }
65*8975f5c5SAndroid Build Coastguard Worker    return info
66*8975f5c5SAndroid Build Coastguard Worker
67*8975f5c5SAndroid Build Coastguard Worker
68*8975f5c5SAndroid Build Coastguard Workergenerators = {
69*8975f5c5SAndroid Build Coastguard Worker    'ANGLE format':
70*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/renderer/gen_angle_format_table.py',
71*8975f5c5SAndroid Build Coastguard Worker    'ANGLE load functions table':
72*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/renderer/gen_load_functions_table.py',
73*8975f5c5SAndroid Build Coastguard Worker    'ANGLE shader preprocessor':
74*8975f5c5SAndroid Build Coastguard Worker        'src/compiler/preprocessor/generate_parser.py',
75*8975f5c5SAndroid Build Coastguard Worker    'ANGLE shader translator':
76*8975f5c5SAndroid Build Coastguard Worker        'src/compiler/translator/generate_parser.py',
77*8975f5c5SAndroid Build Coastguard Worker    'D3D11 blit shader selection':
78*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/renderer/d3d/d3d11/gen_blit11helper.py',
79*8975f5c5SAndroid Build Coastguard Worker    'D3D11 format':
80*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/renderer/d3d/d3d11/gen_texture_format_table.py',
81*8975f5c5SAndroid Build Coastguard Worker    'DXGI format':
82*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/renderer/gen_dxgi_format_table.py',
83*8975f5c5SAndroid Build Coastguard Worker    'DXGI format support':
84*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/renderer/gen_dxgi_support_tables.py',
85*8975f5c5SAndroid Build Coastguard Worker    'Emulated HLSL functions':
86*8975f5c5SAndroid Build Coastguard Worker        'src/compiler/translator/hlsl/gen_emulated_builtin_function_tables.py',
87*8975f5c5SAndroid Build Coastguard Worker    'Extension files':
88*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/gen_extensions.py',
89*8975f5c5SAndroid Build Coastguard Worker    'GL copy conversion table':
90*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/gen_copy_conversion_table.py',
91*8975f5c5SAndroid Build Coastguard Worker    'GL CTS (dEQP) build files':
92*8975f5c5SAndroid Build Coastguard Worker        'scripts/gen_vk_gl_cts_build.py',
93*8975f5c5SAndroid Build Coastguard Worker    'GL/EGL/WGL loader':
94*8975f5c5SAndroid Build Coastguard Worker        'scripts/generate_loader.py',
95*8975f5c5SAndroid Build Coastguard Worker    'GL/EGL entry points':
96*8975f5c5SAndroid Build Coastguard Worker        'scripts/generate_entry_points.py',
97*8975f5c5SAndroid Build Coastguard Worker    'GLenum value to string map':
98*8975f5c5SAndroid Build Coastguard Worker        'scripts/gen_gl_enum_utils.py',
99*8975f5c5SAndroid Build Coastguard Worker    'GL format map':
100*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/gen_format_map.py',
101*8975f5c5SAndroid Build Coastguard Worker    'interpreter utils':
102*8975f5c5SAndroid Build Coastguard Worker        'scripts/gen_interpreter_utils.py',
103*8975f5c5SAndroid Build Coastguard Worker    'Metal format table':
104*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/renderer/metal/gen_mtl_format_table.py',
105*8975f5c5SAndroid Build Coastguard Worker    'Metal default shaders':
106*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/renderer/metal/shaders/gen_mtl_internal_shaders.py',
107*8975f5c5SAndroid Build Coastguard Worker    'OpenGL dispatch table':
108*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/renderer/gl/generate_gl_dispatch_table.py',
109*8975f5c5SAndroid Build Coastguard Worker    'overlay fonts':
110*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/gen_overlay_fonts.py',
111*8975f5c5SAndroid Build Coastguard Worker    'overlay widgets':
112*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/gen_overlay_widgets.py',
113*8975f5c5SAndroid Build Coastguard Worker    'packed enum':
114*8975f5c5SAndroid Build Coastguard Worker        'src/common/gen_packed_gl_enums.py',
115*8975f5c5SAndroid Build Coastguard Worker    'proc table':
116*8975f5c5SAndroid Build Coastguard Worker        'scripts/gen_proc_table.py',
117*8975f5c5SAndroid Build Coastguard Worker    'restricted traces':
118*8975f5c5SAndroid Build Coastguard Worker        'src/tests/restricted_traces/gen_restricted_traces.py',
119*8975f5c5SAndroid Build Coastguard Worker    'SPIR-V helpers':
120*8975f5c5SAndroid Build Coastguard Worker        'src/common/spirv/gen_spirv_builder_and_parser.py',
121*8975f5c5SAndroid Build Coastguard Worker    'Static builtins':
122*8975f5c5SAndroid Build Coastguard Worker        'src/compiler/translator/gen_builtin_symbols.py',
123*8975f5c5SAndroid Build Coastguard Worker    'uniform type':
124*8975f5c5SAndroid Build Coastguard Worker        'src/common/gen_uniform_type_table.py',
125*8975f5c5SAndroid Build Coastguard Worker    'Vulkan format':
126*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/renderer/vulkan/gen_vk_format_table.py',
127*8975f5c5SAndroid Build Coastguard Worker    'Vulkan internal shader programs':
128*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/renderer/vulkan/gen_vk_internal_shaders.py',
129*8975f5c5SAndroid Build Coastguard Worker    'Vulkan mandatory format support table':
130*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/renderer/vulkan/gen_vk_mandatory_format_support_table.py',
131*8975f5c5SAndroid Build Coastguard Worker    'WebGPU format':
132*8975f5c5SAndroid Build Coastguard Worker        'src/libANGLE/renderer/wgpu/gen_wgpu_format_table.py',
133*8975f5c5SAndroid Build Coastguard Worker}
134*8975f5c5SAndroid Build Coastguard Worker
135*8975f5c5SAndroid Build Coastguard Worker
136*8975f5c5SAndroid Build Coastguard Worker# Fast and supports --verify-only without hashes.
137*8975f5c5SAndroid Build Coastguard Workerhashless_generators = {
138*8975f5c5SAndroid Build Coastguard Worker    'ANGLE features': 'include/platform/gen_features.py',
139*8975f5c5SAndroid Build Coastguard Worker    'Test spec JSON': 'infra/specs/generate_test_spec_json.py',
140*8975f5c5SAndroid Build Coastguard Worker}
141*8975f5c5SAndroid Build Coastguard Worker
142*8975f5c5SAndroid Build Coastguard Worker
143*8975f5c5SAndroid Build Coastguard Workerdef md5(fname):
144*8975f5c5SAndroid Build Coastguard Worker    hash_md5 = hashlib.md5()
145*8975f5c5SAndroid Build Coastguard Worker    with open(fname, 'rb') as f:
146*8975f5c5SAndroid Build Coastguard Worker        if sys.platform.startswith('win') or sys.platform == 'cygwin':
147*8975f5c5SAndroid Build Coastguard Worker            # Beware: Windows crlf + git behavior + unicode in some files
148*8975f5c5SAndroid Build Coastguard Worker            hash_md5.update(f.read().replace(b'\r\n', b'\n'))
149*8975f5c5SAndroid Build Coastguard Worker        else:
150*8975f5c5SAndroid Build Coastguard Worker            for chunk in iter(lambda: f.read(4096), b''):
151*8975f5c5SAndroid Build Coastguard Worker                hash_md5.update(chunk)
152*8975f5c5SAndroid Build Coastguard Worker    return hash_md5.hexdigest()
153*8975f5c5SAndroid Build Coastguard Worker
154*8975f5c5SAndroid Build Coastguard Worker
155*8975f5c5SAndroid Build Coastguard Workerdef get_hash_file_name(name):
156*8975f5c5SAndroid Build Coastguard Worker    return name.replace(' ', '_').replace('/', '_') + '.json'
157*8975f5c5SAndroid Build Coastguard Worker
158*8975f5c5SAndroid Build Coastguard Worker
159*8975f5c5SAndroid Build Coastguard Workerdef any_hash_dirty(name, filenames, new_hashes, old_hashes):
160*8975f5c5SAndroid Build Coastguard Worker    found_dirty_hash = False
161*8975f5c5SAndroid Build Coastguard Worker
162*8975f5c5SAndroid Build Coastguard Worker    for fname in filenames:
163*8975f5c5SAndroid Build Coastguard Worker        if not os.path.isfile(os.path.join(root_dir, fname)):
164*8975f5c5SAndroid Build Coastguard Worker            print('File not found: "%s". Code gen dirty for %s' % (fname, name))
165*8975f5c5SAndroid Build Coastguard Worker            found_dirty_hash = True
166*8975f5c5SAndroid Build Coastguard Worker        else:
167*8975f5c5SAndroid Build Coastguard Worker            new_hashes[fname] = md5(fname)
168*8975f5c5SAndroid Build Coastguard Worker            if (not fname in old_hashes) or (old_hashes[fname] != new_hashes[fname]):
169*8975f5c5SAndroid Build Coastguard Worker                print('Hash for "%s" dirty for %s generator.' % (fname, name))
170*8975f5c5SAndroid Build Coastguard Worker                found_dirty_hash = True
171*8975f5c5SAndroid Build Coastguard Worker    return found_dirty_hash
172*8975f5c5SAndroid Build Coastguard Worker
173*8975f5c5SAndroid Build Coastguard Worker
174*8975f5c5SAndroid Build Coastguard Workerdef any_old_hash_missing(all_new_hashes, all_old_hashes):
175*8975f5c5SAndroid Build Coastguard Worker    result = False
176*8975f5c5SAndroid Build Coastguard Worker    for file, old_hashes in all_old_hashes.items():
177*8975f5c5SAndroid Build Coastguard Worker        if file not in all_new_hashes:
178*8975f5c5SAndroid Build Coastguard Worker            print('"%s" does not exist. Code gen dirty.' % file)
179*8975f5c5SAndroid Build Coastguard Worker            result = True
180*8975f5c5SAndroid Build Coastguard Worker        else:
181*8975f5c5SAndroid Build Coastguard Worker            for name, _ in old_hashes.items():
182*8975f5c5SAndroid Build Coastguard Worker                if name not in all_new_hashes[file]:
183*8975f5c5SAndroid Build Coastguard Worker                    print('Hash for %s is missing from "%s". Code gen is dirty.' % (name, file))
184*8975f5c5SAndroid Build Coastguard Worker                    result = True
185*8975f5c5SAndroid Build Coastguard Worker    return result
186*8975f5c5SAndroid Build Coastguard Worker
187*8975f5c5SAndroid Build Coastguard Worker
188*8975f5c5SAndroid Build Coastguard Workerdef update_output_hashes(script, outputs, new_hashes):
189*8975f5c5SAndroid Build Coastguard Worker    for output in outputs:
190*8975f5c5SAndroid Build Coastguard Worker        if not os.path.isfile(output):
191*8975f5c5SAndroid Build Coastguard Worker            print('Output is missing from %s: %s' % (script, output))
192*8975f5c5SAndroid Build Coastguard Worker            sys.exit(1)
193*8975f5c5SAndroid Build Coastguard Worker        new_hashes[output] = md5(output)
194*8975f5c5SAndroid Build Coastguard Worker
195*8975f5c5SAndroid Build Coastguard Worker
196*8975f5c5SAndroid Build Coastguard Workerdef load_hashes():
197*8975f5c5SAndroid Build Coastguard Worker    hashes = {}
198*8975f5c5SAndroid Build Coastguard Worker    for file in os.listdir(hash_dir):
199*8975f5c5SAndroid Build Coastguard Worker        hash_fname = os.path.join(hash_dir, file)
200*8975f5c5SAndroid Build Coastguard Worker        with open(hash_fname) as hash_file:
201*8975f5c5SAndroid Build Coastguard Worker            try:
202*8975f5c5SAndroid Build Coastguard Worker                hashes[file] = json.load(hash_file)
203*8975f5c5SAndroid Build Coastguard Worker            except ValueError:
204*8975f5c5SAndroid Build Coastguard Worker                raise Exception("Could not decode JSON from %s" % file)
205*8975f5c5SAndroid Build Coastguard Worker    return hashes
206*8975f5c5SAndroid Build Coastguard Worker
207*8975f5c5SAndroid Build Coastguard Worker
208*8975f5c5SAndroid Build Coastguard Workerdef main():
209*8975f5c5SAndroid Build Coastguard Worker    all_old_hashes = load_hashes()
210*8975f5c5SAndroid Build Coastguard Worker    all_new_hashes = {}
211*8975f5c5SAndroid Build Coastguard Worker    any_dirty = False
212*8975f5c5SAndroid Build Coastguard Worker    format_workaround = False
213*8975f5c5SAndroid Build Coastguard Worker
214*8975f5c5SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser(description='Generate ANGLE internal code.')
215*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument(
216*8975f5c5SAndroid Build Coastguard Worker        '-v',
217*8975f5c5SAndroid Build Coastguard Worker        '--verify-no-dirty',
218*8975f5c5SAndroid Build Coastguard Worker        dest='verify_only',
219*8975f5c5SAndroid Build Coastguard Worker        action='store_true',
220*8975f5c5SAndroid Build Coastguard Worker        help='verify hashes are not dirty')
221*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument(
222*8975f5c5SAndroid Build Coastguard Worker        '-g', '--generator', action='append', nargs='*', type=str, dest='specified_generators'),
223*8975f5c5SAndroid Build Coastguard Worker
224*8975f5c5SAndroid Build Coastguard Worker    args = parser.parse_args()
225*8975f5c5SAndroid Build Coastguard Worker
226*8975f5c5SAndroid Build Coastguard Worker    ranGenerators = generators
227*8975f5c5SAndroid Build Coastguard Worker    runningSingleGenerator = False
228*8975f5c5SAndroid Build Coastguard Worker    if (args.specified_generators):
229*8975f5c5SAndroid Build Coastguard Worker        ranGenerators = {k: v for k, v in generators.items() if k in args.specified_generators[0]}
230*8975f5c5SAndroid Build Coastguard Worker        runningSingleGenerator = True
231*8975f5c5SAndroid Build Coastguard Worker
232*8975f5c5SAndroid Build Coastguard Worker    if len(ranGenerators) == 0:
233*8975f5c5SAndroid Build Coastguard Worker        print("No valid generators specified.")
234*8975f5c5SAndroid Build Coastguard Worker        return 1
235*8975f5c5SAndroid Build Coastguard Worker
236*8975f5c5SAndroid Build Coastguard Worker    # Just get 'inputs' and 'outputs' from scripts but this runs the scripts so it's a bit slow
237*8975f5c5SAndroid Build Coastguard Worker    infos = {}
238*8975f5c5SAndroid Build Coastguard Worker    with futures.ThreadPoolExecutor(max_workers=8) as executor:
239*8975f5c5SAndroid Build Coastguard Worker        for _, script in sorted(ranGenerators.items()):
240*8975f5c5SAndroid Build Coastguard Worker            infos[script] = executor.submit(auto_script, script)
241*8975f5c5SAndroid Build Coastguard Worker
242*8975f5c5SAndroid Build Coastguard Worker    for name, script in sorted(ranGenerators.items()):
243*8975f5c5SAndroid Build Coastguard Worker        info = infos[script].result()
244*8975f5c5SAndroid Build Coastguard Worker        fname = get_hash_file_name(name)
245*8975f5c5SAndroid Build Coastguard Worker        filenames = info['inputs'] + info['outputs'] + [script]
246*8975f5c5SAndroid Build Coastguard Worker        new_hashes = {}
247*8975f5c5SAndroid Build Coastguard Worker        if fname not in all_old_hashes:
248*8975f5c5SAndroid Build Coastguard Worker            all_old_hashes[fname] = {}
249*8975f5c5SAndroid Build Coastguard Worker        if any_hash_dirty(name, filenames, new_hashes, all_old_hashes[fname]):
250*8975f5c5SAndroid Build Coastguard Worker            any_dirty = True
251*8975f5c5SAndroid Build Coastguard Worker            if "preprocessor" in name:
252*8975f5c5SAndroid Build Coastguard Worker                format_workaround = True
253*8975f5c5SAndroid Build Coastguard Worker
254*8975f5c5SAndroid Build Coastguard Worker            if not args.verify_only:
255*8975f5c5SAndroid Build Coastguard Worker                print('Running ' + name + ' code generator')
256*8975f5c5SAndroid Build Coastguard Worker
257*8975f5c5SAndroid Build Coastguard Worker                exe = get_executable_name(script)
258*8975f5c5SAndroid Build Coastguard Worker                subprocess.check_call([exe, os.path.basename(script)],
259*8975f5c5SAndroid Build Coastguard Worker                                      cwd=get_child_script_dirname(script))
260*8975f5c5SAndroid Build Coastguard Worker
261*8975f5c5SAndroid Build Coastguard Worker        # Update the hash dictionary.
262*8975f5c5SAndroid Build Coastguard Worker        all_new_hashes[fname] = new_hashes
263*8975f5c5SAndroid Build Coastguard Worker
264*8975f5c5SAndroid Build Coastguard Worker    if not runningSingleGenerator and any_old_hash_missing(all_new_hashes, all_old_hashes):
265*8975f5c5SAndroid Build Coastguard Worker        any_dirty = True
266*8975f5c5SAndroid Build Coastguard Worker
267*8975f5c5SAndroid Build Coastguard Worker    # Handle hashless_generators separately as these don't have hash maps.
268*8975f5c5SAndroid Build Coastguard Worker    hashless_generators_dirty = False
269*8975f5c5SAndroid Build Coastguard Worker    for name, script in sorted(hashless_generators.items()):
270*8975f5c5SAndroid Build Coastguard Worker        cmd = [get_executable_name(script), os.path.basename(script)]
271*8975f5c5SAndroid Build Coastguard Worker        rc = subprocess.call(cmd + ['--verify-only'], cwd=get_child_script_dirname(script))
272*8975f5c5SAndroid Build Coastguard Worker        if rc != 0:
273*8975f5c5SAndroid Build Coastguard Worker            print(name + ' generator dirty')
274*8975f5c5SAndroid Build Coastguard Worker            # Don't set any_dirty as we don't need git cl format in this case.
275*8975f5c5SAndroid Build Coastguard Worker            hashless_generators_dirty = True
276*8975f5c5SAndroid Build Coastguard Worker
277*8975f5c5SAndroid Build Coastguard Worker            if not args.verify_only:
278*8975f5c5SAndroid Build Coastguard Worker                print('Running ' + name + ' code generator')
279*8975f5c5SAndroid Build Coastguard Worker                subprocess.check_call(cmd, cwd=get_child_script_dirname(script))
280*8975f5c5SAndroid Build Coastguard Worker
281*8975f5c5SAndroid Build Coastguard Worker    if args.verify_only:
282*8975f5c5SAndroid Build Coastguard Worker        return int(any_dirty or hashless_generators_dirty)
283*8975f5c5SAndroid Build Coastguard Worker
284*8975f5c5SAndroid Build Coastguard Worker    if any_dirty:
285*8975f5c5SAndroid Build Coastguard Worker        args = ['git.bat'] if os.name == 'nt' else ['git']
286*8975f5c5SAndroid Build Coastguard Worker        args += ['cl', 'format']
287*8975f5c5SAndroid Build Coastguard Worker        print('Calling git cl format')
288*8975f5c5SAndroid Build Coastguard Worker        subprocess.check_call(args)
289*8975f5c5SAndroid Build Coastguard Worker        if format_workaround:
290*8975f5c5SAndroid Build Coastguard Worker            # Some formattings fail, and thus we can never submit such a cl because
291*8975f5c5SAndroid Build Coastguard Worker            # of vicious circle of needing clean formatting but formatting not generating
292*8975f5c5SAndroid Build Coastguard Worker            # clean formatting.
293*8975f5c5SAndroid Build Coastguard Worker            print('Calling git cl format again')
294*8975f5c5SAndroid Build Coastguard Worker            subprocess.check_call(args)
295*8975f5c5SAndroid Build Coastguard Worker
296*8975f5c5SAndroid Build Coastguard Worker
297*8975f5c5SAndroid Build Coastguard Worker        # Update the output hashes again since they can be formatted.
298*8975f5c5SAndroid Build Coastguard Worker        for name, script in sorted(ranGenerators.items()):
299*8975f5c5SAndroid Build Coastguard Worker            info = auto_script(script)
300*8975f5c5SAndroid Build Coastguard Worker            fname = get_hash_file_name(name)
301*8975f5c5SAndroid Build Coastguard Worker            update_output_hashes(name, info['outputs'], all_new_hashes[fname])
302*8975f5c5SAndroid Build Coastguard Worker
303*8975f5c5SAndroid Build Coastguard Worker        for fname, new_hashes in all_new_hashes.items():
304*8975f5c5SAndroid Build Coastguard Worker            hash_fname = os.path.join(hash_dir, fname)
305*8975f5c5SAndroid Build Coastguard Worker            with open(hash_fname, "w") as f:
306*8975f5c5SAndroid Build Coastguard Worker                json.dump(new_hashes, f, indent=2, sort_keys=True, separators=(',', ':\n    '))
307*8975f5c5SAndroid Build Coastguard Worker                f.write('\n')  # json.dump doesn't end with newline
308*8975f5c5SAndroid Build Coastguard Worker
309*8975f5c5SAndroid Build Coastguard Worker    return 0
310*8975f5c5SAndroid Build Coastguard Worker
311*8975f5c5SAndroid Build Coastguard Worker
312*8975f5c5SAndroid Build Coastguard Workerif __name__ == '__main__':
313*8975f5c5SAndroid Build Coastguard Worker    sys.exit(main())
314