From cce0129c7b9019de832bbc7b03638bcd003c06e8 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sat, 2 May 2009 03:39:51 +0000 Subject: [PATCH] better support for pyc's --- direct/src/showbase/MakeAppMF.py | 53 ++++++++++++++++++++++++++---- direct/src/showbase/VFSImporter.py | 44 ++++++++++++++----------- 2 files changed, 70 insertions(+), 27 deletions(-) diff --git a/direct/src/showbase/MakeAppMF.py b/direct/src/showbase/MakeAppMF.py index 55b6d2ff8f..c89a4e35b9 100644 --- a/direct/src/showbase/MakeAppMF.py +++ b/direct/src/showbase/MakeAppMF.py @@ -23,11 +23,22 @@ Options: (this is preferable to having the module start itself immediately upon importing). + -c [py,pyc,pyo] + + Specifies the compilation mode of python files. 'py' means to + leave them as source files, 'pyc' and 'pyo' are equivalent, and + mean to compile to byte code. pyc files will be written if the + interpreter is running in normal debug mode, while pyo files will + be written if it is running in optimize mode (-O or -OO). + """ import sys import getopt +import imp +import marshal import direct +from direct.stdpy.file import open from pandac.PandaModules import * vfs = VirtualFileSystem.getGlobalPtr() @@ -51,6 +62,9 @@ class AppPacker: # without compression. uncompressible_extensions = [ 'mp3' ] + # Specifies how or if python files are compiled. + compilation_mode = 'pyc' + def __init__(self, multifile_name): # Make sure any pre-existing file is removed. Filename(multifile_name).unlink() @@ -67,6 +81,12 @@ class AppPacker: self.image_extensions += type.getExtensions() def scan(self, root, main): + if self.compilation_mode != 'py': + if __debug__: + self.compilation_mode = 'pyc' + else: + self.compilation_mode = 'pyo' + self.root = Filename(root) self.root.makeAbsolute(vfs.getCwd()) @@ -131,15 +151,30 @@ class AppPacker: self.addUncompressibleFile(filename) def addPyFile(self, filename): - # For now, just add it as an ordinary file. Later we'll - # precompile these to .pyo's. + targetFilename = self.makeRelFilename(filename) + if filename == self.main: # This one is the "main.py"; the starter file. - self.multifile.addSubfile('main.py', filename, self.compression_level) - else: - # Any other Python file; add it normally. - self.addTextFile(filename) + targetFilename = Filename('main.py') + if self.compilation_mode == 'py': + # Add python files as source files. + self.multifile.addSubfile(targetFilename.cStr(), filename, self.compression_level) + elif self.compilation_mode == 'pyc' or self.compilation_mode == 'pyo': + # Compile it to bytecode. + targetFilename.setExtension(self.compilation_mode) + source = open(filename, 'r').read() + if source and source[-1] != '\n': + source = source + '\n' + code = compile(source, targetFilename.cStr(), 'exec') + data = imp.get_magic() + '\0\0\0\0' + marshal.dumps(code) + + stream = StringStream(data) + self.multifile.addSubfile(targetFilename.cStr(), stream, self.compression_level) + self.multifile.flush() + else: + raise StandardError, 'Unsupported compilation mode %s' % (self.compilation_mode) + def addEggFile(self, filename, outFilename): # Precompile egg files to bam's. node = loadEggFile(filename) @@ -268,15 +303,18 @@ class AppPacker: def makePackedApp(args): - opts, args = getopt.getopt(args, 'r:m:h') + opts, args = getopt.getopt(args, 'r:m:c:h') root = '.' main = None + compilation_mode = AppPacker.compilation_mode for option, value in opts: if option == '-r': root = value elif option == '-m': main = value + elif option == '-c': + compilation_mode = value elif option == '-h': print __doc__ sys.exit(1) @@ -289,6 +327,7 @@ def makePackedApp(args): raise ArgumentError, "Too many arguments." p = AppPacker(multifile_name) + p.compilation_mode = compilation_mode p.scan(root = root, main = main) if __name__ == '__main__': diff --git a/direct/src/showbase/VFSImporter.py b/direct/src/showbase/VFSImporter.py index c72bd750f4..b2b6330cc5 100644 --- a/direct/src/showbase/VFSImporter.py +++ b/direct/src/showbase/VFSImporter.py @@ -17,11 +17,11 @@ FTPythonSource = 0 FTPythonCompiled = 1 FTCompiledModule = 2 -pycExtension = 'pyc' +compiledExtensions = [ 'pyc', 'pyo' ] if not __debug__: - # In optimized mode, we actually operate on .pyo files, not .pyc - # files. - pycExtension = 'pyo' + # In optimized mode, we prefer loading .pyo files over .pyc files. + # We implement that by reversing the extension names. + compiledExtensions = [ 'pyo', 'pyc' ] class VFSImporter: """ This class serves as a Python importer to support loading @@ -45,11 +45,12 @@ class VFSImporter: # If there's no .py file, but there's a .pyc file, load that # anyway. - filename = Filename(path) - filename.setExtension(pycExtension) - vfile = vfs.getFile(filename, True) - if vfile: - return VFSLoader(self, vfile, filename, FTPythonCompiled) + for ext in compiledExtensions: + filename = Filename(path) + filename.setExtension(ext) + vfile = vfs.getFile(filename, True) + if vfile: + return VFSLoader(self, vfile, filename, FTPythonCompiled) # Look for a compiled C/C++ module. for desc in imp.get_suffixes(): @@ -71,11 +72,12 @@ class VFSImporter: if vfile: return VFSLoader(self, vfile, filename, FTPythonSource, packagePath = path) - filename = Filename(path, '__init__.' + pycExtension) - vfile = vfs.getFile(filename, True) - if vfile: - return VFSLoader(self, vfile, filename, FTPythonCompiled, - packagePath = path) + for ext in compiledExtensions: + filename = Filename(path, '__init__.' + ext) + vfile = vfs.getFile(filename, True) + if vfile: + return VFSLoader(self, vfile, filename, FTPythonCompiled, + packagePath = path) return None @@ -192,12 +194,14 @@ class VFSLoader: # It's a .py file (or an __init__.py file; same thing). Read # the .pyc file if it is available and current; otherwise read # the .py file and compile it. - pycFilename = Filename(self.filename) - pycFilename.setExtension(pycExtension) - pycVfile = vfs.getFile(pycFilename, False) t_pyc = None - if pycVfile: - t_pyc = pycVfile.getTimestamp() + for ext in compiledExtensions: + pycFilename = Filename(self.filename) + pycFilename.setExtension(ext) + pycVfile = vfs.getFile(pycFilename, False) + if pycVfile: + t_pyc = pycVfile.getTimestamp() + break code = None if t_pyc and t_pyc >= self.timestamp: @@ -233,7 +237,7 @@ class VFSLoader: # try to cache the compiled code pycFilename = Filename(filename) - pycFilename.setExtension(pycExtension) + pycFilename.setExtension(compiledExtensions[0]) try: f = open(pycFilename, 'wb') except IOError: