xref: /aosp_15_r20/external/OpenCL-ICD-Loader/scripts/gen/__init__.py (revision 1cddb830dba8aa7c1cc1039338e56b3b9fa24952)
1# Copyright (c) 2020 The Khronos Group Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15from collections import OrderedDict
16from collections import namedtuple
17
18import argparse
19import sys
20import urllib
21import xml.etree.ElementTree as etree
22import urllib.request
23
24# parse_xml - Helper function to parse the XML file from a URL or local file.
25def parse_xml(path):
26    file = urllib.request.urlopen(path) if path.startswith("http") else open(path, 'r')
27    with file:
28        tree = etree.parse(file)
29        return tree
30
31# noneStr - returns string argument, or "" if argument is None.
32def noneStr(s):
33    if s:
34        return s
35    return ""
36
37def parse_args():
38    parser = argparse.ArgumentParser()
39
40    # To pull the latest registry file from GitHub, pass:
41    # -registry "https://raw.githubusercontent.com/KhronosGroup/OpenCL-Docs/main/xml/cl.xml"
42
43    parser.add_argument('-registry', action='store',
44                        default='cl.xml',
45                        help='Use specified registry file instead of cl.xml')
46    parser.add_argument('-o', action='store', dest='directory',
47                        default='.',
48                        help='Create target and related files in specified directory')
49
50    args = parser.parse_args()
51    return args
52
53def load_spec(args):
54    specpath = args.registry
55
56    print('Parsing XML file from: ' + specpath)
57    spec = parse_xml(specpath)
58    return spec
59
60def get_apisigs(spec):
61    # Generate the API function signatures dictionary:
62    apisigs = OrderedDict()
63    ApiSignature = namedtuple('ApiSignature', 'Name RetType Params Suffix')
64    ApiParam = namedtuple('ApiParam', 'Type TypeEnd Name')
65    print('Generating API signatures dictionary...')
66    for command in spec.findall('commands/command'):
67        suffix = noneStr(command.get('suffix'))
68        proto = command.find('proto')
69        ret = noneStr(proto.text)
70        name = ""
71        params = ""
72        for elem in proto:
73            if elem.tag == 'name':
74                name = noneStr(elem.text) + noneStr(elem.tail)
75            else:
76                ret = ret + noneStr(elem.text) + noneStr(elem.tail)
77        ret = ret.strip()
78        name = name.strip()
79
80        plist = []
81        for param in command.findall('param'):
82            ptype = noneStr(param.text)
83            ptypeend = ""
84            pname = ""
85            for elem in param:
86                if elem.tag == 'name':
87                    pname = noneStr(elem.text)
88                    ptypeend = noneStr(elem.tail)
89                else:
90                    ptype = ptype + noneStr(elem.text) + noneStr(elem.tail)
91            ptype = ptype.strip()
92            ptypeend = ptypeend.strip()
93            pname = pname.strip()
94            plist.append(ApiParam(ptype, ptypeend, pname))
95
96        # For an empty parameter list (for e.g. clUnloadCompiler), add a single
97        # unnamed void parameter to make generation easier.
98        if len(plist) == 0:
99            plist.append(ApiParam("void", "", ""))
100
101        apisigs[name] = ApiSignature(name, ret, plist, suffix)
102    return apisigs
103
104def get_apis(spec, apisigs):
105    # Generate the core API dictionary:
106    coreapis = OrderedDict()
107    print('Generating core API dictionary...')
108    for feature in spec.findall('feature'):
109        version = noneStr(feature.get('name'))
110
111        alist = []
112        for function in feature.findall('require/command'):
113            name = function.get('name')
114            alist.append(apisigs[name])
115        coreapis[version] = alist
116
117    # Generate the extensions API dictionary:
118    extapis = OrderedDict()
119    print('Generating API extensions dictionary...')
120    for feature in spec.findall('extensions/extension'):
121        extension = noneStr(feature.get('name'))
122
123        alist = []
124        for function in feature.findall('require/command'):
125            name = function.get('name')
126            alist.append(apisigs[name])
127        extapis[extension] = alist
128    return (coreapis, extapis)
129
130
131