- Rewrote bootstapping code in sh so we're really independent of an
installed Python. So we don't use os.execve any longer, which means we need an actual executable in <myapp>.app/Contents/MacOS. For applets we make a symlink to the Python executable used to build the applet, for standalone apps we simply copy it. - Added support for the new any_missing_maybe() feature of modulefinder.py, which is pending as patch #643711. Its use is optional so it still works with the existing version of modulefinder.py
This commit is contained in:
parent
a34b1a0749
commit
74bdca8a20
|
@ -197,8 +197,7 @@ class BundleBuilder(Defaults):
|
||||||
|
|
||||||
def report(self):
|
def report(self):
|
||||||
# XXX something decent
|
# XXX something decent
|
||||||
import pprint
|
pass
|
||||||
pprint.pprint(self.__dict__)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -227,7 +226,7 @@ imp.set_frozenmodules(marshal.load(f))
|
||||||
f.close()
|
f.close()
|
||||||
""" % FROZEN_ARCHIVE
|
""" % FROZEN_ARCHIVE
|
||||||
|
|
||||||
SITE_CO = compile(SITE_PY, "<-bundlebuilder->", "exec")
|
SITE_CO = compile(SITE_PY, "<-bundlebuilder.py->", "exec")
|
||||||
|
|
||||||
MAYMISS_MODULES = ['mac', 'os2', 'nt', 'ntpath', 'dos', 'dospath',
|
MAYMISS_MODULES = ['mac', 'os2', 'nt', 'ntpath', 'dos', 'dospath',
|
||||||
'win32api', 'ce', '_winreg', 'nturl2path', 'sitecustomize',
|
'win32api', 'ce', '_winreg', 'nturl2path', 'sitecustomize',
|
||||||
|
@ -236,24 +235,18 @@ MAYMISS_MODULES = ['mac', 'os2', 'nt', 'ntpath', 'dos', 'dospath',
|
||||||
|
|
||||||
STRIP_EXEC = "/usr/bin/strip"
|
STRIP_EXEC = "/usr/bin/strip"
|
||||||
|
|
||||||
EXECVE_WRAPPER = """\
|
BOOTSTRAP_SCRIPT = """\
|
||||||
#!/usr/bin/env python
|
#!/bin/sh
|
||||||
|
|
||||||
import os
|
execdir=$(dirname ${0})
|
||||||
from sys import argv, executable
|
executable=${execdir}/%(executable)s
|
||||||
resources = os.path.join(os.path.dirname(os.path.dirname(argv[0])),
|
resdir=$(dirname ${execdir})/Resources
|
||||||
"Resources")
|
main=${resdir}/%(mainprogram)s
|
||||||
mainprogram = os.path.join(resources, "%(mainprogram)s")
|
PYTHONPATH=$resdir
|
||||||
assert os.path.exists(mainprogram)
|
export PYTHONPATH
|
||||||
argv.insert(1, mainprogram)
|
exec ${executable} ${main} ${1}
|
||||||
os.environ["PYTHONPATH"] = resources
|
|
||||||
%(setexecutable)s
|
|
||||||
os.execve(executable, argv, os.environ)
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
setExecutableTemplate = """executable = os.path.join(resources, "%s")"""
|
|
||||||
pythonhomeSnippet = """os.environ["home"] = resources"""
|
|
||||||
|
|
||||||
|
|
||||||
class AppBuilder(BundleBuilder):
|
class AppBuilder(BundleBuilder):
|
||||||
|
|
||||||
|
@ -300,6 +293,7 @@ class AppBuilder(BundleBuilder):
|
||||||
|
|
||||||
# Modules that modulefinder couldn't find:
|
# Modules that modulefinder couldn't find:
|
||||||
missingModules = []
|
missingModules = []
|
||||||
|
maybeMissingModules = []
|
||||||
|
|
||||||
# List of all binaries (executables or shared libs), for stripping purposes
|
# List of all binaries (executables or shared libs), for stripping purposes
|
||||||
binaries = []
|
binaries = []
|
||||||
|
@ -321,6 +315,11 @@ class AppBuilder(BundleBuilder):
|
||||||
if self.name[-4:] != ".app":
|
if self.name[-4:] != ".app":
|
||||||
self.name += ".app"
|
self.name += ".app"
|
||||||
|
|
||||||
|
if self.executable is None:
|
||||||
|
if not self.standalone:
|
||||||
|
self.symlink_exec = 1
|
||||||
|
self.executable = sys.executable
|
||||||
|
|
||||||
if self.nibname:
|
if self.nibname:
|
||||||
self.plist.NSMainNibFile = self.nibname
|
self.plist.NSMainNibFile = self.nibname
|
||||||
if not hasattr(self.plist, "NSPrincipalClass"):
|
if not hasattr(self.plist, "NSPrincipalClass"):
|
||||||
|
@ -331,35 +330,31 @@ class AppBuilder(BundleBuilder):
|
||||||
self.plist.CFBundleExecutable = self.name
|
self.plist.CFBundleExecutable = self.name
|
||||||
|
|
||||||
if self.standalone:
|
if self.standalone:
|
||||||
if self.executable is None: # *assert* that it is None?
|
|
||||||
self.executable = sys.executable
|
|
||||||
self.findDependencies()
|
self.findDependencies()
|
||||||
|
|
||||||
def preProcess(self):
|
def preProcess(self):
|
||||||
resdir = "Contents/Resources"
|
resdir = "Contents/Resources"
|
||||||
if self.executable is not None:
|
if self.executable is not None:
|
||||||
if self.mainprogram is None:
|
if self.mainprogram is None:
|
||||||
execpath = pathjoin(self.execdir, self.name)
|
execname = self.name
|
||||||
else:
|
else:
|
||||||
execpath = pathjoin(resdir, os.path.basename(self.executable))
|
execname = os.path.basename(self.executable)
|
||||||
|
execpath = pathjoin(self.execdir, execname)
|
||||||
if not self.symlink_exec:
|
if not self.symlink_exec:
|
||||||
self.files.append((self.executable, execpath))
|
self.files.append((self.executable, execpath))
|
||||||
self.binaries.append(execpath)
|
self.binaries.append(execpath)
|
||||||
self.execpath = execpath
|
self.execpath = execpath
|
||||||
# For execve wrapper
|
|
||||||
setexecutable = setExecutableTemplate % os.path.basename(self.executable)
|
|
||||||
else:
|
|
||||||
setexecutable = "" # XXX for locals() call
|
|
||||||
|
|
||||||
if self.mainprogram is not None:
|
if self.mainprogram is not None:
|
||||||
mainname = os.path.basename(self.mainprogram)
|
mainname = os.path.basename(self.mainprogram)
|
||||||
self.files.append((self.mainprogram, pathjoin(resdir, mainname)))
|
self.files.append((self.mainprogram, pathjoin(resdir, mainname)))
|
||||||
# Create execve wrapper
|
# Create execve wrapper
|
||||||
mainprogram = self.mainprogram # XXX for locals() call
|
mainprogram = self.mainprogram # XXX for locals() call
|
||||||
|
executable = os.path.basename(self.executable)
|
||||||
execdir = pathjoin(self.bundlepath, self.execdir)
|
execdir = pathjoin(self.bundlepath, self.execdir)
|
||||||
mainwrapperpath = pathjoin(execdir, self.name)
|
mainwrapperpath = pathjoin(execdir, self.name)
|
||||||
makedirs(execdir)
|
makedirs(execdir)
|
||||||
open(mainwrapperpath, "w").write(EXECVE_WRAPPER % locals())
|
open(mainwrapperpath, "w").write(BOOTSTRAP_SCRIPT % locals())
|
||||||
os.chmod(mainwrapperpath, 0777)
|
os.chmod(mainwrapperpath, 0777)
|
||||||
|
|
||||||
def postProcess(self):
|
def postProcess(self):
|
||||||
|
@ -374,7 +369,7 @@ class AppBuilder(BundleBuilder):
|
||||||
makedirs(os.path.dirname(dst))
|
makedirs(os.path.dirname(dst))
|
||||||
os.symlink(os.path.abspath(self.executable), dst)
|
os.symlink(os.path.abspath(self.executable), dst)
|
||||||
|
|
||||||
if self.missingModules:
|
if self.missingModules or self.maybeMissingModules:
|
||||||
self.reportMissing()
|
self.reportMissing()
|
||||||
|
|
||||||
def addPythonModules(self):
|
def addPythonModules(self):
|
||||||
|
@ -474,24 +469,43 @@ class AppBuilder(BundleBuilder):
|
||||||
# include a real .pyc file if USE_FROZEN is True.
|
# include a real .pyc file if USE_FROZEN is True.
|
||||||
self.pymodules.append((name, mod.__code__, ispkg))
|
self.pymodules.append((name, mod.__code__, ispkg))
|
||||||
|
|
||||||
self.missingModules.extend(mf.any_missing())
|
if hasattr(mf, "any_missing_maybe"):
|
||||||
|
missing, maybe = mf.any_missing_maybe()
|
||||||
|
else:
|
||||||
|
missing = mf.any_missing()
|
||||||
|
maybe = []
|
||||||
|
self.missingModules.extend(missing)
|
||||||
|
self.maybeMissingModules.extend(maybe)
|
||||||
|
|
||||||
def reportMissing(self):
|
def reportMissing(self):
|
||||||
missing = [name for name in self.missingModules
|
missing = [name for name in self.missingModules
|
||||||
if name not in MAYMISS_MODULES]
|
if name not in MAYMISS_MODULES]
|
||||||
missingsub = [name for name in missing if "." in name]
|
if self.maybeMissingModules:
|
||||||
missing = [name for name in missing if "." not in name]
|
maybe = self.maybeMissingModules
|
||||||
|
else:
|
||||||
|
maybe = [name for name in missing if "." in name]
|
||||||
|
missing = [name for name in missing if "." not in name]
|
||||||
missing.sort()
|
missing.sort()
|
||||||
missingsub.sort()
|
maybe.sort()
|
||||||
|
if maybe:
|
||||||
|
self.message("Warning: couldn't find the following submodules:", 1)
|
||||||
|
self.message(" (Note that these could be false alarms -- "
|
||||||
|
"it's not always", 1)
|
||||||
|
self.message(" possible to distinguish between from \"package import submodule\" ", 1)
|
||||||
|
self.message(" and \"from package import name\")", 1)
|
||||||
|
for name in maybe:
|
||||||
|
self.message(" ? " + name, 1)
|
||||||
if missing:
|
if missing:
|
||||||
self.message("Warning: couldn't find the following modules:", 1)
|
self.message("Warning: couldn't find the following modules:", 1)
|
||||||
self.message(" " + ", ".join(missing))
|
for name in missing:
|
||||||
if missingsub:
|
self.message(" ? " + name, 1)
|
||||||
self.message("Warning: couldn't find the following submodules "
|
|
||||||
"(but it's probably OK since modulefinder can't distinguish "
|
def report(self):
|
||||||
"between from \"module import submodule\" and "
|
# XXX something decent
|
||||||
"\"from module import name\"):", 1)
|
import pprint
|
||||||
self.message(" " + ", ".join(missingsub))
|
pprint.pprint(self.__dict__)
|
||||||
|
if self.standalone:
|
||||||
|
self.reportMissing()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Utilities.
|
# Utilities.
|
||||||
|
|
Loading…
Reference in New Issue