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