Changeset 484

Show
Ignore:
Timestamp:
Wed Jul 23 13:58:36 2008
Author:
htgoebel
Message:

Implemented support for cross-plattfrom bundeling linux->win32.

Configure.py: support for --target-patform and --python-executable
bindepend.py: Support for target-platform and search imported

modules in `xtrapath`, too
Build.py: Test for `target_iswin` instead of `iswin`
mf.py: get suffixes to search for from `suffixes` instead of `imp`
suffixes.py: new module (used by mf.py) to specify suffixes for
target platform (currently only win32 is supported)

KNOW BUGS:
* Have to check sys.version of --python-executable

Files:

Legend:

Unmodified
Added
Removed
Modified
  • trunk/bindepend.py

    r449 r484  
    1 1 #! /usr/bin/env python  
      2 #  
    2 3 # Find external dependencies of binary libraries.  
      4 #  
    3 5 # Copyright (C) 2005, Giovanni Bajo  
    4 6 # Based on previous work under copyright (c) 2002 McMillan Enterprises, Inc.  
     
    41 43 iswin = sys.platform[:3] == 'win'  
    42 44 cygwin = sys.platform == 'cygwin'  
      45  
    43 46 excludes = {'KERNEL32.DLL':1,  
    44 47       'ADVAPI.DLL':1,  
     
    102 105     if os.path.exists(npth):  
    103 106       return npth  
      107     # second try: lower case filename  
      108     for p in epath:  
      109         npth = os.path.join(p, string.lower(mod))  
      110         if os.path.exists(npth):  
      111             return npth  
    104 112   return ''  
    105 113  
     
    256 264     return dlls  
    257 265  
    258   def Dependencies(lTOC):  
      266 def Dependencies(lTOC, platform=sys.platform, xtrapath=None):  
    258 266   """Expand LTOC to include all the closure of binary dependencies.  
    259 267  
     
    268 276     #print "I: analyzing", pth  
    269 277     seen[string.upper(nm)] = 1  
    270       for lib, npth in selectImports(pth):  
      278     for lib, npth in selectImports(pth, platform, xtrapath):  
    270 278         if seen.get(string.upper(lib),0):  
    271 279             continue  
     
    275 283   return lTOC  
    276 284  
    277   def selectImports(pth):  
      285 def selectImports(pth, platform=sys.platform, xtrapath=None):  
    277 285     """Return the dependencies of a binary that should be included.  
    278 286  
     
    281 289     """  
    282 290     rv = []  
    283       dlls = getImports(pth)  
      291     if xtrapath is None:  
      292         xtrapath = [os.path.dirname(pth)]  
      293     else:  
      294         assert isinstance(xtrapath, list)  
      295         xtrapath = [os.path.dirname(pth)] + xtrapath # make a copy  
      296     dlls = getImports(pth, platform=platform)  
      297     iswin = platform[:3] == 'win'  
    284 298     for lib in dlls:  
    285 299         if not iswin and not cygwin:  
     
    291 305         else:  
    292 306             # all other platforms  
    293               npth = getfullnameof(lib, os.path.dirname(pth))  
      307             npth = getfullnameof(lib, xtrapath)  
    293 307          
    294 308         # now npth is a candidate lib  
     
    349 363     return rslt  
    350 364  
    351   def getImports(pth):  
      365 def getImports(pth, platform=sys.platform):  
    351 365     """Forwards to the correct getImports implementation for the platform.  
    352 366     """  
    353       if sys.platform[:3] == 'win' or sys.platform == 'cygwin':  
      367     if platform[:3] == 'win' or platform == 'cygwin':  
    353 367         return _getImports_pe(pth)  
    354       elif sys.platform == 'darwin':  
      368     elif platform == 'darwin':  
    354 368         return _getImports_otool(pth)  
    355 369     else:  
     
    434 448     if m: return m.group(1)  
    435 449  
    436   if __name__ == "__main__":  
    437       if len(sys.argv) < 2:  
    438           print "Usage: python %s BINARYFILE" % sys.argv[0]  
    439           sys.exit(0)  
    440       print getImports(sys.argv[1])  
    441 450  
      451 if __name__ == "__main__":  
      452     from optparse import OptionParser  
      453     parser = OptionParser(usage="%prog [options] <executable_or_dynamic_library>")  
      454     parser.add_option('--target-platform', default=sys.platform,  
      455                       help='Target platform, required for cross-bundling (default: current platform)')  
      456                    
      457     opts, args = parser.parse_args()  
      458     if len (args) != 1:  
      459         parser.error('Requires exactly one filename')  
      460     print getImports(args[0], opts.target_platform)  
  • trunk/Build.py

    r482 r484  
    1 1 #! /usr/bin/env python  
      2 #  
    2 3 # Build packages using spec files  
      4 #  
    3 5 # Copyright (C) 2005, Giovanni Bajo  
    4 6 # Based on previous work under copyright (c) 1999, 2002 McMillan Enterprises, Inc.  
     
    17 19 # along with this program; if not, write to the Free Software  
    18 20 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA  
      21  
    19 22 import sys  
    20 23 import os  
     
    39 42 BUILDPATH = None  
    40 43 WARNFILE = None  
      44  
    41 45 rthooks = {}  
    42 46 iswin = sys.platform[:3] == 'win'  
     
    57 61     sys.exit(1)  
    58 62  
    59   if config['pythonVersion'] != sys.version:  
    60       print "The current version of Python is not the same with which PyInstaller was configured."  
    61       print "Please re-run Configure.py with this version."  
    62       sys.exit(1)  
      63 target_platform = config.get('target_platform', sys.platform)  
      64 mf.target_platform = target_platform  
      65 target_iswin = target_platform[:3] == 'win'  
      66  
      67 if target_platform == sys.platform:  
      68     # _not_ cross compiling  
      69     if config['pythonVersion'] != sys.version:  
      70         print "The current version of Python is not the same with which PyInstaller was configured."  
      71         print "Please re-run Configure.py with this version."  
      72         sys.exit(1)  
    63 73  
    64 74 if config['hasRsrcUpdate']:  
     
    270 280         it in its output.  
    271 281         """  
    272           if sys.platform != 'linux2': return  
      282         if target_platform != 'linux2': return  
    272 282  
    273 283         name = 'libpython%d.%d.so' % sys.version_info[:2]  
     
    540 550         if not os.path.isabs(self.name):  
    541 551             self.name = os.path.join(SPECPATH, self.name)  
    542           if iswin or cygwin:  
      552         if target_iswin or cygwin:  
    542 552             self.pkgname = self.name[:-3] + 'pkg'  
    543 553         else:  
     
    605 615         return 0  
    606 616     def _bootloader_postfix(self, exe):  
    607           if iswin:  
      617         if target_iswin:  
    607 617             exe = exe + "_"  
    608 618             is24 = hasattr(sys, "version_info") and sys.version_info[:2] >= (2,4)  
     
    623 633         exe = self._bootloader_postfix('support/loader/run')  
    624 634         exe = os.path.join(HOMEPATH, exe)  
    625           if iswin or cygwin:  
      635         if target_iswin or cygwin:  
    625 635             exe = exe + '.exe'  
    626 636         if config['hasRsrcUpdate']:  
     
    923 933     else:  
    924 934         build(sys.argv[1])  
    925    
    926    
    927    
    928    
  • trunk/mf.py

    r479 r484  
      1 #  
    1 2 # Copyright (C) 2005, Giovanni Bajo  
      3 #  
    2 4 # Based on previous work under copyright (c) 2002 McMillan Enterprises, Inc.  
    3 5 #  
     
    15 17 # along with this program; if not, write to the Free Software  
    16 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA  
      19 #  
      20  
    17 21 import sys, string, os, imp, marshal, dircache  
    18 22 try:  
     
    22 26     zipimport = None  
    23 27  
      28 import suffixes  
      29  
    24 30 #=======================Owners==========================#  
    25 31 # An Owner does imports from a particular piece of turf  
     
    67 73             raise ValueError, "%s is not a directory" % path  
    68 74         Owner.__init__(self, path)  
    69       def getmod(self, nm, getsuffixes=imp.get_suffixes, loadco=marshal.loads):  
      75     def getmod(self, nm, getsuffixes=suffixes.get_suffixes, loadco=marshal.loads):  
    69 75         pth =  os.path.join(self.path, nm)  
    70 76         possibles = [(pth, 0, None)]  
  • trunk/Configure.py

    r449 r484  
    1 1 #! /usr/bin/env python  
      2 #  
    2 3 # Configure PyInstaller for the current Python installation.  
      4 #  
    3 5 # Copyright (C) 2005, Giovanni Bajo  
    4 6 # Based on previous work under copyright (c) 2002 McMillan Enterprises, Inc.  
     
    18 20 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA  
    19 21  
    20   import os, sys, string, shutil  
      22 import os  
      23 import sys  
      24 import string  
      25 import shutil  
      26 import pprint  
      27 import re  
      28 import glob  
      29  
      30 import mf  
      31 import bindepend  
      32  
    21 33 HOME = os.path.dirname(sys.argv[0])  
    22   iswin = sys.platform[:3] == 'win'  
    23   is24 = hasattr(sys, "version_info") and sys.version_info[:2] >= (2,4)  
    24   cygwin = sys.platform == 'cygwin'  
      34  
      35 from optparse import OptionParser  
      36 parser = OptionParser(usage="%prog [options] <executable_or_dynamic_library>")  
      37 parser.add_option('--target-platform', default=None,  
      38                   help='Target platform, required for cross-bundling (default: current platform).')  
      39 parser.add_option('--executable', default=None,  
      40                   help='Python executable to use. Required for cross-bundling.')  
      41  
      42 opts, args = parser.parse_args()  
      43 if args:  
      44     parser.error('Does not expect any arguments')  
      45  
    25 46 configfile = os.path.join(HOME, 'config.dat')  
    26 47 try:  
     
    30 51     # SyntaxError: invalid file (platform change?)  
    31 52     config = {'useELFEXE':1}    # if not set by Make.py we can assume Windows  
    32        
    33 53  
    34 54 # Save Python version, to detect and avoid conflicts  
    35 55 config["pythonVersion"] = sys.version  
    36 56  
    37   import mf, bindepend  
      57 iswin = sys.platform[:3] == 'win'  
      58 is24 = hasattr(sys, "version_info") and sys.version_info[:2] >= (2,4)  
      59 cygwin = sys.platform == 'cygwin'  
    38 60  
    39 61 # EXE_dependencies  
    40 62 print "I: computing EXE_dependencies"  
    41   python = sys.executable  
      63 python = opts.executable or config.get('python') or sys.executable  
      64 target_platform = opts.target_platform or config.get('target_platform') or sys.platform  
      65 config['python'] = python  
      66 config['target_platform'] = target_platform  
      67 target_iswin = target_platform[:3] == 'win'  
      68  
    42 69 if not iswin:  
    43 70     while os.path.islink(python):  
    44 71         python = os.path.join(os.path.split(python)[0], os.readlink(python))  
    45 72  
    46   toc = bindepend.Dependencies([('', python, '')])  
      73 xtrapath = []  
      74 if target_iswin and not iswin:  
      75     # try to find a mounted Windows system  
      76     xtrapath = glob.glob('/mnt/*/WINDOWS/system32/')  
      77     if not xtrapath:  
      78         print "E: Can not find a mounted Windows system"  
      79         print "W: Please set 'xtrpath' in the config file yourself"  
      80  
      81 xtrapath = config.get('xtrapath') or xtrapath  
      82 config['xtrapath'] = xtrapath  
      83  
      84 toc = bindepend.Dependencies([('', python, '')], target_platform, xtrapath)  
      85  
    47 86 if iswin and sys.version[:3] == '1.5':  
    48 87     import exceptions  
     
    68 107 # TCL_root, TK_root and support/useTK.py  
    69 108 print "I: Finding TCL/TK..."  
    70   if not iswin:  
      109 if not (target_iswin):  
    70 109     saveexcludes = bindepend.excludes  
    71 110     bindepend.excludes = {}  
    72   import re  
    73   pattern = [r'libtcl(\d\.\d)?\.so', r'(?i)tcl(\d\d)\.dll'][iswin]  
      111 pattern = [r'libtcl(\d\.\d)?\.so', r'(?i)tcl(\d\d)\.dll'][target_iswin]  
    74 112 a = mf.ImportTracker()  
    75 113 a.analyze_r('Tkinter')  
     
    86 124         ver = mo.group(1)  
    87 125         tclbindir = os.path.dirname(fnm)  
    88           if iswin:  
      126         if target_iswin:  
    88 126             ver = ver[0] + '.' + ver[1:]  
    89 127         elif ver is None:  
     
    95 133                     ver = mo.group(1)  
    96 134         print "I: found TCL/TK version %s" % ver  
    97           open(os.path.join(HOME, 'support/useTK.py'), 'w').write(_useTK % (ver, ver))  
      135         open(os.path.join(HOME, 'support', 'useTK.py'), 'w').write(_useTK % (ver, ver))  
    97 135         tclnm = 'tcl%s' % ver  
    98 136         tknm = 'tk%s' % ver  
     
    101 139         # Windows: Python21/DLLs with the .tcl files in Python21/tcl/tcl8.3 and Python21/tcl/tk8.3  
    102 140         #      or  D:/Programs/Tcl/bin with the .tcl files in D:/Programs/Tcl/lib/tcl8.0 and D:/Programs/Tcl/lib/tk8.0  
    103           if iswin:  
      141         if target_iswin:  
    103 141             for attempt in ['../tcl', '../lib']:  
    104 142                 if os.path.exists(os.path.join(tclbindir, attempt, tclnm)):  
     
    113 151 else:  
    114 152     print "I: could not find TCL/TK"  
    115   if not iswin:  
      153 if not target_iswin:  
    115 153     bindepend.excludes = saveexcludes  
    116 154  
     
    137 175         print 'I: ... resource update unavailable -', detail  
    138 176     else:  
    139           test_exe = os.path.join(HOME, r'support\loader\run_7rw.exe')  
      177         test_exe = os.path.join(HOME, 'support', 'loader', 'run_7rw.exe')  
    139 177         if not os.path.exists( test_exe ):  
    140 178             config['hasRsrcUpdate'] = 0  
     
    209 247 # now write out config, so Build can load  
    210 248 outf = open(configfile, 'w')  
    211   import pprint  
    212 249 pprint.pprint(config, outf)  
    213 250 outf.close()  
     
    237 274  
    238 275 outf = open(configfile, 'w')  
    239   import pprint  
    240 276 pprint.pprint(config, outf)  
    241 277 outf.close()