macgen_bin.py 5.75 KB
Newer Older
1 2
"""macgen_bin - Generate application from shared libraries"""

3 4 5 6 7 8 9 10 11 12 13 14
import os
import sys
import string
import types
import macfs
from MACFS import *
import Res
import py_resource
import cfmfile
import buildtools


15
def generate(input, output, module_dict=None, architecture='fat', debug=0):
16 17 18 19 20 21 22 23 24
	# try to remove old file
	try:
		os.remove(output)
	except:
		pass
	
	if module_dict is None:
		import macmodulefinder
		print "Searching for modules..."
25 26 27 28 29 30 31 32
		module_dict, missing = macmodulefinder.process(input, [], [], 1)
		if missing:
			import EasyDialogs
			missing.sort()
			answer = EasyDialogs.AskYesNoCancel("Some modules could not be found; continue anyway?\n(%s)" 
					% string.join(missing, ", "))
			if answer <> 1:
				sys.exit(0)
33 34 35 36 37
	
	applettemplatepath = buildtools.findtemplate()
	corepath = findpythoncore()
	
	dynamicmodules, dynamicfiles, extraresfiles = findfragments(module_dict, architecture)
38
	
39
	print 'Adding "__main__"'
40 41 42 43 44 45 46 47 48 49
	buildtools.process(applettemplatepath, input, output, 0)
	
	outputref = Res.OpenResFile(output)
	try:
		Res.UseResFile(outputref)
		
		print "Adding Python modules"
		addpythonmodules(module_dict)
		
		print "Adding PythonCore resources"
50
		copyres(corepath, outputref, ['cfrg', 'Popt', 'GU\267I'], 1)
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
		
		print "Adding resources from shared libraries"
		for ppcpath, cfm68kpath in extraresfiles:
			if os.path.exists(ppcpath):
				copyres(ppcpath, outputref, ['cfrg'], 1)
			elif os.path.exists(cfm68kpath):
				copyres(cfm68kpath, outputref, ['cfrg'], 1)
		
		print "Fixing sys.path prefs"
		Res.UseResFile(outputref)
		try:
			res = Res.Get1Resource('STR#', 228) # from PythonCore
		except Res.Error: pass
		else:
			res.RemoveResource()
		# setting pref file name to empty string
		res = Res.Get1NamedResource('STR ', "PythonPreferenceFileName")
		res.data = Pstring("")
		res.ChangedResource()
		syspathpref = "$(APPLICATION)"
		res = Res.Resource("\000\001" + Pstring(syspathpref))
		res.AddResource("STR#", 229, "sys.path preference")
		
		print "Creating 'PYD ' resources"
		for modname, (ppcfrag, cfm68kfrag) in dynamicmodules.items():
			res = Res.Resource(Pstring(ppcfrag) + Pstring(cfm68kfrag))
			id = 0
			while id < 128:
				id = Res.Unique1ID('PYD ')
			res.AddResource('PYD ', id, modname)
	finally:
		Res.CloseResFile(outputref)
	print "Merging code fragments"
	cfmfile.mergecfmfiles([applettemplatepath, corepath] + dynamicfiles.keys(), 
			output, architecture)
	
	print "done!"


def findfragments(module_dict, architecture):
	dynamicmodules = {}
	dynamicfiles = {}
	extraresfiles = []
	for name, module in module_dict.items():
		if module.gettype() <> 'dynamic':
			continue
		path = resolvealiasfile(module.__file__)
		dir, filename = os.path.split(path)
		ppcfile, cfm68kfile = makefilenames(filename)
		
		# ppc stuff
		ppcpath = os.path.join(dir, ppcfile)
		if architecture <> 'm68k':
			ppcfrag, dynamicfiles = getfragname(ppcpath, dynamicfiles)
		else:
			ppcfrag = "_no_fragment_"
		
		# 68k stuff
		cfm68kpath = os.path.join(dir, cfm68kfile)
		if architecture <> 'pwpc':
			cfm68kfrag, dynamicfiles = getfragname(cfm68kpath, dynamicfiles)
		else:
			cfm68kfrag = "_no_fragment_"
		
		dynamicmodules[name] = ppcfrag, cfm68kfrag
		if (ppcpath, cfm68kpath) not in extraresfiles:
			extraresfiles.append((ppcpath, cfm68kpath))
	return dynamicmodules, dynamicfiles, extraresfiles


def getfragname(path, dynamicfiles):
	if not dynamicfiles.has_key(path):
		if os.path.exists(path):
			lib = cfmfile.CfrgResource(path)
			fragname = lib.fragments[0].name
		else:
			print "shared lib not found:", path
			fragname = "_no_fragment_"
		dynamicfiles[path] = fragname
	else:
		fragname = dynamicfiles[path]
	return fragname, dynamicfiles


def addpythonmodules(module_dict):
136
	# XXX should really use macgen_rsrc.generate(), this does the same, but skips __main__
137 138 139
	items = module_dict.items()
	items.sort()
	for name, module in items:
140 141
		mtype = module.gettype()
		if mtype not in ['module', 'package'] or name == "__main__":
142 143 144 145 146 147 148 149 150 151
			continue
		location = module.__file__
		
		if location[-4:] == '.pyc':
			# Attempt corresponding .py
			location = location[:-1]
		if location[-3:] != '.py':
			print '*** skipping', location
			continue
		
152
		print 'Adding module "%s"' % name
153 154
		id, name = py_resource.frompyfile(location, name, preload=0, 
				ispackage=mtype=='package')
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208

def Pstring(str):
	if len(str) > 255:
		raise TypeError, "Str255 must be at most 255 chars long"
	return chr(len(str)) + str

def makefilenames(name):
	lname = string.lower(name)
	pos = string.find(lname, ".ppc.")
	if pos > 0:
		return name, name[:pos] + '.CFM68K.' + name[pos+5:]
	pos = string.find(lname, ".cfm68k.")
	if pos > 0:
		return name[:pos] + '.ppc.' + name[pos+8:], name
	raise ValueError, "can't make ppc/cfm68k filenames"

def copyres(input, output, *args, **kwargs):
	openedin = openedout = 0
	if type(input) == types.StringType:
		input = Res.OpenResFile(input)
		openedin = 1
	if type(output) == types.StringType:
		output = Res.OpenResFile(output)
		openedout = 1
	try:
		apply(buildtools.copyres, (input, output) + args, kwargs)
	finally:
		if openedin:
			Res.CloseResFile(input)
		if openedout:
			Res.CloseResFile(output)

def findpythoncore():
	"""find the PythonCore shared library, possibly asking the user if we can't find it"""
	
	vRefNum, dirID = macfs.FindFolder(kOnSystemDisk, kExtensionFolderType, 0)
	extpath = macfs.FSSpec((vRefNum, dirID, "")).as_pathname()
	version = string.split(sys.version)[0]
	corepath = os.path.join(extpath, "PythonCore " + version)
	if not os.path.exists(corepath):
		fss, ok = macfs.PromptGetFile("Please locate PythonCore:", "shlb")
		if not ok:
			raise KeyboardInterrupt, "cancelled"
		corepath = fss.as_pathname()
	return resolvealiasfile(corepath)

def resolvealiasfile(path):
	try:
		fss, dummy1, dummy2 = macfs.ResolveAliasFile(path)
	except macfs.error:
		pass
	else:
		path = fss.as_pathname()
	return path