• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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# Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
7# Copyright (c) 2023-2023 RasterGrid Kft.
8#
9# Licensed under the Apache License, Version 2.0 (the "License");
10# you may not use this file except in compliance with the License.
11# You may obtain a copy of the License at
12#
13#     http://www.apache.org/licenses/LICENSE-2.0
14#
15# Unless required by applicable law or agreed to in writing, software
16# distributed under the License is distributed on an "AS IS" BASIS,
17# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18# See the License for the specific language governing permissions and
19# limitations under the License.
20#
21# Author: Mike Schuchardt <mikes@lunarg.com>
22
23import argparse
24import common_codegen
25import filecmp
26import os
27import shutil
28import subprocess
29import sys
30import tempfile
31import datetime
32import re
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    parser.add_argument('--api',
38                        default='vulkan',
39                        choices=['vulkan'],
40                        help='Specify API name to generate')
41    parser.add_argument('--generated-version', help='sets the header version used to generate the repo')
42    group = parser.add_mutually_exclusive_group()
43    group.add_argument('-i', '--incremental', action='store_true', help='only update repo files that change')
44    group.add_argument('-v', '--verify', action='store_true', help='verify repo files match generator output')
45    args = parser.parse_args(argv)
46
47    gen_cmds = [[common_codegen.repo_relative('scripts/loader_genvk.py'),
48                 '-registry', os.path.abspath(os.path.join(args.registry,  'vk.xml')),
49                 '-quiet',
50                 filename] for filename in ['vk_layer_dispatch_table.h',
51                                            'vk_loader_extensions.h',
52                                            'vk_loader_extensions.c',
53                                            'vk_object_types.h']]
54
55    repo_dir = common_codegen.repo_relative('loader/generated')
56
57    # get directory where generators will run
58    if args.verify or args.incremental:
59        # generate in temp directory so we can compare or copy later
60        temp_obj = tempfile.TemporaryDirectory(prefix='loader_codegen_')
61        temp_dir = temp_obj.name
62        gen_dir = temp_dir
63    else:
64        # generate directly in the repo
65        gen_dir = repo_dir
66
67    # run each code generator
68    for cmd in gen_cmds:
69        print(' '.join(cmd))
70        try:
71            subprocess.check_call([sys.executable] + cmd,
72                                  # ignore generator output, vk_validation_stats.py is especially noisy
73                                  stdout=subprocess.DEVNULL,
74                                  cwd=gen_dir)
75        except Exception as e:
76            print('ERROR:', str(e))
77            return 1
78
79    # optional post-generation steps
80    if args.verify:
81        # compare contents of temp dir and repo
82        temp_files = set(os.listdir(temp_dir))
83        repo_files = set(os.listdir(repo_dir))
84        files_match = True
85        for filename in sorted((temp_files | repo_files)):
86            if filename not in repo_files:
87                print('ERROR: Missing repo file', filename)
88                files_match = False
89            elif filename not in temp_files:
90                print('ERROR: Missing generator for', filename)
91                files_match = False
92            elif not filecmp.cmp(os.path.join(temp_dir, filename),
93                               os.path.join(repo_dir, filename),
94                               shallow=False):
95                print('ERROR: Repo files do not match generator output for', filename)
96                files_match = False
97
98        # return code for test scripts
99        if files_match:
100            print('SUCCESS: Repo files match generator output')
101            return 0
102        return 1
103
104    elif args.incremental:
105        # copy missing or differing files from temp directory to repo
106        for filename in os.listdir(temp_dir):
107            temp_filename = os.path.join(temp_dir, filename)
108            repo_filename = os.path.join(repo_dir, filename)
109            if not os.path.exists(repo_filename) or \
110               not filecmp.cmp(temp_filename, repo_filename, shallow=False):
111                print('update', repo_filename)
112                shutil.copyfile(temp_filename, repo_filename)
113
114    # write out the header version used to generate the code to a checked in CMake file
115    if args.generated_version:
116        # Update the CMake project version
117        with open(common_codegen.repo_relative('CMakeLists.txt'), "r+") as f:
118            data = f.read()
119            f.seek(0)
120            f.write(re.sub("project.*VERSION.*", f"project(VULKAN_LOADER VERSION {args.generated_version} LANGUAGES C)", data))
121            f.truncate()
122
123        with open(common_codegen.repo_relative('loader/loader.rc.in'), "r") as rc_file:
124            rc_file_contents = rc_file.read()
125        rc_ver = ', '.join(args.generated_version.split('.') + ['0'])
126        rc_file_contents = rc_file_contents.replace('${LOADER_VER_FILE_VERSION}', f'{rc_ver}')
127        rc_file_contents = rc_file_contents.replace('${LOADER_VER_FILE_DESCRIPTION_STR}', f'"{args.generated_version}.Dev Build"')
128        rc_file_contents = rc_file_contents.replace('${LOADER_VER_FILE_VERSION_STR}', f'"Vulkan Loader - Dev Build"')
129        rc_file_contents = rc_file_contents.replace('${LOADER_CUR_COPYRIGHT_YEAR}', f'{datetime.date.today().year}')
130        with open(common_codegen.repo_relative('loader/loader.rc'), "w") as rc_file_out:
131            rc_file_out.write(rc_file_contents)
132            rc_file_out.close()
133
134    return 0
135
136if __name__ == '__main__':
137    sys.exit(main(sys.argv[1:]))
138
139