blob: ce021a7fa07b65b75c71222220e7f72be3f41792 [file] [log] [blame]
#!/usr/bin/python3
#
# Copyright (c) 2013-2019 The Khronos Group Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import cProfile
import pdb
import string
import sys
import time
import os
# Simple timer functions
startTime = None
def startTimer(timeit):
global startTime
if timeit:
startTime = time.process_time()
def endTimer(timeit, msg):
global startTime
if timeit:
endTime = time.process_time()
write(msg, endTime - startTime, file=sys.stderr)
startTime = None
# Turn a list of strings into a regexp string matching exactly those strings
def makeREstring(list, default=None):
if len(list) > 0 or default is None:
return '^(' + '|'.join(list) + ')$'
else:
return default
# Returns a directory of [ generator function, generator options ] indexed
# by specified short names. The generator options incorporate the following
# parameters:
#
# args is an parsed argument object; see below for the fields that are used.
def makeGenOpts(args):
global genOpts
genOpts = {}
# Default class of extensions to include, or None
defaultExtensions = args.defaultExtensions
# Additional extensions to include (list of extensions)
extensions = args.extension
# Extensions to remove (list of extensions)
removeExtensions = args.removeExtensions
# Extensions to emit (list of extensions)
emitExtensions = args.emitExtensions
# Features to include (list of features)
features = args.feature
# Whether to disable inclusion protect in headers
protect = args.protect
# Output target directory
directory = args.directory
# Descriptive names for various regexp patterns used to select
# versions and extensions
allFeatures = allExtensions = '.*'
noFeatures = noExtensions = None
# Turn lists of names/patterns into matching regular expressions
addExtensionsPat = makeREstring(extensions, None)
removeExtensionsPat = makeREstring(removeExtensions, None)
emitExtensionsPat = makeREstring(emitExtensions, allExtensions)
featuresPat = makeREstring(features, allFeatures)
# Copyright text prefixing all headers (list of strings).
prefixStrings = [
'/*',
'** Copyright (c) 2015-2018 The Khronos Group Inc.',
'**',
'** Licensed under the Apache License, Version 2.0 (the "License");',
'** you may not use this file except in compliance with the License.',
'** You may obtain a copy of the License at',
'**',
'** http://www.apache.org/licenses/LICENSE-2.0',
'**',
'** Unless required by applicable law or agreed to in writing, software',
'** distributed under the License is distributed on an "AS IS" BASIS,',
'** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.',
'** See the License for the specific language governing permissions and',
'** limitations under the License.',
'*/',
''
]
# Text specific to Vulkan headers
vkPrefixStrings = [
'/*',
'** This header is generated from the Khronos Vulkan XML API Registry.',
'**',
'*/',
''
]
# Defaults for generating re-inclusion protection wrappers (or not)
protectFeature = protect
# An API style conventions object
conventions = VulkanConventions()
# Helper file generator options for typemap_helper.h
genOpts['vk_typemap_helper.h'] = [
HelperFileOutputGenerator,
HelperFileOutputGeneratorOptions(
conventions=conventions,
filename='vk_typemap_helper.h',
directory=directory,
apiname='vulkan',
profile=None,
versions=featuresPat,
emitversions=featuresPat,
defaultExtensions='vulkan',
addExtensions=addExtensionsPat,
removeExtensions=removeExtensionsPat,
emitExtensions=emitExtensionsPat,
prefixText=prefixStrings + vkPrefixStrings,
protectFeature=False,
apicall='VKAPI_ATTR ',
apientry='VKAPI_CALL ',
apientryp='VKAPI_PTR *',
alignFuncParam=48,
expandEnumerants=False,
helper_file_type='typemap_helper_header')
]
# Options for mock ICD header
genOpts['mock_icd.h'] = [
MockICDOutputGenerator,
MockICDGeneratorOptions(
conventions=conventions,
filename='mock_icd.h',
directory=directory,
apiname='vulkan',
profile=None,
versions=featuresPat,
emitversions=featuresPat,
defaultExtensions='vulkan',
addExtensions=addExtensionsPat,
removeExtensions=removeExtensionsPat,
emitExtensions=emitExtensionsPat,
prefixText=prefixStrings + vkPrefixStrings,
protectFeature=False,
apicall='VKAPI_ATTR ',
apientry='VKAPI_CALL ',
apientryp='VKAPI_PTR *',
alignFuncParam=48,
expandEnumerants=False,
helper_file_type='mock_icd_header')
]
# Options for mock ICD cpp
genOpts['mock_icd.cpp'] = [
MockICDOutputGenerator,
MockICDGeneratorOptions(
conventions=conventions,
filename='mock_icd.cpp',
directory=directory,
apiname='vulkan',
profile=None,
versions=featuresPat,
emitversions=featuresPat,
defaultExtensions='vulkan',
addExtensions=addExtensionsPat,
removeExtensions=removeExtensionsPat,
emitExtensions=emitExtensionsPat,
prefixText=prefixStrings + vkPrefixStrings,
protectFeature=False,
apicall='VKAPI_ATTR ',
apientry='VKAPI_CALL ',
apientryp='VKAPI_PTR *',
alignFuncParam=48,
expandEnumerants=False,
helper_file_type='mock_icd_source')
]
# Options for vulkaninfo.hpp
genOpts['vulkaninfo.hpp'] = [
VulkanInfoGenerator,
VulkanInfoGeneratorOptions(
conventions=conventions,
filename='vulkaninfo.hpp',
directory=directory,
apiname='vulkan',
profile=None,
versions=featuresPat,
emitversions=featuresPat,
defaultExtensions='vulkan',
addExtensions=addExtensionsPat,
removeExtensions=removeExtensionsPat,
emitExtensions=emitExtensionsPat,
prefixText=prefixStrings + vkPrefixStrings,
protectFeature=False,
apicall='VKAPI_ATTR ',
apientry='VKAPI_CALL ',
apientryp='VKAPI_PTR *',
alignFuncParam=48,
expandEnumerants=False)
]
# Generate a target based on the options in the matching genOpts{} object.
# This is encapsulated in a function so it can be profiled and/or timed.
# The args parameter is an parsed argument object containing the following
# fields that are used:
# target - target to generate
# directory - directory to generate it in
# protect - True if re-inclusion wrappers should be created
# extensions - list of additional extensions to include in generated
# interfaces
def genTarget(args):
global genOpts
# Create generator options with specified parameters
makeGenOpts(args)
if (args.target in genOpts.keys()):
createGenerator = genOpts[args.target][0]
options = genOpts[args.target][1]
if not args.quiet:
write('* Building', options.filename, file=sys.stderr)
write('* options.versions =',
options.versions, file=sys.stderr)
write('* options.emitversions =',
options.emitversions, file=sys.stderr)
write('* options.defaultExtensions =',
options.defaultExtensions, file=sys.stderr)
write('* options.addExtensions =',
options.addExtensions, file=sys.stderr)
write('* options.removeExtensions =',
options.removeExtensions, file=sys.stderr)
write('* options.emitExtensions =',
options.emitExtensions, file=sys.stderr)
startTimer(args.time)
gen = createGenerator(errFile=errWarn,
warnFile=errWarn,
diagFile=diag)
reg.setGenerator(gen)
reg.apiGen(options)
if not args.quiet:
write('* Generated', options.filename, file=sys.stderr)
endTimer(args.time, '* Time to generate ' + options.filename + ' =')
else:
write('No generator options for unknown target:',
args.target, file=sys.stderr)
# -feature name
# -extension name
# For both, "name" may be a single name, or a space-separated list
# of names, or a regular expression.
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-defaultExtensions', action='store',
default='vulkan',
help='Specify a single class of extensions to add to targets')
parser.add_argument('-extension', action='append',
default=[],
help='Specify an extension or extensions to add to targets')
parser.add_argument('-removeExtensions', action='append',
default=[],
help='Specify an extension or extensions to remove from targets')
parser.add_argument('-emitExtensions', action='append',
default=[],
help='Specify an extension or extensions to emit in targets')
parser.add_argument('-feature', action='append',
default=[],
help='Specify a core API feature name or names to add to targets')
parser.add_argument('-debug', action='store_true',
help='Enable debugging')
parser.add_argument('-dump', action='store_true',
help='Enable dump to stderr')
parser.add_argument('-diagfile', action='store',
default=None,
help='Write diagnostics to specified file')
parser.add_argument('-errfile', action='store',
default=None,
help='Write errors and warnings to specified file instead of stderr')
parser.add_argument('-noprotect', dest='protect', action='store_false',
help='Disable inclusion protection in output headers')
parser.add_argument('-profile', action='store_true',
help='Enable profiling')
parser.add_argument('-registry', action='store',
default='vk.xml',
help='Use specified registry file instead of vk.xml')
parser.add_argument('-time', action='store_true',
help='Enable timing')
parser.add_argument('-validate', action='store_true',
help='Enable group validation')
parser.add_argument('-o', action='store', dest='directory',
default='.',
help='Create target and related files in specified directory')
parser.add_argument('target', metavar='target', nargs='?',
help='Specify target')
parser.add_argument('-quiet', action='store_true', default=True,
help='Suppress script output during normal execution.')
parser.add_argument('-verbose', action='store_false', dest='quiet', default=True,
help='Enable script output during normal execution.')
# This argument tells us where to load the script from the Vulkan-Headers registry
parser.add_argument('-scripts', action='store',
help='Find additional scripts in this directory')
args = parser.parse_args()
# default scripts path to be same as registry
if not args.scripts:
args.scripts = os.path.dirname(args.registry)
scripts_directory_path = os.path.dirname(os.path.abspath(__file__))
registry_headers_path = os.path.join(scripts_directory_path, args.scripts)
sys.path.insert(0, registry_headers_path)
from reg import *
from generator import write
from cgenerator import CGeneratorOptions, COutputGenerator
# Generator Modifications
from mock_icd_generator import MockICDGeneratorOptions, MockICDOutputGenerator
from vulkan_tools_helper_file_generator import HelperFileOutputGenerator, HelperFileOutputGeneratorOptions
from vulkaninfo_generator import VulkanInfoGenerator, VulkanInfoGeneratorOptions
# Temporary workaround for vkconventions python2 compatibility
import abc
abc.ABC = abc.ABCMeta('ABC', (object,), {})
from vkconventions import VulkanConventions
# This splits arguments which are space-separated lists
args.feature = [name for arg in args.feature for name in arg.split()]
args.extension = [name for arg in args.extension for name in arg.split()]
# Load & parse registry
reg = Registry()
startTimer(args.time)
tree = etree.parse(args.registry)
endTimer(args.time, '* Time to make ElementTree =')
if args.debug:
pdb.run('reg.loadElementTree(tree)')
else:
startTimer(args.time)
reg.loadElementTree(tree)
endTimer(args.time, '* Time to parse ElementTree =')
if (args.validate):
reg.validateGroups()
if (args.dump):
write('* Dumping registry to regdump.txt', file=sys.stderr)
reg.dumpReg(filehandle=open('regdump.txt', 'w', encoding='utf-8'))
# create error/warning & diagnostic files
if (args.errfile):
errWarn = open(args.errfile, 'w', encoding='utf-8')
else:
errWarn = sys.stderr
if (args.diagfile):
diag = open(args.diagfile, 'w', encoding='utf-8')
else:
diag = None
if (args.debug):
pdb.run('genTarget(args)')
elif (args.profile):
import cProfile
import pstats
cProfile.run('genTarget(args)', 'profile.txt')
p = pstats.Stats('profile.txt')
p.strip_dirs().sort_stats('time').print_stats(50)
else:
genTarget(args)