From 82ab43bb1ea1b58ab01c715c2b5df3f69c8dc14e Mon Sep 17 00:00:00 2001 From: naufraghi Date: Wed, 30 Apr 2008 14:30:09 +0000 Subject: [PATCH] Merged revisions 342-393,401-404,413,424,426-427,429-433,435-437,439-442,445,448 via svnmerge from https://svn.pyinstaller.python-hosting.com/branches/python2.5 ........ r342 | naufraghi | 2007-12-03 20:02:47 +0100 (Lun, 03 Dic 2007) | 5 lines r238@rosen: naufraghi | 2007-12-03 19:59:24 +0100 r200@rosen: naufraghi | 2007-11-23 15:54:13 +0100 Cleanup, remove some warning ........ r343 | naufraghi | 2007-12-03 20:02:56 +0100 (Lun, 03 Dic 2007) | 5 lines r239@rosen: naufraghi | 2007-12-03 19:59:24 +0100 r201@rosen: naufraghi | 2007-11-23 17:23:15 +0100 Allow starting runtests from any path ........ r344 | naufraghi | 2007-12-03 20:03:04 +0100 (Lun, 03 Dic 2007) | 5 lines r240@rosen: naufraghi | 2007-12-03 20:00:51 +0100 r202@rosen: naufraghi | 2007-11-23 17:24:17 +0100 Add natural sort for tests ........ r345 | naufraghi | 2007-12-03 20:03:12 +0100 (Lun, 03 Dic 2007) | 5 lines r241@rosen: naufraghi | 2007-12-03 20:00:51 +0100 r203@rosen: naufraghi | 2007-11-23 17:32:46 +0100 Fix some fragile import? ........ r346 | naufraghi | 2007-12-03 20:03:21 +0100 (Lun, 03 Dic 2007) | 5 lines r242@rosen: naufraghi | 2007-12-03 20:01:01 +0100 r204@rosen: naufraghi | 2007-11-23 17:46:41 +0100 Adds a basic way to choose tests to run ........ r347 | naufraghi | 2007-12-03 20:03:29 +0100 (Lun, 03 Dic 2007) | 5 lines r243@rosen: naufraghi | 2007-12-03 20:01:04 +0100 r205@rosen: naufraghi | 2007-11-23 17:57:31 +0100 Adds and xml.dom test ........ r348 | naufraghi | 2007-12-03 20:03:38 +0100 (Lun, 03 Dic 2007) | 5 lines r244@rosen: naufraghi | 2007-12-03 20:01:04 +0100 r206@rosen: naufraghi | 2007-11-23 18:05:04 +0100 Remove cmd line quoting ........ r349 | naufraghi | 2007-12-03 20:03:46 +0100 (Lun, 03 Dic 2007) | 5 lines r245@rosen: naufraghi | 2007-12-03 20:01:06 +0100 r207@rosen: naufraghi | 2007-11-23 19:47:13 +0100 Adds 'import os' in one specfile ........ r350 | naufraghi | 2007-12-03 20:03:54 +0100 (Lun, 03 Dic 2007) | 5 lines r246@rosen: naufraghi | 2007-12-03 20:01:08 +0100 r208@rosen: naufraghi | 2007-11-23 19:49:21 +0100 Add an 'encoding' hiddeimport test ........ r351 | naufraghi | 2007-12-03 20:04:05 +0100 (Lun, 03 Dic 2007) | 5 lines r248@rosen: naufraghi | 2007-12-03 20:01:08 +0100 r211@rosen: naufraghi | 2007-11-27 16:13:30 +0100 Rewrite exec in execfile ........ r352 | naufraghi | 2007-12-03 20:04:15 +0100 (Lun, 03 Dic 2007) | 5 lines r250@rosen: naufraghi | 2007-12-03 20:01:09 +0100 r214@rosen: naufraghi | 2007-11-30 11:49:23 +0100 Adds support for extended __path__ ........ r353 | naufraghi | 2007-12-03 20:04:23 +0100 (Lun, 03 Dic 2007) | 5 lines r251@rosen: naufraghi | 2007-12-03 20:01:13 +0100 r215@rosen: naufraghi | 2007-11-30 11:52:18 +0100 Simplify execfile ........ r354 | naufraghi | 2007-12-03 20:04:30 +0100 (Lun, 03 Dic 2007) | 5 lines r252@rosen: naufraghi | 2007-12-03 20:01:15 +0100 r216@rosen: naufraghi | 2007-11-30 11:52:56 +0100 Fix output path ........ r355 | naufraghi | 2007-12-03 20:04:38 +0100 (Lun, 03 Dic 2007) | 5 lines r253@rosen: naufraghi | 2007-12-03 20:01:16 +0100 r217@rosen: naufraghi | 2007-11-30 12:13:17 +0100 Add optional logging of self.moduleds ........ r356 | naufraghi | 2007-12-03 20:04:46 +0100 (Lun, 03 Dic 2007) | 5 lines r254@rosen: naufraghi | 2007-12-03 20:01:16 +0100 r218@rosen: naufraghi | 2007-11-30 12:19:13 +0100 Add __str__ at Module class (and adds a default __file__ too) ........ r357 | naufraghi | 2007-12-03 20:04:54 +0100 (Lun, 03 Dic 2007) | 5 lines r255@rosen: naufraghi | 2007-12-03 20:01:18 +0100 r219@rosen: naufraghi | 2007-11-30 12:30:19 +0100 Add version info to log filename ........ r358 | naufraghi | 2007-12-03 20:05:01 +0100 (Lun, 03 Dic 2007) | 5 lines r256@rosen: naufraghi | 2007-12-03 20:01:19 +0100 r220@rosen: naufraghi | 2007-11-30 16:11:07 +0100 Asset-ize a comment + cosmetics (align variable name to other scopes) ........ r359 | naufraghi | 2007-12-03 20:05:09 +0100 (Lun, 03 Dic 2007) | 5 lines r257@rosen: naufraghi | 2007-12-03 20:01:21 +0100 r221@rosen: naufraghi | 2007-11-30 16:46:17 +0100 Add comments and a None-iti assert ........ r360 | naufraghi | 2007-12-03 20:05:16 +0100 (Lun, 03 Dic 2007) | 5 lines r258@rosen: naufraghi | 2007-12-03 20:01:24 +0100 r222@rosen: naufraghi | 2007-12-03 16:23:17 +0100 Remove user interaction ........ r361 | naufraghi | 2007-12-03 20:05:25 +0100 (Lun, 03 Dic 2007) | 5 lines r259@rosen: naufraghi | 2007-12-03 20:01:25 +0100 r223@rosen: naufraghi | 2007-12-03 16:39:48 +0100 Activate the option to run selected tests: runtests.py --run 12 13 ........ r362 | naufraghi | 2007-12-03 20:05:32 +0100 (Lun, 03 Dic 2007) | 5 lines r260@rosen: naufraghi | 2007-12-03 20:01:28 +0100 r224@rosen: naufraghi | 2007-12-03 16:51:02 +0100 Adds a test that fails ........ r363 | naufraghi | 2007-12-03 20:05:41 +0100 (Lun, 03 Dic 2007) | 5 lines r261@rosen: naufraghi | 2007-12-03 20:01:28 +0100 r225@rosen: naufraghi | 2007-12-03 17:11:07 +0100 Expand imports ........ r364 | naufraghi | 2007-12-03 20:05:48 +0100 (Lun, 03 Dic 2007) | 5 lines r262@rosen: naufraghi | 2007-12-03 20:01:29 +0100 r226@rosen: naufraghi | 2007-12-03 17:12:21 +0100 Reorder imports ........ r365 | naufraghi | 2007-12-03 20:05:55 +0100 (Lun, 03 Dic 2007) | 5 lines r263@rosen: naufraghi | 2007-12-03 20:01:30 +0100 r227@rosen: naufraghi | 2007-12-03 17:16:11 +0100 Turns 1-0 to True-False ........ r366 | naufraghi | 2007-12-03 20:06:03 +0100 (Lun, 03 Dic 2007) | 5 lines r264@rosen: naufraghi | 2007-12-03 20:01:30 +0100 r228@rosen: naufraghi | 2007-12-03 17:32:17 +0100 Path cleanup ........ r367 | naufraghi | 2007-12-03 20:06:10 +0100 (Lun, 03 Dic 2007) | 5 lines r265@rosen: naufraghi | 2007-12-03 20:01:32 +0100 r229@rosen: naufraghi | 2007-12-03 17:35:21 +0100 Followup: Path cleanup ........ r368 | naufraghi | 2007-12-03 20:06:17 +0100 (Lun, 03 Dic 2007) | 5 lines r266@rosen: naufraghi | 2007-12-03 20:01:33 +0100 r230@rosen: naufraghi | 2007-12-03 18:42:00 +0100 Add some docs to assemble() ........ r369 | naufraghi | 2007-12-03 20:06:23 +0100 (Lun, 03 Dic 2007) | 5 lines r267@rosen: naufraghi | 2007-12-03 20:01:35 +0100 r231@rosen: naufraghi | 2007-12-03 18:55:32 +0100 Remove criptic outN.toc numbering, use class names + reformat docs ........ r370 | naufraghi | 2007-12-03 20:06:30 +0100 (Lun, 03 Dic 2007) | 5 lines r268@rosen: naufraghi | 2007-12-03 20:01:36 +0100 r232@rosen: naufraghi | 2007-12-03 18:56:26 +0100 Restore common prefix 'out' ........ r371 | naufraghi | 2007-12-03 20:06:38 +0100 (Lun, 03 Dic 2007) | 5 lines r269@rosen: naufraghi | 2007-12-03 20:01:37 +0100 r236@rosen: naufraghi | 2007-12-03 19:16:19 +0100 Cosmetic ........ r372 | naufraghi | 2007-12-03 20:06:45 +0100 (Lun, 03 Dic 2007) | 5 lines r270@rosen: naufraghi | 2007-12-03 20:01:37 +0100 r237@rosen: naufraghi | 2007-12-03 19:17:17 +0100 Factorize py[c|o] extension choice ........ r373 | naufraghi | 2007-12-04 12:01:51 +0100 (Mar, 04 Dic 2007) | 3 lines r302@rosen: naufraghi | 2007-12-04 12:00:38 +0100 Restore invcnum ........ r374 | naufraghi | 2007-12-04 12:01:58 +0100 (Mar, 04 Dic 2007) | 3 lines r303@rosen: naufraghi | 2007-12-04 12:01:41 +0100 Add warning for mod == None ........ r375 | naufraghi | 2007-12-04 12:08:04 +0100 (Mar, 04 Dic 2007) | 2 lines Add final final "done" message ........ r376 | naufraghi | 2007-12-04 12:09:30 +0100 (Mar, 04 Dic 2007) | 3 lines Ops, is "config.dat" ........ r377 | naufraghi | 2007-12-04 12:26:20 +0100 (Mar, 04 Dic 2007) | 2 lines Restored removed "break" ........ r378 | naufraghi | 2007-12-04 16:01:18 +0100 (Mar, 04 Dic 2007) | 2 lines Remove already logged warning ........ r379 | naufraghi | 2007-12-04 17:46:50 +0100 (Mar, 04 Dic 2007) | 1 line Minimize test case ........ r380 | naufraghi | 2007-12-04 17:51:07 +0100 (Mar, 04 Dic 2007) | 1 line Update PathImportDirector if __path__ changes (for example if modified by _xmlplus hook) ........ r381 | naufraghi | 2007-12-04 18:06:10 +0100 (Mar, 04 Dic 2007) | 1 line Localize hiddenimport and add hook ........ r382 | naufraghi | 2007-12-04 19:37:45 +0100 (Mar, 04 Dic 2007) | 1 line Add another elementree test ........ r383 | naufraghi | 2007-12-17 12:58:57 +0100 (Lun, 17 Dic 2007) | 1 line Fix importHook debug print, add other (commented) print debugs ........ r384 | naufraghi | 2007-12-17 13:00:32 +0100 (Lun, 17 Dic 2007) | 1 line Support more then one log per spec ........ r385 | naufraghi | 2007-12-17 13:01:10 +0100 (Lun, 17 Dic 2007) | 1 line Add hidden xml.etree.ElementTree import ........ r386 | naufraghi | 2007-12-17 13:02:35 +0100 (Lun, 17 Dic 2007) | 1 line Restore PATH before assert + comments ........ r387 | naufraghi | 2007-12-17 14:42:32 +0100 (Lun, 17 Dic 2007) | 1 line Print warnings for generic excepts in the code ........ r388 | naufraghi | 2007-12-17 14:56:12 +0100 (Lun, 17 Dic 2007) | 1 line Use a specific exception for Owners ........ r389 | naufraghi | 2007-12-17 16:44:59 +0100 (Lun, 17 Dic 2007) | 1 line Remove final comma ........ r390 | naufraghi | 2007-12-18 14:51:06 +0100 (Mar, 18 Dic 2007) | 1 line Expand debug print ........ r391 | naufraghi | 2007-12-19 18:21:05 +0100 (Mer, 19 Dic 2007) | 1 line Avoid 'import os' that causes problems in py25 ........ r392 | naufraghi | 2007-12-19 18:34:46 +0100 (Mer, 19 Dic 2007) | 1 line Represent with %r the exception ........ r393 | naufraghi | 2007-12-19 18:37:52 +0100 (Mer, 19 Dic 2007) | 1 line Add comments and commented prints ........ r401 | naufraghi | 2008-01-11 16:47:02 +0100 (Ven, 11 Gen 2008) | 1 line Use sys.executable saved at build time (unknown when frozen) ........ r402 | naufraghi | 2008-01-11 17:17:37 +0100 (Ven, 11 Gen 2008) | 1 line Restore linux compatibility ........ r403 | naufraghi | 2008-01-11 18:37:22 +0100 (Ven, 11 Gen 2008) | 1 line Add test for sys.getfilesystemencoding() ........ r404 | naufraghi | 2008-01-11 19:42:42 +0100 (Ven, 11 Gen 2008) | 1 line Accept different error under windows (FIXME: do a real isfile check) ........ r413 | naufraghi | 2008-01-25 19:47:50 +0100 (Ven, 25 Gen 2008) | 1 line Restore compatibility with python 2.4 ........ r424 | naufraghi | 2008-02-18 11:53:12 +0100 (Lun, 18 Feb 2008) | 3 lines r343@trinity: naufraghi | 2008-02-18 11:53:00 +0100 Merge dal trunk ........ r426 | naufraghi | 2008-02-18 14:49:15 +0100 (Lun, 18 Feb 2008) | 1 line Catch SyntaxError too ........ r427 | naufraghi | 2008-02-18 15:02:45 +0100 (Lun, 18 Feb 2008) | 1 line Revert: DummyZlib is a zero commpression zlib ........ r429 | naufraghi | 2008-02-23 17:05:35 +0100 (Sab, 23 Feb 2008) | 1 line Add a (failing) test on module imp ........ r430 | naufraghi | 2008-02-23 18:12:59 +0100 (Sab, 23 Feb 2008) | 1 line Modified runtest, now all tests are executed (default) but the interactive one(s), thet are executed if -i option is provided ........ r431 | naufraghi | 2008-02-23 18:18:02 +0100 (Sab, 23 Feb 2008) | 1 line Merge dal branch dl ........ r432 | danielevarrazzo | 2008-02-24 14:38:15 +0100 (Dom, 24 Feb 2008) | 2 lines Added missing file from the 'dl' branch. ........ r433 | naufraghi | 2008-02-25 13:07:44 +0100 (Lun, 25 Feb 2008) | 1 line Continue on test failure and report (...) at the end ........ r435 | naufraghi | 2008-02-25 13:28:08 +0100 (Lun, 25 Feb 2008) | 1 line Stub of a launcher rebuilder ........ r436 | danielevarrazzo | 2008-02-25 13:30:56 +0100 (Lun, 25 Feb 2008) | 2 lines The Python library is found both in onedir and onefile mode. ........ r437 | naufraghi | 2008-02-25 18:42:16 +0100 (Lun, 25 Feb 2008) | 1 line Add comments and (commented) debug prints ........ r439 | naufraghi | 2008-02-28 00:16:38 +0100 (Gio, 28 Feb 2008) | 1 line Cosmetics ........ r440 | danielevarrazzo | 2008-02-28 20:21:15 +0100 (Gio, 28 Feb 2008) | 4 lines The Python library is added to the package even if bindepend couldn't find it. This may happen when Python is statically linked, e.g. on debian-based systems. ........ r441 | naufraghi | 2008-03-01 00:46:00 +0100 (Sab, 01 Mar 2008) | 1 line Remove too restrictive assert ........ r442 | naufraghi | 2008-03-01 00:47:07 +0100 (Sab, 01 Mar 2008) | 1 line Run Configure.py after make ........ r445 | naufraghi | 2008-04-28 19:42:13 +0200 (Lun, 28 Apr 2008) | 1 line Merge follow up ........ r448 | naufraghi | 2008-04-30 15:41:51 +0200 (Mer, 30 Apr 2008) | 2 lines ops, svnmerge was not complete... ........ git-svn-id: http://svn.pyinstaller.org/trunk@449 8dd32b29-ccff-0310-8a9a-9233e24343b1 --- Build.py | 102 +++++++++----- Configure.py | 16 +-- archive.py | 12 +- bindepend.py | 101 ++++++++++++-- buildtests/runtests.py | 42 ++++-- buildtests/test10.py | 5 +- buildtests/test11.py | 5 +- buildtests/test12.py | 19 +++ buildtests/test12.spec | 14 ++ buildtests/test13.py | 26 ++++ buildtests/test13.spec | 18 +++ buildtests/test14.py | 38 ++++++ buildtests/test14.spec | 18 +++ buildtests/test15.py | 35 +++++ buildtests/test15.spec | 18 +++ buildtests/test16.py | 35 +++++ buildtests/test16.spec | 18 +++ buildtests/{test4.py => test4i.py} | 2 +- buildtests/{test4.spec => test4i.spec} | 6 +- hooks/hook-_elementtree.py | 18 +++ iu.py | 34 +++-- make-linux.sh | 5 + mf.py | 77 ++++++++--- source/common/launch.c | 176 ++++++++++++------------- source/common/launch.h | 87 +++++++----- source/linux/Make.py | 6 +- source/linux/getpath.c | 32 ++++- source/linux/getpath.h | 42 ++++++ source/linux/main.c | 9 +- source/windows/dllmain.c | 36 ++--- 30 files changed, 794 insertions(+), 258 deletions(-) create mode 100644 buildtests/test12.py create mode 100644 buildtests/test12.spec create mode 100644 buildtests/test13.py create mode 100644 buildtests/test13.spec create mode 100644 buildtests/test14.py create mode 100644 buildtests/test14.spec create mode 100644 buildtests/test15.py create mode 100644 buildtests/test15.spec create mode 100644 buildtests/test16.py create mode 100644 buildtests/test16.spec rename buildtests/{test4.py => test4i.py} (98%) rename buildtests/{test4.spec => test4i.spec} (63%) create mode 100644 hooks/hook-_elementtree.py create mode 100755 make-linux.sh create mode 100644 source/linux/getpath.h diff --git a/Build.py b/Build.py index 83c58e4..81b879b 100755 --- a/Build.py +++ b/Build.py @@ -86,7 +86,7 @@ def build(spec): BUILDPATH = os.path.join(SPECPATH, bpath) if not os.path.exists(BUILDPATH): os.mkdir(BUILDPATH) - exec open(spec, 'r').read()+'\n' + execfile(spec) def mtime(fnm): try: @@ -94,12 +94,16 @@ def mtime(fnm): except: return 0 +def absnormpath(apath): + return os.path.abspath(os.path.normpath(apath)) + class Target: invcnum = 0 def __init__(self): self.invcnum = Target.invcnum - Target.invcnum = Target.invcnum + 1 - self.out = os.path.join(BUILDPATH, 'out%d.toc' % self.invcnum) + Target.invcnum += 1 + self.out = os.path.join(BUILDPATH, 'out%s%d.toc' % (self.__class__.__name__, + self.invcnum)) self.dependencies = TOC() def __postinit__(self): print "checking %s" % (self.__class__.__name__,) @@ -116,7 +120,7 @@ class Analysis(Target): self.pathex = [] if pathex: for path in pathex: - self.pathex.append(os.path.abspath(os.path.normpath(path))) + self.pathex.append(absnormpath(path)) self.hookspath = hookspath self.excludes = excludes self.scripts = TOC() @@ -127,54 +131,57 @@ class Analysis(Target): outnm = os.path.basename(self.out) if last_build == 0: print "building %s because %s non existent" % (self.__class__.__name__, outnm) - return 1 + return True for fnm in self.inputs: if mtime(fnm) > last_build: print "building because %s changed" % fnm - return 1 + return True try: inputs, pathex, hookspath, excludes, scripts, pure, binaries = eval(open(self.out, 'r').read()) except: print "building because %s disappeared" % outnm - return 1 + return True if inputs != self.inputs: print "building %s because inputs changed" % outnm - return 1 + return True if pathex != self.pathex: print "building %s because pathex changed" % outnm - return 1 + return True if hookspath != self.hookspath: print "building %s because hookspath changed" % outnm - return 1 + return True if excludes != self.excludes: print "building %s because excludes changed" % outnm - return 1 + return True for (nm, fnm, typ) in scripts: if mtime(fnm) > last_build: print "building because %s changed" % fnm - return 1 + return True for (nm, fnm, typ) in pure: if mtime(fnm) > last_build: print "building because %s changed" % fnm - return 1 + return True elif mtime(fnm[:-1]) > last_build: print "building because %s changed" % fnm[:-1] - return 1 + return True for (nm, fnm, typ) in binaries: if mtime(fnm) > last_build: print "building because %s changed" % fnm - return 1 + return True self.scripts = TOC(scripts) self.pure = TOC(pure) self.binaries = TOC(binaries) - return 0 + return False def assemble(self): print "running Analysis", os.path.basename(self.out) paths = self.pathex for i in range(len(paths)): - paths[i] = os.path.abspath(os.path.normpath(paths[i])) - dirs = {} - pynms = [] + # FIXME: isn't self.pathex already norm-abs-pathed? + paths[i] = absnormpath(paths[i]) + ################################################### + # Scan inputs and prepare: + dirs = {} # input directories + pynms = [] # python filenames with no extension for script in self.inputs: if not os.path.exists(script): print "Analysis: script %s not found!" % script @@ -182,22 +189,27 @@ class Analysis(Target): d, base = os.path.split(script) if not d: d = os.getcwd() - d = os.path.abspath(os.path.normpath(d)) + d = absnormpath(d) pynm, ext = os.path.splitext(base) dirs[d] = 1 pynms.append(pynm) + ################################################### + # Initialize analyzer and analyze scripts analyzer = mf.ImportTracker(dirs.keys()+paths, self.hookspath, self.excludes) #print analyzer.path - scripts = [] + scripts = [] # will contain scripts to bundle for i in range(len(self.inputs)): script = self.inputs[i] print "Analyzing:", script analyzer.analyze_script(script) scripts.append((pynms[i], script, 'PYSOURCE')) - pure = [] - binaries = [] - rthooks = [] + ################################################### + # Fills pure, binaries and rthookcs lists to TOC + pure = [] # pure python modules + binaries = [] # binaries to bundle + rthooks = [] # rthooks if needed for modnm, mod in analyzer.modules.items(): + # FIXME: why can we have a mod == None here? if mod is not None: hooks = findRTHook(modnm) #XXX if hooks: @@ -213,11 +225,12 @@ class Analysis(Target): else: pure.append((modnm, fnm, 'PYMODULE')) binaries.extend(bindepend.Dependencies(binaries)) + self.fixMissingPythonLib(binaries) scripts[1:1] = rthooks self.scripts = TOC(scripts) self.pure = TOC(pure) self.binaries = TOC(binaries) - try: + try: # read .toc oldstuff = eval(open(self.out, 'r').read()) except: oldstuff = None @@ -236,6 +249,28 @@ class Analysis(Target): print self.out, "no change!" return 0 + def fixMissingPythonLib(self, binaries): + """Add the Python library if missing from the binaries. + + Some linux distributions (e.g. debian-based) statically build the + Python executable to the libpython, so bindepend doesn't include + it in its output. + """ + if sys.platform != 'linux2': return + + name = 'libpython%d.%d.so' % sys.version_info[:2] + for (nm, fnm, typ) in binaries: + if typ == 'BINARY' and name in fnm: + # lib found + return + + lib = bindepend.findLibrary(name) + if lib is None: + raise IOError("Python library not found!") + + binaries.append((os.path.split(lib)[1], lib, 'BINARY')) + + def findRTHook(modnm): hooklist = rthooks.get(modnm) if hooklist: @@ -311,8 +346,10 @@ def cacheDigest(fnm): digest = md5.new(data).digest() return digest -def checkCache(fnm, strip, upx): - if not strip and not upx: +def checkCache(fnm, strip, upx, fix_paths=1): + # On darwin a cache is required anyway to keep the libaries + # with relative install names + if not strip and not upx and sys.platform != 'darwin': return fnm if strip: strip = 1 @@ -337,6 +374,7 @@ def checkCache(fnm, strip, upx): basenm = os.path.normcase(os.path.basename(fnm)) digest = cacheDigest(fnm) cachedfile = os.path.join(cachedir, basenm) + cmd = None if cache_index.has_key(basenm): if digest != cache_index[basenm]: os.remove(cachedfile) @@ -344,13 +382,17 @@ def checkCache(fnm, strip, upx): return cachedfile if upx: if strip: - fnm = checkCache(fnm, 1, 0) + fnm = checkCache(fnm, 1, 0, fix_paths=0) cmd = "upx --best -q \"%s\"" % cachedfile else: - cmd = "strip \"%s\"" % cachedfile + if strip: + cmd = "strip \"%s\"" % cachedfile shutil.copy2(fnm, cachedfile) os.chmod(cachedfile, 0755) - os.system(cmd) + if cmd: os.system(cmd) + + if sys.platform == 'darwin' and fix_paths: + bindepend.fixOsxPaths(cachedfile) # update cache index cache_index[basenm] = digest diff --git a/Configure.py b/Configure.py index 5cab4f3..9466fbe 100755 --- a/Configure.py +++ b/Configure.py @@ -25,8 +25,11 @@ cygwin = sys.platform == 'cygwin' configfile = os.path.join(HOME, 'config.dat') try: config = eval(open(configfile, 'r').read()) -except IOError: +except IOError, SyntaxError: + # IOerror: file not present + # SyntaxError: invalid file (platform change?) config = {'useELFEXE':1} # if not set by Make.py we can assume Windows + # Save Python version, to detect and avoid conflicts config["pythonVersion"] = sys.version @@ -38,13 +41,8 @@ print "I: computing EXE_dependencies" python = sys.executable if not iswin: while os.path.islink(python): - python = os.readlink(python) - if not os.path.isabs(python): - for dir in string.split(os.environ['PATH'], os.pathsep): - test = os.path.join(dir, python) - if os.path.exists(test): - python = test - break + python = os.path.join(os.path.split(python)[0], os.readlink(python)) + toc = bindepend.Dependencies([('', python, '')]) if iswin and sys.version[:3] == '1.5': import exceptions @@ -241,4 +239,4 @@ outf = open(configfile, 'w') import pprint pprint.pprint(config, outf) outf.close() - +print "I: config.dat generation done!" diff --git a/archive.py b/archive.py index 0adccbe..2570a95 100644 --- a/archive.py +++ b/archive.py @@ -275,9 +275,11 @@ class Archive: class DummyZlib: def decompress(self, data): - raise RuntimeError, "zlib required but cannot be imported" + #raise RuntimeError, "zlib required but cannot be imported" + return data def compress(self, data, lvl): - raise RuntimeError, "zlib required but cannot be imported" + #raise RuntimeError, "zlib required but cannot be imported" + return data import iu ############################################################## @@ -313,6 +315,7 @@ class ZlibArchive(Archive): except ImportError: zlib = DummyZlib() else: + print "WARNING: compression level=0!!!" zlib = DummyZlib() @@ -367,7 +370,10 @@ class ZlibArchive(Archive): class PYZOwner(iu.Owner): def __init__(self, path): - self.pyz = ZlibArchive(path) + try: + self.pyz = ZlibArchive(path) + except IOError, e: + raise iu.OwnerError(e) iu.Owner.__init__(self, path) def getmod(self, nm, newmod=imp.new_module): rslt = self.pyz.extract(nm) diff --git a/bindepend.py b/bindepend.py index 887d9b5..1d3515a 100755 --- a/bindepend.py +++ b/bindepend.py @@ -34,6 +34,7 @@ import time import string import sys import re +from glob import glob seen = {} _bpath = None @@ -73,6 +74,7 @@ excludes = {'KERNEL32.DLL':1, 'PSAPI.DLL':1, 'MSVCP80.DLL':1, 'MSVCR80.DLL':1, + # regex excludes '^/usr/lib':1, '^/lib':1, '^/lib/tls':1, @@ -265,25 +267,48 @@ def Dependencies(lTOC): continue #print "I: analyzing", pth seen[string.upper(nm)] = 1 + for lib, npth in selectImports(pth): + if seen.get(string.upper(lib),0): + continue + lTOC.append((lib, npth, 'BINARY')) + + return lTOC + +def selectImports(pth): + """Return the dependencies of a binary that should be included. + + Return a list of pairs (name, fullpath) + """ + rv = [] dlls = getImports(pth) for lib in dlls: - #print "I: found", lib if not iswin and not cygwin: + # plain win case npth = lib dir, lib = os.path.split(lib) if excludes.get(dir,0): continue else: + # all other platforms npth = getfullnameof(lib, os.path.dirname(pth)) + + # now npth is a candidate lib + # check again for excludes but with regex FIXME: split the list if excludesRe.search(npth): - continue - if seen.get(string.upper(lib),0): - continue + if 'libpython' not in npth and 'Python.framework' not in npth: + # skip libs not containing (libpython or Python.framework) + #print "I: skipping %20s <- %s" % (npth, pth) + continue + else: + #print "I: inserting %20s <- %s" % (npth, pth) + pass + if npth: - lTOC.append((lib, npth, 'BINARY')) + rv.append((lib, npth)) else: print "E: lib not found:", lib, "dependency of", pth - return lTOC + + return rv def _getImports_ldd(pth): """Find the binary dependencies of PTH. @@ -353,8 +378,64 @@ def getWindowsPath(): _bpath.extend(string.split(os.environ.get('PATH', ''), os.pathsep)) return _bpath +def fixOsxPaths(moduleName): + for name, lib in selectImports(moduleName): + dest = os.path.join("@executable_path", name) + cmd = "install_name_tool -change %s %s %s" % (lib, dest, moduleName) + os.system(cmd) + +def findLibrary(name): + """Look for a library in the system. + + Emulate the algorithm used by dlopen. + + `name`must include the prefix, e.g. ``libpython2.4.so`` + """ + assert sys.platform == 'linux2', "Current implementation for Linux only" + + lib = None + + # Look in the LD_LIBRARY_PATH + lp = os.environ.get('LD_LIBRARY_PATH') + if lp: + for path in string.split(lp, os.pathsep): + libs = glob(os.path.join(path, name + '*')) + if libs: + lib = libs[0] + break + + # Look in /etc/ld.so.cache + if lib is None: + expr = r'/[^\(\)\s]*%s\.[^\(\)\s]*' % re.escape(name) + m = re.search(expr, os.popen('/sbin/ldconfig -p 2>/dev/null').read()) + if m: + lib = m.group(0) + + # Look in the known safe paths + if lib is None: + for path in ['/lib', '/usr/lib']: + libs = glob(os.path.join(path, name + '*')) + if libs: + lib = libs[0] + break + + # give up :( + if lib is None: + return None + + # Resolve the file name into the soname + dir, file = os.path.split(lib) + return os.path.join(dir, getSoname(lib)) + +def getSoname(filename): + """Return the soname of a library.""" + cmd = "objdump -p -j .dynamic 2>/dev/null " + filename + m = re.search(r'\s+SONAME\s+([^\s]+)', os.popen(cmd).read()) + if m: return m.group(1) + if __name__ == "__main__": - if len(sys.argv) < 2: - print "Usage: python %s BINARYFILE" % sys.argv[0] - sys.exit(0) - print getImports(sys.argv[1]) + if len(sys.argv) < 2: + print "Usage: python %s BINARYFILE" % sys.argv[0] + sys.exit(0) + print getImports(sys.argv[1]) + diff --git a/buildtests/runtests.py b/buildtests/runtests.py index d61ed2d..36a6f12 100644 --- a/buildtests/runtests.py +++ b/buildtests/runtests.py @@ -23,6 +23,7 @@ import os, sys, glob, string import shutil + try: here=os.path.dirname(__file__) except NameError: @@ -53,20 +54,23 @@ def clean(): except OSError, e: print e -def runtests(sources=None): +def runtests(alltests, filters=None): info = "Executing PyInstaller tests in: %s" % os.getcwd() print "*"*len(info) print info print "*"*len(info) - alltests = glob.glob('test*[0-9].py') - if not sources: + build_python = open("python_exe.build", "w") + build_python.write(sys.executable) + build_python.close() + if not filters: tests = alltests else: tests = [] - for part in sources: + for part in filters: tests += [t for t in alltests if part in t and t not in tests] tests.sort(key=lambda x: (len(x), x)) # test1 < test10 path = os.environ["PATH"] + counter = dict(passed=[],failed=[]) for src in tests: print print "################## BUILDING TEST %s #################################" % src @@ -80,14 +84,26 @@ def runtests(sources=None): print res = os.system('dist%s%s%s.exe' % (test, os.sep, test)) os.environ["PATH"] = path - assert res == 0, "%s Test error!" % src - print "################## FINISHING TEST %s ################################" % src + if res == 0: + counter["passed"].append(src) + print "################## FINISHING TEST %s ################################" % src + else: + counter["failed"].append(src) + print "#################### TEST %s FAILED #################################" % src + print counter if __name__ == '__main__': - if len(sys.argv) == 1: - clean() - runtests() - if '--clean' in sys.argv: - clean() - if '--run' in sys.argv: - runtests(sys.argv[2:]) + normal_tests = glob.glob('test*[0-9].py') + interactive_tests = glob.glob('test*[0-9]i.py') + args = sys.argv[1:] + + if "-i" in args: + print "Running interactive tests" + tests = interactive_tests + else: + print "Running normal tests (-i for interactive tests)" + tests = normal_tests + + clean() + runtests(tests) + diff --git a/buildtests/test10.py b/buildtests/test10.py index 7b95acb..1e51f9f 100644 --- a/buildtests/test10.py +++ b/buildtests/test10.py @@ -1,4 +1,7 @@ # Verify packagin of PIL.Image. Specifically, the hidden import of FixTk # importing tkinter is causing some problems. -from Image import fromstring +try: + from Image import fromstring +except ImportError: + fromstring = "PIL missing!! Install PIL before running this test!" print fromstring diff --git a/buildtests/test11.py b/buildtests/test11.py index cc42193..9d284b7 100644 --- a/buildtests/test11.py +++ b/buildtests/test11.py @@ -1,4 +1,7 @@ # Verify packagin of PIL.Image. Specifically, the hidden import of FixTk # importing tkinter is causing some problems. -from PIL.Image import fromstring +try: + from PIL.Image import fromstring +except ImportError: + fromstring = "PIL missing!! Install PIL before running this test!" print fromstring diff --git a/buildtests/test12.py b/buildtests/test12.py new file mode 100644 index 0000000..28f1617 --- /dev/null +++ b/buildtests/test12.py @@ -0,0 +1,19 @@ +# Copyright (C) 2005, Giovanni Bajo +# Based on previous work under copyright (c) 2001, 2002 McMillan Enterprises, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +print "test12 - xml.com" +from xml.dom import pulldom +print "test12 - done" diff --git a/buildtests/test12.spec b/buildtests/test12.spec new file mode 100644 index 0000000..a0e7e06 --- /dev/null +++ b/buildtests/test12.spec @@ -0,0 +1,14 @@ +import os + +a = Analysis(['../support/_mountzlib.py', 'test12.py'], + pathex=[]) +pyz = PYZ(a.pure) +exe = EXE(pyz, + a.scripts, + exclude_binaries=1, + name='test12.exe', + debug=0, + console=1) +coll = COLLECT( exe, + a.binaries, + name='disttest12') diff --git a/buildtests/test13.py b/buildtests/test13.py new file mode 100644 index 0000000..4abc5fb --- /dev/null +++ b/buildtests/test13.py @@ -0,0 +1,26 @@ +# Copyright (C) 2007, Matteo Bertini +# Based on previous work under copyright (c) 2001, 2002 McMillan Enterprises, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +print "test13 - Used to fail if _xmlplus is installed" + +import sys +if sys.version_info[:2] >= (2, 5): + import _elementtree + print "test13 DONE" +else: + print "Python 2.5 test13 skipped" + diff --git a/buildtests/test13.spec b/buildtests/test13.spec new file mode 100644 index 0000000..be13d14 --- /dev/null +++ b/buildtests/test13.spec @@ -0,0 +1,18 @@ +a = Analysis(['../support/_mountzlib.py', + '../support/useUnicode.py', + 'test13.py'], + pathex=[]) +pyz = PYZ(a.pure) +exe = EXE(pyz, + a.scripts, + exclude_binaries=1, + name='test13.exe', + debug=False, + strip=False, + upx=False, + console=1 ) +coll = COLLECT( exe, + a.binaries, + strip=False, + upx=False, + name='disttest13') diff --git a/buildtests/test14.py b/buildtests/test14.py new file mode 100644 index 0000000..5812690 --- /dev/null +++ b/buildtests/test14.py @@ -0,0 +1,38 @@ +# Copyright (C) 2007, Matteo Bertini +# Based on previous work under copyright (c) 2001, 2002 McMillan Enterprises, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +print "test14 - Used to fail if _xmlplus is installed" + +import sys +if sys.version_info[:2] >= (2, 5): + import subprocess + import xml.etree.ElementTree as ET + print "#"*50 + print "xml.etree.ElementTree", dir(ET) + print "#"*50 + import xml.etree.cElementTree as cET + + pyexe = open("python_exe.build").read() + + out = subprocess.Popen(pyexe + ' -c "import xml.etree.cElementTree as cET; print dir(cET)"', + stdout=subprocess.PIPE, shell=True).stdout.read().strip() + assert str(dir(cET)) == out, (str(dir(cET)), out) + + print "test14 DONE" +else: + print "Python 2.5 test14 skipped" + diff --git a/buildtests/test14.spec b/buildtests/test14.spec new file mode 100644 index 0000000..89048da --- /dev/null +++ b/buildtests/test14.spec @@ -0,0 +1,18 @@ +a = Analysis(['../support/_mountzlib.py', + '../support/useUnicode.py', + 'test14.py'], + pathex=[]) +pyz = PYZ(a.pure) +exe = EXE(pyz, + a.scripts, + exclude_binaries=1, + name='test14.exe', + debug=False, + strip=False, + upx=False, + console=1 ) +coll = COLLECT( exe, + a.binaries, + strip=False, + upx=False, + name='disttest14') diff --git a/buildtests/test15.py b/buildtests/test15.py new file mode 100644 index 0000000..c236349 --- /dev/null +++ b/buildtests/test15.py @@ -0,0 +1,35 @@ +# Copyright (C) 2007, Matteo Bertini +# Based on previous work under copyright (c) 2001, 2002 McMillan Enterprises, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +print "test15 sys.getfilesystemencoding()" + +import sys +if sys.version_info[:2] >= (2, 5): + import subprocess + import email + + assert type(email.Header) == email.LazyImporter + + pyexe = open("python_exe.build").read() + out = subprocess.Popen(pyexe + ' -c "import sys; print sys.getfilesystemencoding()"', + stdout=subprocess.PIPE, shell=True).stdout.read().strip() + assert str(sys.getfilesystemencoding()) == out, (str(sys.getfilesystemencoding()), out) + + print "test15 DONE" +else: + print "Python 2.5 test14 skipped" + diff --git a/buildtests/test15.spec b/buildtests/test15.spec new file mode 100644 index 0000000..9466725 --- /dev/null +++ b/buildtests/test15.spec @@ -0,0 +1,18 @@ +a = Analysis(['../support/_mountzlib.py', + '../support/useUnicode.py', + 'test15.py'], + pathex=[]) +pyz = PYZ(a.pure) +exe = EXE(pyz, + a.scripts, + exclude_binaries=1, + name='test15.exe', + debug=False, + strip=False, + upx=False, + console=1 ) +coll = COLLECT( exe, + a.binaries, + strip=False, + upx=False, + name='disttest15') diff --git a/buildtests/test16.py b/buildtests/test16.py new file mode 100644 index 0000000..9fea929 --- /dev/null +++ b/buildtests/test16.py @@ -0,0 +1,35 @@ +# Copyright (C) 2007, Matteo Bertini +# Based on previous work under copyright (c) 2001, 2002 McMillan Enterprises, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +print "test16 imp.find_module" + +import sys +import imp + +modname = "test15" + +for p in sys.path: + try: + i = imp.find_module(modname, [p]) + except ImportError: + continue +else: + raise ImportError("Couldn't find the real '%s' module" % modname) + # as in setuptools/site.py + +print "test16 DONE" + diff --git a/buildtests/test16.spec b/buildtests/test16.spec new file mode 100644 index 0000000..f180562 --- /dev/null +++ b/buildtests/test16.spec @@ -0,0 +1,18 @@ +a = Analysis(['../support/_mountzlib.py', + '../support/useUnicode.py', + 'test16.py'], + pathex=[]) +pyz = PYZ(a.pure) +exe = EXE(pyz, + a.scripts, + exclude_binaries=1, + name='test16.exe', + debug=False, + strip=False, + upx=False, + console=1 ) +coll = COLLECT( exe, + a.binaries, + strip=False, + upx=False, + name='disttest16') diff --git a/buildtests/test4.py b/buildtests/test4i.py similarity index 98% rename from buildtests/test4.py rename to buildtests/test4i.py index 05a4517..befacb3 100644 --- a/buildtests/test4.py +++ b/buildtests/test4i.py @@ -27,4 +27,4 @@ while 1: sys.stdout.write(data) if 'Q' in data: break -print "test4 - done" +print "test4i - done" diff --git a/buildtests/test4.spec b/buildtests/test4i.spec similarity index 63% rename from buildtests/test4.spec rename to buildtests/test4i.spec index 25c3f34..fad86ee 100644 --- a/buildtests/test4.spec +++ b/buildtests/test4i.spec @@ -1,13 +1,13 @@ -a = Analysis(['../support/_mountzlib.py', 'test4.py'], +a = Analysis(['../support/_mountzlib.py', 'test4i.py'], pathex=[]) pyz = PYZ(a.pure) exe = EXE(pyz, a.scripts, [('u', '', 'OPTION')], exclude_binaries=1, - name='buildtest4/test4.exe', + name='buildtest4i/test4i.exe', debug=0, console=1) coll = COLLECT( exe, a.binaries, - name='disttest4') + name='disttest4i') diff --git a/hooks/hook-_elementtree.py b/hooks/hook-_elementtree.py new file mode 100644 index 0000000..0fad3f9 --- /dev/null +++ b/hooks/hook-_elementtree.py @@ -0,0 +1,18 @@ +# Copyright (C) 2005, Giovanni Bajo +# Based on previous work under copyright (c) 2001, 2002 McMillan Enterprises, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +hiddenimports = ['pyexpat', 'xml.etree.ElementTree'] diff --git a/iu.py b/iu.py index 6816108..aa0f152 100644 --- a/iu.py +++ b/iu.py @@ -44,6 +44,12 @@ except AttributeError: STRINGTYPE = type('') +class OwnerError(IOError): + def __init__(self, msg): + self.msg = msg + def __str__(self): + return "" % self.msg + class Owner: def __init__(self, path): self.path = path @@ -56,7 +62,7 @@ class DirOwner(Owner): if path == '': path = _os_getcwd() if not pathisdir(path): - raise ValueError, "%s is not a directory" % path + raise OwnerError("%s is not a directory" % path) Owner.__init__(self, path) def getmod(self, nm, getsuffixes=imp.get_suffixes, loadco=marshal.loads, newmod=imp.new_module): pth = _os_path_join(self.path, nm) @@ -69,8 +75,8 @@ class DirOwner(Owner): attempt = pth+ext try: st = _os_stat(attempt) - except: - pass + except OSError, e: + assert e.errno == 2 #[Errno 2] No such file or directory else: if typ == imp.C_EXTENSION: fp = open(attempt, 'rb') @@ -164,8 +170,8 @@ class RegistryImportDirector(ImportDirector): try: #hkey = win32api.RegOpenKeyEx(root, subkey, 0, KEY_ALL_ACCESS) hkey = win32api.RegOpenKeyEx(root, subkey, 0, KEY_READ) - except: - pass + except Exception, e: + print "FIXME: RegOpenKeyEx Exception", e else: numsubkeys, numvalues, lastmodified = win32api.RegQueryInfoKey(hkey) for i in range(numsubkeys): @@ -228,7 +234,7 @@ class PathImportDirector(ImportDirector): # this may cause an import, which may cause recursion # hence the protection owner = klass(path) - except: + except OwnerError, e: pass else: break @@ -247,6 +253,12 @@ def getDescr(fnm): UNTRIED = -1 +class ImportManagerException(Exception): + def __init__(self, args): + self.args = args + def __repr__(self): + return "<%s: %s>" % (self.__name__, self.args) + class ImportManager: # really the equivalent of builtin import def __init__(self): @@ -273,7 +285,7 @@ class ImportManager: __builtin__.reload = self.reloadHook def importHook(self, name, globals=None, locals=None, fromlist=None, level=-1): # first see if we could be importing a relative name - #print "importHook(%s, %s, locals, %s)" % (name, globals['__name__'], fromlist) + #print "importHook(%s, %s, locals, %s)" % (name, getattr(globals, '__name__', None), fromlist) _sys_modules_get = sys.modules.get contexts = [None] if globals and level == -1: @@ -312,7 +324,9 @@ class ImportManager: if mod is UNTRIED: try: mod = _self_doimport(nm, ctx, fqname) - except: + except Exception, e: + print "FIXME: _self_doimport %r" % e, + print " nm='%s' ctx='%s' fqname='%s'" % (nm, ctx, fqname) if threaded: self._release() raise @@ -356,8 +370,8 @@ class ImportManager: self._acquire() try: mod = self.doimport(nm, ctx, ctx+'.'+nm) - except: - pass + except Exception, e: + print "FIXME: self.doimport Exception", e if threaded: self._release() #print "importHook done with %s %s %s (case 3)" % (name, globals['__name__'], fromlist) diff --git a/make-linux.sh b/make-linux.sh new file mode 100755 index 0000000..35b4b61 --- /dev/null +++ b/make-linux.sh @@ -0,0 +1,5 @@ +#!/bin/bash +echo "USAGE $0 some-python-version" +cd source/linux && $1 Make.py && make clean && make && cd - +$1 Configure.py + diff --git a/mf.py b/mf.py index b2af8c3..a3122ec 100644 --- a/mf.py +++ b/mf.py @@ -37,6 +37,14 @@ else: def caseOk(filename): return True +def pyco(): + """ + Returns correct extension ending: 'c' or 'o' + """ + if __debug__: + return 'c' + else: + return 'o' class Owner: def __init__(self, path): @@ -64,13 +72,15 @@ class DirOwner(Owner): attempt = pth+ext try: st = os.stat(attempt) - except: + except Exception, e: + #print "DirOwner", e pass else: # Check case if not caseOk(attempt): continue if typ == imp.C_EXTENSION: + #print "DirOwner.getmod -> ExtensionModule(%s, %s)" % (nm, attempt) return ExtensionModule(nm, attempt) elif typ == imp.PY_SOURCE: py = (attempt, st) @@ -79,16 +89,15 @@ class DirOwner(Owner): if py or pyc: break if py is None and pyc is None: + #print "DirOwner.getmod -> (py == pyc == None)" return None while 1: + # If we have no pyc or py is newer if pyc is None or py and pyc[1][8] < py[1][8]: try: stuff = open(py[0], 'r').read()+'\n' co = compile(string.replace(stuff, "\r\n", "\n"), py[0], 'exec') - if __debug__: - pth = py[0] + 'c' - else: - pth = py[0] + 'o' + pth = py[0] + pyco() break except SyntaxError, e: print "Syntax error in", py[0] @@ -101,9 +110,10 @@ class DirOwner(Owner): pth = pyc[0] break except (ValueError, EOFError): - print "W: bad .pyc found (%s)" % pyc[0] + print "W: bad .pyc found (%s), will use .py" % pyc[0] pyc = None else: + #print "DirOwner.getmod while 1 -> None" return None if not os.path.isabs(pth): pth = os.path.abspath(pth) @@ -111,6 +121,7 @@ class DirOwner(Owner): mod = PkgModule(nm, pth, co) else: mod = PyModule(nm, pth, co) + #print "DirOwner.getmod -> %s" % mod return mod class PYZOwner(Owner): @@ -172,7 +183,8 @@ class RegistryImportDirector(ImportDirector): try: #hkey = win32api.RegOpenKeyEx(root, subkey, 0, win32con.KEY_ALL_ACCESS) hkey = win32api.RegOpenKeyEx(root, subkey, 0, win32con.KEY_READ) - except: + except Exception, e: + #print "RegistryImportDirector", e pass else: numsubkeys, numvalues, lastmodified = win32api.RegQueryInfoKey(hkey) @@ -246,7 +258,8 @@ class PathImportDirector(ImportDirector): # this may cause an import, which may cause recursion # hence the protection owner = klass(path) - except: + except Exception, e: + #print "PathImportDirector", e pass else: break @@ -269,6 +282,25 @@ UNTRIED = -1 imptyps = ['top-level', 'conditional', 'delayed', 'delayed, conditional'] import hooks +if __debug__: + import sys + import UserDict + class LogDict(UserDict.UserDict): + count = 0 + def __init__(self, *args): + UserDict.UserDict.__init__(self, *args) + LogDict.count += 1 + self.logfile = open("logdict%s-%d.log" % (".".join(map(str, sys.version_info)), + LogDict.count), "w") + def __setitem__(self, key, value): + self.logfile.write("%s: %s -> %s\n" % (key, self.data.get(key), value)) + UserDict.UserDict.__setitem__(self, key, value) + def __delitem__(self, key): + self.logfile.write(" DEL %s\n" % key) + UserDict.UserDict.__delitem__(self, key) +else: + LogDict = dict + class ImportTracker: # really the equivalent of builtin import def __init__(self, xpath=None, hookspath=None, excludes=None): @@ -277,7 +309,7 @@ class ImportTracker: if xpath: self.path = xpath self.path.extend(sys.path) - self.modules = {} + self.modules = LogDict() self.metapath = [ BuiltinImportDirector(), FrozenImportDirector(), @@ -400,24 +432,33 @@ class ImportTracker: def ispackage(self, nm): return self.modules[nm].ispackage() - def doimport(self, nm, parentnm, fqname): + def doimport(self, nm, ctx, fqname): # Not that nm is NEVER a dotted name at this point + assert ("." not in nm), nm if fqname in self.excludes: return None - if parentnm: - parent = self.modules[parentnm] + if ctx: + parent = self.modules[ctx] if parent.ispackage(): mod = parent.doimport(nm) if mod: + # insert the new module in the parent package + # FIXME why? setattr(parent, nm, mod) else: + # if parent is not a package, there is nothing more to do return None else: # now we're dealing with an absolute import + # try to import nm using available directors for director in self.metapath: mod = director.getmod(nm) if mod: break + # here we have `mod` from: + # mod = parent.doimport(nm) + # or + # mod = director.getmod(nm) if mod: mod.__name__ = fqname self.modules[fqname] = mod @@ -445,7 +486,11 @@ class ImportTracker: print "W: %s is changing it's name to %s" % (fqname, mod.__name__) self.modules[mod.__name__] = mod else: + assert (mod == None), mod self.modules[fqname] = None + # should be equivalent using only one + # self.modules[fqname] = mod + # here return mod def getwarnings(self): warnings = self.warnings.keys() @@ -474,6 +519,7 @@ class Module: typ = 'UNKNOWN' def __init__(self, nm): self.__name__ = nm + self.__file__ = None self._all = [] self.imports = [] self.warnings = [] @@ -484,6 +530,8 @@ class Module: pass def xref(self, nm): self._xref[nm] = 1 + def __str__(self): + return "" % (self.__name__, self.__file__, self.imports) class BuiltinModule(Module): typ = 'BUILTIN' @@ -503,10 +551,7 @@ class PyModule(Module): self.co = co self.__file__ = pth if os.path.splitext(self.__file__)[1] == '.py': - if __debug__: - self.__file__ = self.__file__ + 'c' - else: - self.__file__ = self.__file__ + 'o' + self.__file__ = self.__file__ + pyco() self.scancode() def scancode(self): self.imports, self.warnings, allnms = scan_code(self.co) diff --git a/source/common/launch.c b/source/common/launch.c index bef5dd4..e159b0c 100644 --- a/source/common/launch.c +++ b/source/common/launch.c @@ -34,6 +34,7 @@ #else #include #include + #include #include #endif #include @@ -42,7 +43,7 @@ #ifndef NOZLIB #include "zlib.h" #endif -#ifdef WIN32 + /* * Python Entry point declarations (see macros in launch.h). */ @@ -51,10 +52,8 @@ DECLVAR(Py_OptimizeFlag); DECLVAR(Py_VerboseFlag); DECLPROC(Py_Initialize); DECLPROC(Py_Finalize); -DECLPROC(Py_CompileString); DECLPROC(PyImport_ExecCodeModule); DECLPROC(PyRun_SimpleString); -DECLPROC(PySys_SetArgv); DECLPROC(Py_SetProgramName); DECLPROC(PyImport_ImportModule); DECLPROC(PyImport_AddModule); @@ -62,7 +61,6 @@ DECLPROC(PyObject_SetAttrString); DECLPROC(PyList_New); DECLPROC(PyList_Append); DECLPROC(Py_BuildValue); -DECLPROC(PyFile_FromString); DECLPROC(PyString_FromStringAndSize); DECLPROC(PyObject_CallFunction); DECLPROC(PyModule_GetDict); @@ -70,24 +68,15 @@ DECLPROC(PyDict_GetItemString); DECLPROC(PyErr_Clear); DECLPROC(PyErr_Occurred); DECLPROC(PyErr_Print); -DECLPROC(PyObject_CallObject); -DECLPROC(PyObject_CallMethod); DECLPROC(PySys_AddWarnOption); DECLPROC(PyEval_InitThreads); DECLPROC(PyEval_AcquireThread); DECLPROC(PyEval_ReleaseThread); -DECLPROC(PyEval_AcquireLock); -DECLPROC(PyEval_ReleaseLock); DECLPROC(PyThreadState_Swap); -DECLPROC(PyThreadState_New); -DECLPROC(PyThreadState_Clear); -DECLPROC(PyThreadState_Delete); -DECLPROC(PyInterpreterState_New); DECLPROC(Py_NewInterpreter); DECLPROC(Py_EndInterpreter); DECLPROC(PyInt_AsLong); DECLPROC(PySys_SetObject); -#endif #ifdef WIN32 #define PATHSEP ";" @@ -319,7 +308,11 @@ int openArchive() } return 0; } -#ifdef WIN32 +#ifndef WIN32 +#define HMODULE void * +#define HINSTANCE void * +#endif + int mapNames(HMODULE dll) { /* Get all of the entry points that we are interested in */ @@ -328,10 +321,8 @@ int mapNames(HMODULE dll) GETVAR(dll, Py_VerboseFlag); GETPROC(dll, Py_Initialize); GETPROC(dll, Py_Finalize); - GETPROC(dll, Py_CompileString); GETPROC(dll, PyImport_ExecCodeModule); GETPROC(dll, PyRun_SimpleString); - GETPROC(dll, PySys_SetArgv); GETPROC(dll, Py_SetProgramName); GETPROC(dll, PyImport_ImportModule); GETPROC(dll, PyImport_AddModule); @@ -339,7 +330,6 @@ int mapNames(HMODULE dll) GETPROC(dll, PyList_New); GETPROC(dll, PyList_Append); GETPROC(dll, Py_BuildValue); - GETPROC(dll, PyFile_FromString); GETPROC(dll, PyString_FromStringAndSize); GETPROC(dll, PyObject_CallFunction); GETPROC(dll, PyModule_GetDict); @@ -347,39 +337,30 @@ int mapNames(HMODULE dll) GETPROC(dll, PyErr_Clear); GETPROC(dll, PyErr_Occurred); GETPROC(dll, PyErr_Print); - GETPROC(dll, PyObject_CallObject); - GETPROC(dll, PyObject_CallMethod); if (ntohl(f_cookie.pyvers) >= 21) { GETPROC(dll, PySys_AddWarnOption); } GETPROC(dll, PyEval_InitThreads); GETPROC(dll, PyEval_AcquireThread); GETPROC(dll, PyEval_ReleaseThread); - GETPROC(dll, PyEval_AcquireLock); - GETPROC(dll, PyEval_ReleaseLock); GETPROC(dll, PyThreadState_Swap); - GETPROC(dll, PyThreadState_New); - GETPROC(dll, PyThreadState_Clear); - GETPROC(dll, PyThreadState_Delete); - GETPROC(dll, PyInterpreterState_New); GETPROC(dll, Py_NewInterpreter); GETPROC(dll, Py_EndInterpreter); - GETPROC(dll, PyErr_Print); GETPROC(dll, PyInt_AsLong); GETPROC(dll, PySys_SetObject); + return 0; } -#endif + /* * Load the Python DLL, and get all of the necessary entry points - * Windows only (dynamic load) */ int loadPython() { -#ifdef WIN32 HINSTANCE dll; char dllpath[_MAX_PATH + 1]; +#ifdef WIN32 /* Determine the path */ sprintf(dllpath, "%spython%02d.dll", f_homepathraw, ntohl(f_cookie.pyvers)); @@ -402,11 +383,36 @@ int loadPython() } mapNames(dll); +#else + + /* Determine the path */ +#ifdef __APPLE__ + sprintf(dllpath, "%sPython", + f_workpath ? f_workpath : f_homepath); +#else + sprintf(dllpath, "%slibpython%01d.%01d.so.1.0", + f_workpath ? f_workpath : f_homepath, + ntohl(f_cookie.pyvers) / 10, ntohl(f_cookie.pyvers) % 10); +#endif + + /* Load the DLL */ + dll = dlopen(dllpath, RTLD_NOW|RTLD_GLOBAL); + if (dll) { + VS("%s\n", dllpath); + } + if (dll == 0) { + FATALERROR("Error loading Python lib '%s': %s\n", + dllpath, dlerror()); + return -1; + } + + mapNames(dll); + #endif return 0; } -#ifdef WIN32 + /* * use this from a dll instead of loadPython() * it will attach to an existing pythonXX.dll, @@ -414,6 +420,7 @@ int loadPython() */ int attachPython(int *loadedNew) { +#ifdef WIN32 HMODULE dll; char nm[_MAX_PATH + 1]; @@ -428,9 +435,9 @@ int attachPython(int *loadedNew) } mapNames(dll); *loadedNew = 0; +#endif return 0; } -#endif /* * Return pointer to next toc entry. @@ -472,11 +479,7 @@ int setRuntimeOptions(void) VS("%s\n", ptoc->name); switch (ptoc->name[0]) { case 'v': -#if defined WIN32 - *Py_VerboseFlag = 1; -#else - Py_VerboseFlag = 1; -#endif + *PI_Py_VerboseFlag = 1; break; case 'u': unbuffered = 1; @@ -484,23 +487,15 @@ int setRuntimeOptions(void) #ifdef HAVE_WARNINGS case 'W': if (ntohl(f_cookie.pyvers) >= 21) { - PySys_AddWarnOption(&ptoc->name[2]); + PI_PySys_AddWarnOption(&ptoc->name[2]); } break; #endif case 's': -#if defined WIN32 - *Py_NoSiteFlag = 0; -#else - Py_NoSiteFlag = 0; -#endif + *PI_Py_NoSiteFlag = 0; break; case 'O': -#if defined WIN32 - *Py_OptimizeFlag = 1; -#else - Py_OptimizeFlag = 1; -#endif + *PI_Py_OptimizeFlag = 1; break; } } @@ -572,46 +567,40 @@ int startPython(int argc, char *argv[]) /* Start python. */ /* VS("Loading python\n"); */ -#if defined WIN32 - *Py_NoSiteFlag = 1; /* maybe changed to 0 by setRuntimeOptions() */ -#else - Py_NoSiteFlag = 1; -#endif + *PI_Py_NoSiteFlag = 1; /* maybe changed to 0 by setRuntimeOptions() */ setRuntimeOptions(); -#ifdef WIN32 - Py_SetProgramName(f_archivename); /*XXX*/ -#endif - Py_Initialize(); + PI_Py_SetProgramName(f_archivename); /*XXX*/ + PI_Py_Initialize(); /* Set sys.path */ /* VS("Manipulating Python's sys.path\n"); */ strcpy(tmp, f_homepath); tmp[strlen(tmp)-1] = '\0'; - PyRun_SimpleString("import sys\n"); - PyRun_SimpleString("while sys.path:\n del sys.path[0]\n"); + PI_PyRun_SimpleString("import sys\n"); + PI_PyRun_SimpleString("while sys.path:\n del sys.path[0]\n"); sprintf(cmd, "sys.path.append('%s')", tmp); - PyRun_SimpleString (cmd); + PI_PyRun_SimpleString (cmd); if (pathlen == 2) { strcpy(tmp, f_workpath); tmp[strlen(tmp)-1] = '\0'; sprintf(cmd, "sys.path.insert(0, '%s')", tmp); - PyRun_SimpleString(cmd); + PI_PyRun_SimpleString(cmd); } /* Set argv[0] to be the archiveName */ - py_argv = PyList_New(0); - val = Py_BuildValue("s", f_archivename); - PyList_Append(py_argv, val); + py_argv = PI_PyList_New(0); + val = PI_Py_BuildValue("s", f_archivename); + PI_PyList_Append(py_argv, val); for (i = 1; i < argc; ++i) { - val = Py_BuildValue ("s", argv[i]); - PyList_Append (py_argv, val); + val = PI_Py_BuildValue ("s", argv[i]); + PI_PyList_Append (py_argv, val); } - sys = PyImport_ImportModule("sys"); + sys = PI_PyImport_ImportModule("sys"); /* VS("Setting sys.argv\n"); */ - PyObject_SetAttrString(sys, "argv", py_argv); + PI_PyObject_SetAttrString(sys, "argv", py_argv); /* Check for a python error */ - if (PyErr_Occurred()) + if (PI_PyErr_Occurred()) { FATALERROR("Error detected starting Python VM."); return -1; @@ -628,12 +617,9 @@ int importModules() PyObject *marshal; PyObject *marshaldict; PyObject *loadfunc; - PyObject *pyfile; TOC *ptoc; PyObject *co; PyObject *mod; - PyObject *res; - char buf[32]; VS("importing modules from CArchive\n"); @@ -641,9 +627,9 @@ int importModules() * Here we collect some reference to PyObject that we don't dereference * Doesn't matter because the objects won't be going away anyway. */ - marshal = PyImport_ImportModule("marshal"); - marshaldict = PyModule_GetDict(marshal); - loadfunc = PyDict_GetItemString(marshaldict, "loads"); + marshal = PI_PyImport_ImportModule("marshal"); + marshaldict = PI_PyModule_GetDict(marshal); + loadfunc = PI_PyDict_GetItemString(marshaldict, "loads"); /* Iterate through toc looking for module entries (type 'm') * this is normally just bootstrap stuff (archive and iu) @@ -657,22 +643,22 @@ int importModules() /* .pyc/.pyo files have 8 bytes header. Skip it and get a Python * string directly pointing at the marshalled code. */ - PyObject *mods = PyString_FromStringAndSize(modbuf + 8, + PyObject *mods = PI_PyString_FromStringAndSize(modbuf + 8, ntohl(ptoc->ulen) - 8); VS("%s\n", ptoc->name); - co = PyObject_CallFunction(loadfunc, "O", mods); - mod = PyImport_ExecCodeModule(ptoc->name, co); + co = PI_PyObject_CallFunction(loadfunc, "O", mods); + mod = PI_PyImport_ExecCodeModule(ptoc->name, co); /* Check for errors in loading */ if (mod == NULL) { FATALERROR("mod is NULL - %s", ptoc->name); } - if (PyErr_Occurred()) + if (PI_PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); + PI_PyErr_Print(); + PI_PyErr_Clear(); } Py_DECREF(mods); @@ -696,7 +682,7 @@ int installZlib(TOC *ptoc) char *cmd = (char *) malloc(strlen(tmpl) + strlen(f_archivename) + 32); sprintf(cmd, tmpl, f_archivename, zlibpos); /*VS(cmd);*/ - rc = PyRun_SimpleString(cmd); + rc = PI_PyRun_SimpleString(cmd); if (rc != 0) { FATALERROR("Error in command: %s\n", cmd); @@ -902,7 +888,7 @@ int runScripts() /* Get data out of the archive. */ data = extract(ptoc); /* Run it */ - rc = PyRun_SimpleString(data); + rc = PI_PyRun_SimpleString(data); /* log errors and abort */ if (rc != 0) { VS("RC: %d from %s\n", rc, ptoc->name); @@ -930,27 +916,27 @@ int callSimpleEntryPoint(char *name, int *presult) /* Objects with refs to kill. */ PyObject *func = NULL, *pyresult = NULL; - mod = PyImport_AddModule("__main__"); /* NO ref added */ + mod = PI_PyImport_AddModule("__main__"); /* NO ref added */ if (!mod) { VS("No __main__\n"); goto done; } - dict = PyModule_GetDict(mod); /* NO ref added */ + dict = PI_PyModule_GetDict(mod); /* NO ref added */ if (!mod) { VS("No __dict__\n"); goto done; } - func = PyDict_GetItemString(dict, name); + func = PI_PyDict_GetItemString(dict, name); if (func == NULL) { /* should explicitly check KeyError */ VS("CallSimpleEntryPoint can't find the function name\n"); rc = -2; goto done; } - pyresult = PyObject_CallFunction(func, ""); + pyresult = PI_PyObject_CallFunction(func, ""); if (pyresult==NULL) goto done; - PyErr_Clear(); - *presult = PyInt_AsLong(pyresult); - rc = PyErr_Occurred() ? -1 : 0; + PI_PyErr_Clear(); + *presult = PI_PyInt_AsLong(pyresult); + rc = PI_PyErr_Occurred() ? -1 : 0; VS( rc ? "Finished with failure\n" : "Finished OK\n"); /* all done! */ done: @@ -960,8 +946,8 @@ done: cause failures in later async code */ if (rc) /* But we will print them 'cos they may be useful */ - PyErr_Print(); - PyErr_Clear(); + PI_PyErr_Print(); + PI_PyErr_Clear(); return rc; } @@ -995,7 +981,7 @@ int launchembedded(char const * archivePath, char const * archiveName) VS("Started Python\n"); /* a signal to scripts */ - PyRun_SimpleString("import sys;sys.frozen='dll'\n"); + PI_PyRun_SimpleString("import sys;sys.frozen='dll'\n"); VS("set sys.frozen\n"); /* Import modules from archive - this is to bootstrap */ if (importModules()) @@ -1009,7 +995,7 @@ int launchembedded(char const * archivePath, char const * archiveName) if (runScripts()) return -1; VS("All scripts run\n"); - if (PyErr_Occurred()) { + if (PI_PyErr_Occurred()) { /*PyErr_Clear();*/ VS("Some error occurred\n"); } @@ -1024,7 +1010,9 @@ int launchembedded(char const * archivePath, char const * archiveName) */ int init(char const * archivePath, char const * archiveName, char const * workpath) { +#ifdef WIN32 char *p; +#endif if (workpath) { f_workpath = (char *)workpath; @@ -1173,6 +1161,6 @@ int getPyVersion(void) } void finalizePython(void) { - Py_Finalize(); + PI_Py_Finalize(); } diff --git a/source/common/launch.h b/source/common/launch.h index 36b8de4..58ced5e 100644 --- a/source/common/launch.h +++ b/source/common/launch.h @@ -42,29 +42,42 @@ #include #endif -/* On Windows, we use dynamic loading so one binary +/* We use dynamic loading so one binary can be used with (nearly) any Python version. - This is the cruft necessary to do Windows dynamic loading + This is the cruft necessary to do dynamic loading */ -#ifdef WIN32 /* * These macros used to define variables to hold dynamically accessed entry * points. These are declared 'extern' in this header, and defined fully later. */ +#ifdef WIN32 + #define EXTDECLPROC(result, name, args)\ typedef result (__cdecl *__PROC__##name) args;\ - extern __PROC__##name name; + extern __PROC__##name PI_##name; #define EXTDECLVAR(vartyp, name)\ typedef vartyp __VAR__##name;\ - extern __VAR__##name *name; + extern __VAR__##name *PI_##name; -/* +#else + +#define EXTDECLPROC(result, name, args)\ + typedef result (*__PROC__##name) args;\ + extern __PROC__##name PI_##name; + +#define EXTDECLVAR(vartyp, name)\ + typedef vartyp __VAR__##name;\ + extern __VAR__##name *PI_##name; + +#endif /* WIN32 */ + +/* * These types and macros are included from the Python header file object.h * They are needed to do very basic Python functionality. */ -typedef _typeobject; +/*typedef _typeobject;*/ typedef struct _object { int ob_refcnt; struct _typeobject *ob_type; @@ -125,10 +138,8 @@ EXTDECLVAR(int, Py_OptimizeFlag); EXTDECLVAR(int, Py_VerboseFlag); EXTDECLPROC(int, Py_Initialize, (void)); EXTDECLPROC(int, Py_Finalize, (void)); -EXTDECLPROC(PyObject *, Py_CompileString, (char *, char *, int)); EXTDECLPROC(PyObject *, PyImport_ExecCodeModule, (char *, PyObject *)); EXTDECLPROC(int, PyRun_SimpleString, (char *)); -EXTDECLPROC(int, PySys_SetArgv, (int, char **)); EXTDECLPROC(void, Py_SetProgramName, (char *)); EXTDECLPROC(PyObject *, PyImport_ImportModule, (char *)); EXTDECLPROC(PyObject *, PyImport_AddModule, (char *)); @@ -136,55 +147,65 @@ EXTDECLPROC(int, PyObject_SetAttrString, (PyObject *, char *, PyObject *)); EXTDECLPROC(PyObject *, PyList_New, (int)); EXTDECLPROC(int, PyList_Append, (PyObject *, PyObject *)); EXTDECLPROC(PyObject *, Py_BuildValue, (char *, ...)); -EXTDECLPROC(PyObject *, PyFile_FromString, (char *, char *)); EXTDECLPROC(PyObject *, PyString_FromStringAndSize, (const char *, int)); EXTDECLPROC(PyObject *, PyObject_CallFunction, (PyObject *, char *, ...)); EXTDECLPROC(PyObject *, PyModule_GetDict, (PyObject *)); EXTDECLPROC(PyObject *, PyDict_GetItemString, (PyObject *, char *)); -EXTDECLPROC(void, PyErr_Clear, () ); -EXTDECLPROC(PyObject *, PyErr_Occurred, () ); -EXTDECLPROC(void, PyErr_Print, () ); -EXTDECLPROC(PyObject *, PyObject_CallObject, (PyObject *, PyObject*) ); -EXTDECLPROC(PyObject *, PyObject_CallMethod, (PyObject *, char *, char *, ...) ); -EXTDECLPROC(void, PySys_AddWarnOption, (char *)); -EXTDECLPROC(void, PyEval_InitThreads, () ); +EXTDECLPROC(void, PyErr_Clear, (void) ); +EXTDECLPROC(PyObject *, PyErr_Occurred, (void) ); +EXTDECLPROC(void, PyErr_Print, (void) ); +EXTDECLPROC(void, PySys_AddWarnOption, (char *)); +EXTDECLPROC(void, PyEval_InitThreads, (void) ); EXTDECLPROC(void, PyEval_AcquireThread, (PyThreadState *) ); EXTDECLPROC(void, PyEval_ReleaseThread, (PyThreadState *) ); -EXTDECLPROC(void, PyEval_AcquireLock, (void) ); -EXTDECLPROC(void, PyEval_ReleaseLock, (void) ); EXTDECLPROC(PyThreadState *, PyThreadState_Swap, (PyThreadState *) ); -EXTDECLPROC(PyThreadState *, PyThreadState_New, (PyInterpreterState *) ); -EXTDECLPROC(void, PyThreadState_Clear, (PyThreadState *) ); -EXTDECLPROC(void, PyThreadState_Delete, (PyThreadState *) ); -EXTDECLPROC(PyInterpreterState *, PyInterpreterState_New, () ); -EXTDECLPROC(PyThreadState *, Py_NewInterpreter, () ); +EXTDECLPROC(PyThreadState *, Py_NewInterpreter, (void) ); EXTDECLPROC(void, Py_EndInterpreter, (PyThreadState *) ); -EXTDECLPROC(void, PyErr_Print, () ); EXTDECLPROC(long, PyInt_AsLong, (PyObject *) ); EXTDECLPROC(int, PySys_SetObject, (char *, PyObject *)); /* Macros to declare and get Python entry points in the C file. * Typedefs '__PROC__...' have been done above */ +#ifdef WIN32 + #define DECLPROC(name)\ - __PROC__##name name = NULL; + __PROC__##name PI_##name = NULL; #define GETPROC(dll, name)\ - name = (__PROC__##name)GetProcAddress (dll, #name);\ - if (!name) {\ + PI_##name = (__PROC__##name)GetProcAddress (dll, #name);\ + if (!PI_##name) {\ FATALERROR ("Cannot GetProcAddress for " #name);\ return -1;\ } #define DECLVAR(name)\ - __VAR__##name *name = NULL; + __VAR__##name *PI_##name = NULL; #define GETVAR(dll, name)\ - name = (__VAR__##name *)GetProcAddress (dll, #name);\ - if (!name) {\ + PI_##name = (__VAR__##name *)GetProcAddress (dll, #name);\ + if (!PI_##name) {\ FATALERROR ("Cannot GetProcAddress for " #name);\ return -1;\ } + #else -#include -#endif /* WIN32 dynamic load cruft */ + +#define DECLPROC(name)\ + __PROC__##name PI_##name = NULL; +#define GETPROC(dll, name)\ + PI_##name = (__PROC__##name)dlsym (dll, #name);\ + if (!PI_##name) {\ + FATALERROR ("Cannot dlsym for " #name);\ + return -1;\ + } +#define DECLVAR(name)\ + __VAR__##name *PI_##name = NULL; +#define GETVAR(dll, name)\ + PI_##name = (__VAR__##name *)dlsym(dll, #name);\ + if (!PI_##name) {\ + FATALERROR ("Cannot dlsym for " #name);\ + return -1;\ + } + +#endif /* WIN32 */ /* * #defines diff --git a/source/linux/Make.py b/source/linux/Make.py index 9281a36..32a9bef 100644 --- a/source/linux/Make.py +++ b/source/linux/Make.py @@ -164,10 +164,6 @@ def main(): if non_elf: cflags.append('-DNONELF') - libs = [os.path.join(sysconfig.get_config_vars('LIBPL')[0], sysconfig.get_config_vars('LIBRARY')[0])] - if not os.path.isfile(libs[0]): - print "WARNING: could not find Python static library at:", libs[0] - somevars = {} if os.path.exists(makefile_in): makevars = sysconfig.parse_makefile(makefile_in) @@ -178,7 +174,7 @@ def main(): somevars['CFLAGS'] = string.join(cflags) # override files = ['$(OPT)', '$(LDFLAGS)', '$(LINKFORSHARED)', 'getpath.c'] + \ - files + libs + \ + files + \ ['$(MODLIBS)', '$(LIBS)', '$(SYSLIBS)', '-lz'] # XXX zlib not always -lz outfp = bkfile.open('Makefile', 'w') diff --git a/source/linux/getpath.c b/source/linux/getpath.c index df76f0d..e955715 100644 --- a/source/linux/getpath.c +++ b/source/linux/getpath.c @@ -36,12 +36,13 @@ PERFORMANCE OF THIS SOFTWARE. /* Return the initial module search path. */ -#include "Python.h" +#include "getpath.h" #include "osdefs.h" #include #include #include +#include /* getenv */ #if HAVE_UNISTD_H #include @@ -149,12 +150,14 @@ joinpath(char *buffer, char *stuff) static void calculate_path(void) { - char *prog = Py_GetProgramName(); /* use Py_SetProgramName(argv[0]) before Py_Initialize() */ + char *prog = PI_GetProgramName(); /* use Py_SetProgramName(argv[0]) before Py_Initialize() */ char argv0_path[MAXPATHLEN+1]; char *epath; char *path = NULL; char *ppath = NULL; - int numchars; +#if HAVE_READLINK + int numchars; +#endif if (strchr(prog, SEP)) strcpy(progpath, prog); @@ -236,8 +239,23 @@ calculate_path(void) } /* External interface */ +static char *progname = "python"; + +void +PI_SetProgramName(char *pn) +{ + if (pn && *pn) + progname = pn; +} + char * -Py_GetPath(void) +PI_GetProgramName(void) +{ + return progname; +} + +char * +PI_GetPath(void) { if (!module_search_path) calculate_path(); @@ -245,7 +263,7 @@ Py_GetPath(void) } char * -Py_GetPrefix(void) +PI_GetPrefix(void) { if (!module_search_path) calculate_path(); @@ -253,7 +271,7 @@ Py_GetPrefix(void) } char * -Py_GetExecPrefix(void) +PI_GetExecPrefix(void) { if (!module_search_path) calculate_path(); @@ -261,7 +279,7 @@ Py_GetExecPrefix(void) } char * -Py_GetProgramFullPath(void) +PI_GetProgramFullPath(void) { if (!module_search_path) calculate_path(); diff --git a/source/linux/getpath.h b/source/linux/getpath.h new file mode 100644 index 0000000..78c7131 --- /dev/null +++ b/source/linux/getpath.h @@ -0,0 +1,42 @@ +/* + * A special version for minimal installs, where + * the bootstrap path is the directory in which + * the executable lives. + * + * Copyright (C) 2007, Daniele Varrazzo + * Based on previous work under copyright (c) 2002 McMillan Enterprises, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * In addition to the permissions in the GNU General Public License, the + * authors give you unlimited permission to link or embed the compiled + * version of this file into combinations with other programs, and to + * distribute those combinations without any restriction coming from the + * use of this file. (The General Public License restrictions do apply in + * other respects; for example, they cover modification of the file, and + * distribution when not linked into a combine executable.) + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef PI_GETPATH_H +#define PI_GETPATH_H + +void PI_SetProgramName(char *pn); +char *PI_GetProgramName(void); +char *PI_GetPath(void); +char *PI_GetPrefix(void); +char *PI_GetExecPrefix(void); +char *PI_GetProgramFullPath(void); + +#endif /* PI_GETPATH_H */ diff --git a/source/linux/main.c b/source/linux/main.c index 10311ca..46600ae 100644 --- a/source/linux/main.c +++ b/source/linux/main.c @@ -26,6 +26,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include "launch.h" +#include "getpath.h" #ifdef FREEZE_EXCEPTIONS extern unsigned char M_exceptions[]; @@ -54,19 +55,19 @@ int main(int argc, char* argv[]) if (strncasecmp(&argv[0][strlen(argv[0])-4], ".exe", 4)) { strcpy(thisfile, argv[0]); strcat(thisfile, ".exe"); - Py_SetProgramName(thisfile); + PI_SetProgramName(thisfile); } else #endif - Py_SetProgramName(argv[0]); - strcpy(thisfile, Py_GetProgramFullPath()); + PI_SetProgramName(argv[0]); + strcpy(thisfile, PI_GetProgramFullPath()); VS("thisfile is %s\n", thisfile); workpath = getenv( "_MEIPASS2" ); VS("_MEIPASS2 (workpath) is %s\n", (workpath ? workpath : "NULL")); /* fill in here (directory of thisfile) */ - strcpy(homepath, Py_GetPrefix()); + strcpy(homepath, PI_GetPrefix()); strcat(homepath, "/"); VS("homepath is %s\n", homepath); diff --git a/source/windows/dllmain.c b/source/windows/dllmain.c index 21b2263..832c303 100644 --- a/source/windows/dllmain.c +++ b/source/windows/dllmain.c @@ -70,36 +70,36 @@ int launch(char const * archivePath, char const * archiveName) if (loadedNew) { /* Start Python with silly command line */ - PyEval_InitThreads(); + PI_PyEval_InitThreads(); if (startPython(1, (char**)&pathnm)) return -1; VS("Started new Python"); - thisthread = PyThreadState_Swap(NULL); - PyThreadState_Swap(thisthread); + thisthread = PI_PyThreadState_Swap(NULL); + PI_PyThreadState_Swap(thisthread); } else { VS("Attached to existing Python"); /* start a mew interp */ - thisthread = PyThreadState_Swap(NULL); - PyThreadState_Swap(thisthread); + thisthread = PI_PyThreadState_Swap(NULL); + PI_PyThreadState_Swap(thisthread); if (thisthread == NULL) { - thisthread = Py_NewInterpreter(); + thisthread = PI_Py_NewInterpreter(); VS("created thisthread"); } else VS("grabbed thisthread"); - PyRun_SimpleString("import sys;sys.argv=[]"); + PI_PyRun_SimpleString("import sys;sys.argv=[]"); } /* a signal to scripts */ - PyRun_SimpleString("import sys;sys.frozen='dll'\n"); + PI_PyRun_SimpleString("import sys;sys.frozen='dll'\n"); VS("set sys.frozen"); /* Create a 'frozendllhandle' as a counterpart to sys.dllhandle (which is the Pythonxx.dll handle) */ - obHandle = Py_BuildValue("i", gInstance); - PySys_SetObject("frozendllhandle", obHandle); + obHandle = PI_Py_BuildValue("i", gInstance); + PI_PySys_SetObject("frozendllhandle", obHandle); Py_XDECREF(obHandle); /* Import modules from archive - this is to bootstrap */ if (importModules()) @@ -113,14 +113,14 @@ int launch(char const * archivePath, char const * archiveName) if (runScripts()) return -1; VS("All scripts run"); - if (PyErr_Occurred()) { - // PyErr_Print(); - //PyErr_Clear(); + if (PI_PyErr_Occurred()) { + // PI_PyErr_Print(); + //PI_PyErr_Clear(); VS("Some error occurred"); } VS("PGL released"); // Abandon our thread state. - PyEval_ReleaseThread(thisthread); + PI_PyEval_ReleaseThread(thisthread); VS("OK."); return 0; } @@ -262,9 +262,9 @@ STDAPI DllRegisterServer() int rc, pyrc; if (gPythoncom == 0) startUp(); - PyEval_AcquireThread(thisthread); + PI_PyEval_AcquireThread(thisthread); rc = callSimpleEntryPoint("DllRegisterServer", &pyrc); - PyEval_ReleaseThread(thisthread); + PI_PyEval_ReleaseThread(thisthread); return rc==0 ? pyrc : SELFREG_E_CLASS; } @@ -273,8 +273,8 @@ STDAPI DllUnregisterServer() int rc, pyrc; if (gPythoncom == 0) startUp(); - PyEval_AcquireThread(thisthread); + PI_PyEval_AcquireThread(thisthread); rc = callSimpleEntryPoint("DllUnregisterServer", &pyrc); - PyEval_ReleaseThread(thisthread); + PI_PyEval_ReleaseThread(thisthread); return rc==0 ? pyrc : SELFREG_E_CLASS; }