| #!/usr/bin/env python3 |
| # |
| # Copyright 2020-2023 The Khronos Group Inc. |
| # |
| # SPDX-License-Identifier: Apache-2.0 |
| |
| # Build a spec with requested extension sets and options. |
| # |
| # Usage: makeSpec script-options make-options |
| # Script options are parsed by this script before invoking 'make': |
| # -genpath path - directory for generated files and outputs |
| # -spec core - make a spec with no extensions (default) |
| # -spec khr - make a spec with all KHR extensions |
| # -spec ratified - make a spec with all ratified (KHR + some EXT) extensions |
| # -spec all - make a spec with all registered extensions |
| # -version {1.0 | 1.1 | 1.2 | 1.3 | sc1.0} - make a spec with this core version |
| # -ext name - add specified extension and its dependencies |
| # -clean - clean generated files before building |
| # -registry path - API XML to use instead of default |
| # -apiname name - API name to use instead of default |
| # -test - Build the test spec instead |
| # -v - verbose, print actions before executing them |
| # -n - dry-run, print actions instead of executing them |
| # make-options - all other options are passed to 'make', including |
| # requested build targets |
| |
| import argparse, copy, io, os, re, string, subprocess, sys |
| |
| def execute(args, results): |
| if results.verbose or results.dryrun: |
| print("'" + "' '".join(args) + "'") |
| if not results.dryrun: |
| subprocess.check_call(args) |
| |
| if __name__ == '__main__': |
| parser = argparse.ArgumentParser() |
| |
| parser.add_argument('-clean', action='store_true', |
| help='Clean generated files before building') |
| parser.add_argument('-extension', action='append', |
| default=[], |
| help='Specify a required extension or extensions to add to targets') |
| parser.add_argument('-genpath', action='store', |
| default='gen', |
| help='Path to directory containing generated files') |
| parser.add_argument('-spec', action='store', |
| choices=[ 'core', 'khr', 'ratified', 'all' ], |
| default='core', |
| help='Type of spec to generate') |
| parser.add_argument('-version', action='store', |
| choices=[ '1.0', '1.1', '1.2', '1.3', 'sc1.0' ], |
| default='1.3', |
| help='Type of spec to generate') |
| parser.add_argument('-registry', action='store', |
| default=None, |
| help='Path to API XML registry file specifying version and extension dependencies') |
| parser.add_argument('-apiname', action='store', |
| default=None, |
| help='API name to generate') |
| parser.add_argument('-test', action='store_true', |
| help='Build the test spec instead of the Vulkan spec') |
| parser.add_argument('-n', action='store_true', dest='dryrun', |
| help='Only prints actions, do not execute them') |
| parser.add_argument('-v', action='store_true', dest='verbose', |
| help='Print actions before executing them') |
| |
| (results, options) = parser.parse_known_args() |
| |
| # Ensure genpath is an absolute path, not relative |
| if results.genpath[0] != '/': |
| results.genpath = os.getcwd() + '/' + results.genpath |
| |
| # Look for scripts/extdependency.py |
| # This requires makeSpec to be invoked from the repository root, but we |
| # could derive that path. |
| sys.path.insert(0, 'scripts') |
| from extdependency import ApiDependencies |
| deps = ApiDependencies(results.registry, results.apiname) |
| |
| # List of versions to build with from the requested -version |
| # This should come from the extdependency module as well, eventually |
| #@ Note that at present, building sc1.0 does *not* include Vulkan 1.3 automatically. |
| versionDict = { |
| '1.0' : [ 'VK_VERSION_1_0' ], |
| '1.1' : [ 'VK_VERSION_1_0', 'VK_VERSION_1_1' ], |
| '1.2' : [ 'VK_VERSION_1_0', 'VK_VERSION_1_1', 'VK_VERSION_1_2' ], |
| '1.3' : [ 'VK_VERSION_1_0', 'VK_VERSION_1_1', 'VK_VERSION_1_2', 'VK_VERSION_1_3' ], |
| 'sc1.0' : [ 'VK_VERSION_1_0', 'VK_VERSION_1_1', 'VK_VERSION_1_2', 'VKSC_VERSION_1_0' ], |
| } |
| versions = 'VERSIONS={}'.format(' '.join(versionDict[results.version])) |
| |
| # List of extensions to build with from the requested -spec |
| # Also construct a spec title |
| # This should respect version dependencies as well |
| if results.spec == 'core': |
| title = '' |
| exts = set() |
| elif results.spec == 'khr': |
| title = 'with all KHR extensions' |
| exts = set(deps.khrExtensions()) |
| elif results.spec == 'ratified': |
| title = 'with all ratified extensions' |
| exts = set(deps.ratifiedExtensions()) |
| elif results.spec == 'all': |
| title = 'with all registered extensions' |
| exts = set(deps.allExtensions()) |
| |
| # List of explicitly requested extension and all its supported dependencies |
| extraexts = set() |
| for name in results.extension: |
| if name in deps.allExtensions(): |
| extraexts.add(name) |
| for dep in deps.children(name): |
| if dep in deps.allExtensions(): |
| extraexts.update({dep}) |
| else: |
| raise Exception(f'ERROR: unknown extension {name}') |
| |
| # See if any explicitly requested extensions are not implicitly requested |
| # Add any such extensions to the spec title |
| extraexts -= exts |
| if len(extraexts) > 0: |
| exts.update(extraexts) |
| if title != '': |
| title += ' and ' + ', '.join(sorted(extraexts)) |
| else: |
| title += 'with ' + ', '.join(sorted(extraexts)) |
| |
| if title != '': |
| title = '(' + title + ')' |
| |
| # Finally, actually invoke make as needed for the targets |
| args = [ 'make', 'GENERATED=' + results.genpath ] |
| |
| if results.clean: |
| # If OUTDIR is set on the command line, pass it to the 'clean' |
| # target so it is cleaned as well. |
| cleanopts = ['clean'] |
| for opt in options: |
| if opt[:7] == 'OUTDIR=': |
| cleanopts.append(opt) |
| try: |
| execute(args + cleanopts, results) |
| except: |
| sys.exit(1) |
| |
| # Use the test spec if specified. This is used solely by self tests. |
| rootdir = os.path.dirname(os.path.abspath(__file__)) |
| if results.test: |
| # Set the spec source to the test spec |
| args.append(f'SPECSRC={rootdir}/build_tests/testspec.adoc') |
| args.append(f'SPECDIR={rootdir}/build_tests/') |
| # Make sure the build is invariant |
| args.append('SPECREVISION=1.2.3') |
| args.append('SPECDATE=\\"2100-11-22 00:33:44Z\\"') |
| args.append('SPECREMARK=\\"test build\\"') |
| |
| args.append(versions) |
| |
| # The actual target |
| if len(exts) > 0: |
| args.append(f'EXTENSIONS={" ".join(sorted(exts))}') |
| args.append(f'APITITLE={title}') |
| args += options |
| |
| try: |
| execute(args, results) |
| except: |
| sys.exit(1) |