blob: b16faa42de341b10e9c61bffac1816ff5ce34f61 [file] [edit]
#!/usr/bin/python3
# Copyright 2019-2024 The Khronos Group Inc.
# SPDX-License-Identifier: Apache-2.0
from collections import OrderedDict
import argparse
import sys
import os
import urllib
import xml.etree.ElementTree as etree
import urllib.request
def parse_xml(path):
file = urllib.request.urlopen(path) if path.startswith("http") else open(
path, 'r')
with file:
tree = etree.parse(file)
return tree
# File Header:
def GetHeader():
return """// Copyright 2017-2024 The Khronos Group.
// SPDX-License-Identifier: CC-BY-4.0
"""
# File Footer:
def GetFooter():
return """
"""
def FullNote(name, added_in, deprecated_by):
# Four patterns: (1) always present in OpenCL, (2) added after 1.0, (3) in
# 1.0 but now deprecated, and (4) added after 1.0 but now deprecated.
if added_in == "1.0" and deprecated_by == None:
return "\n// Intentionally empty, %s has always been present." % name
if added_in != "1.0" and deprecated_by == None:
return "\nIMPORTANT: {%s} is {missing_before} version %s." % (name, added_in)
if added_in == "1.0" and deprecated_by != None:
return "\nIMPORTANT: {%s} is {deprecated_by} version %s." % (name, deprecated_by)
if added_in != "1.0" and deprecated_by != None:
return "\nIMPORTANT: {%s} is {missing_before} version %s and {deprecated_by} version %s." % (name, added_in, deprecated_by)
def ShortNote(name, added_in, deprecated_by):
# Four patterns: (1) always present in OpenCL, (2) added after 1.0, (3) in
# 1.0 but now deprecated, and (4) added after 1.0 but now deprecated.
if added_in == "1.0" and deprecated_by == None:
return "// Intentionally empty, %s has always been present." % name
if added_in != "1.0" and deprecated_by == None:
return "{missing_before} version %s." % added_in
if added_in == "1.0" and deprecated_by != None:
return "{deprecated_by} version %s." % deprecated_by
if added_in != "1.0" and deprecated_by != None:
return "{missing_before} version %s and {deprecated_by} version %s." % (added_in, deprecated_by)
# Find feature or extension groups that are parents of a <feature> or
# <extension> <require> <${entry_type}> tag, and then find all the
# ${entry_type} within each hierarchy:
def process_xml(spec, entry_type, note_printer):
numberOfEntries = 0
numberOfNewEntries = 0
numberOfDeprecatedEntries = 0
# Track the APIs which have already had a version file written, to avoid
# a couple of cases like CL_DEPTH, which is required by both a core
# version and an extension.
seen_apis = set()
for feature_type in [ 'feature', 'extension' ]:
for feature in spec.findall(f'.//{feature_type}/require/{entry_type}/../..'):
for entry in feature.findall(f'.//{entry_type}'):
name = entry.get('name')
deprecated_by = None
numberOfEntries += 1
if feature_type == 'feature':
added_in = feature.get('number')
# All the groups that this specific API ${entry_type} belongs.
categories = spec.findall(
'.//require[@comment]/%s[@name="%s"]/..' % (entry_type, name))
for category in categories:
comment = category.get('comment')
if "deprecated in OpenCL" in comment:
words = comment.split(" ")
assert " ".join(words[-4:-1]) == "deprecated in OpenCL"
assert deprecated_by == None # Can't deprecate something twice.
deprecated_by = words[-1]
else:
if name in seen_apis:
print(f'WARNING: {name} exists as both a core version and extension API in the XML')
print('This is not currently handled correctly - only the core version dependency is noted')
continue
# Extensions do not allow for deprecation
added_in = feature.get('name')
seen_apis.add(name)
versionFileName = os.path.join(args.directory, name + ".asciidoc")
with open(versionFileName, 'w') as versionFile:
versionFile.write(GetHeader())
versionFile.write(note_printer(name, added_in, deprecated_by))
versionFile.write(GetFooter())
numberOfNewEntries += 0 if added_in == "1.0" else 1
numberOfDeprecatedEntries += 0 if deprecated_by == None else 1
print('Found ' + str(numberOfEntries) + ' API ' + entry_type + 's, '
+ str(numberOfNewEntries) + " newer than 1.0, "
+ str(numberOfDeprecatedEntries) + " are deprecated.")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
'-registry',
action='store',
default='cl.xml',
help='Use specified registry file instead of cl.xml')
parser.add_argument(
'-o',
action='store',
dest='directory',
default='.',
help='Create target and related files in specified directory')
args = parser.parse_args()
specpath = args.registry
print('Generating version notes from: ' + specpath)
spec = parse_xml(specpath)
# Generate the API functions dictionaries:
process_xml(spec, "command", FullNote)
process_xml(spec, "enum", ShortNote)