scripts: Add wrapper script for all codegen
Simplify running the 3 different code generators with a wrapper script.
Provides options:
--verify diff generator output and repo files
--incremental only touh files that actually changed
Add wrapper script to CMake as VulkanVL_generated_source target
Change-Id: I9d8440092748adf546602bd1f1b204470cf161aa
diff --git a/scripts/generate_source.py b/scripts/generate_source.py
new file mode 100755
index 0000000..4b3b606
--- /dev/null
+++ b/scripts/generate_source.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 The Khronos Group Inc.
+# Copyright (c) 2019 Valve Corporation
+# Copyright (c) 2019 LunarG, Inc.
+# Copyright (c) 2019 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Author: Mike Schuchardt <mikes@lunarg.com>
+
+import argparse
+import filecmp
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+
+# files to exclude from --verify check
+verify_exclude = ['.clang-format']
+
+# helper to define paths relative to this file
+def script_relative(path):
+ return os.path.abspath(os.path.join(os.path.dirname(__file__), path))
+
+def main(argv):
+ parser = argparse.ArgumentParser(description='Generate source code for this repository')
+ parser.add_argument('registry', metavar='REGISTRY_PATH', help='path to the Vulkan-Headers registry directory')
+ group = parser.add_mutually_exclusive_group()
+ group.add_argument('-i', '--incremental', action='store_true', help='only update repo files that change')
+ group.add_argument('-v', '--verify', action='store_true', help='verify repo files match generator output')
+ args = parser.parse_args(argv)
+
+ gen_cmds = [*[[script_relative('lvl_genvk.py'),
+ '-registry', os.path.abspath(os.path.join(args.registry, 'vk.xml')),
+ '-quiet',
+ filename] for filename in ["chassis.cpp",
+ "chassis.h",
+ "layer_chassis_dispatch.cpp",
+ "layer_chassis_dispatch.h",
+ "object_tracker.cpp",
+ "object_tracker.h",
+ "parameter_validation.cpp",
+ "parameter_validation.h",
+ "thread_safety.cpp",
+ "thread_safety.h",
+ "vk_dispatch_table_helper.h",
+ "vk_enum_string_helper.h",
+ "vk_extension_helper.h",
+ "vk_layer_dispatch_table.h",
+ "vk_object_types.h",
+ "vk_safe_struct.cpp",
+ "vk_safe_struct.h",
+ "vk_typemap_helper.h"]],
+ [script_relative('vk_validation_stats.py'),
+ os.path.abspath(os.path.join(args.registry, 'validusage.json')),
+ '-export_header'],
+ [script_relative('external_revision_generator.py'),
+ '--rev_file', script_relative('known_good.json'),
+ '-s', 'SPIRV_TOOLS_COMMIT_ID',
+ '-o', 'spirv_tools_commit_id.h']]
+
+ repo_dir = script_relative('../layers/generated')
+
+ # get directory where generators will run
+ if args.verify or args.incremental:
+ # generate in temp directory so we can compare or copy later
+ temp_obj = tempfile.TemporaryDirectory(prefix='VulkanVL_generated_source_')
+ temp_dir = temp_obj.name
+ gen_dir = temp_dir
+ else:
+ # generate directly in the repo
+ gen_dir = repo_dir
+
+ # run each code generator
+ for cmd in gen_cmds:
+ print(' '.join(cmd))
+ try:
+ subprocess.check_call([sys.executable] + cmd,
+ # ignore generator output, vk_validation_stats.py is especially noisy
+ stdout=subprocess.DEVNULL,
+ cwd=gen_dir)
+ except Exception as e:
+ print('ERROR:', str(e))
+ return 1
+
+ # optional post-generation steps
+ if args.verify:
+ # compare contents of temp dir and repo
+ temp_files = set(os.listdir(temp_dir))
+ repo_files = set(os.listdir(repo_dir))
+ files_match = True
+ for filename in sorted((temp_files | repo_files) - set(verify_exclude)):
+ if filename not in repo_files:
+ print('ERROR: Missing repo file', filename)
+ files_match = False
+ elif filename not in temp_files:
+ print('ERROR: Missing generator for', filename)
+ files_match = False
+ elif not filecmp.cmp(os.path.join(temp_dir, filename),
+ os.path.join(repo_dir, filename),
+ shallow=False):
+ print('ERROR: Repo files do not match generator output for', filename)
+ files_match = False
+
+ # return code for test scripts
+ if files_match:
+ print('SUCCESS: Repo files match generator output')
+ return 0
+ return 1
+
+ elif args.incremental:
+ # copy missing or differing files from temp directory to repo
+ for filename in os.listdir(temp_dir):
+ temp_filename = os.path.join(temp_dir, filename)
+ repo_filename = os.path.join(repo_dir, filename)
+ if not os.path.exists(repo_filename) or \
+ not filecmp.cmp(temp_filename, repo_filename, shallow=False):
+ print('update', repo_filename)
+ shutil.copyfile(temp_filename, repo_filename)
+
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
+
diff --git a/scripts/lvl_genvk.py b/scripts/lvl_genvk.py
index cd9612e..b35b3a9 100644
--- a/scripts/lvl_genvk.py
+++ b/scripts/lvl_genvk.py
@@ -651,6 +651,10 @@
args = parser.parse_args()
+ # default scripts path to be same as registry
+ if not args.scripts:
+ args.scripts = os.path.dirname(args.registry)
+
scripts_directory_path = os.path.dirname(os.path.abspath(__file__))
registry_headers_path = os.path.join(scripts_directory_path, args.scripts)
sys.path.insert(0, registry_headers_path)