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