forked from panda3d/panda3d
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDoGenPyCode.py
More file actions
346 lines (294 loc) · 11.7 KB
/
DoGenPyCode.py
File metadata and controls
346 lines (294 loc) · 11.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
""" This module implements genPyCode, which is itself a generated
script with a few default parameters filled in. This module allows
the user to specify alternate parameters on the command line. """
import getopt
import sys
import os
import glob
import types
import time
from direct.ffi import FFIConstants
# Define a help string for the user
helpString ="""
genPyCode -h
genPyCode
genPyCode [opts] -i libdtoolconfig libcode1 libcode2 ...
This script generates Python wrappers to interface with the C++
libraries that have already been run through interrogate. It is
necessary to run this script after building the Panda tools for the
first time, or after any major change in which some of the interface
may have changed.
The default options are baked into genPyCode by ppremake and need not
be specified. However, it is possible to override these on the
command line if you need to fine-tune the behavior of genPyCode for
some reason. Most often, the only needed change will be to add one or
more additional libraries to the list of libraries instrumented by
default.
Options:
-h print this message
-v verbose
-d generate HTML documentation too
-C dir directory to write output code
-H dir directory to write output HTML
-x dir directory to pull extension code from
-i lib interrogate library
-e dir directory to search for *.in files (may be repeated)
-p dir directory to search for Python source files (may be repeated)
-r remove the default library list; instrument only named libraries
-O no C++ comments or assertion statements
-n Don't use squeezeTool to squeeze the result into one .pyz file
-s Don't delete source files after squeezing
Any additional names listed on the command line are taken to be names
of libraries that are to be instrumented.
"""
HTMLHeader = """
<html>
<head>
<title>Panda3D documentation generated %s</title>
</head>
<body>
"""
HTMLFooter = """
</body>
</html>
"""
# Initialize variables
outputCodeDir = ''
outputHTMLDir = ''
directDir = ''
extensionsDir = ''
interrogateLib = ''
codeLibs = []
etcPath = []
pythonSourcePath = []
doSqueeze = True
deleteSourceAfterSqueeze = True
doHTML = False
native = False # This is set by genPyCode.py
def doGetopts():
global outputCodeDir
global outputHTMLDir
global extensionsDir
global interrogateLib
global codeLibs
global doSqueeze
global deleteSourceAfterSqueeze
global doHTML
global etcPath
global pythonSourcePath
# These options are allowed but are flagged as warnings (they are
# deprecated with the new genPyCode script):
# -g adds libgateway
# -t adds libtoontown
# -p adds libpirates
# -o adds libopt
FFIConstants.notify.setDebug(0)
FFIConstants.notify.setInfo(0)
# Extract the args the user passed in
try:
opts, pargs = getopt.getopt(sys.argv[1:], 'hvdOC:H:x:Ni:e:p:rns')
except e:
# User passed in a bad option, print the error and the help, then exit
print(e)
print(helpString)
sys.exit()
# Store the option values into our variables
for opt in opts:
flag, value = opt
if (flag == '-h'):
print(helpString)
sys.exit()
elif (flag == '-v'):
if not FFIConstants.notify.getInfo():
FFIConstants.notify.setInfo(1)
else:
FFIConstants.notify.setDebug(1)
elif (flag == '-d'):
doHTML = True
elif (flag == '-C'):
outputCodeDir = value
elif (flag == '-H'):
outputHTMLDir = value
elif (flag == '-x'):
extensionsDir = value
elif (flag == '-i'):
interrogateLib = value
elif (flag == '-e'):
etcPath.append(value)
elif (flag == '-p'):
pythonSourcePath.append(value)
elif (flag == '-r'):
codeLibs = []
elif (flag == '-O'):
FFIConstants.wantComments = 0
FFIConstants.wantTypeChecking = 0
elif (flag == '-n'):
doSqueeze = False
elif (flag == '-s'):
deleteSourceAfterSqueeze = False
else:
FFIConstants.notify.error('illegal option: ' + flag)
# Check for old, no-longer-used parameter:
invalidParameters = [
'linux', 'win-debug', 'win-release', 'win-publish',
'install', 'release'
]
if pargs and pargs[0] in invalidParameters:
FFIConstants.notify.warning("parameter is deprecated: %s" % (pargs[0]))
del pargs[0]
# Store the program arguments into the codeLibs
for arg in pargs:
arg = arg.strip()
if arg:
codeLibs.append(arg)
# Make sure each name appears on codeLibs exactly once.
newLibs = []
for codeLib in codeLibs:
if codeLib not in newLibs:
newLibs.append(codeLib)
codeLibs = newLibs
def doErrorCheck():
global outputCodeDir
global outputHTMLDir
global extensionsDir
global interrogateLib
global codeLibs
global doSqueeze
global etcPath
# Now do some error checking and verbose output
if (not interrogateLib):
FFIConstants.notify.error('You must specify an interrogate library (-i lib)')
else:
FFIConstants.notify.debug('Setting interrogate library to: ' + interrogateLib)
FFIConstants.InterrogateModuleName = interrogateLib
if (not outputCodeDir):
FFIConstants.notify.info('Setting output code directory to current directory')
outputCodeDir = '.'
elif (not os.path.exists(outputCodeDir)):
FFIConstants.notify.info('Directory does not exist, creating: ' + outputCodeDir)
os.mkdir(outputCodeDir)
FFIConstants.notify.info('Setting output code directory to: ' + outputCodeDir)
else:
FFIConstants.notify.info('Setting output code directory to: ' + outputCodeDir)
if doHTML:
if (not outputHTMLDir):
FFIConstants.notify.info('Setting output HTML directory to current directory')
outputHTMLDir = '.'
elif (not os.path.exists(outputHTMLDir)):
FFIConstants.notify.info('Directory does not exist, creating: ' + outputHTMLDir)
os.makedirs(outputHTMLDir)
FFIConstants.notify.info('Setting output HTML directory to: ' + outputHTMLDir)
else:
FFIConstants.notify.info('Setting output HTML directory to: ' + outputHTMLDir)
if (not extensionsDir):
FFIConstants.notify.debug('Setting extensions directory to current directory')
extensionsDir = '.'
elif (not os.path.exists(extensionsDir)):
FFIConstants.notify.error('Directory does not exist: ' + extensionsDir)
else:
FFIConstants.notify.debug('Setting extensions directory to: ' + extensionsDir)
if (not codeLibs):
FFIConstants.notify.error('You must specify one or more libraries to generate code from')
else:
FFIConstants.notify.debug('Generating code for: ' + repr(codeLibs))
FFIConstants.CodeModuleNameList = codeLibs
def generateNativeWrappers():
from direct.extensions_native.extension_native_helpers import Dtool_FindModule, Dtool_PreloadDLL
# Empty out the output directories of unnecessary crud from
# previous runs before we begin.
for file in os.listdir(outputCodeDir):
pathname = os.path.join(outputCodeDir, file)
if not os.path.isdir(pathname):
os.unlink(pathname)
# Generate __init__.py
initFilename = os.path.join(outputCodeDir, '__init__.py')
init = open(initFilename, 'w')
# Generate PandaModules.py
pandaModulesFilename = os.path.join(outputCodeDir, 'PandaModules.py')
pandaModules = open(pandaModulesFilename, 'w')
# Copy in any helper classes from the extensions_native directory
extensionHelperFiles = ['extension_native_helpers.py']
for name in extensionHelperFiles:
inFilename = os.path.join(extensionsDir, name)
outFilename = os.path.join(outputCodeDir, name)
if os.path.exists(inFilename):
inFile = open(inFilename, 'r')
outFile = open(outFilename, 'w')
outFile.write(inFile.read())
# Generate a series of "libpandaModules.py" etc. files, one for
# each named module.
for moduleName in FFIConstants.CodeModuleNameList:
print('Importing code library: ' + moduleName)
Dtool_PreloadDLL(moduleName)
__import__(moduleName)
module = sys.modules[moduleName]
# Make a suitable meta module name
metaModuleName = ""
nextCap = False
for ch in moduleName:
if ch == '.':
nextCap = True
elif nextCap:
metaModuleName += ch.upper()
nextCap = False
else:
metaModuleName += ch
metaModuleName += "Modules"
# Wrap the import in a try..except so that we can continue if
# the library isn't present. This is particularly necessary
# in the runtime (plugin) environment, where all libraries are
# not necessarily downloaded.
if sys.version_info >= (3, 0):
pandaModules.write('try:\n from .%s import *\nexcept ImportError as err:\n if "DLL loader cannot find" not in str(err):\n raise\n' % (metaModuleName))
else:
pandaModules.write('try:\n from %s import *\nexcept ImportError, err:\n if "DLL loader cannot find" not in str(err):\n raise\n' % (metaModuleName))
# Not sure if this message is helpful or annoying.
#pandaModules.write(' print("Failed to import %s")\n' % (moduleName))
pandaModules.write('\n')
moduleModulesFilename = os.path.join(outputCodeDir, '%s.py' % (metaModuleName))
moduleModules = open(moduleModulesFilename, 'w')
if sys.version_info >= (3, 0):
moduleModules.write('from .extension_native_helpers import *\n')
else:
moduleModules.write('from extension_native_helpers import *\n')
moduleModules.write('Dtool_PreloadDLL("%s")\n' % (moduleName))
moduleModules.write('from %s import *\n\n' % (moduleName))
# Now look for extensions
for className, classDef in module.__dict__.items():
if isinstance(classDef, type):
extensionFilename = os.path.join(extensionsDir, '%s_extensions.py' % (className))
if os.path.exists(extensionFilename):
print(' Found extensions for class: %s' % (className))
extension = open(extensionFilename, 'r')
moduleModules.write(extension.read())
moduleModules.write('\n')
def run():
global outputCodeDir
global outputHTMLDir
global directDir
global extensionsDir
global interrogateLib
global codeLibs
global doSqueeze
global deleteSourceAfterSqueeze
global etcPath
global pythonSourcePath
doGetopts()
doErrorCheck()
# Ok, now we can start generating code
if native:
generateNativeWrappers()
else:
from direct.ffi import FFIInterrogateDatabase
db = FFIInterrogateDatabase.FFIInterrogateDatabase(etcPath = etcPath)
db.generateCode(outputCodeDir, extensionsDir)
if doSqueeze:
db.squeezeGeneratedCode(outputCodeDir, deleteSourceAfterSqueeze)
if doHTML:
from direct.directscripts import gendocs
from pandac.PandaModules import PandaSystem
versionString = '%s %s' % (
PandaSystem.getDistributor(), PandaSystem.getVersionString())
gendocs.generate(versionString, etcPath, pythonSourcePath,
outputHTMLDir, HTMLHeader % time.asctime(),
HTMLFooter, '', '.html')