| 36 |
|
from optparse import OptionParser
|
| 37 |
|
parser = OptionParser(usage="%prog [options] <executable_or_dynamic_library>")
|
| 38 |
|
parser.add_option('--target-platform', default=None,
|
| 39 |
|
help='Target platform, required for cross-bundling (default: current platform).')
|
| 40 |
|
parser.add_option('--executable', default=None,
|
| 41 |
|
help='Python executable to use. Required for cross-bundling.')
|
| 42 |
|
|
| 43 |
|
opts, args = parser.parse_args()
|
| 44 |
|
if args:
|
| 45 |
|
parser.error('Does not expect any arguments')
|
| 46 |
|
|
| 47 |
|
configfile = os.path.join(HOME, 'config.dat')
|
| 48 |
|
try:
|
| 49 |
|
config = eval(open(configfile, 'r').read())
|
| 50 |
|
except IOError, SyntaxError:
|
| 51 |
|
# IOerror: file not present
|
| 52 |
|
# SyntaxError: invalid file (platform change?)
|
| 53 |
|
config = {'useELFEXE':1} # if not set by Make.py we can assume Windows
|
| 54 |
|
|
| 55 |
|
# Save Python version, to detect and avoid conflicts
|
| 56 |
|
config["pythonVersion"] = sys.version
|
| 57 |
|
|
| 62 |
|
# EXE_dependencies
|
| 63 |
|
print "I: computing EXE_dependencies"
|
| 64 |
|
python = opts.executable or config.get('python') or sys.executable
|
| 65 |
|
target_platform = opts.target_platform or config.get('target_platform') or sys.platform
|
| 66 |
|
config['python'] = python
|
| 67 |
|
config['target_platform'] = target_platform
|
| 68 |
|
target_iswin = target_platform[:3] == 'win'
|
| 69 |
|
|
| 70 |
|
if not iswin:
|
| 71 |
|
while os.path.islink(python):
|
| 72 |
|
python = os.path.join(os.path.split(python)[0], os.readlink(python))
|
| 73 |
|
|
| 74 |
|
xtrapath = []
|
| 75 |
|
if target_iswin and not iswin:
|
| 76 |
|
# try to find a mounted Windows system
|
| 77 |
|
xtrapath = glob.glob('/mnt/*/WINDOWS/system32/')
|
| 78 |
|
if not xtrapath:
|
| 79 |
|
print "E: Can not find a mounted Windows system"
|
| 80 |
|
print "W: Please set 'xtrpath' in the config file yourself"
|
| 81 |
|
|
| 82 |
|
xtrapath = config.get('xtrapath') or xtrapath
|
| 83 |
|
config['xtrapath'] = xtrapath
|
| 84 |
|
|
| 85 |
|
toc = bindepend.Dependencies([('', python, '')], target_platform, xtrapath)
|
| 86 |
|
|
| 87 |
|
if iswin and sys.version[:3] == '1.5':
|
| 88 |
|
import exceptions
|
| 89 |
|
toc.append((os.path.basename(exceptions.__file__), exceptions.__file__, 'BINARY'))
|
| 90 |
|
config['EXE_dependencies'] = toc[1:]
|
| |
40 |
|
| |
41 |
def find_EXE_dependencies(config):
|
| |
42 |
global target_platform, target_iswin
|
| |
43 |
print "I: computing EXE_dependencies"
|
| |
44 |
python = opts.executable or config.get('python') or sys.executable
|
| |
45 |
target_platform = opts.target_platform or config.get('target_platform') or sys.platform
|
| |
46 |
config['python'] = python
|
| |
47 |
config['target_platform'] = target_platform
|
| |
48 |
target_iswin = target_platform[:3] == 'win'
|
| |
49 |
|
| |
50 |
if not iswin:
|
| |
51 |
while os.path.islink(python):
|
| |
52 |
python = os.path.join(os.path.split(python)[0], os.readlink(python))
|
| |
53 |
|
| |
54 |
xtrapath = []
|
| |
55 |
if target_iswin and not iswin:
|
| |
56 |
# try to find a mounted Windows system
|
| |
57 |
xtrapath = glob.glob('/mnt/*/WINDOWS/system32/')
|
| |
58 |
if not xtrapath:
|
| |
59 |
print "E: Can not find a mounted Windows system"
|
| |
60 |
print "W: Please set 'xtrpath' in the config file yourself"
|
| |
61 |
|
| |
62 |
xtrapath = config.get('xtrapath') or xtrapath
|
| |
63 |
config['xtrapath'] = xtrapath
|
| |
64 |
|
| |
65 |
toc = bindepend.Dependencies([('', python, '')], target_platform, xtrapath)
|
| |
66 |
|
| |
67 |
if iswin and sys.version[:3] == '1.5':
|
| |
68 |
import exceptions
|
| |
69 |
toc.append((os.path.basename(exceptions.__file__), exceptions.__file__, 'BINARY'))
|
| |
70 |
config['EXE_dependencies'] = toc[1:]
|
| |
71 |
|
| 108 |
|
# TCL_root, TK_root and support/useTK.py
|
| 109 |
|
print "I: Finding TCL/TK..."
|
| 110 |
|
if not (target_iswin):
|
| 111 |
|
saveexcludes = bindepend.excludes
|
| 112 |
|
bindepend.excludes = {}
|
| 113 |
|
pattern = [r'libtcl(\d\.\d)?\.so', r'(?i)tcl(\d\d)\.dll'][target_iswin]
|
| 114 |
|
a = mf.ImportTracker()
|
| 115 |
|
a.analyze_r('Tkinter')
|
| 116 |
|
binaries = []
|
| 117 |
|
for modnm, mod in a.modules.items():
|
| 118 |
|
if isinstance(mod, mf.ExtensionModule):
|
| 119 |
|
binaries.append((mod.__name__, mod.__file__, 'EXTENSION'))
|
| 120 |
|
binaries.extend(bindepend.Dependencies(binaries))
|
| 121 |
|
binaries.extend(bindepend.Dependencies([('', sys.executable, '')]))
|
| 122 |
|
for nm, fnm, typ in binaries:
|
| 123 |
|
mo = re.match(pattern, nm)
|
| 124 |
|
if mo:
|
| 125 |
|
ver = mo.group(1)
|
| 126 |
|
tclbindir = os.path.dirname(fnm)
|
| 127 |
|
if target_iswin:
|
| 128 |
|
ver = ver[0] + '.' + ver[1:]
|
| 129 |
|
elif ver is None:
|
| 130 |
|
# we found "libtcl.so.0" so we need to get the version from the lib directory
|
| 131 |
|
for name in os.listdir(tclbindir):
|
| 132 |
|
mo = re.match(r'tcl(\d.\d)', name)
|
| 133 |
|
if mo:
|
| 134 |
|
ver = mo.group(1)
|
| 135 |
|
print "I: found TCL/TK version %s" % ver
|
| 136 |
|
open(os.path.join(HOME, 'support', 'useTK.py'), 'w').write(_useTK % (ver, ver))
|
| 137 |
|
tclnm = 'tcl%s' % ver
|
| 138 |
|
tknm = 'tk%s' % ver
|
| 139 |
|
# Linux: /usr/lib with the .tcl files in /usr/lib/tcl8.3 and /usr/lib/tk8.3
|
| 140 |
|
# Windows: Python21/DLLs with the .tcl files in Python21/tcl/tcl8.3 and Python21/tcl/tk8.3
|
| 141 |
|
# or D:/Programs/Tcl/bin with the .tcl files in D:/Programs/Tcl/lib/tcl8.0 and D:/Programs/Tcl/lib/tk8.0
|
| 142 |
|
if target_iswin:
|
| 143 |
|
for attempt in ['../tcl', '../lib']:
|
| 144 |
|
if os.path.exists(os.path.join(tclbindir, attempt, tclnm)):
|
| 145 |
|
config['TCL_root'] = os.path.join(tclbindir, attempt, tclnm)
|
| 146 |
|
config['TK_root'] = os.path.join(tclbindir, attempt, tknm)
|
| 147 |
|
break
|
| 148 |
|
else:
|
| 149 |
|
config['TCL_root'] = os.path.join(tclbindir, tclnm)
|
| 150 |
|
config['TK_root'] = os.path.join(tclbindir, tknm)
|
| 151 |
|
break
|
| 152 |
|
else:
|
| 153 |
|
print "I: could not find TCL/TK"
|
| 154 |
|
if not target_iswin:
|
| 155 |
|
bindepend.excludes = saveexcludes
|
| |
89 |
def test_TCL_TK(config):
|
| |
90 |
# TCL_root, TK_root and support/useTK.py
|
| |
91 |
print "I: Finding TCL/TK..."
|
| |
92 |
if not (target_iswin):
|
| |
93 |
saveexcludes = bindepend.excludes
|
| |
94 |
bindepend.excludes = {}
|
| |
95 |
pattern = [r'libtcl(\d\.\d)?\.so', r'(?i)tcl(\d\d)\.dll'][target_iswin]
|
| |
96 |
a = mf.ImportTracker()
|
| |
97 |
a.analyze_r('Tkinter')
|
| |
98 |
binaries = []
|
| |
99 |
for modnm, mod in a.modules.items():
|
| |
100 |
if isinstance(mod, mf.ExtensionModule):
|
| |
101 |
binaries.append((mod.__name__, mod.__file__, 'EXTENSION'))
|
| |
102 |
binaries.extend(bindepend.Dependencies(binaries))
|
| |
103 |
binaries.extend(bindepend.Dependencies([('', sys.executable, '')]))
|
| |
104 |
for nm, fnm, typ in binaries:
|
| |
105 |
mo = re.match(pattern, nm)
|
| |
106 |
if mo:
|
| |
107 |
ver = mo.group(1)
|
| |
108 |
tclbindir = os.path.dirname(fnm)
|
| |
109 |
if target_iswin:
|
| |
110 |
ver = ver[0] + '.' + ver[1:]
|
| |
111 |
elif ver is None:
|
| |
112 |
# we found "libtcl.so.0" so we need to get the version from the lib directory
|
| |
113 |
for name in os.listdir(tclbindir):
|
| |
114 |
mo = re.match(r'tcl(\d.\d)', name)
|
| |
115 |
if mo:
|
| |
116 |
ver = mo.group(1)
|
| |
117 |
print "I: found TCL/TK version %s" % ver
|
| |
118 |
open(os.path.join(HOME, 'support', 'useTK.py'), 'w').write(_useTK % (ver, ver))
|
| |
119 |
tclnm = 'tcl%s' % ver
|
| |
120 |
tknm = 'tk%s' % ver
|
| |
121 |
# Linux: /usr/lib with the .tcl files in /usr/lib/tcl8.3 and /usr/lib/tk8.3
|
| |
122 |
# Windows: Python21/DLLs with the .tcl files in Python21/tcl/tcl8.3 and Python21/tcl/tk8.3
|
| |
123 |
# or D:/Programs/Tcl/bin with the .tcl files in D:/Programs/Tcl/lib/tcl8.0 and D:/Programs/Tcl/lib/tk8.0
|
| |
124 |
if target_iswin:
|
| |
125 |
for attempt in ['../tcl', '../lib']:
|
| |
126 |
if os.path.exists(os.path.join(tclbindir, attempt, tclnm)):
|
| |
127 |
config['TCL_root'] = os.path.join(tclbindir, attempt, tclnm)
|
| |
128 |
config['TK_root'] = os.path.join(tclbindir, attempt, tknm)
|
| |
129 |
break
|
| |
130 |
else:
|
| |
131 |
config['TCL_root'] = os.path.join(tclbindir, tclnm)
|
| |
132 |
config['TK_root'] = os.path.join(tclbindir, tknm)
|
| |
133 |
break
|
| |
134 |
else:
|
| |
135 |
print "I: could not find TCL/TK"
|
| |
136 |
if not target_iswin:
|
| |
137 |
bindepend.excludes = saveexcludes
|
| 178 |
|
test_exe = os.path.join(HOME, 'support', 'loader', 'run_7rw.exe')
|
| 179 |
|
if not os.path.exists( test_exe ):
|
| 180 |
|
config['hasRsrcUpdate'] = 0
|
| 181 |
|
print 'E: ... resource update unavailable - %s not found' % test_exe
|
| 182 |
|
else:
|
| 183 |
|
# The test_exe may be read-only
|
| 184 |
|
# make a writable copy and test using that
|
| 185 |
|
rw_test_exe = os.path.join( os.environ['TEMP'], 'me_test_exe.tmp' )
|
| 186 |
|
shutil.copyfile( test_exe, rw_test_exe )
|
| 187 |
|
try:
|
| 188 |
|
hexe = win32api.BeginUpdateResource(rw_test_exe,0)
|
| 189 |
|
except:
|
| 190 |
|
config['hasRsrcUpdate'] = 0
|
| 191 |
|
print 'I: ... resource update unavailable - win32api.BeginUpdateResource failed'
|
| 192 |
|
else:
|
| 193 |
|
win32api.EndUpdateResource(hexe, 1)
|
| 194 |
|
config['hasRsrcUpdate'] = 1
|
| 195 |
|
print 'I: ... resource update available'
|
| 196 |
|
os.remove(rw_test_exe)
|
| 197 |
|
else:
|
| 198 |
|
config['hasRsrcUpdate'] = 0
|
| |
178 |
win32api.EndUpdateResource(hexe, 1)
|
| |
179 |
config['hasRsrcUpdate'] = 1
|
| |
180 |
print 'I: ... resource update available'
|
| |
181 |
os.remove(rw_test_exe)
|
| |
182 |
|
| 223 |
|
os.remove(_useUnicodeFN)
|
| 224 |
|
except OSError:
|
| 225 |
|
pass
|
| 226 |
|
config['hasUnicode'] = 0
|
| 227 |
|
print 'I: ... Unicode NOT available'
|
| 228 |
|
|
| 229 |
|
#hasUPX
|
| 230 |
|
print 'I: testing for UPX...'
|
| 231 |
|
hasUPX = 0
|
| |
217 |
vers = os.popen("upx -V").readlines()
|
| |
218 |
if vers:
|
| |
219 |
v = string.split(vers[0])[1]
|
| |
220 |
hasUPX = tuple(map(int, string.split(v, ".")))
|
| |
221 |
if iswin and is24 and hasUPX < (1,92):
|
| |
222 |
print 'E: UPX is too old! Python 2.4 under Windows requires UPX 1.92+'
|
| |
223 |
hasUPX = 0
|
| |
224 |
print 'I: ...UPX %s' % (('unavailable','available')[hasUPX != 0])
|
| |
225 |
except Exception, e:
|
| |
226 |
print 'I: ...exception result in testing for UPX'
|
| |
227 |
print e, e.args
|
| |
228 |
config['hasUPX'] = hasUPX
|
| |
229 |
|
| |
230 |
|
| |
231 |
def find_PYZ_dependencies(config):
|
| |
232 |
print "I: computing PYZ dependencies..."
|
| |
233 |
a = mf.ImportTracker([os.path.join(HOME, 'support')])
|
| |
234 |
a.analyze_r('archive')
|
| |
235 |
mod = a.modules['archive']
|
| |
236 |
toc = Build.TOC([(mod.__name__, mod.__file__, 'PYMODULE')])
|
| |
237 |
for i in range(len(toc)):
|
| |
238 |
nm, fnm, typ = toc[i]
|
| |
239 |
mod = a.modules[nm]
|
| |
240 |
tmp = []
|
| |
241 |
for importednm, isdelayed, isconditional in mod.imports:
|
| |
242 |
if not isconditional:
|
| |
243 |
realnms = a.analyze_one(importednm, nm)
|
| |
244 |
for realnm in realnms:
|
| |
245 |
imported = a.modules[realnm]
|
| |
246 |
if not isinstance(imported, mf.BuiltinModule):
|
| |
247 |
tmp.append((imported.__name__, imported.__file__, imported.typ))
|
| |
248 |
toc.extend(tmp)
|
| |
249 |
toc.reverse()
|
| |
250 |
config['PYZ_dependencies'] = toc.data
|
| |
251 |
|
| |
252 |
|
| |
253 |
|
| |
254 |
from optparse import OptionParser
|
| |
255 |
parser = OptionParser(usage="%prog [options] <executable_or_dynamic_library>")
|
| |
256 |
parser.add_option('--target-platform', default=None,
|
| |
257 |
help='Target platform, required for cross-bundling (default: current platform).')
|
| |
258 |
parser.add_option('--executable', default=None,
|
| |
259 |
help='Python executable to use. Required for cross-bundling.')
|
| |
260 |
|
| |
261 |
opts, args = parser.parse_args()
|
| |
262 |
if args:
|
| |
263 |
parser.error('Does not expect any arguments')
|
| |
264 |
|
| |
265 |
configfile = os.path.join(HOME, 'config.dat')
|
| 233 |
|
vers = os.popen("upx -V").readlines()
|
| 234 |
|
if not vers:
|
| 235 |
|
hasUPX = 0
|
| 236 |
|
else:
|
| 237 |
|
v = string.split(vers[0])[1]
|
| 238 |
|
hasUPX = tuple(map(int, string.split(v, ".")))
|
| 239 |
|
if iswin and is24 and hasUPX < (1,92):
|
| 240 |
|
print 'E: UPX is too old! Python 2.4 under Windows requires UPX 1.92+'
|
| 241 |
|
hasUPX = 0
|
| 242 |
|
print 'I: ...UPX %s' % (('unavailable','available')[hasUPX != 0])
|
| 243 |
|
except Exception, e:
|
| 244 |
|
print 'I: ...exception result in testing for UPX'
|
| 245 |
|
print e, e.args
|
| 246 |
|
config['hasUPX'] = hasUPX
|
| 247 |
|
|
| 248 |
|
# PYZ_dependencies
|
| 249 |
|
print "I: computing PYZ dependencies..."
|
| 250 |
|
a = mf.ImportTracker([os.path.join(HOME, 'support')])
|
| 251 |
|
a.analyze_r('archive')
|
| 252 |
|
mod = a.modules['archive']
|
| 253 |
|
toc = Build.TOC([(mod.__name__, mod.__file__, 'PYMODULE')])
|
| 254 |
|
for i in range(len(toc)):
|
| 255 |
|
nm, fnm, typ = toc[i]
|
| 256 |
|
mod = a.modules[nm]
|
| 257 |
|
tmp = []
|
| 258 |
|
for importednm, isdelayed, isconditional in mod.imports:
|
| 259 |
|
if not isconditional:
|
| 260 |
|
realnms = a.analyze_one(importednm, nm)
|
| 261 |
|
for realnm in realnms:
|
| 262 |
|
imported = a.modules[realnm]
|
| 263 |
|
if not isinstance(imported, mf.BuiltinModule):
|
| 264 |
|
tmp.append((imported.__name__, imported.__file__, imported.typ))
|
| 265 |
|
toc.extend(tmp)
|
| 266 |
|
toc.reverse()
|
| 267 |
|
config['PYZ_dependencies'] = toc.data
|
| |
267 |
config = eval(open(configfile, 'r').read())
|
| |
268 |
except IOError, SyntaxError:
|
| |
269 |
# IOerror: file not present
|
| |
270 |
# SyntaxError: invalid file (platform change?)
|
| |
271 |
config = {'useELFEXE':1} # if not set by Make.py we can assume Windows
|
| |
272 |
|
| |
273 |
# Save Python version, to detect and avoid conflicts
|
| |
274 |
config["pythonVersion"] = sys.version
|
| |
275 |
|
| |
276 |
find_EXE_dependencies(config)
|
| |
277 |
test_TCL_TK(config)
|
| |
278 |
test_Zlib(config)
|
| |
279 |
test_RsrcUpdate(config)
|
| |
280 |
test_unicode(config)
|
| |
281 |
test_UPX(config)
|
| |
282 |
find_PYZ_dependencies(config)
|