vulkaninfo: Add video profiles support
[KhronosGroup/Vulkan-Tools.git] / scripts / generate_source.py
blob70e138db0b81fb0c572299d40cd4a9d0d54131a4
1 #!/usr/bin/env python3
2 # Copyright (c) 2019-2023 The Khronos Group Inc.
3 # Copyright (c) 2019-2023 Valve Corporation
4 # Copyright (c) 2019-2023 LunarG, Inc.
5 # Copyright (c) 2019-2023 Google Inc.
6 # Copyright (c) 2023-2023 RasterGrid Kft.
8 # Licensed under the Apache License, Version 2.0 (the "License");
9 # you may not use this file except in compliance with the License.
10 # You may obtain a copy of the License at
12 # http://www.apache.org/licenses/LICENSE-2.0
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS,
16 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 # See the License for the specific language governing permissions and
18 # limitations under the License.
20 # Author: Mike Schuchardt <mikes@lunarg.com>
22 import argparse
23 import filecmp
24 import os
25 import json
26 import shutil
27 import subprocess
28 import sys
29 import tempfile
31 import common_codegen
33 # files to exclude from --verify check
34 verify_exclude = ['.clang-format']
36 def main(argv):
37 parser = argparse.ArgumentParser(description='Generate source code for this repository')
38 parser.add_argument('--api',
39 default='vulkan',
40 choices=['vulkan', 'vulkansc'],
41 help='Specify API name to generate')
42 parser.add_argument('--generated-version', help='sets the header version used to generate the repo')
43 parser.add_argument('registry', metavar='REGISTRY_PATH', help='path to the Vulkan-Headers registry directory')
44 group = parser.add_mutually_exclusive_group()
45 group.add_argument('-i', '--incremental', action='store_true', help='only update repo files that change')
46 group.add_argument('-v', '--verify', action='store_true', help='verify repo files match generator output')
47 args = parser.parse_args(argv)
49 # output paths and the list of files in the path
50 files_to_gen = {str(os.path.join('icd','generated')) : ['vk_typemap_helper.h',
51 'function_definitions.h',
52 'function_declarations.h'],
53 str(os.path.join('vulkaninfo','generated')): ['vulkaninfo.hpp']}
55 #base directory for the source repository
56 repo_dir = common_codegen.repo_relative('')
58 # Update the api_version in the respective json files
59 if args.generated_version:
60 json_files = []
61 json_files.append(common_codegen.repo_relative('icd/VkICD_mock_icd.json.in'))
62 for json_file in json_files:
63 with open(json_file) as f:
64 data = json.load(f)
66 data["ICD"]["api_version"] = args.generated_version
68 with open(json_file, mode='w', encoding='utf-8', newline='\n') as f:
69 f.write(json.dumps(data, indent=4))
71 # get directory where generators will run if needed
72 if args.verify or args.incremental:
73 # generate in temp directory so we can compare or copy later
74 temp_obj = tempfile.TemporaryDirectory(prefix='VulkanLoader_generated_source_')
75 temp_dir = temp_obj.name
76 for path in files_to_gen.keys():
77 os.makedirs(os.path.join(temp_dir, path))
79 registry = os.path.abspath(os.path.join(args.registry, 'vk.xml'))
80 if not os.path.isfile(registry):
81 registry = os.path.abspath(os.path.join(args.registry, 'Vulkan-Headers/registry/vk.xml'))
82 if not os.path.isfile(registry):
83 print(f'cannot find vk.xml in {args.registry}')
84 return -1
86 # run each code generator
87 for path, filenames in files_to_gen.items():
88 for filename in filenames:
89 if args.verify or args.incremental:
90 output_path = os.path.join(temp_dir, path)
91 else:
92 output_path = common_codegen.repo_relative(path)
94 cmd = [common_codegen.repo_relative(os.path.join('scripts','kvt_genvk.py')),
95 '-api', args.api,
96 '-registry', registry,
97 '-quiet', '-directory', output_path, filename]
98 print(' '.join(cmd))
99 try:
100 if args.verify or args.incremental:
101 subprocess.check_call([sys.executable] + cmd, cwd=temp_dir)
102 else:
103 subprocess.check_call([sys.executable] + cmd, cwd=repo_dir)
105 except Exception as e:
106 print('ERROR:', str(e))
107 return 1
109 # optional post-generation steps
110 if args.verify:
111 # compare contents of temp dir and repo
112 temp_files = {}
113 for path in files_to_gen.keys():
114 temp_files[path] = set()
115 temp_files[path].update(set(os.listdir(os.path.join(temp_dir, path))))
117 repo_files = {}
118 for path in files_to_gen.keys():
119 repo_files[path] = set()
120 repo_files[path].update(set(os.listdir(os.path.join(repo_dir, path))) - set(verify_exclude))
122 files_match = True
123 for path in files_to_gen.keys():
124 for filename in sorted((temp_files[path] | repo_files[path])):
125 if filename not in repo_files[path]:
126 print('ERROR: Missing repo file', filename)
127 files_match = False
128 elif filename not in temp_files[path]:
129 print('ERROR: Missing generator for', filename)
130 files_match = False
131 elif not filecmp.cmp(os.path.join(temp_dir, path, filename),
132 os.path.join(repo_dir, path, filename),
133 shallow=False):
134 print('ERROR: Repo files do not match generator output for', filename)
135 files_match = False
137 # return code for test scripts
138 if files_match:
139 print('SUCCESS: Repo files match generator output')
140 return 0
141 return 1
143 elif args.incremental:
144 # copy missing or differing files from temp directory to repo
145 for path in files_to_gen.keys():
146 for filename in os.listdir(os.path.join(temp_dir,path)):
147 temp_filename = os.path.join(temp_dir, path, filename)
148 repo_filename = os.path.join(repo_dir, path, filename)
149 if not os.path.exists(repo_filename) or \
150 not filecmp.cmp(temp_filename, repo_filename, shallow=False):
151 print('update', repo_filename)
152 shutil.copyfile(temp_filename, repo_filename)
154 return 0
156 if __name__ == '__main__':
157 sys.exit(main(sys.argv[1:]))