DoGenPyCode.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. """ This module implements genPyCode, which is itself a generated
  2. script with a few default parameters filled in. This module allows
  3. the user to specify alternate parameters on the command line. """
  4. import getopt
  5. import sys
  6. import os
  7. import glob
  8. import types
  9. from direct.ffi import FFIConstants
  10. # Define a help string for the user
  11. helpString ="""
  12. genPyCode -h
  13. genPyCode
  14. genPyCode [opts] -i libdtoolconfig libcode1 libcode2 ...
  15. This script generates Python wrappers to interface with the C++
  16. libraries that have already been run through interrogate. It is
  17. necessary to run this script after building the Panda tools for the
  18. first time, or after any major change in which some of the interface
  19. may have changed.
  20. The default options are baked into genPyCode by ppremake and need not
  21. be specified. However, it is possible to override these on the
  22. command line if you need to fine-tune the behavior of genPyCode for
  23. some reason. Most often, the only needed change will be to add one or
  24. more additional libraries to the list of libraries instrumented by
  25. default.
  26. Options:
  27. -h print this message
  28. -v verbose
  29. -d dir directory to write output code
  30. -x dir directory to pull extension code from
  31. -i lib interrogate library
  32. -e dir directory to search for *.in files (may be repeated)
  33. -r remove the default library list; instrument only named libraries
  34. -O no C++ comments or assertion statements
  35. -n Don't use squeezeTool to squeeze the result into one .pyz file
  36. -s Don't delete source files after squeezing
  37. -m Generate the API reference manual as well
  38. Any additional names listed on the command line are taken to be names
  39. of libraries that are to be instrumented.
  40. """
  41. # Initialize variables
  42. outputDir = ''
  43. directDir = ''
  44. extensionsDir = ''
  45. interrogateLib = ''
  46. codeLibs = []
  47. etcPath = []
  48. doSqueeze = True
  49. deleteSourceAfterSqueeze = True
  50. generateManual = False
  51. native = False # This is set by genPyCode.py
  52. def doGetopts():
  53. global outputDir
  54. global extensionsDir
  55. global interrogateLib
  56. global codeLibs
  57. global doSqueeze
  58. global deleteSourceAfterSqueeze
  59. global generateManual
  60. global etcPath
  61. # These options are allowed but are flagged as warnings (they are
  62. # deprecated with the new genPyCode script):
  63. # -g adds libgateway
  64. # -t adds libtoontown
  65. # -p adds libpirates
  66. # -o adds libopt
  67. FFIConstants.notify.setDebug(0)
  68. FFIConstants.notify.setInfo(0)
  69. # Extract the args the user passed in
  70. try:
  71. opts, pargs = getopt.getopt(sys.argv[1:], 'hvOd:x:Ni:e:rnsgtpom')
  72. except Exception, e:
  73. # User passed in a bad option, print the error and the help, then exit
  74. print e
  75. print helpString
  76. sys.exit()
  77. # Store the option values into our variables
  78. for opt in opts:
  79. flag, value = opt
  80. if (flag == '-h'):
  81. print helpString
  82. sys.exit()
  83. elif (flag == '-v'):
  84. if not FFIConstants.notify.getInfo():
  85. FFIConstants.notify.setInfo(1)
  86. else:
  87. FFIConstants.notify.setDebug(1)
  88. elif (flag == '-d'):
  89. outputDir = value
  90. elif (flag == '-x'):
  91. extensionsDir = value
  92. elif (flag == '-i'):
  93. interrogateLib = value
  94. elif (flag == '-e'):
  95. etcPath.append(value)
  96. elif (flag == '-r'):
  97. codeLibs = []
  98. elif (flag == '-O'):
  99. FFIConstants.wantComments = 0
  100. FFIConstants.wantTypeChecking = 0
  101. elif (flag == '-n'):
  102. doSqueeze = False
  103. elif (flag == '-s'):
  104. deleteSourceAfterSqueeze = False
  105. elif (flag == '-m'):
  106. generateManual = True
  107. elif (flag in ['-g', '-t', '-p', '-o']):
  108. FFIConstants.notify.warning("option is deprecated: %s" % (flag))
  109. else:
  110. FFIConstants.notify.error('illegal option: ' + flag)
  111. # Check for old, no-longer-used parameter:
  112. invalidParameters = [
  113. 'linux', 'win-debug', 'win-release', 'win-publish',
  114. 'install', 'release'
  115. ]
  116. if pargs and pargs[0] in invalidParameters:
  117. FFIConstants.notify.warning("parameter is deprecated: %s" % (pargs[0]))
  118. del pargs[0]
  119. # Store the program arguments into the codeLibs
  120. codeLibs += pargs
  121. # Make sure each name appears on codeLibs exactly once.
  122. newLibs = []
  123. for codeLib in codeLibs:
  124. if codeLib not in newLibs:
  125. newLibs.append(codeLib)
  126. codeLibs = newLibs
  127. def doErrorCheck():
  128. global outputDir
  129. global extensionsDir
  130. global interrogateLib
  131. global codeLibs
  132. global doSqueeze
  133. global etcPath
  134. # Now do some error checking and verbose output
  135. if (not interrogateLib):
  136. FFIConstants.notify.error('You must specify an interrogate library (-i lib)')
  137. else:
  138. FFIConstants.notify.debug('Setting interrogate library to: ' + interrogateLib)
  139. FFIConstants.InterrogateModuleName = interrogateLib
  140. if (not outputDir):
  141. FFIConstants.notify.info('Setting output directory to current directory')
  142. outputDir = '.'
  143. elif (not os.path.exists(outputDir)):
  144. FFIConstants.notify.info('Directory does not exist, creating: ' + outputDir)
  145. os.mkdir(outputDir)
  146. FFIConstants.notify.info('Setting output directory to: ' + outputDir)
  147. else:
  148. FFIConstants.notify.info('Setting output directory to: ' + outputDir)
  149. if (not extensionsDir):
  150. FFIConstants.notify.debug('Setting extensions directory to current directory')
  151. extensionsDir = '.'
  152. elif (not os.path.exists(extensionsDir)):
  153. FFIConstants.notify.error('Directory does not exist: ' + extensionsDir)
  154. else:
  155. FFIConstants.notify.debug('Setting extensions directory to: ' + extensionsDir)
  156. if (not codeLibs):
  157. FFIConstants.notify.error('You must specify one or more libraries to generate code from')
  158. else:
  159. FFIConstants.notify.debug('Generating code for: ' + `codeLibs`)
  160. FFIConstants.CodeModuleNameList = codeLibs
  161. def generateNativeWrappers():
  162. # Empty out the codeDir of unnecessary crud from previous runs
  163. # before we begin.
  164. for file in os.listdir(outputDir):
  165. pathname = os.path.join(outputDir, file)
  166. if not os.path.isdir(pathname):
  167. os.unlink(pathname)
  168. # Generate __init__.py
  169. initFilename = os.path.join(outputDir, '__init__.py')
  170. init = open(initFilename, 'w')
  171. # Generate PandaModules.py
  172. pandaModulesFilename = os.path.join(outputDir, 'PandaModules.py')
  173. pandaModules = open(pandaModulesFilename, 'w')
  174. # Copy in any helper classes from the extensions_native directory
  175. extensionHelperFiles = [ 'extension_native_helpers.py' ]
  176. for name in extensionHelperFiles:
  177. inFilename = os.path.join(extensionsDir, name)
  178. outFilename = os.path.join(outputDir, name)
  179. if os.path.exists(inFilename):
  180. inFile = open(inFilename, 'r')
  181. outFile = open(outFilename, 'w')
  182. outFile.write(inFile.read())
  183. # Generate a series of "libpandaModules.py" etc. files, one for
  184. # each named module.
  185. for moduleName in FFIConstants.CodeModuleNameList:
  186. print 'Importing code library: ' + moduleName
  187. exec('import %s as module' % moduleName)
  188. pandaModules.write('from %sModules import *\n' % (moduleName))
  189. moduleModulesFilename = os.path.join(outputDir, '%sModules.py' % (moduleName))
  190. moduleModules = open(moduleModulesFilename, 'w')
  191. moduleModules.write('from %s import *\n\n' % (moduleName))
  192. # Now look for extensions
  193. for className, classDef in module.__dict__.items():
  194. if type(classDef) == types.TypeType:
  195. extensionFilename = os.path.join(extensionsDir, '%s_extensions.py' % (className))
  196. if os.path.exists(extensionFilename):
  197. print ' Found extensions for class: %s' % (className)
  198. extension = open(extensionFilename, 'r')
  199. moduleModules.write(extension.read())
  200. moduleModules.write('\n')
  201. def run():
  202. global outputDir
  203. global directDir
  204. global extensionsDir
  205. global interrogateLib
  206. global codeLibs
  207. global doSqueeze
  208. global deleteSourceAfterSqueeze
  209. global generateManual
  210. global etcPath
  211. doGetopts()
  212. doErrorCheck()
  213. # Ok, now we can start generating code
  214. if native:
  215. generateNativeWrappers()
  216. else:
  217. from direct.ffi import FFIInterrogateDatabase
  218. db = FFIInterrogateDatabase.FFIInterrogateDatabase(etcPath = etcPath)
  219. db.generateCode(outputDir, extensionsDir)
  220. if doSqueeze:
  221. db.squeezeGeneratedCode(outputDir, deleteSourceAfterSqueeze)
  222. if generateManual:
  223. import epydoc.cli
  224. import direct.directbase.DirectStart
  225. mandir = os.path.join(outputDir,"docs")
  226. cmd = ["epydoc","-n","Panda3D","-o",mandir,"--docformat","panda","--ignore-param-mismatch",outputDir,directDir]
  227. sys.argv = cmd
  228. epydoc.cli.cli()