1#!/usr/bin/env python3 2# 3# Copyright 2020-2022 The Khronos Group Inc. 4# 5# SPDX-License-Identifier: Apache-2.0 6 7# Build a spec with requested extension sets and options. 8# 9# Usage: makeSpec script-options make-options 10# Script options are parsed by this script before invoking 'make': 11# -genpath path - directory for generated files and outputs 12# -spec core - make a spec with no extensions (default) 13# -spec khr - make a spec with all KHR extensions 14# -spec all - make a spec with all registered extensions 15# -version {1.0 | 1.1 | 1.2 | 1.3} - make a spec with this core version 16# -ext name - add specified extension and its dependencies 17# -clean - clean generated files before building 18# -registry path - API XML to use instead of default 19# -apiname name - API name to use instead of default 20# -v - verbose, print actions before executing them 21# -n - dry-run, print actions instead of executing them 22# make-options - all other options are passed to 'make', including 23# requested build targets 24 25import argparse, copy, io, os, re, string, subprocess, sys 26 27def execute(args, results): 28 if results.verbose or results.dryrun: 29 print("'" + "' '".join(args) + "'") 30 if not results.dryrun: 31 subprocess.check_call(args) 32 33if __name__ == '__main__': 34 parser = argparse.ArgumentParser() 35 36 parser.add_argument('-clean', action='store_true', 37 help='Clean generated files before building') 38 parser.add_argument('-extension', action='append', 39 default=[], 40 help='Specify a required extension or extensions to add to targets') 41 parser.add_argument('-genpath', action='store', 42 default='gen', 43 help='Path to directory containing generated files') 44 parser.add_argument('-spec', action='store', 45 choices=[ 'core', 'khr', 'all' ], 46 default='core', 47 help='Type of spec to generate') 48 parser.add_argument('-version', action='store', 49 choices=[ '1.0', '1.1', '1.2', '1.3' ], 50 default='1.3', 51 help='Type of spec to generate') 52 53 parser.add_argument('-registry', action='store', 54 default=None, 55 help='Path to API XML registry file specifying version and extension dependencies') 56 parser.add_argument('-apiname', action='store', 57 default=None, 58 help='API name to generate') 59 60 parser.add_argument('-n', action='store_true', dest='dryrun', 61 help='Only prints actions, do not execute them') 62 parser.add_argument('-v', action='store_true', dest='verbose', 63 help='Print actions before executing them') 64 65 (results, options) = parser.parse_known_args() 66 67 # Ensure genpath is an absolute path, not relative 68 if results.genpath[0] != '/': 69 results.genpath = os.getcwd() + '/' + results.genpath 70 71 # Look for scripts/extdependency.py 72 # This requires makeSpec to be invoked from the repository root, but we 73 # could derive that path. 74 sys.path.insert(0, 'scripts') 75 from extdependency import ApiDependencies 76 deps = ApiDependencies(results.registry, results.apiname) 77 78 # List of versions to build with from the requested -version 79 # This should come from the extdependency module as well, eventually 80 versionDict = { 81 '1.0' : [ 'VK_VERSION_1_0' ], 82 '1.1' : [ 'VK_VERSION_1_0', 'VK_VERSION_1_1' ], 83 '1.2' : [ 'VK_VERSION_1_0', 'VK_VERSION_1_1', 'VK_VERSION_1_2' ], 84 '1.3' : [ 'VK_VERSION_1_0', 'VK_VERSION_1_1', 'VK_VERSION_1_2', 'VK_VERSION_1_3' ], 85 } 86 versions = 'VERSIONS={}'.format(' '.join(versionDict[results.version])) 87 88 # List of extensions to build with from the requested -spec 89 # Also construct a spec title 90 # This should respect version dependencies as well 91 if results.spec == 'core': 92 title = '' 93 exts = set() 94 if results.spec == 'khr': 95 title = 'with all KHR extensions' 96 exts = set(deps.khrExtensions()) 97 elif results.spec == 'all': 98 title = 'with all registered extensions' 99 exts = set(deps.allExtensions()) 100 101 # List of explicitly requested extension and all its dependencies 102 extraexts = set() 103 for name in results.extension: 104 if name in deps.allExtensions(): 105 extraexts.add(name) 106 extraexts.update(deps.children(name)) 107 else: 108 raise Exception(f'ERROR: unknown extension {name}') 109 110 # See if any explicitly requested extensions are not implicitly requested 111 # Add any such extensions to the spec title 112 extraexts -= exts 113 if len(extraexts) > 0: 114 exts.update(extraexts) 115 if title != '': 116 title += ' and ' + ', '.join(sorted(extraexts)) 117 else: 118 title += 'with ' + ', '.join(sorted(extraexts)) 119 120 if title != '': 121 title = '(' + title + ')' 122 123 # Finally, actually invoke make as needed for the targets 124 args = [ 'make', 'GENERATED=' + results.genpath ] 125 126 if results.clean: 127 # If OUTDIR is set on the command line, pass it to the 'clean' 128 # target so it is cleaned as well. 129 cleanopts = ['clean'] 130 for opt in options: 131 if opt[:7] == 'OUTDIR=': 132 cleanopts.append(opt) 133 try: 134 execute(args + cleanopts, results) 135 except: 136 sys.exit(1) 137 138 args.append(versions) 139 140 # The actual target 141 if len(exts) > 0: 142 args.append(f'EXTENSIONS={" ".join(sorted(exts))}') 143 args.append(f'APITITLE={title}') 144 args += options 145 146 try: 147 execute(args, results) 148 except: 149 sys.exit(1) 150