| #!/usr/bin/env python3 | |
| # | |
| # Copyright 2020-2024 The Khronos Group Inc. | |
| # | |
| # SPDX-License-Identifier: Apache-2.0 | |
| # Build OpenCL specification 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 all - make a spec with all available registered extensions | |
| # -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', 'all' ], | |
| default='core', | |
| 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 extensions to build with from the requested -spec | |
| # Also construct a spec title | |
| # This should respect version dependencies as well | |
| # Temporary workaround, as the spec markup does not include non-khr | |
| # extension appendices yet. | |
| if results.spec == 'all': | |
| results.spec = 'khr' | |
| print("WARNING: 'all' argument to -results interpreted as 'khr' at present", file=sys.stderr) | |
| if results.spec == 'core': | |
| title = '' | |
| exts = set() | |
| elif results.spec == 'khr': | |
| title = 'with all KHR extensions' | |
| exts = set(deps.khrExtensions()) | |
| 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\\"') | |
| # 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) |