importsym.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. #
  2. # importsym.py: Import C symbol decls (structs, enums, etc) and write them
  3. # to another file
  4. #
  5. # Copyright (C)2013 Teluu Inc. (http://www.teluu.com)
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 2 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program; if not, write to the Free Software
  19. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. #
  21. import pycparser
  22. from pycparser import c_generator
  23. import sys
  24. import os
  25. def which(program):
  26. import os
  27. def is_exe(fpath):
  28. return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
  29. if sys.platform == 'win32' and not program.endswith(".exe"):
  30. program += ".exe"
  31. fpath, fname = os.path.split(program)
  32. if fpath:
  33. if is_exe(program):
  34. return program
  35. else:
  36. for path in os.environ["PATH"].split(os.pathsep):
  37. path = path.strip('"')
  38. exe_file = os.path.join(path, program)
  39. if is_exe(exe_file):
  40. return exe_file
  41. return None
  42. #
  43. PJ_ROOT_PATH = "../../../"
  44. # CPP is needed by pycparser.
  45. CPP_PATH = which("cpp")
  46. if not CPP_PATH:
  47. print 'Error: need to have cpp in PATH'
  48. sys.exit(1)
  49. # Hardcoded!
  50. # Note for win32:
  51. # - temporarily comment "#include <pj/compat/socket.h>" in pj/sock.h (line ~29)
  52. if sys.platform == 'win32':
  53. PYCPARSER_DIR="D:/work/tool/pycparser-master"
  54. elif sys.platform == "linux2":
  55. PYCPARSER_DIR="/home/bennylp/Desktop/opt/src/pycparser-master"
  56. else:
  57. PYCPARSER_DIR="/Library/Python/2.7/site-packages/pycparser"
  58. if not os.path.exists(PYCPARSER_DIR + '/utils/fake_libc_include'):
  59. print "Error: couldn't find pycparser utils in '%s'" % PYCPARSER_DIR
  60. sys.exit(1)
  61. # Heading, to be placed before the source files
  62. C_HEADING_SECTION = """
  63. #define PJ_AUTOCONF 1
  64. #define jmp_buf int
  65. #define __attribute__(x)
  66. """
  67. # CPP (C preprocessor) settings
  68. CPP_CFLAGS = [
  69. '-I' + PYCPARSER_DIR + '/utils/fake_libc_include',
  70. "-I" + PJ_ROOT_PATH + "pjlib/include",
  71. "-I" + PJ_ROOT_PATH + "pjlib-util/include",
  72. "-I" + PJ_ROOT_PATH + "pjnath/include",
  73. "-I" + PJ_ROOT_PATH + "pjmedia/include",
  74. "-I" + PJ_ROOT_PATH + "pjsip/include"
  75. ]
  76. class SymbolVisitor(pycparser.c_ast.NodeVisitor):
  77. def __init__(self, names):
  78. self.nodeDict = {}
  79. for name in names:
  80. self.nodeDict[name] = None
  81. def _add(self, node):
  82. if self.nodeDict.has_key(node.name):
  83. self.nodeDict[node.name] = node
  84. def visit_Struct(self, node):
  85. self._add(node)
  86. def visit_Enum(self, node):
  87. self._add(node)
  88. def visit_Typename(self, node):
  89. self._add(node)
  90. def visit_Typedef(self, node):
  91. self._add(node)
  92. TEMP_FILE="tmpsrc.h"
  93. class SymbolImporter:
  94. """
  95. Import C selected declarations from C source file and move it
  96. to another file.
  97. Parameters:
  98. - listfile Path of file containing list of C source file
  99. and identifier names to be imported. The format
  100. of the listfile is:
  101. filename name1 name2 name3
  102. for example:
  103. pj/sock_qos.h pj_qos_type pj_qos_flag
  104. pj/types.h pj_status_t PJ_SUCCESS
  105. """
  106. def __init__(self):
  107. pass
  108. def process(self, listfile, outfile):
  109. # Read listfile
  110. f = open(listfile)
  111. lines = f.readlines()
  112. f.close()
  113. # Process each line in list file, while generating the
  114. # temporary C file to be processed by pycparser
  115. f = open(TEMP_FILE, "w")
  116. f.write(C_HEADING_SECTION)
  117. names = []
  118. fcnt = 0
  119. for line in lines:
  120. spec = line.split()
  121. if len(spec) < 2:
  122. continue
  123. fcnt += 1
  124. f.write("#include <%s>\n" % spec[0])
  125. names.extend(spec[1:])
  126. f.close()
  127. print 'Parsing %d symbols from %d files..' % (len(names), fcnt)
  128. # Parse the temporary C file
  129. ast = pycparser.parse_file(TEMP_FILE, use_cpp=True, cpp_path=CPP_PATH, cpp_args=CPP_CFLAGS)
  130. os.remove(TEMP_FILE)
  131. # Filter the declarations that we wanted
  132. print 'Filtering..'
  133. visitor = SymbolVisitor(names)
  134. visitor.visit(ast)
  135. # Print symbol declarations to outfile
  136. print 'Writing declarations..'
  137. f = open(outfile, 'w')
  138. f.write("// This file is autogenerated by importsym script, do not modify!\n\n")
  139. gen = pycparser.c_generator.CGenerator()
  140. for name in names:
  141. node = visitor.nodeDict[name]
  142. if not node:
  143. print " warning: declaration for '%s' is not found **" % k
  144. else:
  145. print " writing '%s'.." % name
  146. output = gen.visit(node) + ";\n\n"
  147. f.write(output)
  148. f.close()
  149. print "Done."
  150. if __name__ == "__main__":
  151. print "Importing symbols: 'symbols.lst' --> 'symbols.i'"
  152. si = SymbolImporter()
  153. si.process("symbols.lst", "symbols.i")
  154. try:
  155. os.remove("lextab.py")
  156. except OSError:
  157. pass
  158. try:
  159. os.remove("yacctab.py")
  160. except OSError:
  161. pass