1
|
1 |
#! /usr/bin/env/python
|
|
2 |
# Automatically build spec files containing a description of the project
|
|
3 |
# Copyright (C) 2005, Giovanni Bajo
|
|
4 |
# Based on previous work under copyright (c) 2002 McMillan Enterprises, Inc.
|
|
5 |
#
|
|
6 |
# This program is free software; you can redistribute it and/or
|
|
7 |
# modify it under the terms of the GNU General Public License
|
|
8 |
# as published by the Free Software Foundation; either version 2
|
|
9 |
# of the License, or (at your option) any later version.
|
|
10 |
#
|
|
11 |
# This program is distributed in the hope that it will be useful,
|
|
12 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14 |
# GNU General Public License for more details.
|
|
15 |
#
|
|
16 |
# You should have received a copy of the GNU General Public License
|
|
17 |
# along with this program; if not, write to the Free Software
|
|
18 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
19 |
|
|
20 |
import sys, os, string
|
|
21 |
|
|
22 |
# For Python 1.5 compatibility
|
|
23 |
try:
|
|
24 |
True
|
|
25 |
except:
|
|
26 |
True,False = 1,0
|
|
27 |
|
|
28 |
freezetmplt = """\
|
|
29 |
a = Analysis(%(scripts)s,
|
|
30 |
pathex=%(pathex)s)
|
|
31 |
pyz = PYZ(a.pure)
|
|
32 |
exe = EXE(%(tkpkg)s pyz,
|
|
33 |
a.scripts,
|
|
34 |
a.binaries,
|
|
35 |
name='%(exename)s',
|
|
36 |
debug=%(debug)s,
|
|
37 |
strip=%(strip)s,
|
|
38 |
upx=%(upx)s,
|
|
39 |
console=%(console)s %(exe_options)s)
|
|
40 |
""" # pathex scripts exename tkpkg debug console
|
|
41 |
|
|
42 |
collecttmplt = """\
|
|
43 |
a = Analysis(%(scripts)s,
|
|
44 |
pathex=%(pathex)s)
|
|
45 |
pyz = PYZ(a.pure)
|
|
46 |
exe = EXE(pyz,
|
|
47 |
a.scripts,
|
|
48 |
exclude_binaries=1,
|
|
49 |
name='%(builddir)s/%(exename)s',
|
|
50 |
debug=%(debug)s,
|
|
51 |
strip=%(strip)s,
|
|
52 |
upx=%(upx)s,
|
|
53 |
console=%(console)s %(exe_options)s)
|
|
54 |
coll = COLLECT(%(tktree)s exe,
|
|
55 |
a.binaries,
|
|
56 |
strip=%(strip)s,
|
|
57 |
upx=%(upx)s,
|
|
58 |
name='%(distdir)s')
|
|
59 |
""" # scripts pathex, exename, debug, console tktree distdir
|
|
60 |
|
|
61 |
comsrvrtmplt = """\
|
|
62 |
a = Analysis(%(scripts)s,
|
|
63 |
pathex=%(pathex)s)
|
|
64 |
pyz = PYZ(a.pure)
|
|
65 |
exe = EXE(pyz,
|
|
66 |
a.scripts,
|
|
67 |
exclude_binaries=1,
|
|
68 |
name='%(builddir)s/%(exename)s',
|
|
69 |
debug=%(debug)s,
|
|
70 |
strip=%(strip)s,
|
|
71 |
upx=%(upx)s,
|
|
72 |
console=%(console)s %(exe_options)s)
|
|
73 |
dll = DLL(pyz,
|
|
74 |
a.scripts,
|
|
75 |
exclude_binaries=1,
|
|
76 |
name='%(builddir)s/%(dllname)s',
|
|
77 |
debug=%(debug)s)
|
|
78 |
coll = COLLECT(exe, dll,
|
|
79 |
a.binaries,
|
|
80 |
strip=%(strip)s,
|
|
81 |
upx=%(upx)s,
|
|
82 |
name='%(distdir)s')
|
|
83 |
""" # scripts pathex, exename, debug, console tktree distdir
|
|
84 |
HOME = os.path.dirname(sys.argv[0])
|
|
85 |
if HOME == '':
|
|
86 |
HOME = os.getcwd()
|
|
87 |
if not os.path.isabs(HOME):
|
|
88 |
HOME = os.path.abspath(HOME)
|
|
89 |
iswin = sys.platform[:3] == "win"
|
|
90 |
cygwin = sys.platform == "cygwin"
|
|
91 |
try:
|
|
92 |
config = eval(open(os.path.join(HOME, 'config.dat'), 'r').read())
|
|
93 |
except IOError:
|
|
94 |
print "You must run Configure.py before building!"
|
|
95 |
sys.exit(1)
|
|
96 |
|
|
97 |
if config['pythonVersion'] != sys.version:
|
|
98 |
print "The current version of Python is not the same with which PyInstaller was configured."
|
|
99 |
print "Please re-run Configure.py with this version."
|
|
100 |
sys.exit(1)
|
|
101 |
|
|
102 |
def quote_win_filepath( path ):
|
|
103 |
# quote all \ with another \ after using normpath to clean up the path
|
|
104 |
return string.join( string.split( os.path.normpath( path ), '\\' ), '\\\\' )
|
|
105 |
|
|
106 |
# Support for trying to avoid hard-coded paths in the .spec files.
|
|
107 |
# Eg, all files rooted in the Installer directory tree will be
|
|
108 |
# written using "HOMEPATH", thus allowing this spec file to
|
|
109 |
# be used with any Installer installation.
|
|
110 |
# Same thing could be done for other paths too.
|
|
111 |
path_conversions = (
|
|
112 |
(HOME, "HOMEPATH"),
|
|
113 |
# Add Tk etc?
|
|
114 |
)
|
|
115 |
|
|
116 |
def make_variable_path(filename, conversions = path_conversions):
|
|
117 |
for (from_path, to_name) in conversions:
|
|
118 |
assert os.path.abspath(from_path)==from_path, \
|
|
119 |
"path '%s' should already be absolute" % (from_path,)
|
|
120 |
if filename[:len(from_path)] == from_path:
|
|
121 |
rest = filename[len(from_path):]
|
|
122 |
if rest[0] in "\\/":
|
|
123 |
rest = rest[1:]
|
|
124 |
return to_name, rest
|
|
125 |
return None, filename
|
|
126 |
|
|
127 |
# An object used in place of a "path string" which knows how to repr()
|
|
128 |
# itself using variable names instead of hard-coded paths.
|
|
129 |
class Path:
|
|
130 |
def __init__(self, *parts):
|
|
131 |
self.path = apply(os.path.join, parts)
|
|
132 |
self.variable_prefix = self.filename_suffix = None
|
|
133 |
def __repr__(self):
|
|
134 |
if self.filename_suffix is None:
|
|
135 |
self.variable_prefix, self.filename_suffix = make_variable_path(self.path)
|
|
136 |
if self.variable_prefix is None:
|
|
137 |
return repr(self.path)
|
|
138 |
return "os.path.join(" + self.variable_prefix + "," + repr(self.filename_suffix) + ")"
|
|
139 |
|
|
140 |
def main(scripts, name=None, tk=0, freeze=0, console=1, debug=0, strip=0, upx=0,
|
|
141 |
comserver=0, ascii=0, workdir=None, pathex=[], version_file=None, icon_file=None):
|
|
142 |
if name is None:
|
|
143 |
name = os.path.splitext(os.path.basename(scripts[0]))[0]
|
|
144 |
distdir = "dist%s" % name
|
|
145 |
builddir = "build%s" % name
|
|
146 |
pathex = pathex[:]
|
|
147 |
if workdir is None:
|
|
148 |
workdir = os.getcwd()
|
|
149 |
pathex.append(workdir)
|
|
150 |
else:
|
|
151 |
pathex.append(os.getcwd())
|
|
152 |
if workdir == HOME:
|
|
153 |
workdir = os.path.join(HOME, name)
|
|
154 |
if not os.path.exists(workdir):
|
|
155 |
os.makedirs(workdir)
|
|
156 |
exe_options = ''
|
|
157 |
if version_file:
|
|
158 |
exe_options = "%s, version='%s'" % (exe_options, quote_win_filepath(version_file))
|
|
159 |
if icon_file:
|
|
160 |
exe_options = "%s, icon='%s'" % (exe_options, quote_win_filepath(icon_file))
|
|
161 |
if not ascii and config['hasUnicode']:
|
|
162 |
scripts.insert(0, os.path.join(HOME, 'support', 'useUnicode.py'))
|
|
163 |
for i in range(len(scripts)):
|
|
164 |
scripts[i] = Path(scripts[i]) # Use relative path in specfiles
|
|
165 |
|
|
166 |
d = {'tktree':'',
|
|
167 |
'tkpkg' :'',
|
|
168 |
'scripts':scripts,
|
|
169 |
'pathex' :pathex,
|
|
170 |
'exename': '',
|
|
171 |
'distdir': distdir,
|
|
172 |
'builddir': builddir,
|
|
173 |
'debug': debug,
|
|
174 |
'strip': strip,
|
|
175 |
'upx' : upx,
|
|
176 |
'console': console or debug,
|
|
177 |
'exe_options': exe_options}
|
|
178 |
if tk:
|
|
179 |
d['tktree'] = "TkTree(),"
|
|
180 |
if freeze:
|
|
181 |
scripts.insert(0, Path(HOME, 'support', 'useTK.py'))
|
|
182 |
scripts.insert(0, Path(HOME, 'support', 'unpackTK.py'))
|
|
183 |
scripts.append(Path(HOME, 'support', 'removeTK.py'))
|
|
184 |
d['tkpkg'] = "TkPKG(),"
|
|
185 |
else:
|
|
186 |
scripts.insert(0, Path(HOME, 'support', 'useTK.py'))
|
|
187 |
scripts.insert(0, Path(HOME, 'support', '_mountzlib.py'))
|
|
188 |
if iswin or cygwin:
|
|
189 |
d['exename'] = name+'.exe'
|
|
190 |
d['dllname'] = name+'.dll'
|
|
191 |
else:
|
|
192 |
d['exename'] = name
|
|
193 |
d['console'] = 1
|
|
194 |
specfnm = os.path.join(workdir, name+'.spec')
|
|
195 |
specfile = open(specfnm, 'w')
|
|
196 |
if freeze:
|
|
197 |
specfile.write(freezetmplt % d)
|
|
198 |
elif comserver:
|
|
199 |
specfile.write(comsrvrtmplt % d)
|
|
200 |
else:
|
|
201 |
specfile.write(collecttmplt % d)
|
|
202 |
specfile.close()
|
|
203 |
return specfnm
|
|
204 |
|
|
205 |
if __name__ == '__main__':
|
|
206 |
import optparse
|
|
207 |
p = optparse.OptionParser(
|
|
208 |
usage="python %prog [opts] <scriptname> [<scriptname> ...]"
|
|
209 |
)
|
|
210 |
p.add_option("-F", "--onefile", dest="freeze",
|
|
211 |
action="store_true", default=False,
|
|
212 |
help="create a single file deployment")
|
|
213 |
p.add_option("-D", "--onedir", dest="freeze", action="store_false",
|
|
214 |
help="create a single directory deployment (default)")
|
|
215 |
p.add_option("-w", "--windowed", "--noconsole", dest="console",
|
|
216 |
action="store_false", default=True,
|
|
217 |
help="use a Windows subsystem executable (Windows only)")
|
|
218 |
p.add_option("-c", "--nowindowed", "--console", dest="console",
|
|
219 |
action="store_true",
|
|
220 |
help="use a console subsystem executable (Windows only) "
|
|
221 |
"(default)")
|
|
222 |
p.add_option("-a", "--ascii", action="store_true", default=False,
|
|
223 |
help="do NOT include unicode encodings "
|
|
224 |
"(default: included if available)")
|
|
225 |
p.add_option("-d", "--debug", action="store_true", default=False,
|
|
226 |
help="use the debug (verbose) build of the executable")
|
|
227 |
p.add_option("-s", "--strip", action="store_true", default=False,
|
|
228 |
help="strip the exe and shared libs "
|
|
229 |
"(don't try this on Windows)")
|
|
230 |
p.add_option("-X", "--upx", action="store_true", default=False,
|
|
231 |
help="use UPX if available (works differently between "
|
|
232 |
"Windows and *nix)")
|
|
233 |
p.add_option("-K", "--tk", default=False, action="store_true",
|
|
234 |
help="include TCL/TK in the deployment")
|
|
235 |
p.add_option("-o", "--out", type="string", default=None,
|
|
236 |
dest="workdir", metavar="DIR",
|
|
237 |
help="generate the spec file in the specified directory")
|
|
238 |
p.add_option("-n", "--name", type="string", default=None,
|
|
239 |
help="name to assign to the project, from which the spec file "
|
|
240 |
"name is generated. (default: use the basename of the "
|
|
241 |
"(first) script)")
|
|
242 |
p.add_option("-p", "--paths", type="string", default=[], dest="pathex",
|
|
243 |
metavar="DIR", action="append",
|
|
244 |
help="set base path for import (like using PYTHONPATH). "
|
|
245 |
"Multiple directories are allowed, separating them "
|
|
246 |
"with %s, or using this option multiple times"
|
|
247 |
% repr(os.pathsep))
|
|
248 |
p.add_option("-v", "--version", type="string",
|
|
249 |
dest="version_file", metavar="FILE",
|
|
250 |
help="add a version resource from FILE to the exe "
|
|
251 |
"(Windows only)")
|
|
252 |
p.add_option("--icon", type="string", dest="icon_file",
|
|
253 |
metavar="FILE.ICO or FILE.EXE,ID",
|
|
254 |
help="If FILE is an .ico file, add the icon to the final "
|
|
255 |
"executable. Otherwise, the syntax 'file.exe,id' to "
|
|
256 |
"extract the icon with the specified id "
|
|
257 |
"from file.exe and add it to the final executable")
|
|
258 |
|
|
259 |
opts,args = p.parse_args()
|
|
260 |
|
|
261 |
# Split pathex by using the path separator
|
|
262 |
temppaths = opts.pathex[:]
|
|
263 |
opts.pathex = []
|
|
264 |
for p in temppaths:
|
|
265 |
opts.pathex.extend(string.split(p, os.pathsep))
|
|
266 |
|
|
267 |
if not args:
|
|
268 |
p.print_help()
|
|
269 |
sys.exit(1)
|
|
270 |
|
|
271 |
nm = apply(main, (args,), opts.__dict__)
|
|
272 |
print "wrote %s" % nm
|
|
273 |
print "now run Build.py to build the executable"
|