# $Id$ # # importsym.py: Import C symbol decls (structs, enums, etc) and write them # to another file # # Copyright (C)2013 Teluu Inc. (http://www.teluu.com) # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # import pycparser from pycparser import c_generator import sys import os def which(program): import os def is_exe(fpath): return os.path.isfile(fpath) and os.access(fpath, os.X_OK) if sys.platform == 'win32' and not program.endswith(".exe"): program += ".exe" fpath, fname = os.path.split(program) if fpath: if is_exe(program): return program else: for path in os.environ["PATH"].split(os.pathsep): path = path.strip('"') exe_file = os.path.join(path, program) if is_exe(exe_file): return exe_file return None # PJ_ROOT_PATH = "../../../" # CPP is needed by pycparser. CPP_PATH = which("cpp") if not CPP_PATH: print 'Error: need to have cpp in PATH' sys.exit(1) # Hardcoded! if sys.platform == 'win32': PYCPARSER_DIR="D:/work/tool/pycparser-master" elif sys.platform == "linux2": PYCPARSER_DIR="/home/bennylp/Desktop/opt/src/pycparser-master" else: PYCPARSER_DIR="/Library/Python/2.7/site-packages/pycparser" if not os.path.exists(PYCPARSER_DIR + '/utils/fake_libc_include'): print "Error: couldn't find pycparser utils in '%s'" % PYCPARSER_DIR sys.exit(1) # Heading, to be placed before the source files C_HEADING_SECTION = """ #define PJ_AUTOCONF 1 #define jmp_buf int #define __attribute__(x) """ # CPP (C preprocessor) settings CPP_CFLAGS = [ '-I' + PYCPARSER_DIR + '/utils/fake_libc_include', "-I" + PJ_ROOT_PATH + "pjlib/include", "-I" + PJ_ROOT_PATH + "pjlib-util/include", "-I" + PJ_ROOT_PATH + "pjnath/include", "-I" + PJ_ROOT_PATH + "pjmedia/include", "-I" + PJ_ROOT_PATH + "pjsip/include" ] class SymbolVisitor(pycparser.c_ast.NodeVisitor): def __init__(self, names): self.nodeDict = {} for name in names: self.nodeDict[name] = None def _add(self, node): if self.nodeDict.has_key(node.name): self.nodeDict[node.name] = node def visit_Struct(self, node): self._add(node) def visit_Enum(self, node): self._add(node) def visit_Typename(self, node): self._add(node) def visit_Typedef(self, node): self._add(node) TEMP_FILE="tmpsrc.h" class SymbolImporter: """ Import C selected declarations from C source file and move it to another file. Parameters: - listfile Path of file containing list of C source file and identifier names to be imported. The format of the listfile is: filename name1 name2 name3 for example: pj/sock_qos.h pj_qos_type pj_qos_flag pj/types.h pj_status_t PJ_SUCCESS """ def __init__(self): pass def process(self, listfile, outfile): # Read listfile f = open(listfile) lines = f.readlines() f.close() # Process each line in list file, while generating the # temporary C file to be processed by pycparser f = open(TEMP_FILE, "w") f.write(C_HEADING_SECTION) names = [] fcnt = 0 for line in lines: spec = line.split() if len(spec) < 2: continue fcnt += 1 f.write("#include <%s>\n" % spec[0]) names.extend(spec[1:]) f.close() print 'Parsing %d symbols from %d files..' % (len(names), fcnt) # Parse the temporary C file ast = pycparser.parse_file(TEMP_FILE, use_cpp=True, cpp_path=CPP_PATH, cpp_args=CPP_CFLAGS) os.remove(TEMP_FILE) # Filter the declarations that we wanted print 'Filtering..' visitor = SymbolVisitor(names) visitor.visit(ast) # Print symbol declarations to outfile print 'Writing declarations..' f = open(outfile, 'w') f.write("// This file is autogenerated by importsym script, do not modify!\n\n") gen = pycparser.c_generator.CGenerator() for name in names: node = visitor.nodeDict[name] if not node: print " warning: declaration for '%s' is not found **" % k else: print " writing '%s'.." % name output = gen.visit(node) + ";\n\n" f.write(output) f.close() print "Done." if __name__ == "__main__": print "Importing symbols: 'symbols.lst' --> 'symbols.i'" si = SymbolImporter() si.process("symbols.lst", "symbols.i") try: os.remove("lextab.py") except OSError: pass try: os.remove("yacctab.py") except OSError: pass