xref: /aosp_15_r20/external/OpenCL-CTS/dependencies/ocl-stubs/apis_generator.py (revision 6467f958c7de8070b317fc65bcb0f6472e388d82)
1*6467f958SSadaf Ebrahimi#!/usr/bin/env python3
2*6467f958SSadaf Ebrahimi"""apis_generator.py - Generate a C++ interface that automates loading OpenCL.
3*6467f958SSadaf Ebrahimi
4*6467f958SSadaf EbrahimiUsage: apis_generator.py <headerPaths...>
5*6467f958SSadaf Ebrahimi
6*6467f958SSadaf EbrahimiThe generated code looks roughly like this:
7*6467f958SSadaf Ebrahimi------------------------------------------------------------------------
8*6467f958SSadaf Ebrahimi
9*6467f958SSadaf Ebrahimi// apis.h
10*6467f958SSadaf Ebrahimi
11*6467f958SSadaf EbrahimiCL_MACRO ( returnType, funcname, (fargs...), (callArgs...) )
12*6467f958SSadaf Ebrahimi
13*6467f958SSadaf Ebrahimi"""
14*6467f958SSadaf Ebrahimi
15*6467f958SSadaf Ebrahimiimport os.path
16*6467f958SSadaf Ebrahimiimport re
17*6467f958SSadaf Ebrahimiimport sys
18*6467f958SSadaf Ebrahimi
19*6467f958SSadaf EbrahimiGENERATED_FILE_WARNING = """
20*6467f958SSadaf Ebrahimi/*
21*6467f958SSadaf Ebrahimi * This file is generated by {}
22*6467f958SSadaf Ebrahimi * Do not edit this file directly.
23*6467f958SSadaf Ebrahimi */""".format(os.path.basename(__file__))
24*6467f958SSadaf Ebrahimi
25*6467f958SSadaf EbrahimiMACRO_GUARD = """
26*6467f958SSadaf Ebrahimi#ifndef CL_MACRO
27*6467f958SSadaf Ebrahimi#error You need to define CL_MACRO before including apis
28*6467f958SSadaf Ebrahimi#endif"""
29*6467f958SSadaf Ebrahimi
30*6467f958SSadaf Ebrahimi
31*6467f958SSadaf Ebrahimidef include_for_header(header):
32*6467f958SSadaf Ebrahimi  return '#include <CL/{}>'.format(header)
33*6467f958SSadaf Ebrahimi
34*6467f958SSadaf Ebrahimi
35*6467f958SSadaf Ebrahimidef extract_license_lines(lines):
36*6467f958SSadaf Ebrahimi  license_lines = []
37*6467f958SSadaf Ebrahimi  for line in lines:
38*6467f958SSadaf Ebrahimi    license_lines.append(line)
39*6467f958SSadaf Ebrahimi    if line.find('*/') != -1:
40*6467f958SSadaf Ebrahimi      return license_lines
41*6467f958SSadaf Ebrahimi  sys.exit("License text didn't terminate")
42*6467f958SSadaf Ebrahimi
43*6467f958SSadaf Ebrahimi
44*6467f958SSadaf Ebrahimiassert (extract_license_lines(['/* LICENSE */',
45*6467f958SSadaf Ebrahimi                               'something']) == ['/* LICENSE */'])
46*6467f958SSadaf Ebrahimiassert (extract_license_lines(['/* LICENSE', ' * TEXT */',
47*6467f958SSadaf Ebrahimi                               'something']) == ['/* LICENSE', ' * TEXT */'])
48*6467f958SSadaf Ebrahimiassert (extract_license_lines(['/* LICENSE', ' * TEXT', ' */', 'something'
49*6467f958SSadaf Ebrahimi                              ]) == ['/* LICENSE', ' * TEXT', ' */'])
50*6467f958SSadaf Ebrahimi
51*6467f958SSadaf Ebrahimi
52*6467f958SSadaf Ebrahimidef parse_arg_strs(str):
53*6467f958SSadaf Ebrahimi  paren_depth = 0
54*6467f958SSadaf Ebrahimi  current_arg = ''
55*6467f958SSadaf Ebrahimi  ret = []
56*6467f958SSadaf Ebrahimi  for c in str:
57*6467f958SSadaf Ebrahimi    if c == '(':
58*6467f958SSadaf Ebrahimi      paren_depth += 1
59*6467f958SSadaf Ebrahimi    elif c == ')':
60*6467f958SSadaf Ebrahimi      paren_depth -= 1
61*6467f958SSadaf Ebrahimi    if c == ',' and paren_depth == 0:
62*6467f958SSadaf Ebrahimi      ret.append(current_arg)
63*6467f958SSadaf Ebrahimi      current_arg = ''
64*6467f958SSadaf Ebrahimi    else:
65*6467f958SSadaf Ebrahimi      current_arg += c
66*6467f958SSadaf Ebrahimi  if current_arg != '':
67*6467f958SSadaf Ebrahimi    ret.append(current_arg)
68*6467f958SSadaf Ebrahimi  return ret
69*6467f958SSadaf Ebrahimi
70*6467f958SSadaf Ebrahimi
71*6467f958SSadaf Ebrahimidef process_type(raw):
72*6467f958SSadaf Ebrahimi  # strip redundant [] (where one is before the name)
73*6467f958SSadaf Ebrahimi  raw = re.sub(r'(\[[0-9]*\])\s*(\w+)\s*\[[0-9]*\]', r'\2\1', raw)
74*6467f958SSadaf Ebrahimi  # strip cases where the name comment hinted at the number of elements in an array
75*6467f958SSadaf Ebrahimi  raw = re.sub(r'\*\s*(\w+)\s*\[[0-9]+\]', r'*\1', raw)
76*6467f958SSadaf Ebrahimi  raw = ' '.join(raw.split())
77*6467f958SSadaf Ebrahimi  return raw
78*6467f958SSadaf Ebrahimi
79*6467f958SSadaf Ebrahimi
80*6467f958SSadaf Ebrahimidef parse_api(api_signature):
81*6467f958SSadaf Ebrahimi  m = None
82*6467f958SSadaf Ebrahimi
83*6467f958SSadaf Ebrahimi  api_signature = re.sub(r'\bextern\b', '', api_signature)
84*6467f958SSadaf Ebrahimi  api_signature = re.sub('CL_\w+', '', api_signature)
85*6467f958SSadaf Ebrahimi
86*6467f958SSadaf Ebrahimi  m = re.match(r'\s*(.*)\s+(\w+)\((.*)\)\s*;', api_signature)
87*6467f958SSadaf Ebrahimi  if m == None:
88*6467f958SSadaf Ebrahimi    print(api_signature)
89*6467f958SSadaf Ebrahimi
90*6467f958SSadaf Ebrahimi  assert (m is not None)
91*6467f958SSadaf Ebrahimi  assert (len(m.groups()) == 3)
92*6467f958SSadaf Ebrahimi  arg_strs = None
93*6467f958SSadaf Ebrahimi  if re.match('\s*void\s*', m.group(3)):
94*6467f958SSadaf Ebrahimi    arg_strs = []
95*6467f958SSadaf Ebrahimi  else:
96*6467f958SSadaf Ebrahimi    arg_strs = parse_arg_strs(m.group(3))
97*6467f958SSadaf Ebrahimi  args = []
98*6467f958SSadaf Ebrahimi  for arg_str in arg_strs:
99*6467f958SSadaf Ebrahimi    nm = re.search(r'(\w+)\s*(\)|\[|$)', arg_str)
100*6467f958SSadaf Ebrahimi    assert (nm is not None)
101*6467f958SSadaf Ebrahimi    args.append({'type': process_type(arg_str), 'name': nm.group(1)})
102*6467f958SSadaf Ebrahimi  return {'return': m.group(1).strip(), 'name': m.group(2), 'args': args}
103*6467f958SSadaf Ebrahimi
104*6467f958SSadaf Ebrahimi
105*6467f958SSadaf Ebrahimidef extract_apis(lines):
106*6467f958SSadaf Ebrahimi  state = 'scanning'
107*6467f958SSadaf Ebrahimi  apis = []
108*6467f958SSadaf Ebrahimi  api_signature = ''
109*6467f958SSadaf Ebrahimi  for line in lines:
110*6467f958SSadaf Ebrahimi    if state == 'scanning':
111*6467f958SSadaf Ebrahimi      if line.find('CL_API_ENTRY') != -1 and line.find('typedef') == -1:
112*6467f958SSadaf Ebrahimi        api_signature = line
113*6467f958SSadaf Ebrahimi        if line.find(';') != -1:
114*6467f958SSadaf Ebrahimi          apis.append(
115*6467f958SSadaf Ebrahimi              parse_api(
116*6467f958SSadaf Ebrahimi                  api_signature.replace('/*', '').replace('*/', '').replace(
117*6467f958SSadaf Ebrahimi                      'CL_CALLBACK ', '')))
118*6467f958SSadaf Ebrahimi          api_signature = ''
119*6467f958SSadaf Ebrahimi        else:
120*6467f958SSadaf Ebrahimi          state = 'expectAPILine'
121*6467f958SSadaf Ebrahimi    elif state == 'expectAPILine':
122*6467f958SSadaf Ebrahimi      api_signature += ' ' + line
123*6467f958SSadaf Ebrahimi      if line.find(';') != -1:
124*6467f958SSadaf Ebrahimi        apis.append(
125*6467f958SSadaf Ebrahimi            parse_api(
126*6467f958SSadaf Ebrahimi                api_signature.replace('/*', '').replace('*/', '').replace(
127*6467f958SSadaf Ebrahimi                    'CL_CALLBACK ', '')))
128*6467f958SSadaf Ebrahimi        api_signature = ''
129*6467f958SSadaf Ebrahimi        state = 'scanning'
130*6467f958SSadaf Ebrahimi  return apis
131*6467f958SSadaf Ebrahimi
132*6467f958SSadaf Ebrahimi
133*6467f958SSadaf Ebrahimidef generate_apis(apis):
134*6467f958SSadaf Ebrahimi  print(GENERATED_FILE_WARNING)
135*6467f958SSadaf Ebrahimi  print()
136*6467f958SSadaf Ebrahimi  print(MACRO_GUARD)
137*6467f958SSadaf Ebrahimi  print()
138*6467f958SSadaf Ebrahimi
139*6467f958SSadaf Ebrahimi  for api in apis:
140*6467f958SSadaf Ebrahimi    fargs = (arg['type'] for arg in api['args'])
141*6467f958SSadaf Ebrahimi    cargs = (arg['name'] for arg in api['args'])
142*6467f958SSadaf Ebrahimi    print('CL_MACRO( {}, {}, ({}), ({}) )\n'.format(api['return'], api['name'],
143*6467f958SSadaf Ebrahimi                                                    ', '.join(fargs),
144*6467f958SSadaf Ebrahimi                                                    ', '.join(cargs)))
145*6467f958SSadaf Ebrahimi
146*6467f958SSadaf Ebrahimi
147*6467f958SSadaf Ebrahimidef main():
148*6467f958SSadaf Ebrahimi  headers = sys.argv[1:]
149*6467f958SSadaf Ebrahimi  apis = []
150*6467f958SSadaf Ebrahimi
151*6467f958SSadaf Ebrahimi  with open(headers[0]) as header:
152*6467f958SSadaf Ebrahimi    lines = [line.strip() for line in header.readlines()]
153*6467f958SSadaf Ebrahimi    license_lines = extract_license_lines(lines)
154*6467f958SSadaf Ebrahimi
155*6467f958SSadaf Ebrahimi  for header_name in headers:
156*6467f958SSadaf Ebrahimi    with open(header_name) as header:
157*6467f958SSadaf Ebrahimi      lines = [line.strip() for line in header.readlines()]
158*6467f958SSadaf Ebrahimi      apis = apis + extract_apis(lines)
159*6467f958SSadaf Ebrahimi
160*6467f958SSadaf Ebrahimi  generate_apis(apis)
161*6467f958SSadaf Ebrahimi
162*6467f958SSadaf Ebrahimi
163*6467f958SSadaf Ebrahimiif __name__ == '__main__':
164*6467f958SSadaf Ebrahimi  main()
165