srcanamdw/codescanner/pyinstaller/Build.py
changeset 1 22878952f6e2
equal deleted inserted replaced
0:509e4801c378 1:22878952f6e2
       
     1 #! /usr/bin/env python
       
     2 # Build packages using spec files
       
     3 # Copyright (C) 2005, Giovanni Bajo
       
     4 # Based on previous work under copyright (c) 1999, 2002 McMillan Enterprises, Inc.
       
     5 #
       
     6 # This program is free software; you can redistribute it and/or
       
     7 # modify it under the terms of the GNU General Public License
       
     8 # as published by the Free Software Foundation; either version 2
       
     9 # of the License, or (at your option) any later version.
       
    10 #
       
    11 # This program is distributed in the hope that it will be useful,
       
    12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    14 # GNU General Public License for more details.
       
    15 #
       
    16 # You should have received a copy of the GNU General Public License
       
    17 # along with this program; if not, write to the Free Software
       
    18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
       
    19 import sys, os, shutil, mf, archive, iu, carchive, pprint, time, py_compile, bindepend, tempfile
       
    20 
       
    21 STRINGTYPE = type('')
       
    22 TUPLETYPE = type((None,))
       
    23 
       
    24 HOMEPATH = os.path.dirname(sys.argv[0])
       
    25 SPECPATH = None
       
    26 BUILDPATH = None
       
    27 WARNFILE = None
       
    28 rthooks = {}
       
    29 iswin = sys.platform[:3] == 'win'
       
    30 cygwin = sys.platform == 'cygwin'
       
    31 try:
       
    32     config = eval(open(os.path.join(HOMEPATH, 'config.dat'), 'r').read())
       
    33 except IOError:
       
    34     print "You must run Configure.py before building!"
       
    35     sys.exit(1)
       
    36 
       
    37 if config['pythonVersion'] != sys.version:
       
    38     print "The current version of Python is not the same with which PyInstaller was configured."
       
    39     print "Please re-run Configure.py with this version."
       
    40     sys.exit(1)
       
    41 
       
    42 if config['hasRsrcUpdate']:
       
    43     import icon, versionInfo
       
    44 
       
    45 def setupUPXFlags():
       
    46     f = os.environ.get("UPX", "")
       
    47     is24 = hasattr(sys, "version_info") and sys.version_info[:2] >= (2,4)
       
    48     if iswin and is24:
       
    49         # Binaries built with Visual Studio 7.1 require --strip-loadconf
       
    50         # or they won't compress. Configure.py makes sure that UPX is new
       
    51         # enough to support --strip-loadconf.
       
    52         f = "--strip-loadconf " + f
       
    53     f = "--best " + f
       
    54     os.environ["UPX"] = f
       
    55 
       
    56 if config['hasUPX']:
       
    57     setupUPXFlags()
       
    58 
       
    59 def build(spec):
       
    60     global SPECPATH, BUILDPATH, WARNFILE, rthooks
       
    61     rthooks = eval(open(os.path.join(HOMEPATH, 'rthooks.dat'), 'r').read())
       
    62     SPECPATH, specnm = os.path.split(spec)
       
    63     specnm = os.path.splitext(specnm)[0]
       
    64     if SPECPATH == '':
       
    65         SPECPATH = os.getcwd()
       
    66     WARNFILE = os.path.join(SPECPATH, 'warn%s.txt' % specnm)
       
    67     BUILDPATH = os.path.join(SPECPATH, 'build%s' % specnm)
       
    68     if '-o' in sys.argv:
       
    69         bpath = sys.argv[sys.argv.index('-o')+1]
       
    70         if os.path.isabs(bpath):
       
    71             BUILDPATH = bpath
       
    72         else:
       
    73             BUILDPATH = os.path.join(SPECPATH, bpath)
       
    74     if not os.path.exists(BUILDPATH):
       
    75         os.mkdir(BUILDPATH)
       
    76     exec open(spec, 'r').read()+'\n'
       
    77 
       
    78 def mtime(fnm):
       
    79     try:
       
    80         return os.stat(fnm)[8]
       
    81     except:
       
    82         return 0
       
    83 
       
    84 class Target:
       
    85     invcnum = 0
       
    86     def __init__(self):
       
    87         self.invcnum = Target.invcnum
       
    88         Target.invcnum = Target.invcnum + 1
       
    89         self.out = os.path.join(BUILDPATH, 'out%d.toc' % self.invcnum)
       
    90         self.dependencies = TOC()
       
    91     def __postinit__(self):
       
    92         print "checking %s" % (self.__class__.__name__,)
       
    93         if self.check_guts(mtime(self.out)):
       
    94             self.assemble()
       
    95 
       
    96 class Analysis(Target):
       
    97     def __init__(self, scripts=None, pathex=None, hookspath=None, excludes=None):
       
    98         Target.__init__(self)
       
    99         self.inputs = scripts
       
   100         for script in scripts:
       
   101             if not os.path.exists(script):
       
   102                 raise ValueError, "script '%s' not found" % script
       
   103         self.pathex = []
       
   104         if pathex:
       
   105             for path in pathex:
       
   106                 self.pathex.append(os.path.abspath(os.path.normpath(path)))
       
   107         self.hookspath = hookspath
       
   108         self.excludes = excludes
       
   109         self.scripts = TOC()
       
   110         self.pure = TOC()
       
   111         self.binaries = TOC()
       
   112         self.__postinit__()
       
   113     def check_guts(self, last_build):
       
   114         outnm = os.path.basename(self.out)
       
   115         if last_build == 0:
       
   116             print "building %s because %s non existent" % (self.__class__.__name__, outnm)
       
   117             return 1
       
   118         for fnm in self.inputs:
       
   119             if mtime(fnm) > last_build:
       
   120                 print "building because %s changed" % fnm
       
   121                 return 1
       
   122         try:
       
   123             inputs, pathex, hookspath, excludes, scripts, pure, binaries = eval(open(self.out, 'r').read())
       
   124         except:
       
   125             print "building because %s disappeared" % outnm
       
   126             return 1
       
   127         if inputs != self.inputs:
       
   128             print "building %s because inputs changed" % outnm
       
   129             return 1
       
   130         if pathex != self.pathex:
       
   131             print "building %s because pathex changed" % outnm
       
   132             return 1
       
   133         if hookspath != self.hookspath:
       
   134             print "building %s because hookspath changed" % outnm
       
   135             return 1
       
   136         if excludes != self.excludes:
       
   137             print "building %s because excludes changed" % outnm
       
   138             return 1
       
   139         for (nm, fnm, typ) in scripts:
       
   140             if mtime(fnm) > last_build:
       
   141                 print "building because %s changed" % fnm
       
   142                 return 1
       
   143         for (nm, fnm, typ) in pure:
       
   144             if mtime(fnm) > last_build:
       
   145                 print "building because %s changed" % fnm
       
   146                 return 1
       
   147             elif mtime(fnm[:-1]) > last_build:
       
   148                 print "building because %s changed" % fnm[:-1]
       
   149                 return 1
       
   150         for (nm, fnm, typ) in binaries:
       
   151             if mtime(fnm) > last_build:
       
   152                 print "building because %s changed" % fnm
       
   153                 return 1
       
   154         self.scripts = TOC(scripts)
       
   155         self.pure = TOC(pure)
       
   156         self.binaries = TOC(binaries)
       
   157         return 0
       
   158     def assemble(self):
       
   159         print "running Analysis", os.path.basename(self.out)
       
   160         paths = self.pathex
       
   161         for i in range(len(paths)):
       
   162             paths[i] = os.path.abspath(os.path.normpath(paths[i]))
       
   163         dirs = {}
       
   164         pynms = []
       
   165         for script in self.inputs:
       
   166             if not os.path.exists(script):
       
   167                 print "Analysis: script %s not found!" % script
       
   168                 sys.exit(1)
       
   169             d, base = os.path.split(script)
       
   170             if not d:
       
   171                 d = os.getcwd()
       
   172             d = os.path.abspath(os.path.normpath(d))
       
   173             pynm, ext = os.path.splitext(base)
       
   174             dirs[d] = 1
       
   175             pynms.append(pynm)
       
   176         analyzer = mf.ImportTracker(dirs.keys()+paths, self.hookspath, self.excludes)
       
   177         #print analyzer.path
       
   178         scripts = []
       
   179         for i in range(len(self.inputs)):
       
   180             script = self.inputs[i]
       
   181             print "Analyzing:", script
       
   182             analyzer.analyze_script(script)
       
   183             scripts.append((pynms[i], script, 'PYSOURCE'))
       
   184         pure = []
       
   185         binaries = []
       
   186         rthooks = []
       
   187         for modnm, mod in analyzer.modules.items():
       
   188             if mod is not None:
       
   189                 hooks = findRTHook(modnm)  #XXX
       
   190                 if hooks:
       
   191                     rthooks.extend(hooks)
       
   192                 if isinstance(mod, mf.BuiltinModule):
       
   193                     pass
       
   194                 else:
       
   195                     fnm = mod.__file__
       
   196                     if isinstance(mod, mf.ExtensionModule):
       
   197                         binaries.append((mod.__name__, fnm, 'EXTENSION'))
       
   198                     elif modnm == '__main__':
       
   199                         pass
       
   200                     else:
       
   201                         pure.append((modnm, fnm, 'PYMODULE'))
       
   202         binaries.extend(bindepend.Dependencies(binaries))
       
   203         scripts[1:1] = rthooks
       
   204         self.scripts = TOC(scripts)
       
   205         self.pure = TOC(pure)
       
   206         self.binaries = TOC(binaries)
       
   207         try:
       
   208             oldstuff = eval(open(self.out, 'r').read())
       
   209         except:
       
   210             oldstuff = None
       
   211         if oldstuff != (self.inputs, self.pathex, self.hookspath, self.excludes, scripts, pure, binaries):
       
   212             outf = open(self.out, 'w')
       
   213             pprint.pprint(
       
   214                 (self.inputs, self.pathex, self.hookspath, self.excludes, self.scripts, self.pure, self.binaries),
       
   215                 outf)
       
   216             outf.close()
       
   217             wf = open(WARNFILE, 'w')
       
   218             for ln in analyzer.getwarnings():
       
   219                 wf.write(ln+'\n')
       
   220             wf.close()
       
   221             print "Warnings written to %s" % WARNFILE
       
   222             return 1
       
   223         print self.out, "no change!"
       
   224         return 0
       
   225 
       
   226 def findRTHook(modnm):
       
   227     hooklist = rthooks.get(modnm)
       
   228     if hooklist:
       
   229         rslt = []
       
   230         for script in hooklist:
       
   231             nm = os.path.basename(script)
       
   232             nm = os.path.splitext(nm)[0]
       
   233             if os.path.isabs(script):
       
   234                 path = script
       
   235             else:
       
   236                 path = os.path.join(HOMEPATH, script)
       
   237             rslt.append((nm, path, 'PYSOURCE'))
       
   238         return rslt
       
   239     return None
       
   240 
       
   241 class PYZ(Target):
       
   242     typ = 'PYZ'
       
   243     def __init__(self, toc, name=None, level=9):
       
   244         Target.__init__(self)
       
   245         self.toc = toc
       
   246         self.name = name
       
   247         if name is None:
       
   248             self.name = self.out[:-3] + 'pyz'
       
   249         if config['useZLIB']:
       
   250             self.level = level
       
   251         else:
       
   252             self.level = 0
       
   253         self.dependencies = config['PYZ_dependencies']
       
   254         self.__postinit__()
       
   255     def check_guts(self, last_build):
       
   256         outnm = os.path.basename(self.out)
       
   257         if not os.path.exists(self.name):
       
   258             print "rebuilding %s because %s is missing" % (outnm, os.path.basename(self.name))
       
   259             return 1
       
   260         try:
       
   261             name, level, toc = eval(open(self.out, 'r').read())
       
   262         except:
       
   263             print "rebuilding %s because missing" % outnm
       
   264             return 1
       
   265         if name != self.name:
       
   266             print "rebuilding %s because name changed" % outnm
       
   267             return 1
       
   268         if level != self.level:
       
   269             print "rebuilding %s because level changed" % outnm
       
   270             return 1
       
   271         if toc != self.toc:
       
   272             print "rebuilding %s because toc changed" % outnm
       
   273             return 1
       
   274         for (nm, fnm, typ) in toc:
       
   275             if mtime(fnm) > last_build:
       
   276                 print "rebuilding %s because %s changed" % (outnm, fnm)
       
   277                 return 1
       
   278             if fnm[-1] in ('c', 'o'):
       
   279                 if mtime(fnm[:-1]) > last_build:
       
   280                     print "rebuilding %s because %s changed" % (outnm, fnm[:-1])
       
   281                     return 1
       
   282         return 0
       
   283     def assemble(self):
       
   284         print "building PYZ", os.path.basename(self.out)
       
   285         pyz = archive.ZlibArchive(level=self.level)
       
   286         toc = self.toc - config['PYZ_dependencies']
       
   287         for (nm, fnm, typ) in toc:
       
   288             if mtime(fnm[:-1]) > mtime(fnm):
       
   289                 py_compile.compile(fnm[:-1])
       
   290         pyz.build(self.name, toc)
       
   291         outf = open(self.out, 'w')
       
   292         pprint.pprint((self.name, self.level, self.toc), outf)
       
   293         outf.close()
       
   294         return 1
       
   295 
       
   296 def checkCache(fnm, strip, upx):
       
   297     if not strip and not upx:
       
   298         return fnm
       
   299     if strip:
       
   300         strip = 1
       
   301     else:
       
   302         strip = 0
       
   303     if upx:
       
   304         upx = 1
       
   305     else:
       
   306         upx = 0
       
   307     cachedir = os.path.join(HOMEPATH, 'bincache%d%d' %  (strip, upx))
       
   308     if not os.path.exists(cachedir):
       
   309         os.makedirs(cachedir)
       
   310     basenm = os.path.basename(fnm)
       
   311     cachedfile = os.path.join(cachedir, basenm )
       
   312     if os.path.exists(cachedfile):
       
   313         if mtime(fnm) > mtime(cachedfile):
       
   314             os.remove(cachedfile)
       
   315         else:
       
   316             return cachedfile
       
   317     if upx:
       
   318         if strip:
       
   319             fnm = checkCache(fnm, 1, 0)
       
   320         cmd = "upx --best -q \"%s\"" % cachedfile
       
   321     else:
       
   322         cmd = "strip \"%s\"" % cachedfile
       
   323     shutil.copy2(fnm, cachedfile)
       
   324     os.chmod(cachedfile, 0755)
       
   325     os.system(cmd)
       
   326     return cachedfile
       
   327 
       
   328 UNCOMPRESSED, COMPRESSED = range(2)
       
   329 class PKG(Target):
       
   330     typ = 'PKG'
       
   331     xformdict = {'PYMODULE' : 'm',
       
   332                  'PYSOURCE' : 's',
       
   333                  'EXTENSION' : 'b',
       
   334                  'PYZ' : 'z',
       
   335                  'PKG' : 'a',
       
   336                  'DATA': 'x',
       
   337                  'BINARY': 'b',
       
   338                  'EXECUTABLE': 'b'}
       
   339     def __init__(self, toc, name=None, cdict=None, exclude_binaries=0,
       
   340                  strip_binaries=0, upx_binaries=0):
       
   341         Target.__init__(self)
       
   342         self.toc = toc
       
   343         self.cdict = cdict
       
   344         self.name = name
       
   345         self.exclude_binaries = exclude_binaries
       
   346         self.strip_binaries = strip_binaries
       
   347         self.upx_binaries = upx_binaries
       
   348         if name is None:
       
   349             self.name = self.out[:-3] + 'pkg'
       
   350         if self.cdict is None:
       
   351             if config['useZLIB']:
       
   352                 self.cdict = {'EXTENSION':COMPRESSED,
       
   353                               'DATA':COMPRESSED,
       
   354                               'BINARY':COMPRESSED,
       
   355                               'EXECUTABLE':COMPRESSED,
       
   356                               'PYSOURCE':COMPRESSED,
       
   357                               'PYMODULE':COMPRESSED }
       
   358             else:
       
   359                 self.cdict = { 'PYSOURCE':UNCOMPRESSED }
       
   360         self.__postinit__()
       
   361     def check_guts(self, last_build):
       
   362         outnm = os.path.basename(self.out)
       
   363         if not os.path.exists(self.name):
       
   364             print "rebuilding %s because %s is missing" % (outnm, os.path.basename(self.name))
       
   365             return 1
       
   366         try:
       
   367             name, cdict, toc, exclude_binaries, strip_binaries, upx_binaries = eval(open(self.out, 'r').read())
       
   368         except:
       
   369             print "rebuilding %s because %s is missing" % (outnm, outnm)
       
   370             return 1
       
   371         if name != self.name:
       
   372             print "rebuilding %s because name changed" % outnm
       
   373             return 1
       
   374         if cdict != self.cdict:
       
   375             print "rebuilding %s because cdict changed" % outnm
       
   376             return 1
       
   377         if toc != self.toc:
       
   378             print "rebuilding %s because toc changed" % outnm
       
   379             return 1
       
   380         if exclude_binaries != self.exclude_binaries:
       
   381             print "rebuilding %s because exclude_binaries changed" % outnm
       
   382             return 1
       
   383         if strip_binaries != self.strip_binaries:
       
   384             print "rebuilding %s because strip_binaries changed" % outnm
       
   385             return 1
       
   386         if upx_binaries != self.upx_binaries:
       
   387             print "rebuilding %s because upx_binaries changed" % outnm
       
   388             return 1
       
   389         for (nm, fnm, typ) in toc:
       
   390             if mtime(fnm) > last_build:
       
   391                 print "rebuilding %s because %s changed" % (outnm, fnm)
       
   392                 return 1
       
   393         return 0
       
   394     def assemble(self):
       
   395         print "building PKG", os.path.basename(self.name)
       
   396         trash = []
       
   397         mytoc = []
       
   398         toc = TOC()
       
   399         for item in self.toc:
       
   400             inm, fnm, typ = item
       
   401             if typ == 'EXTENSION':
       
   402                 binext = os.path.splitext(fnm)[1]
       
   403                 if not os.path.splitext(inm)[1] == binext:
       
   404                     inm = inm + binext
       
   405             toc.append((inm, fnm, typ))
       
   406         seen = {}
       
   407         for inm, fnm, typ in toc:
       
   408             if typ in ('BINARY', 'EXTENSION'):
       
   409                 if self.exclude_binaries:
       
   410                     self.dependencies.append((inm, fnm, typ))
       
   411                 else:
       
   412                     fnm = checkCache(fnm, self.strip_binaries,
       
   413                                      self.upx_binaries and ( iswin or cygwin )
       
   414                                       and config['hasUPX'])
       
   415                     # Avoid importing the same binary extension twice. This might
       
   416                     # happen if they come from different sources (eg. once from
       
   417                     # binary dependence, and once from direct import).
       
   418                     if typ == 'BINARY' and seen.has_key(fnm):
       
   419                         continue
       
   420                     seen[fnm] = 1
       
   421                     mytoc.append((inm, fnm, self.cdict.get(typ,0),
       
   422                                   self.xformdict.get(typ,'b')))
       
   423             elif typ == 'OPTION':
       
   424                 mytoc.append((inm, '', 0, 'o'))
       
   425             else:
       
   426                 mytoc.append((inm, fnm, self.cdict.get(typ,0), self.xformdict.get(typ,'b')))
       
   427         archive = carchive.CArchive()
       
   428         archive.build(self.name, mytoc)
       
   429         outf = open(self.out, 'w')
       
   430         pprint.pprint((self.name, self.cdict, self.toc, self.exclude_binaries, self.strip_binaries, self.upx_binaries), outf)
       
   431         outf.close()
       
   432         for item in trash:
       
   433             os.remove(item)
       
   434         return 1
       
   435 
       
   436 class ELFEXE(Target):
       
   437     typ = 'EXECUTABLE'
       
   438     exclude_binaries = 0
       
   439     def __init__(self, *args, **kws):
       
   440         Target.__init__(self)
       
   441         self.console = kws.get('console',1)
       
   442         self.debug = kws.get('debug',0)
       
   443         self.name = kws.get('name',None)
       
   444         self.icon = kws.get('icon',None)
       
   445         self.versrsrc = kws.get('version',None)
       
   446         self.strip = kws.get('strip',None)
       
   447         self.upx = kws.get('upx',None)
       
   448         self.exclude_binaries = kws.get('exclude_binaries',0)
       
   449         if self.name is None:
       
   450             self.name = self.out[:-3] + 'exe'
       
   451         if not os.path.isabs(self.name):
       
   452             self.name = os.path.join(SPECPATH, self.name)
       
   453         self.toc = TOC()
       
   454         for arg in args:
       
   455             if isinstance(arg, TOC):
       
   456                 self.toc.extend(arg)
       
   457             elif isinstance(arg, Target):
       
   458                 self.toc.append((os.path.basename(arg.name), arg.name, arg.typ))
       
   459                 self.toc.extend(arg.dependencies)
       
   460             else:
       
   461                 self.toc.extend(arg)
       
   462         self.toc.extend(config['EXE_dependencies'])
       
   463         self.pkg = PKG(self.toc, cdict=kws.get('cdict',None), exclude_binaries=self.exclude_binaries,
       
   464                        strip_binaries=self.strip, upx_binaries=self.upx)
       
   465         self.dependencies = self.pkg.dependencies
       
   466         self.__postinit__()
       
   467     def check_guts(self, last_build):
       
   468         outnm = os.path.basename(self.out)
       
   469         if not os.path.exists(self.name):
       
   470             print "rebuilding %s because %s missing" % (outnm, os.path.basename(self.name))
       
   471             return 1
       
   472         try:
       
   473             name, console, debug, icon, versrsrc, strip, upx, mtm = eval(open(self.out, 'r').read())
       
   474         except:
       
   475             print "rebuilding %s because %s missing or bad" % (outnm, outnm)
       
   476             return 1
       
   477         if name != self.name:
       
   478             print "rebuilding %s because name changed" % outnm
       
   479             return 1
       
   480         if console != self.console:
       
   481             print "rebuilding %s because console option changed" % outnm
       
   482             return 1
       
   483         if debug != self.debug:
       
   484             print "rebuilding %s because debug option changed" % outnm
       
   485             return 1
       
   486         if config['hasRsrcUpdate']:
       
   487             if icon != self.icon:
       
   488                 print "rebuilding %s because icon option changed" % outnm
       
   489                 return 1
       
   490             if versrsrc != self.versrsrc:
       
   491                 print "rebuilding %s because versrsrc option changed" % outnm
       
   492                 return 1
       
   493         else:
       
   494             if icon or versrsrc:
       
   495                 print "ignoring icon and version resources = platform not capable"
       
   496         if strip != self.strip:
       
   497             print "rebuilding %s because strip option changed" % outnm
       
   498             return 1
       
   499         if upx != self.upx:
       
   500             print "rebuilding %s because upx option changed" % outnm
       
   501             return 1
       
   502         if mtm != mtime(self.name):
       
   503             print "rebuilding %s because mtimes don't match" % outnm
       
   504             return 1
       
   505         if mtm < mtime(self.pkg.out):
       
   506             print "rebuilding %s because pkg is more recent" % outnm
       
   507             return 1
       
   508         return 0
       
   509     def _bootloader_postfix(self, exe):
       
   510         if iswin:
       
   511             exe = exe + "_"
       
   512             is24 = hasattr(sys, "version_info") and sys.version_info[:2] >= (2,4)
       
   513             exe = exe + "67"[is24]
       
   514             exe = exe + "rd"[self.debug]
       
   515             exe = exe + "wc"[self.console]
       
   516         else:
       
   517             if not self.console:
       
   518                 exe = exe + 'w'
       
   519             if self.debug:
       
   520                 exe = exe + '_d'
       
   521         return exe
       
   522     def assemble(self):
       
   523         print "building ELFEXE", os.path.basename(self.out)
       
   524         trash = []
       
   525         outf = open(self.name, 'wb')
       
   526         exe = self._bootloader_postfix('support/loader/run')
       
   527         exe = os.path.join(HOMEPATH, exe)
       
   528         if iswin or cygwin:
       
   529             exe = exe + '.exe'
       
   530         if config['hasRsrcUpdate']:
       
   531             if self.icon:
       
   532                 tmpnm = tempfile.mktemp()
       
   533                 shutil.copy2(exe, tmpnm)
       
   534                 os.chmod(tmpnm, 0755)
       
   535                 icon.CopyIcons(tmpnm, self.icon)
       
   536                 trash.append(tmpnm)
       
   537                 exe = tmpnm
       
   538             if self.versrsrc:
       
   539                 tmpnm = tempfile.mktemp()
       
   540                 shutil.copy2(exe, tmpnm)
       
   541                 os.chmod(tmpnm, 0755)
       
   542                 versionInfo.SetVersion(tmpnm, self.versrsrc)
       
   543                 trash.append(tmpnm)
       
   544                 exe = tmpnm
       
   545         exe = checkCache(exe, self.strip, self.upx and config['hasUPX'])
       
   546         self.copy(exe, outf)
       
   547         self.copy(self.pkg.name, outf)
       
   548         outf.close()
       
   549         os.chmod(self.name, 0755)
       
   550         f = open(self.out, 'w')
       
   551         pprint.pprint((self.name, self.console, self.debug, self.icon, self.versrsrc,
       
   552                        self.strip, self.upx, mtime(self.name)), f)
       
   553         f.close()
       
   554         for item in trash:
       
   555             os.remove(item)
       
   556         return 1
       
   557     def copy(self, fnm, outf):
       
   558         inf = open(fnm, 'rb')
       
   559         while 1:
       
   560             data = inf.read(64*1024)
       
   561             if not data:
       
   562                 break
       
   563             outf.write(data)
       
   564 
       
   565 class DLL(ELFEXE):
       
   566     def assemble(self):
       
   567         print "building DLL", os.path.basename(self.out)
       
   568         outf = open(self.name, 'wb')
       
   569         dll = self._bootloader_postfix('support/loader/inprocsrvr')
       
   570         dll = os.path.join(HOMEPATH, dll)  + '.dll'
       
   571         self.copy(dll, outf)
       
   572         self.copy(self.pkg.name, outf)
       
   573         outf.close()
       
   574         os.chmod(self.name, 0755)
       
   575         f = open(self.out, 'w')
       
   576         pprint.pprint((self.name, self.console, self.debug, self.icon, self.versrsrc,
       
   577                        self.strip, self.upx, mtime(self.name)), f)
       
   578         f.close()
       
   579         return 1
       
   580 
       
   581 class NonELFEXE(ELFEXE):
       
   582     def assemble(self):
       
   583         print "building NonELFEXE", os.path.basename(self.out)
       
   584         trash = []
       
   585         exe = 'support/loader/run'
       
   586         if not self.console:
       
   587             exe = exe + 'w'
       
   588         if self.debug:
       
   589             exe = exe + '_d'
       
   590         exe = os.path.join(HOMEPATH, exe)
       
   591         exe = checkCache(exe, self.strip, self.upx and config['hasUPX'])
       
   592         shutil.copy2(exe, self.name)
       
   593         os.chmod(self.name, 0755)
       
   594         shutil.copy2(self.pkg.name, self.name+'.pkg')
       
   595         f = open(self.out, 'w')
       
   596         pprint.pprint((self.name, self.console, self.debug, self.icon, self.versrsrc,
       
   597                        self.strip, self.upx, mtime(self.name)), f)
       
   598         f.close()
       
   599         for fnm in trash:
       
   600             os.remove(fnm)
       
   601         return 1
       
   602 
       
   603 if config['useELFEXE']:
       
   604     EXE = ELFEXE
       
   605 else:
       
   606     EXE = NonELFEXE
       
   607 
       
   608 class COLLECT(Target):
       
   609     def __init__(self, *args, **kws):
       
   610         Target.__init__(self)
       
   611         self.name = kws.get('name',None)
       
   612         if self.name is None:
       
   613             self.name = 'dist_' + self.out[:-4]
       
   614         self.strip_binaries = kws.get('strip',0)
       
   615         self.upx_binaries = kws.get('upx',0)
       
   616         if not os.path.isabs(self.name):
       
   617             self.name = os.path.join(SPECPATH, self.name)
       
   618         self.toc = TOC()
       
   619         for arg in args:
       
   620             if isinstance(arg, TOC):
       
   621                 self.toc.extend(arg)
       
   622             elif isinstance(arg, Target):
       
   623                 self.toc.append((os.path.basename(arg.name), arg.name, arg.typ))
       
   624                 if isinstance(arg, NonELFEXE):
       
   625                     self.toc.append((os.path.basename(arg.name)+'.pkg', arg.name+'.pkg', 'PKG'))
       
   626                 self.toc.extend(arg.dependencies)
       
   627             else:
       
   628                 self.toc.extend(arg)
       
   629         self.__postinit__()
       
   630     def check_guts(self, last_build):
       
   631         outnm = os.path.basename(self.out)
       
   632         try:
       
   633             name, strip_binaries, upx_binaries, toc = eval(open(self.out, 'r').read())
       
   634         except:
       
   635             print "building %s because %s missing" % (outnm, outnm)
       
   636             return 1
       
   637         if name != self.name:
       
   638             print "building %s because name changed" % outnm
       
   639             return 1
       
   640         if strip_binaries != self.strip_binaries:
       
   641             print "building %s because strip_binaries option changed" % outnm
       
   642             return 1
       
   643         if upx_binaries != self.upx_binaries:
       
   644             print "building %s because upx_binaries option changed" % outnm
       
   645             return 1
       
   646         if toc != self.toc:
       
   647             print "building %s because toc changed" % outnm
       
   648             return 1
       
   649         for inm, fnm, typ in self.toc:
       
   650             if typ == 'EXTENSION':
       
   651                 ext = os.path.splitext(fnm)[1]
       
   652                 test = os.path.join(self.name, inm+ext)
       
   653             else:
       
   654                 test = os.path.join(self.name, os.path.basename(fnm))
       
   655             if not os.path.exists(test):
       
   656                 print "building %s because %s is missing" % (outnm, test)
       
   657                 return 1
       
   658             if mtime(fnm) > mtime(test):
       
   659                 print "building %s because %s is more recent" % (outnm, fnm)
       
   660                 return 1
       
   661         return 0
       
   662     def assemble(self):
       
   663         print "building COLLECT", os.path.basename(self.out)
       
   664         if not os.path.exists(self.name):
       
   665             os.mkdir(self.name)
       
   666         toc = TOC()
       
   667         for inm, fnm, typ in self.toc:
       
   668             if typ == 'EXTENSION':
       
   669                 binext = os.path.splitext(fnm)[1]
       
   670                 if not os.path.splitext(inm)[1] == binext:
       
   671                     inm = inm + binext
       
   672             toc.append((inm, fnm, typ))
       
   673         for inm, fnm, typ in toc:
       
   674             tofnm = os.path.join(self.name, inm)
       
   675             todir = os.path.dirname(tofnm)
       
   676             if not os.path.exists(todir):
       
   677                 os.makedirs(todir)
       
   678             if typ in ('EXTENSION', 'BINARY'):
       
   679                 fnm = checkCache(fnm, self.strip_binaries,
       
   680                                  self.upx_binaries and ( iswin or cygwin )
       
   681                                   and config['hasUPX'])
       
   682             shutil.copy2(fnm, tofnm)
       
   683             if typ in ('EXTENSION', 'BINARY'):
       
   684                 os.chmod(tofnm, 0755)
       
   685         f = open(self.out, 'w')
       
   686         pprint.pprint((self.name, self.strip_binaries, self.upx_binaries, self.toc), f)
       
   687         f.close()
       
   688         return 1
       
   689 
       
   690 import UserList
       
   691 class TOC(UserList.UserList):
       
   692     def __init__(self, initlist=None):
       
   693         UserList.UserList.__init__(self)
       
   694         self.fltr = {}
       
   695         if initlist:
       
   696             for tpl in initlist:
       
   697                 self.append(tpl)
       
   698     def append(self, tpl):
       
   699         try:
       
   700             if not self.fltr.get(tpl[0]):
       
   701                 self.data.append(tpl)
       
   702                 self.fltr[tpl[0]] = 1
       
   703         except TypeError:
       
   704             print "TOC found a %s, not a tuple" % tpl
       
   705             raise
       
   706     def insert(self, pos, tpl):
       
   707         if not self.fltr.get(tpl[0]):
       
   708             self.data.insert(pos, tpl)
       
   709             self.fltr[tpl[0]] = 1
       
   710     def __add__(self, other):
       
   711         rslt = TOC(self.data)
       
   712         rslt.extend(other)
       
   713         return rslt
       
   714     def __radd__(self, other):
       
   715         rslt = TOC(other)
       
   716         rslt.extend(self.data)
       
   717         return rslt
       
   718     def extend(self, other):
       
   719         for tpl in other:
       
   720             self.append(tpl)
       
   721     def __sub__(self, other):
       
   722         fd = self.fltr.copy()
       
   723         # remove from fd if it's in other
       
   724         for tpl in other:
       
   725             if fd.get(tpl[0],0):
       
   726                 del fd[tpl[0]]
       
   727         rslt = TOC()
       
   728         # return only those things still in fd (preserve order)
       
   729         for tpl in self.data:
       
   730             if fd.get(tpl[0],0):
       
   731                 rslt.append(tpl)
       
   732         return rslt
       
   733     def __rsub__(self, other):
       
   734         rslt = TOC(other)
       
   735         return rslt.__sub__(self)
       
   736     def intersect(self, other):
       
   737         rslt = TOC()
       
   738         for tpl in other:
       
   739             if self.fltr.get(tpl[0],0):
       
   740                 rslt.append(tpl)
       
   741         return rslt
       
   742 
       
   743 class Tree(Target, TOC):
       
   744     def __init__(self, root=None, prefix=None, excludes=None):
       
   745         Target.__init__(self)
       
   746         TOC.__init__(self)
       
   747         self.root = root
       
   748         self.prefix = prefix
       
   749         self.excludes = excludes
       
   750         if excludes is None:
       
   751             self.excludes = []
       
   752         self.__postinit__()
       
   753     def check_guts(self, last_build):
       
   754         outnm = os.path.basename(self.out)
       
   755         try:
       
   756             root, prefix, excludes, toc = eval(open(self.out, 'r').read())
       
   757         except:
       
   758             print "building %s because %s is missing / bad" % (outnm, outnm)
       
   759             return 1
       
   760         if root != self.root:
       
   761             print "building %s because root changed" % outnm
       
   762             return 1
       
   763         if prefix != self.prefix:
       
   764             print "building %s because prefix changed" % outnm
       
   765             return 1
       
   766         if excludes != self.excludes:
       
   767             print "building %s because excludes changed" % outnm
       
   768             return 1
       
   769         stack = [root]
       
   770         while stack:
       
   771             d = stack.pop()
       
   772             if mtime(d) > last_build:
       
   773                 print "building %s because directory %s changed" % (outnm, d)
       
   774                 return 1
       
   775             for nm in os.listdir(d):
       
   776                 path = os.path.join(d, nm)
       
   777                 if os.path.isdir(path):
       
   778                     stack.append(path)
       
   779         self.data = toc
       
   780         return 0
       
   781     def assemble(self):
       
   782         print "building Tree", os.path.basename(self.out)
       
   783         stack = [(self.root, self.prefix)]
       
   784         excludes = {}
       
   785         xexcludes = {}
       
   786         for nm in self.excludes:
       
   787             if nm[0] == '*':
       
   788                 xexcludes[nm[1:]] = 1
       
   789             else:
       
   790                 excludes[nm] = 1
       
   791         rslt = []
       
   792         while stack:
       
   793             dir, prefix = stack.pop()
       
   794             for fnm in os.listdir(dir):
       
   795                 if excludes.get(fnm, 0) == 0:
       
   796                     ext = os.path.splitext(fnm)[1]
       
   797                     if xexcludes.get(ext,0) == 0:
       
   798                         fullfnm = os.path.join(dir, fnm)
       
   799                         rfnm = prefix and os.path.join(prefix, fnm) or fnm
       
   800                         if os.path.isdir(fullfnm):
       
   801                             stack.append((fullfnm, rfnm))
       
   802                         else:
       
   803                             rslt.append((rfnm, fullfnm, 'DATA'))
       
   804         try:
       
   805             oldstuff = eval(open(self.out, 'r').read())
       
   806         except:
       
   807             oldstuff = None
       
   808         if oldstuff != (self.root, self.prefix, self.excludes, rslt):
       
   809             outf = open(self.out, 'w')
       
   810             pprint.pprint((self.root, self.prefix, self.excludes, rslt), outf)
       
   811             outf.close()
       
   812             self.data = rslt
       
   813             return 1
       
   814         print self.out, "no change!"
       
   815         return 0
       
   816 
       
   817 def TkTree():
       
   818     tclroot = config['TCL_root']
       
   819     tclnm = os.path.join('_MEI', os.path.basename(tclroot))
       
   820     tkroot = config['TK_root']
       
   821     tknm = os.path.join('_MEI', os.path.basename(tkroot))
       
   822     tcltree = Tree(tclroot, tclnm, excludes=['demos','encoding','*.lib'])
       
   823     tktree = Tree(tkroot, tknm, excludes=['demos','encoding','*.lib'])
       
   824     return tcltree + tktree
       
   825 
       
   826 def TkPKG():
       
   827     return PKG(TkTree(), name='tk.pkg')
       
   828 
       
   829 usage = """\
       
   830 Usage: python %s <specfile>
       
   831 
       
   832 See doc/Tutorial.html for details.
       
   833 """
       
   834 
       
   835 if __name__ == '__main__':
       
   836     if len(sys.argv) < 2:
       
   837         print usage % sys.argv[0]
       
   838     else:
       
   839         build(sys.argv[1])
       
   840 
       
   841 
       
   842 
       
   843