1#!/usr/bin/env python3 2# Copyright (c) 2019 The Khronos Group Inc. 3# Copyright (c) 2019 Valve Corporation 4# Copyright (c) 2019 LunarG, Inc. 5# Copyright (c) 2019 Google Inc. 6# 7# Licensed under the Apache License, Version 2.0 (the "License"); 8# you may not use this file except in compliance with the License. 9# You may obtain a copy of the License at 10# 11# http://www.apache.org/licenses/LICENSE-2.0 12# 13# Unless required by applicable law or agreed to in writing, software 14# distributed under the License is distributed on an "AS IS" BASIS, 15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16# See the License for the specific language governing permissions and 17# limitations under the License. 18# 19# Author: Mike Schuchardt <mikes@lunarg.com> 20 21import argparse 22import filecmp 23import os 24import shutil 25import subprocess 26import sys 27import tempfile 28 29import common_codegen 30 31# files to exclude from --verify check 32verify_exclude = ['.clang-format'] 33 34def main(argv): 35 parser = argparse.ArgumentParser(description='Generate source code for this repository') 36 parser.add_argument('registry', metavar='REGISTRY_PATH', help='path to the Vulkan-Headers registry directory') 37 group = parser.add_mutually_exclusive_group() 38 group.add_argument('-i', '--incremental', action='store_true', help='only update repo files that change') 39 group.add_argument('-v', '--verify', action='store_true', help='verify repo files match generator output') 40 args = parser.parse_args(argv) 41 42 gen_cmds = [*[[common_codegen.repo_relative('scripts/lvl_genvk.py'), 43 '-registry', os.path.abspath(os.path.join(args.registry, 'vk.xml')), 44 '-quiet', 45 filename] for filename in ["chassis.cpp", 46 "chassis.h", 47 "layer_chassis_dispatch.cpp", 48 "layer_chassis_dispatch.h", 49 "object_tracker.cpp", 50 "object_tracker.h", 51 "parameter_validation.cpp", 52 "parameter_validation.h", 53 "thread_safety.cpp", 54 "thread_safety.h", 55 "vk_dispatch_table_helper.h", 56 "vk_enum_string_helper.h", 57 "vk_extension_helper.h", 58 "vk_layer_dispatch_table.h", 59 "vk_object_types.h", 60 "vk_safe_struct.cpp", 61 "vk_safe_struct.h", 62 "vk_typemap_helper.h"]], 63 [common_codegen.repo_relative('scripts/vk_validation_stats.py'), 64 os.path.abspath(os.path.join(args.registry, 'validusage.json')), 65 '-export_header'], 66 [common_codegen.repo_relative('scripts/external_revision_generator.py'), 67 '--json_file', common_codegen.repo_relative('scripts/known_good.json'), 68 '--json_keys', 'repos,0,commit', 69 '-s', 'SPIRV_TOOLS_COMMIT_ID', 70 '-o', 'spirv_tools_commit_id.h']] 71 72 repo_dir = common_codegen.repo_relative('layers/generated') 73 74 # get directory where generators will run 75 if args.verify or args.incremental: 76 # generate in temp directory so we can compare or copy later 77 temp_obj = tempfile.TemporaryDirectory(prefix='VulkanVL_generated_source_') 78 temp_dir = temp_obj.name 79 gen_dir = temp_dir 80 else: 81 # generate directly in the repo 82 gen_dir = repo_dir 83 84 # run each code generator 85 for cmd in gen_cmds: 86 print(' '.join(cmd)) 87 try: 88 subprocess.check_call([sys.executable] + cmd, cwd=gen_dir) 89 except Exception as e: 90 print('ERROR:', str(e)) 91 return 1 92 93 # optional post-generation steps 94 if args.verify: 95 # compare contents of temp dir and repo 96 temp_files = set(os.listdir(temp_dir)) 97 repo_files = set(os.listdir(repo_dir)) 98 files_match = True 99 for filename in sorted((temp_files | repo_files) - set(verify_exclude)): 100 if filename not in repo_files: 101 print('ERROR: Missing repo file', filename) 102 files_match = False 103 elif filename not in temp_files: 104 print('ERROR: Missing generator for', filename) 105 files_match = False 106 elif not filecmp.cmp(os.path.join(temp_dir, filename), 107 os.path.join(repo_dir, filename), 108 shallow=False): 109 print('ERROR: Repo files do not match generator output for', filename) 110 files_match = False 111 112 # return code for test scripts 113 if files_match: 114 print('SUCCESS: Repo files match generator output') 115 return 0 116 return 1 117 118 elif args.incremental: 119 # copy missing or differing files from temp directory to repo 120 for filename in os.listdir(temp_dir): 121 temp_filename = os.path.join(temp_dir, filename) 122 repo_filename = os.path.join(repo_dir, filename) 123 if not os.path.exists(repo_filename) or \ 124 not filecmp.cmp(temp_filename, repo_filename, shallow=False): 125 print('update', repo_filename) 126 shutil.copyfile(temp_filename, repo_filename) 127 128 return 0 129 130if __name__ == '__main__': 131 sys.exit(main(sys.argv[1:])) 132 133