add extension modules

This commit is contained in:
David Rose 2009-08-13 16:57:35 +00:00
parent efa3af6e46
commit 8e651c8f8e
2 changed files with 133 additions and 52 deletions

View File

@ -402,6 +402,13 @@ class Freezer:
# or dll's; those are always stored with compiled code.
self.storePythonSource = False
# This list will be filled in by generateCode() or
# addToMultifile(). It contains a list of all the extension
# modules that were discovered, which have not been added to
# the output. The list is a list of tuples of the form
# (moduleName, filename).
self.extras = []
# End of public interface. These remaining members should not
# be directly manipulated by callers.
self.previousModules = {}
@ -837,6 +844,19 @@ class Freezer:
if module:
# Get the compiled code directly from the module object.
code = getattr(module, "__code__", None)
if not code:
# This is a module with no associated Python
# code. It must be an extension module. Get the
# filename.
extensionFilename = getattr(module, '__file__', None)
if extensionFilename:
self.extras.append((moduleName, extensionFilename))
else:
# It doesn't even have a filename; it must
# be a built-in module. No worries about
# this one, then.
pass
else:
# Read the code from the source file and compile it on-the-fly.
if sourceFilename and sourceFilename.exists():
@ -849,7 +869,8 @@ class Freezer:
def addToMultifile(self, multifile, compressionLevel = 0):
""" After a call to done(), this stores all of the accumulated
python code into the indicated Multifile. """
python code into the indicated Multifile. Additional
extension modules are listed in self.extras. """
moduleDirs = {}
for moduleName, mdef in self.getModuleDefs():
@ -860,7 +881,8 @@ class Freezer:
def writeMultifile(self, mfname):
""" After a call to done(), this stores all of the accumulated
python code into a Multifile with the indicated filename,
including the extension. """
including the extension. Additional extension modules are
listed in self.extras."""
self.__replacePaths()
@ -881,10 +903,9 @@ class Freezer:
false). The basename is the name of the file to write,
without the extension.
The return value is the tuple (filename, extras) where
filename is the newly-generated filename, including the
filename extension, and extras is a list of (moduleName,
filename), for extension modules. """
The return value is the newly-generated filename, including
the filename extension. Additional extension modules are
listed in self.extras. """
if compileToExe:
# We must have a __main__ module to make an exe file.
@ -897,7 +918,6 @@ class Freezer:
# Now generate the actual export table.
moduleDefs = []
moduleList = []
extras = []
for moduleName, mdef in self.getModuleDefs():
token = mdef.token
@ -932,11 +952,11 @@ class Freezer:
else:
# This is a module with no associated Python
# code. It must be a compiled file. Get the
# code. It must be an extension module. Get the
# filename.
filename = getattr(module, '__file__', None)
if filename:
extras.append((moduleName, filename))
extensionFilename = getattr(module, '__file__', None)
if extensionFilename:
self.extras.append((moduleName, extensionFilename))
else:
# It doesn't even have a filename; it must
# be a built-in module. No worries about
@ -994,7 +1014,7 @@ class Freezer:
if (os.path.exists(basename + self.objectExtension)):
os.unlink(basename + self.objectExtension)
return (target, extras)
return target
def compileExe(self, filename, basename):
compile = self.compileObj % {

View File

@ -83,6 +83,44 @@ class Packager:
for moduleName in self.skipModules.keys():
self.freezer.excludeModule(moduleName)
# First, add the explicit py files. These get turned into
# Python modules.
for file in self.files:
if not file.newName:
file.newName = file.filename
if file.newName in self.skipFilenames:
# Skip this file.
continue
ext = file.filename.getExtension()
if ext == 'py':
self.addPyFile(file)
if not self.mainModule and self.p3dApplication:
message = 'No main_module specified for application %s' % (self.packageName)
raise PackagerError, message
if self.mainModule:
if self.mainModule not in self.freezer.modules:
self.freezer.addModule(self.mainModule)
# Add known module names.
self.moduleNames = {}
for moduleName in self.freezer.getAllModuleNames():
if moduleName == '__main__':
# Ignore this special case.
continue
self.moduleNames[moduleName] = True
xmodule = TiXmlElement('module')
xmodule.SetAttribute('name', moduleName)
self.components.append(xmodule)
# Pick up any unfrozen Python files.
self.freezer.done()
self.freezer.addToMultifile(self.multifile, self.compressionLevel)
self.addExtensionModules()
# Build up a cross-reference of files we've already
# discovered.
self.sourceFilenames = {}
@ -104,10 +142,13 @@ class Packager:
self.targetFilenames[file.newName] = file
processFiles.append(file)
# Now add all the real, non-Python files. This will
# include the extension modules we just discovered above.
for file in processFiles:
ext = file.filename.getExtension()
if ext == 'py':
self.addPyFile(file)
# Already handled, above.
pass
elif not self.dryRun:
if ext == 'pz':
# Strip off an implicit .pz extension.
@ -131,36 +172,18 @@ class Packager:
# Any other file.
self.addComponent(file)
if not self.mainModule and self.p3dApplication:
message = 'No main_module specified for application %s' % (self.packageName)
raise PackagerError, message
if self.mainModule:
if self.mainModule not in self.freezer.modules:
self.freezer.addModule(self.mainModule)
# Pick up any unfrozen Python files.
self.freezer.done()
# Add known module names.
self.moduleNames = {}
for moduleName in self.freezer.getAllModuleNames():
if moduleName == '__main__':
# Ignore this special case.
continue
self.moduleNames[moduleName] = True
xmodule = TiXmlElement('module')
xmodule.SetAttribute('name', moduleName)
self.components.append(xmodule)
# Now that we've processed all of the component files,
# (and set our platform if necessary), we can generate the
# output filename and write the output files.
if not self.p3dApplication and not self.version:
# We must have a version string for packages.
# We must have a version string for packages. Use the
# first versioned string on our require list.
self.version = '0.0'
for p2 in self.requires:
if p2.version:
self.version = p2.version
break
self.packageBasename = self.packageName
packageDir = self.packageName
@ -189,7 +212,6 @@ class Packager:
self.packageFullpath.unlink()
if not self.dryRun:
self.freezer.addToMultifile(self.multifile, self.compressionLevel)
if self.p3dApplication:
self.makeP3dInfo()
self.multifile.repack()
@ -208,6 +230,27 @@ class Packager:
if file.deleteTemp:
file.filename.unlink()
def addExtensionModules(self):
""" Adds the extension modules detected by the freezer to
the current list of files. """
freezer = self.freezer
if freezer.extras:
if not self.platform:
self.platform = PandaSystem.getPlatform()
for moduleName, filename in freezer.extras:
filename = Filename.fromOsSpecific(filename)
newName = filename.getBasename()
if '.' in moduleName:
newName = '/'.join(moduleName.split('.')[:-1])
newName += '/' + filename.getBasename()
# Sometimes the PYTHONPATH has the wrong case in it.
filename.makeTrueCase()
self.files.append(Packager.PackFile(filename, newName = newName, extract = True))
freezer.extras = []
def makeP3dInfo(self):
""" Makes the p3d_info.xml file that defines the
application startup parameters and such. """
@ -278,7 +321,7 @@ class Packager:
for package in self.requires:
xrequires = TiXmlElement('requires')
xrequires.SetAttribute('name', package.packageName)
if package.platform:
if self.platform and package.platform:
xrequires.SetAttribute('platform', package.platform)
if package.version:
xrequires.SetAttribute('version', package.version)
@ -315,7 +358,7 @@ class Packager:
for package in self.requires:
xrequires = TiXmlElement('requires')
xrequires.SetAttribute('name', package.packageName)
if package.platform:
if self.platform and package.platform:
xrequires.SetAttribute('platform', package.platform)
if package.version:
xrequires.SetAttribute('version', package.version)
@ -635,10 +678,10 @@ class Packager:
self.binaryExtensions = [ 'ttf', 'wav', 'mid' ]
# Files that should be extracted to disk.
self.extractExtensions = [ 'dll', 'so', 'dylib', 'exe' ]
self.extractExtensions = [ 'dll', 'pyd', 'so', 'dylib', 'exe' ]
# Files that indicate a platform dependency.
self.platformSpecificExtensions = [ 'dll', 'so', 'dylib', 'exe' ]
self.platformSpecificExtensions = [ 'dll', 'pyd', 'so', 'dylib', 'exe' ]
# Binary files that are considered uncompressible, and are
# copied without compression.
@ -978,6 +1021,24 @@ class Packager:
self.module(moduleName, newName = newName)
def parse_exclude_module(self, words):
"""
exclude_module moduleName [forbid=1]
"""
newName = None
args = self.__parseArgs(words, ['extract'])
try:
command, moduleName = words
except ValueError:
raise ArgumentError
forbid = args.get('forbid', None)
if forbid is not None:
forbid = int(forbid)
self.excludeModule(moduleName, forbid = forbid)
def parse_main_module(self, words):
"""
main_module moduleName
@ -1353,6 +1414,14 @@ class Packager:
self.currentPackage.freezer.addModule(moduleName, newName = newName)
def excludeModule(self, moduleName, forbid = False):
""" Marks the indicated Python module as not to be included. """
if not self.currentPackage:
raise OutsideOfPackageError
self.currentPackage.freezer.excludeModule(moduleName, forbid = forbid)
def mainModule(self, moduleName, newName = None):
""" Names the indicated module as the "main" module of the
application or exe. """
@ -1400,17 +1469,10 @@ class Packager:
dirname, basename = filename.rsplit('/', 1)
dirname += '/'
basename, extras = freezer.generateCode(basename, compileToExe = compileToExe)
basename = freezer.generateCode(basename, compileToExe = compileToExe)
package.files.append(self.PackFile(Filename(basename), newName = dirname + basename, deleteTemp = True, extract = True))
for moduleName, filename in extras:
filename = Filename.fromOsSpecific(filename)
newName = filename.getBasename()
if '.' in moduleName:
newName = '/'.join(moduleName.split('.')[:-1])
newName += '/' + filename.getBasename()
package.files.append(self.PackFile(filename, newName = newName, extract = True))
package.addExtensionModules()
if not package.platform:
package.platform = PandaSystem.getPlatform()
@ -1418,7 +1480,6 @@ class Packager:
freezer.reset()
package.mainModule = None
def file(self, filename, newNameOrDir = None, extract = None):
""" Adds the indicated arbitrary file to the current package.