Kaydet (Commit) 144fa678 authored tarafından Jack Jansen's avatar Jack Jansen

Mac version of freeze. Uses standard freeze modules where it can,

augmenting them here and there. For now, it works more-or-less similar
to unix/windows freeze, generating a config.c file, but storing
modules in PYC resources. A template project is also copied.

The hooks are in place to freeze by merging shared libraries so you
can freeze without a C compiler/linker, but this does not work yet.
üst fa68b075
import re
import os
# The regular expression for freeze directives. These are comments with the
# word macfreeze immedeately followed by a colon, followed by a directive,
# followed by argument(s)
#
# The directives supported are
# include - Include a module or file
# exclude - Exclude a module
# path - Add sys.path entries. Relative paths are relative to the source file.
#
# See the macfreeze.py main program for a real live example.
#
DIRECTIVE_RE=r'^\s*#\s*macfreeze:\s*(\S*)\s*(.*)\s*$'
REPROG=re.compile(DIRECTIVE_RE)
def findfreezedirectives(program):
extra_modules = []
exclude_modules = []
extra_path = []
progdir, filename = os.path.split(program)
fp = open(program)
for line in fp.readlines():
match = REPROG.match(line)
if match:
directive = match.group(1)
argument = match.group(2)
if directive == 'include':
extra_modules.append(argument)
elif directive == 'exclude':
exclude_modules.append(argument)
elif directive == 'path':
argument = os.path.join(progdir, argument)
extra_path.append(argument)
else:
print '** Unknown directive', line
return extra_modules, exclude_modules, extra_path
"""macfreeze - Main program and GUI
macfreeze allows you to turn Python scripts into fully self-contained
Mac applications, by including all the Python and C code needed in a single
executable. Like unix/windows freeze it can produce a config.c allowing you
to build the application with a development environment (CodeWarrior, to be
precise), but unlike the standard freeze it is also possible to create frozen
applications without a development environment, by glueing all the
shared libraries and extension modules needed together in a single
executable, using some Code Fragment Manager tricks."""
import macfs
import sys
import EasyDialogs
import string
import macfreezegui
import macmodulefinder
#
# Here are the macfreeze directives, used when freezing macfreeze itself
# (see directives.py for an explanation)
#
# macfreeze: path ::::Tools:freeze
# macfreeze: exclude win32api
#
def main():
if len(sys.argv) < 2:
gentype, program, output, debug = macfreezegui.dialog()
elif len(sys.argv) == 2:
gentype, program, output, debug = macfreezegui.dialog(sys.argv[1])
else:
EasyDialog.Message(
"Please pass a single script. Additional modules can be specified with directives")
sys.exit(0)
mustwait = process(gentype, program, output, debug=debug)
if mustwait:
sys.exit(1)
def process(gentype, program, output, modules=[], module_files=[], debug=0):
try:
module_dict = macmodulefinder.process(program, modules, module_files, debug)
except macmodulefinder.Missing, arg:
arg.sort()
print '** Missing modules:', string.join(arg, ' ')
sys.exit(1)
#
# And generate
#
if gentype == 'info':
import macgen_info
macgen_info.generate(output, module_dict)
return 1 # So the user can inspect it
elif gentype == 'source':
import macgen_src
warnings = macgen_src.generate(output, module_dict, debug)
return warnings
elif gentype == 'resource':
import macgen_rsrc
macgen_rsrc.generate(output, module_dict, debug)
warnings = macgen_rsrc.warnings(module_dict)
return warnings
elif gentype == 'applet':
import macgen_bin
macgen_bin.generate(output, module_dict, debug)
else:
raise 'unknown gentype', gentype
if __name__ == '__main__':
main()
(This file must be converted with BinHex 4.0)
:$QeKBfCbC@9kC5jbFh*M!(*cFQ058d9%!3#3"`1-AQF!N!3"!!!!!cS!!!)k!!!
!8M4lA$"F-M!dA$)`0(YF-&`b-$4F-M!dHe``A$)`0&`b$QeKBfCbC@9kC5jbFh*
MFfaKH@9bFR0bG(4iG#ia0f`!-(*cFQ058d9%!3!!J!#"!*!5XE4#FJ#3"J0ZA$-
b-&`c0cGF-&`b06"F-c)`A$-h0e``A$)e-&`c-M"F-cFhA$"F-M8`A$-b-&`c0cG
F-&`b06"F-c)`A$-h0e``A$)e-&`c-M"F-cFhA$"F-M8`A$-b-&`c0cGF-&`b06"
F-c)`A$-h0e``A$)e-&`c-M"F-cFhA$"F-M8`A$-b-!!!!"J!2!!U!@)"m3!&!*!
)!J!!!$!+!!!#'J!6!*!&$`!*!"m!9)J(8f0bDA"d1J#3"Ji!L`!H!@@)"R0MFQP
`G!#3"3d"F3!K!Ed%#8*bEhGcC5iZ,R)!N!93!!N!BJ&P"L0(C@jPFQ&dC5"bCA0
[GA*MC5"KEQ3JFfpeFQ0P)'C[FL"$9f`!N!9S!"X!H!#"L!j2GA4`GA3JCQpXC'9
b1J#3"@J!L`"i!@@)"R0MFQP`G!#3"@F"F3"k!Ed%#8*bEhGcC5iZ,Q%!N!@%!!N
!PJ&P"Kp(C@jPFQ&dC5"3@8-JFQ9cEh9bBf8JCQPXC5"[EQajG!#3"Cd!'`#Y!(f
)$%peG("eG#"QD@aP1J#3"Ci!L!#Y!@@)"R0MFQP`G!#3"CX"F!#[!Ed%#8*bEhG
cC5iZ,Q%!N!@j!!N!bJ&L"L9(C@jPFQ&dC5"KF("XD@0KG'P[EL"QFQpY)(0SBA*
PC#"XD@*cE!#3"G%!'`$K!(b)$%peG("eG#"QD@aP1J#3"G%!L!$K!@@)"R0MFQP
`G!#3"Fm"E`$M!Ed%#8*bEhGcC5iZ,T`!N!3""`&[!4X"[33#6dX!N!3""J!,!4S
!8!3'3f&ZBf9X!*!&+J!*!$X!ISJ04'9LG@FJ)'aPGQ9X1XJ!N!8U!)X!1J$@%!%
aG!#3"H`!#3$q!@-'%%PZCQpbE@&dD@pZ)'pZE(N!!!%!!!!$1J!!!MS!!!"5"cH
I$#UD!!!!(!"'!!&%6%p(!!!!%N4*9%`!!!!H!J#3"`FhXI3#!2rr!!!!(!FhY5!
,6@&TEL"ND@&XEfGZ5!:
"""macfreezegui - The GUI for macfreeze"""
import Dlg
import macfs
import EasyDialogs
import sys
import os
import string
import Res
ID_MAINDIALOG=512
ITEM_SCRIPTNAME=2
ITEM_SCRIPTBROWSE=3
ITEM_GENSOURCE=4
ITEM_GENSOURCE_ITEMS=(7,)
ITEM_SOURCEDIRNAME=6
ITEM_SOURCEDIRBROWSE=7
ITEM_GENRESOURCE=8
ITEM_GENRESOURCE_ITEMS=(11,)
ITEM_RESOURCENAME=10
ITEM_RESOURCEBROWSE=11
ITEM_GENAPPLET=12
ITEM_GENAPPLET_ITEMS=(15,)
ITEM_APPLETNAME=14
ITEM_APPLETBROWSE=15
ITEM_OK=16
ITEM_CANCEL=17
ITEM_DEBUG=19
ITEM_GENINFO=20
RADIO_GROUPING={
ITEM_GENSOURCE: ITEM_GENSOURCE_ITEMS,
ITEM_GENRESOURCE: ITEM_GENRESOURCE_ITEMS,
ITEM_GENAPPLET: ITEM_GENAPPLET_ITEMS,
ITEM_GENINFO: ()
}
def dialog(script=None):
# Invent the various names
if not script:
fss, ok = macfs.PromptGetFile("Script?", "TEXT")
if not ok:
sys.exit(0)
script = fss.as_pathname()
basename, ext = os.path.splitext(script)
if ext:
appletname = basename
rsrcname = basename + 'modules.rsrc'
else:
appletname = script + '.applet'
rsrcname = script + 'modules.rsrc'
dirname, basebase = os.path.split(basename)
dirname = os.path.join(dirname, 'build.'+basebase)
# Get the dialog, possibly opening the resource file (if needed)
try:
d = Dlg.GetNewDialog(ID_MAINDIALOG, -1)
except Dlg.Error:
d = None
if d == None:
try:
Res.OpenResFile('macfreeze.rsrc')
except Res.Error:
d = None
else:
d = Dlg.GetNewDialog(ID_MAINDIALOG, -1)
if d == None:
EasyDialogs.Message("Dialog resource not found or faulty")
sys.exit(1)
# Fill the dialog
d.SetDialogDefaultItem(ITEM_OK)
d.SetDialogCancelItem(ITEM_CANCEL)
_dialogsetfile(d, ITEM_SCRIPTNAME, script)
_dialogsetfile(d, ITEM_SOURCEDIRNAME, dirname)
_dialogsetfile(d, ITEM_RESOURCENAME, rsrcname)
_dialogsetfile(d, ITEM_APPLETNAME, appletname)
gentype = ITEM_GENSOURCE
_dialogradiogroup(d, ITEM_GENSOURCE)
# Interact
d.GetDialogWindow().SetWTitle("Standalone application creation options")
d.GetDialogWindow().ShowWindow()
d.DrawDialog()
while 1:
item = Dlg.ModalDialog(None)
if item == ITEM_OK:
break
elif item == ITEM_CANCEL:
sys.exit(0)
elif item in RADIO_GROUPING.keys():
gentype = item
_dialogradiogroup(d, item)
elif item == ITEM_SCRIPTBROWSE:
fss, ok = macfs.PromptGetFile("Script?")
if ok:
script = fss.as_pathname()
_dialogsetfile(d, ITEM_SCRIPTNAME, script)
elif item == ITEM_SOURCEDIRBROWSE:
fss, ok = macfs.StandardPutFile("Output folder name", os.path.split(dirname)[1])
if ok:
dirname = fss.as_pathname()
_dialogsetfile(d, ITEM_SOURCEDIRNAME, dirname)
elif item == ITEM_RESOURCEBROWSE:
fss, ok = macfs.StandardPutFile("Resource output file", os.path.split(rsrcname)[1])
if ok:
rsrcname = fss.as_pathname()
_dialogsetfile(d, ITEM_RESOURCENAME, rsrcname)
elif item == ITEM_APPLETBROWSE:
fss, ok = macfs.StandardPutFile("Applet output file", os.path.split(appletname)[1])
if ok:
appletname = fss.as_pathname()
_dialogsetfile(d, ITEM_APPLETNAME, appletname)
else:
pass
tp, h, rect = d.GetDialogItem(ITEM_DEBUG)
debug = Dlg.GetDialogItemText(h)
try:
debug = string.atoi(string.strip(debug))
except ValueError:
EasyDialogs.Message("Illegal debug value %s, set to zero."%`debug`)
debug = 0
if gentype == ITEM_GENSOURCE:
return 'source', script, dirname, debug
elif gentype == ITEM_GENRESOURCE:
return 'resource', script, rsrcname, debug
elif gentype == ITEM_GENAPPLET:
return 'applet', script, appletname, debug
elif gentype == ITEM_GENINFO:
return 'info', script, '', debug
raise 'Error in gentype', gentype
def _dialogradiogroup(d, item):
for k in RADIO_GROUPING.keys():
subitems = RADIO_GROUPING[k]
tp, h, rect = d.GetDialogItem(k)
if k == item:
h.as_Control().SetControlValue(1)
for i2 in subitems:
d.ShowDialogItem(i2)
else:
h.as_Control().SetControlValue(0)
for i2 in subitems:
d.HideDialogItem(i2)
def _dialogsetfile(d, item, file):
if len(file) > 32:
file = '\311:' + os.path.split(file)[1]
tp, h, rect = d.GetDialogItem(item)
Dlg.SetDialogItemText(h, file)
if __name__ == '__main__':
type, script, file, debug = dialog()
print type, script, file, 'debug=%d'%debug
sys.exit(1)
"""macgen_bin - Generate application from shared libraries"""
import EasyDialogs
def generate(output, module_dict):
EasyDialogs.Message('Not yet implemented')
"""macgen_info - Generate informational output"""
def generate(output, module_dict):
for name in module_dict.keys():
print 'Include %-20s\t'%name,
module = module_dict[name]
print module.gettype(), '\t', `module`
return 0
"""macgen_info - Generate PYC resource file only"""
import EasyDialogs
import py_resource
import Res
import sys
def generate(output, module_dict, debug=0, preload=1):
fsid = py_resource.create(output)
for name, module in module_dict.items():
if module.gettype() != 'module':
continue
location = module.__file__
if location[-4:] == '.pyc':
# Attempt corresponding .py
location = location[:-1]
if location[-3:] != '.py':
print '*** skipping', location
continue
id, name = py_resource.frompyfile(location, name, preload=preload)
if debug > 0:
print 'PYC resource %5d\t%s\t%s'%(id, name, location)
Res.CloseResFile(fsid)
def warnings(module_dict):
problems = 0
for name, module in module_dict.items():
if module.gettype() not in ('builtin', 'module'):
problems = problems + 1
print 'Warning: %s not included: %s %s'%(name, module.gettype(), module)
return problems
"""macgen_info - Generate CodeWarrior project, config source, resource file"""
import EasyDialogs
import os
import sys
import macfs
import MacOS
import macostools
import macgen_rsrc
# Note: this depends on being frozen, or on sys.path already being
# modified by macmodulefinder.
import makeconfig
TEMPLATEDIR=os.path.join(sys.prefix, ':Mac:mwerks:projects:build.macfreeze')
PROJECT_TEMPLATE=os.path.join(TEMPLATEDIR, ':frozen.prj')
CONFIG_TEMPLATE=os.path.join(TEMPLATEDIR, ':templatefrozenconfig.c')
BUNDLE_TEMPLATE=os.path.join(TEMPLATEDIR, ':frozenbundle.rsrc')
def generate(output, module_dict, debug=0):
problems = 0
output_created=0
if not os.path.exists(output):
print 'Creating project folder', output
os.mkdir(output)
output_created = 1
# Resolve aliases, if needed
try:
fss, dummy1, dummy2 = macfs.ResolveAliasFile(output)
except macfs.error:
pass
else:
newname = fss.as_pathname()
if newname != output:
if debug:
print 'Alias', output
print 'Resolved to', newname
output = newname
# Construct the filenames
dummy, outfile = os.path.split(output)
build, ext = os.path.splitext(outfile)
if build == 'build' and ext[0] == '.':
# This is probably a good name for the project
projname = ext[1:]
else:
projname = 'frozenapplet.prj'
config_name = os.path.join(output, ':macfrozenconfig.c')
project_name = os.path.join(output, ':' + projname + '.prj')
resource_name = os.path.join(output, ':frozenmodules.rsrc')
bundle_name = os.path.join(output, ':frozenbundle.rsrc')
# Fill the output folder, if needed.
if output_created:
# Create the project, if needed
if not os.path.exists(project_name):
print 'Creating project', project_name
if not os.path.exists(PROJECT_TEMPLATE):
print '** No template CodeWarrior project found at', PROJECT_TEMPLATE
print ' To generate standalone Python applications from source you need'
print ' a full source distribution. Check http://www.cwi.nl/~jack/macpython.html'
print ' for details.'
problems = 1
else:
macostools.copy(PROJECT_TEMPLATE, project_name)
print 'A template CodeWarrior project has been copied to', project_name
print 'It is up to you to make the following changes:'
print '- Change the output file name'
print '- Change the search path, unless the folder is in the python home'
print '- Add sourcefiles/libraries for any extension modules used'
print '- Remove unused sources, to speed up the build process'
print '- Remove unused resource files (like tcl/tk) for a smaller binary'
problems = 1
macostools.copy(BUNDLE_TEMPLATE, bundle_name)
print 'A template bundle file has also been copied to', bundle_name
print 'You may want to adapt signature, size resource, etc'
# Create the resource file
macgen_rsrc.generate(resource_name, module_dict, debug=debug)
# Create the config.c file
if not os.path.exists(CONFIG_TEMPLATE):
print '** No template config.c found at', PROJECT_TEMPLATE
print ' To generate standalone Python applications from source you need'
print ' a full source distribution. Check http://www.cwi.nl/~jack/macpython.html'
print ' for details.'
problems = 1
else:
# Find elegible modules (builtins and dynamically loaded modules)
c_modules = []
for module in module_dict.keys():
if module_dict[module].gettype() in ('builtin', 'dynamic'):
c_modules.append(module)
ifp = open(CONFIG_TEMPLATE)
ofp = open(config_name, 'w')
makeconfig.makeconfig(ifp, ofp, c_modules)
ifp.close()
ofp.close()
MacOS.SetCreatorAndType(config_name, 'CWIE', 'TEXT')
if warnings(module_dict):
problems = 1
return problems
def warnings(module_dict):
problems = 0
for name, module in module_dict.items():
if module.gettype() not in ('builtin', 'module', 'dynamic'):
problems = problems + 1
print 'Warning: %s not included: %s %s'%(name, module.gettype(), module)
return problems
"""macgenerate - Generate the out for macfreeze"""
def generate(program, module_dict):
for name in module_dict.keys():
print 'Include %-20s\t'%name,
module = module_dict[name]
print module.gettype(), '\t', `module`
return 0
"""macmodulefinder - Find modules used in a script. Only slightly
mac-specific, really."""
import sys
import os
import directives
try:
# This will work if we are frozen ourselves
import modulefinder
except ImportError:
# And this will work otherwise
_FREEZEDIR=os.path.join(sys.prefix, ':Tools:freeze')
sys.path.insert(0, _FREEZEDIR)
import modulefinder
#
# Modules that must be included, and modules that need not be included
# (but are if they are found)
#
MAC_INCLUDE_MODULES=['site', 'exceptions']
MAC_MAYMISS_MODULES=['posix', 'os2', 'nt', 'dos', 'dospath', 'nturl2path', 'pwd', 'sitecustomize']
# An exception:
Missing="macmodulefinder.Missing"
class Module(modulefinder.Module):
def gettype(self):
"""Return type of module"""
if self.__path__:
return 'package'
if self.__code__:
return 'module'
if self.__file__:
return 'dynamic'
return 'builtin'
class ModuleFinder(modulefinder.ModuleFinder):
def add_module(self, fqname):
if self.modules.has_key(fqname):
return self.modules[fqname]
self.modules[fqname] = m = Module(fqname)
return m
def process(program, modules=[], module_files = [], debug=0):
error = []
#
# Add the standard modules needed for startup
#
modules = modules + MAC_INCLUDE_MODULES
#
# search the main source for directives
#
extra_modules, exclude_modules, extra_path = \
directives.findfreezedirectives(program)
for m in extra_modules:
if os.sep in m:
# It is a file
module_files.append(m)
else:
modules.append(m)
path = extra_path + sys.path[:]
#
# Create the module finder and let it do its work
#
modfinder = ModuleFinder(path,
excludes=exclude_modules, debug=debug)
for m in modules:
modfinder.import_hook(m)
for m in module_files:
modfinder.load_file(m)
modfinder.run_script(program)
module_dict = modfinder.modules
#
# Tell the user about missing modules
#
maymiss = exclude_modules + MAC_MAYMISS_MODULES
for m in modfinder.badmodules.keys():
if not m in maymiss:
if debug > 0:
print 'Missing', m
error.append(m)
#
# Warn the user about unused builtins
#
for m in sys.builtin_module_names:
if m in ('__main__', '__builtin__'):
pass
elif not module_dict.has_key(m):
if debug > 0:
print 'Unused', m
elif module_dict[m].gettype() != 'builtin':
# XXXX Can this happen?
if debug > 0:
print 'Conflict', m
if error:
raise Missing, error
return module_dict
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment