4 # Copyright 2016 Intel Corporation
6 # The source code contained or described herein and all documents related to the source code ("Material") are owned by
7 # Intel Corporation or its suppliers or licensors. Title to the Material remains with Intel Corporation or its
8 # suppliers and licensors. The Material contains trade secrets and proprietary and confidential information of Intel
9 # or its suppliers and licensors. The Material is protected by worldwide copyright and trade secret laws and treaty
10 # provisions. No part of the Material may be used, copied, reproduced, modified, published, uploaded, posted,
11 # transmitted, distributed, or disclosed in any way without Intel's prior express written permission.
13 # No license under any patent, copyright, trade secret or other intellectual property right is granted to
14 # or conferred upon you by disclosure or delivery of the Materials, either expressly, by implication, inducement,
15 # estoppel or otherwise. Any license under such intellectual property rights must be express and approved by Intel
19 # For details about script please contact following people:
20 # * [Version: 1.0] Walkowiak, Marcin <marcin.walkowiak@intel.com>
28 # Pattern that filters file names that are headers.
29 headerFileNamePattern = re.compile('^[a-zA-Z0-9_]+\\.[hH]$')
30 # Marker that marks API function/data member (at its beginning).
31 apiMemberMarker = 'CLDNN_API'
32 # Macros that should be expanded to API functions.
33 apiMacroMemberMatchers = [
34 (re.compile('^\\s*CLDNN_DECLARE_PRIMITIVE_TYPE_ID\\s*\\(\\s*([a-zA-Z0-9_]+)\\s*\\)\\s*;', re.MULTILINE),
35 'cldnn_primitive_type_id cldnn_\\1_type_id(cldnn_status* status)')
37 # C language and project reserved keywords (that cannot be used as function/parameter name).
39 'auto', 'else', 'long', 'switch', 'break', 'enum', 'register', 'typedef', 'case', 'extern', 'return', 'union',
40 'char', 'float', 'short', 'unsigned', 'const', 'for', 'signed', 'void', 'continue', 'goto', 'sizeof', 'volatile',
41 'default', 'if', 'static', 'while', 'do', 'int', 'struct', '_Packed', 'double'
43 # C language and project reserved keyword patterns (that cannot be used as function/parameter name).
44 reservedKeywordPatterns = [
45 re.compile('^__[a-z0-9_]+__$', re.IGNORECASE)
49 apiMemberMatcher = re.compile('^\\s*' + re.escape(apiMemberMarker) + '\\s+([^;]+);', re.MULTILINE)
50 typeIdentifierSplitter = re.compile('^(.*?)([a-zA-Z_][a-zA-Z0-9_]*)$')
53 def stripCommentsAndPreprocessor(content):
54 """ Strips out comments and preprocessor constructs from text written in C language (or compatible).
56 :param content: Text with code written in C language (or compatible).
58 :return: Content of C language code with comments and preprocessor constructs stripped out.
62 # 0 - normal context, start state
64 # 2 - string context, after \ character (character escape)
65 # 3 - normal context, after / character (possible comment)
66 # 4 - multi-line comment context
67 # 5 - multi-line comment context, after * character (possible end of comment)
68 # 6 - single-line comment context
69 # 7 - single-line comment context, after \ character (escape)
70 # 8 - preprocessor definition/instruction context
71 # 9 - preprocessor definition/instruction context, after \ character (escape)
74 strippedOutputArray = []
76 # normal context, start state
80 strippedOutputArray.append(c)
82 state = 3 # possible comment (no out)
84 state = 8 # preprocessor (no out)
86 strippedOutputArray.append(c)
90 state = 2 # escape sequence
91 strippedOutputArray.append(c)
94 strippedOutputArray.append(c)
96 strippedOutputArray.append(c)
97 # string context, after \ character (character escape)
99 state = 1 # do not leave string context on any character
100 strippedOutputArray.append(c)
101 # normal context, after / character (possible comment)
104 state = 4 # multi-line comment (no out)
106 state = 6 # single-line comment (no out)
108 state = 0 # not comment (flush previous token)
109 strippedOutputArray.append('/')
110 strippedOutputArray.append(c)
111 # multi-line comment context
114 state = 5 # possible end of comment (no out)
115 # multi-line comment context, after * character (possible end of comment)
118 state = 0 # end of comment (no out)
120 pass # not end of comment, but check next token for possible end of comment (no out)
122 state = 4 # not end of comment (no out)
123 # single-line comment context
126 state = 0 # end of comment (append new line)
127 strippedOutputArray.append('\n')
129 state = 7 # escape in comment (can escape new line character) (no out)
130 # single-line comment context, after \ character (escape)
132 state = 6 # do not leave comment on any character (no out)
133 # preprocessor definition/instruction context
136 state = 0 # end of preprocessor construct (no out)
138 state = 9 # escape in preprocessor construct (no out)
139 # preprocessor definition/instruction context, after \ character (escape)
141 state = 8 # do not leave preprocessor construct on any character (no out)
143 return ''.join(strippedOutputArray)
146 def isReservedName(name):
147 """ Determines whether specified name is reserved in C language or project.
149 :param name: Name to check.
151 :return: True, if name is reserved; otherwise, False.
154 if name.strip() in reservedKeywords:
156 for keywordPattern in reservedKeywordPatterns:
157 if keywordPattern.match(name.strip()):
162 automaticSplitVarIndex = 0
165 def splitTypeAndIdentifier(decl):
166 match = typeIdentifierSplitter.match(decl.strip())
167 if match and not isReservedName(match.group(2)):
168 return match.group(1).strip(), match.group(2).strip()
170 global automaticSplitVarIndex
171 automaticSplitVarIndex += 1
172 return decl.strip(), 'arg{0:05d}'.format(automaticSplitVarIndex)
175 def parseApiMemberDeclarator(apiDecl):
182 paramDecls = [] # Collection of extracted parameter declarations
185 # Reversed array where tokens are collected:
186 nameRArray = [] # API member name
187 returnTypeRArray = [] # Return type declaration
188 paramRArray = [] # Parameter declarator
191 cAttributeSplitLoc = cLoc
197 # API member declarator context, start state
200 state = 1 # possible function declarator
202 attrs = apiDecl[cLoc + 1:]
203 # function parameter declaration
205 if c == ')': # nesting of parentheses (stop normal parsing, only collect tokens)
207 paramRArray.append(c)
209 state = 2 # end of parameters declaration (move to function name, store parameter if needed)
210 if len(paramRArray) > 0:
211 paramDecls.append(''.join(paramRArray[::-1]).strip())
213 elif c == ',': # start of next parameter declaration
214 paramDecls.append(''.join(paramRArray[::-1]).strip())
217 paramRArray.append(c)
218 # function name (optional whitespace)
222 state = 3 # ignore whitespace until non-whitespace character is encountered (re-parse token)
225 if c.isalnum() or c == '_':
228 name = ''.join(nameRArray[::-1]).strip()
231 cLoc += 1 # re-parse unmatched token
232 if isReservedName(name):
233 cAttributeSplitLoc = cLoc
239 attrs = apiDecl[cLoc:]
241 state = 0 # if parsed function declaration has reserved name, it need to be treated as attribute
243 state = 4 # name is not reserved - treat next tokens as return type
244 # return type declarator
246 returnTypeRArray.append(c)
248 # Nesting of parentheses - collect tokens only.
253 paramRArray.append(c)
256 if len(nameRArray) > 0:
257 name = ''.join(nameRArray[::-1]).strip()
258 if len(returnTypeRArray) > 0:
259 returnType = ''.join(returnTypeRArray[::-1]).strip()
260 if len(paramRArray) > 0:
261 paramDecls.append(''.join(paramRArray[::-1]).strip())
263 returnType, name = splitTypeAndIdentifier(apiDecl[:cAttributeSplitLoc])
266 for decl in reversed(paramDecls):
267 paramType, paramName = splitTypeAndIdentifier(decl)
268 paramDeclInfos.append({'name': paramName, 'type': paramType})
272 'isFunction': isFunction,
273 'returnType': returnType,
274 'params': paramDeclInfos,
280 # print parseApiMemberDeclarator('int const __attribute__((pure)) ')
281 # print parseApiMemberDeclarator('int foo1 __attribute__((pure)) ')
282 # print parseApiMemberDeclarator('int foo1')
283 # print parseApiMemberDeclarator('void a(int, const a*bb)')
284 # print parseApiMemberDeclarator('int foo __attribute__((static))')
285 # print parseApiMemberDeclarator('int foo()__attribute__((static))')
286 # print parseApiMemberDeclarator('int foo()__attribute__((static)) __attribute__((data(1,2,3))) do() NN')
287 # print parseApiMemberDeclarator('int foo (int a, int b)__attribute__((static)) __attribute__((data(1,2,3))) do() NN')
288 # print parseApiMemberDeclarator('DD(int,a)* foo(int a, const D(1,I())* b)__attribute__((static)) __attribute__((data(1,2,3))) do() NN')
291 def parseHeaderFile(headerFilePath):
292 """ Opens, reads and parses header file and extracts information about API functions inside.
294 :param headerFilePath: Path to header file that will be parsed.
295 :return: List of API function declarations. Each declaration contains dictionary describing function name,
296 parameter types and return type.
301 headerFile = file(headerFilePath)
302 headerContent = headerFile.read()
303 strippedContent = stripCommentsAndPreprocessor(headerContent)
304 matchedFunctionDecls = apiMemberMatcher.findall(strippedContent)
305 for decl in matchedFunctionDecls:
306 apiMembersInfo.append(parseApiMemberDeclarator(decl))
308 for matcher, replace in apiMacroMemberMatchers:
309 matchedMacroDecls = matcher.finditer(strippedContent)
310 for decl in matchedMacroDecls:
311 apiMembersInfo.append(parseApiMemberDeclarator(decl.expand(replace)))
313 return apiMembersInfo
316 def main(parsedOptions):
317 """ Main script function.
319 The script generates header file with wrappers for all API functions from headers contained in specific directory.
321 :param parsedOptions: Arguments parsed by argparse.ArgumentParser class.
322 :return: Exit code for script.
325 scanDirectory = parsedOptions.dir if parsedOptions.dir is not None and parsedOptions.dir != '' else os.curdir
329 for scanDir, scanSubdirectories, scanFileNames in os.walk(scanDirectory):
330 for scanFileName in scanFileNames:
331 if headerFileNamePattern.match(scanFileName):
332 apiMembersInfo.extend(parseHeaderFile(os.path.join(scanDir, scanFileName)))
334 print r'''/*******************************************************************************
335 * Copyright 2016 Intel Corporation
337 * Licensed under the Apache License, Version 2.0 (the "License");
338 * you may not use this file except in compliance with the License.
339 * You may obtain a copy of the License at
341 * http://www.apache.org/licenses/LICENSE-2.0
343 * Unless required by applicable law or agreed to in writing, software
344 * distributed under the License is distributed on an "AS IS" BASIS,
345 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
346 * See the License for the specific language governing permissions and
347 * limitations under the License.
348 *******************************************************************************/
350 /*********************************************************
351 * AUTOGENERATED FILE; DO NOT EDIT
352 ********************************************************/
356 typedef HINSTANCE lib_handle_t;
359 #define _GNU_SOURCE /* for dlvsym() */
361 typedef void * lib_handle_t;
362 #define NULL_LIB NULL
368 #include "cldnn_prv.h"
369 #include "cldnn/cldnn.h"
371 static inline lib_handle_t load_library(const char *lib_name)
374 return LoadLibraryEx(lib_name, NULL, 0);
376 return dlopen(lib_name, RTLD_LAZY | RTLD_GLOBAL);
380 static inline void *load_symbol(const lib_handle_t lib,
384 return GetProcAddress(lib, name);
386 return dlsym(lib, name);
392 for apiMemberInfo in apiMembersInfo:
393 if apiMemberInfo['isFunction']:
394 print '{0} (*{1}_fptr)({2}){5} = NULL;\n{0} {1}({4}){5} {{\n assert({1}_fptr != NULL);\n return {1}_fptr({3});\n}}\n'.format(
395 apiMemberInfo['returnType'],
396 apiMemberInfo['name'],
397 ', '.join([x['type'] for x in apiMemberInfo['params']]),
398 ', '.join([x['name'] for x in apiMemberInfo['params']]),
399 ', '.join([x['type'] + ' ' + x['name'] for x in apiMemberInfo['params']]),
400 (' ' + apiMemberInfo['attrs']) if len(apiMemberInfo['attrs']) > 0 else '')
402 print 'int cldnn_load_symbols(lib_handle_t handle) {'
403 for apiMemberInfo in apiMembersInfo:
404 if apiMemberInfo['isFunction']:
405 print ' {1}_fptr = ({0} (*)({2}){5}) load_symbol(handle, "{1}");\n if ({1}_fptr == NULL) {{\n return -1;\n }}\n'.format(
406 apiMemberInfo['returnType'],
407 apiMemberInfo['name'],
408 ', '.join([x['type'] for x in apiMemberInfo['params']]),
409 ', '.join([x['name'] for x in apiMemberInfo['params']]),
410 ', '.join([x['type'] + ' ' + x['name'] for x in apiMemberInfo['params']]),
411 (' ' + apiMemberInfo['attrs']) if len(apiMemberInfo['attrs']) > 0 else '')
412 print ' return 0;\n}'
422 int cldnn_load_lib(const char *lib_name)
424 printf("begin cldnn_load_lib: %s\n", lib_name);
425 static int lib_status = lib_unloaded;
426 lib_handle_t lib_handle = NULL;
428 if (lib_status != lib_unloaded)
431 lib_handle = load_library(lib_name);
432 if (lib_handle == NULL)
434 lib_status = lib_failed;
435 printf("Could not load library '%s'\n", lib_name);
439 lib_status = cldnn_load_symbols(lib_handle) == 0 ? lib_loaded : lib_failed;
445 if __name__ == "__main__":
446 optParser = argparse.ArgumentParser(description = 'Generates wrappers for all API functions contained in headers' +
447 'of specific directory.')
449 optParser.add_argument('dir', metavar = '<dir>', type = str, default = None,
450 help = 'Directory to scan for header files. Default/None specified:' +
451 ' current working directory.')
452 optParser.add_argument('--version', action = 'version', version = '%(prog)s 1.0')
454 options = optParser.parse_args()
456 exitCode = main(options)
457 optParser.exit(exitCode)