blob: fade64a902269cfaf32d8a55d4fb005f4099ae63 [file] [log] [blame]
#!/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)