Bladeren bron

add extension modules

David Rose 16 jaren geleden
bovenliggende
commit
8e651c8f8e
2 gewijzigde bestanden met toevoegingen van 133 en 52 verwijderingen
  1. 32 12
      direct/src/showutil/FreezeTool.py
  2. 101 40
      direct/src/showutil/Packager.py

+ 32 - 12
direct/src/showutil/FreezeTool.py

@@ -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 % {

+ 101 - 40
direct/src/showutil/Packager.py

@@ -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.