Update icon and Add info

This commit is contained in:
Andros Fenollosa
2017-04-20 00:57:59 +02:00
parent 65f275850d
commit 014ffce8ed
182 changed files with 9338 additions and 10 deletions

View File

@ -0,0 +1,2 @@
from . import setup
from . import plist_template

View File

@ -0,0 +1,12 @@
#!/bin/sh
#
# This is the default bundletemplate error script
# Note that this DOES NOT present a GUI dialog, because
# it has no output on stdout, and has a return value of 0.
#
if ( test -n "$2" ) ; then
echo "[$1] Unexpected Exception:" 1>&2
echo "$2: $3" 1>&2
else
echo "[$1] Could not find a suitable Python runtime" 1>&2
fi

View File

@ -0,0 +1,132 @@
"""
Append module search paths for third-party packages to sys.path.
This is stripped down and customized for use in py2app applications
"""
import sys
# os is actually in the zip, so we need to do this here.
# we can't call it python24.zip because zlib is not a built-in module (!)
_libdir = '/lib/python' + sys.version[:3]
_parent = '/'.join(__file__.split('/')[:-1])
if not _parent.endswith(_libdir):
_parent += _libdir
sys.path.append(_parent + '/site-packages.zip')
# Stuffit decompresses recursively by default, that can mess up py2app bundles,
# add the uncompressed site-packages to the path to compensate for that.
sys.path.append(_parent + '/site-packages')
USER_SITE=None
import os
try:
basestring
except NameError:
basestring = str
def makepath(*paths):
dir = os.path.abspath(os.path.join(*paths))
return dir, os.path.normcase(dir)
for m in sys.modules.values():
f = getattr(m, '__file__', None)
if isinstance(f, basestring) and os.path.exists(f):
m.__file__ = os.path.abspath(m.__file__)
del m
# This ensures that the initial path provided by the interpreter contains
# only absolute pathnames, even if we're running from the build directory.
L = []
_dirs_in_sys_path = {}
dir = dircase = None # sys.path may be empty at this point
for dir in sys.path:
# Filter out duplicate paths (on case-insensitive file systems also
# if they only differ in case); turn relative paths into absolute
# paths.
dir, dircase = makepath(dir)
if not dircase in _dirs_in_sys_path:
L.append(dir)
_dirs_in_sys_path[dircase] = 1
sys.path[:] = L
del dir, dircase, L
_dirs_in_sys_path = None
def _init_pathinfo():
global _dirs_in_sys_path
_dirs_in_sys_path = d = {}
for dir in sys.path:
if dir and not os.path.isdir(dir):
continue
dir, dircase = makepath(dir)
d[dircase] = 1
def addsitedir(sitedir):
global _dirs_in_sys_path
if _dirs_in_sys_path is None:
_init_pathinfo()
reset = 1
else:
reset = 0
sitedir, sitedircase = makepath(sitedir)
if not sitedircase in _dirs_in_sys_path:
sys.path.append(sitedir) # Add path component
try:
names = os.listdir(sitedir)
except os.error:
return
names.sort()
for name in names:
if name[-4:] == os.extsep + "pth":
addpackage(sitedir, name)
if reset:
_dirs_in_sys_path = None
def addpackage(sitedir, name):
global _dirs_in_sys_path
if _dirs_in_sys_path is None:
_init_pathinfo()
reset = 1
else:
reset = 0
fullname = os.path.join(sitedir, name)
try:
with open(fullname) as f:
while 1:
dir = f.readline()
if not dir:
break
if dir[0] == '#':
continue
if dir.startswith("import"):
exec(dir)
continue
if dir[-1] == '\n':
dir = dir[:-1]
dir, dircase = makepath(sitedir, dir)
if not dircase in _dirs_in_sys_path and os.path.exists(dir):
sys.path.append(dir)
_dirs_in_sys_path[dircase] = 1
except IOError:
return
if reset:
_dirs_in_sys_path = None
#sys.setdefaultencoding('utf-8')
#
# Run custom site specific code, if available.
#
try:
import sitecustomize
except ImportError:
pass
#
# Remove sys.setdefaultencoding() so that users cannot change the
# encoding after initialization. The test for presence is needed when
# this module is run as a script, because this code is executed twice.
#
if hasattr(sys, "setdefaultencoding"):
del sys.setdefaultencoding

View File

@ -0,0 +1,51 @@
import sys
import py2app
__all__ = ['infoPlistDict']
def infoPlistDict(CFBundleExecutable, plist={}):
CFBundleExecutable = CFBundleExecutable
NSPrincipalClass = ''.join(CFBundleExecutable.split())
version = sys.version[:3]
pdict = dict(
CFBundleDevelopmentRegion='English',
CFBundleDisplayName=plist.get('CFBundleName', CFBundleExecutable),
CFBundleExecutable=CFBundleExecutable,
CFBundleIconFile=CFBundleExecutable,
CFBundleIdentifier='org.pythonmac.unspecified.%s' % (NSPrincipalClass,),
CFBundleInfoDictionaryVersion='6.0',
CFBundleName=CFBundleExecutable,
CFBundlePackageType='BNDL',
CFBundleShortVersionString=plist.get('CFBundleVersion', '0.0'),
CFBundleSignature='????',
CFBundleVersion='0.0',
LSHasLocalizedDisplayName=False,
NSAppleScriptEnabled=False,
NSHumanReadableCopyright='Copyright not specified',
NSMainNibFile='MainMen',
NSPrincipalClass=NSPrincipalClass,
PyMainFileNames=['__boot__'],
PyResourcePackages=[ (s % version) for s in [
'lib/python%s',
'lib/python%s/lib-dynload',
'lib/python%s/site-packages.zip',
]] + [ 'lib/python%s.zip' % version.replace('.', '') ],
PyRuntimeLocations=[(s % version) for s in [
'@executable_path/../Frameworks/Python.framework/Versions/%s/Python',
'~/Library/Frameworks/Python.framework/Versions/%s/Python',
'/Library/Frameworks/Python.framework/Versions/%s/Python',
'/Network/Library/Frameworks/Python.framework/Versions/%s/Python',
'/System/Library/Frameworks/Python.framework/Versions/%s/Python',
]],
)
pdict.update(plist)
pythonInfo = pdict.setdefault('PythonInfoDict', {})
pythonInfo.update(dict(
PythonLongVersion=sys.version,
PythonShortVersion=sys.version[:3],
PythonExecutable=sys.executable,
))
py2appInfo = pythonInfo.setdefault('py2app', {}).update(dict(
version=py2app.__version__,
template='bundle',
))
return pdict

View File

@ -0,0 +1,122 @@
import os
import re
import sys
import distutils.sysconfig
import distutils.util
gPreBuildVariants = [
{
'name': 'main-universal',
'target': '10.5',
'cflags': '-isysroot @@XCODE_ROOT@@/SDKs/MacOSX10.5.sdk -arch i386 -arch ppc -arch ppc64 -arch x86_64',
'cc': 'gcc-4.2',
},
{
'name': 'main-ppc64',
'target': '10.5',
'cflags': '-isysroot @@XCODE_ROOT@@/SDKs/MacOSX10.5.sdk -arch ppc64',
'cc': 'gcc-4.2',
},
{
'name': 'main-x86_64',
'target': '10.5',
'cflags': '-isysroot / -arch x86_64',
'cc': 'clang',
},
{
'name': 'main-fat3',
'target': '10.5',
'cflags': '-isysroot / -arch i386 -arch ppc -arch x86_64',
'cc': 'gcc-4.2',
},
{
'name': 'main-intel',
'target': '10.5',
'cflags': '-isysroot / -arch i386 -arch x86_64',
'cc': 'clang',
},
{
'name': 'main-i386',
'target': '10.3',
#'cflags': '-isysroot @@XCODE_ROOT@@/SDKs/MacOSX10.4u.sdk -arch i386',
'cflags': '-arch i386 -isysroot /',
'cc': 'clang',
},
{
'name': 'main-ppc',
'target': '10.3',
'cflags': '-isysroot @@XCODE_ROOT@@/SDKs/MacOSX10.4u.sdk -arch ppc',
'cc': 'gcc-4.0',
},
{
'name': 'main-fat',
'target': '10.3',
'cflags': '-isysroot @@XCODE_ROOT@@/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc',
'cc': 'gcc-4.0',
},
]
def main(all=False, arch=None):
basepath = os.path.dirname(__file__)
builddir = os.path.join(basepath, 'prebuilt')
if not os.path.exists(builddir):
os.makedirs(builddir)
src = os.path.join(basepath, 'src', 'main.m')
cfg = distutils.sysconfig.get_config_vars()
BASE_CFLAGS = cfg['CFLAGS']
BASE_CFLAGS = BASE_CFLAGS.replace('-dynamic', '')
BASE_CFLAGS += ' -bundle -framework Foundation -framework AppKit'
while True:
x = re.sub('-arch\s+\S+', '', BASE_CFLAGS)
if x == BASE_CFLAGS:
break
BASE_CFLAGS=x
while True:
x = re.sub('-isysroot\s+\S+', '', BASE_CFLAGS)
if x == BASE_CFLAGS:
break
BASE_CFLAGS=x
if arch is None:
arch = distutils.util.get_platform().split('-')[-1]
if sys.prefix.startswith('/System') and \
sys.version_info[:2] == (2,5):
arch = "fat"
name = 'main-' + arch
root = None
if all:
for entry in gPreBuildVariants:
if (not all) and entry['name'] != name: continue
dest = os.path.join(builddir, entry['name'])
if not os.path.exists(dest) or (
os.stat(dest).st_mtime < os.stat(src).st_mtime):
if root is None:
fp = os.popen('xcode-select -print-path', 'r')
root = fp.read().strip()
fp.close()
print ("rebuilding %s"%(entry['name']))
#CC=os.path.join(root, 'usr', 'bin', entry['cc'])
CC=entry['cc']
CFLAGS = BASE_CFLAGS + ' ' + entry['cflags'].replace('@@XCODE_ROOT@@', root)
os.environ['MACOSX_DEPLOYMENT_TARGET'] = entry['target']
os.system('"%(CC)s" -o "%(dest)s" "%(src)s" %(CFLAGS)s' % locals())
dest = os.path.join(
builddir,
'main-' + arch
)
return dest
if __name__ == '__main__':
main(all=True)

View File

@ -0,0 +1,692 @@
//
// main.m
// apptemplate
//
// Created by Bob Ippolito on Mon September 20 2004.
// Copyright (c) 2004 Bob Ippolito. All rights reserved.
//
#import <Foundation/Foundation.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syslimits.h>
#include <crt_externs.h>
#include <wchar.h>
#include <locale.h>
#include <langinfo.h>
#include <objc/objc-class.h>
//
// Constants
//
NSString *ERR_CANNOT_SAVE_LOCALE = @"Cannot save locale information";
NSString *ERR_REALLYBADTITLE = @"The bundle could not be launched.";
NSString *ERR_TITLEFORMAT = @"%@ has encountered a fatal error, and will now terminate.";
NSString *ERR_PYRUNTIMELOCATIONS = @"The Info.plist file must have a PyRuntimeLocations array containing string values for preferred Python runtime locations. These strings should be \"otool -L\" style mach ids; \"@executable_stub\" and \"~\" prefixes will be translated accordingly.";
NSString *ERR_NOPYTHONRUNTIME = @"A Python runtime could be located. You may need to install a framework build of Python, or edit the PyRuntimeLocations array in this bundle's Info.plist file.\rThese runtime locations were attempted:\r\r";
NSString *ERR_NOPYTHONSCRIPT = @"A main script could not be located in the Resources folder.\rThese files were tried:\r\r";
NSString *ERR_LINKERRFMT = @"An internal error occurred while attempting to link with:\r\r%s\r\rSee the Console for a detailed dyld error message";
NSString *ERR_PYTHONEXCEPTION = @"An uncaught exception was raised during execution of the main script:\r\r%@: %@\r\rThis may mean that an unexpected error has occurred, or that you do not have all of the dependencies for this bundle.";
NSString *ERR_COLONPATH = @"Python bundles can not currently run from paths containing a '/' (or ':' from the Terminal).";
#define PYMACAPP_NSIMAGEFLAGS (NSADDIMAGE_OPTION_RETURN_ON_ERROR | NSADDIMAGE_OPTION_WITH_SEARCHING)
#define PYMACAPP_NSLOOKUPSYMBOLINIMAGEFLAGS (NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR)
//
// Typedefs
//
#define Py_file_input 257
typedef int PyObject;
typedef int PyThreadState;
typedef enum {PyGILState_LOCKED, PyGILState_UNLOCKED} PyGILState_STATE;
typedef PyGILState_STATE (*PyGILState_EnsurePtr)(void);
typedef void (*PyGILState_ReleasePtr)(PyGILState_STATE);
typedef PyThreadState *(*PyThreadState_SwapPtr)(PyThreadState *);
typedef void (*PyEval_ReleaseLockPtr)(void);
typedef void (*PyErr_ClearPtr)(void);
typedef void (*PyErr_PrintPtr)(void);
typedef int (*PyErr_OccurredPtr)(void);
typedef PyObject *(*PyBytes_FromStringPtr)(const char *);
typedef int (*PyList_InsertPtr)(PyObject *, int, PyObject *);
typedef void (*Py_DecRefPtr)(PyObject *);
typedef void (*Py_SetProgramNamePtr)(const wchar_t *);
typedef int (*Py_IsInitializedPtr)(void);
typedef void (*Py_InitializePtr)(void);
typedef void (*PyEval_InitThreadsPtr)(void);
typedef PyObject *(*PyRun_FilePtr)(FILE *, const char *, int, PyObject *, PyObject *);
typedef PyObject *(*PySys_GetObjectPtr)(const char *);
typedef int *(*PySys_SetArgvPtr)(int argc, char **argv);
typedef PyObject *(*PyObject_StrPtr)(PyObject *);
typedef const char *(*PyBytes_AsStringPtr)(PyObject *);
typedef PyObject *(*PyObject_GetAttrStringPtr)(PyObject *, const char *);
typedef PyObject *(*PyObject_CallMethodPtr)(PyObject *, const char *, const char *, ...);
typedef PyObject *(*PyImport_ImportModulePtr)(char *);
typedef PyObject *(*PyImport_AddModulePtr)(char *);
typedef PyObject *(*PyModule_AddStringConstantPtr)(PyObject *, char *, char *);
typedef PyObject *(*PyModule_AddObjectPtr)(PyObject *, char *, PyObject *);
typedef PyObject *(*PyModule_GetDictPtr)(PyObject *);
typedef void (*PyObject_SetItemPtr)(PyObject *, PyObject *, PyObject *);
typedef wchar_t* (*_Py_DecodeUTF8_surrogateescapePtr)(const char *s, ssize_t size);
//
// Signatures
//
static void DefaultDecRef(PyObject *op);
static int report_error(NSString *err);
static int report_linkEdit_error(const char* name);
static int report_script_error(NSString *err, NSString *errClassName, NSString *errName);
static NSString *pyStandardizePath(NSString *pyLocation);
static BOOL doesPathExist(NSString *path);
static NSString *getBundleName(void);
static NSString *getErrorTitle(NSString *bundleName);
static const char *bundlePath(void);
static NSBundle *bundleBundle(void);
static int pyobjc_main(int argc, char * const *argv, char * const *envp);
//
// Mach-O Constructor
//
static void __attribute__ ((constructor)) _py2app_bundle_load(void);
//
// Implementation
//
static
const char *bundlePath(void) {
int i;
const struct mach_header *myHeader = _dyld_get_image_header_containing_address(&bundlePath);
int count = _dyld_image_count();
for (i = 0; i < count; i++) {
if (_dyld_get_image_header(i) == myHeader) {
return _dyld_get_image_name(i);
}
}
abort();
return NULL;
}
static
NSBundle *bundleBundle(void) {
static NSBundle *myBundle = NULL;
if (!myBundle) {
int i;
NSString *path = [NSString stringWithUTF8String:bundlePath()];
// strip Contents/MacOS/App
for (i = 0; i < 3; i++) {
path = [path stringByDeletingLastPathComponent];
}
myBundle = [[NSBundle alloc] initWithPath:path];
}
return myBundle;
}
//
// THIS WILL NOT WORK WITH Py_TRACE_REFS / Py_DEBUG ON UNLESS USING 2.4 OR LATER!
//
static
void DefaultDecRef(PyObject *op) {
if (op != NULL) {
--(*op);
}
}
static
int report_script_error(NSString *err, NSString *errClassName, NSString *errName) {
return report_error(err);
}
static
int report_error(NSString *err) {
NSLog(@"%@", getErrorTitle(getBundleName()));
NSLog(@"%@", err);
return -1;
}
static
int report_linkEdit_error(const char* name) {
NSLinkEditErrors errorClass;
int errorNumber;
const char *fileName;
const char *errorString;
NSLinkEditError(&errorClass, &errorNumber, &fileName, &errorString);
NSLog(@"%s: %s", name, errorString);
printf("<<<py2app>>>> %s: %s\n", name, errorString);
return report_error([NSString stringWithFormat:ERR_LINKERRFMT, fileName]);
}
static
NSString *pyStandardizePath(NSString *pyLocation) {
if ([pyLocation hasPrefix:@"@executable_path/"]) {
NSMutableArray *newComponents = [[pyLocation pathComponents] mutableCopy];
[newComponents replaceObjectAtIndex:0 withObject:[bundleBundle() privateFrameworksPath]];
pyLocation = [NSString pathWithComponents: newComponents];
}
return [pyLocation stringByStandardizingPath];
};
static
BOOL doesPathExist(NSString *path) {
struct stat sb;
return (stat([path fileSystemRepresentation], &sb) == -1) ? NO : YES;
}
static
NSString *getBundleName(void) {
NSDictionary *infoDictionary = [bundleBundle() infoDictionary];
NSString *bundleName = [infoDictionary objectForKey:@"CFBundleName"];
if (!bundleName) {
bundleName = [infoDictionary objectForKey:@"CFBundleExecutable"];
}
return bundleName;
}
static
NSString *getErrorTitle(NSString *bundleName) {
if (!bundleName) {
return ERR_REALLYBADTITLE;
}
return [NSString stringWithFormat:ERR_TITLEFORMAT,bundleName];
}
static
NSString *getPythonLocation(NSArray *pyLocations) {
// get the runtime locations from the Info.plist
// *does not* inspect DYLD environment variables for overrides, fallbacks, suffixes, etc.
// I don't really consider that a very bad thing, as it makes this search extremely deterministic.
// Note that I use the env variables when the image is actually linked, so what you find here
// may not be what gets linked. If this is the case, you deserve it :)
// find a Python runtime
NSString *pyLocation;
NSEnumerator *pyLocationsEnumerator = [pyLocations objectEnumerator];
while ((pyLocation = [pyLocationsEnumerator nextObject])) {
pyLocation = pyStandardizePath(pyLocation);
if (doesPathExist(pyLocation)) {
return pyLocation;
}
}
return nil;
}
static NSString* getPythonInterpreter(NSString* pyLocation) {
NSBundle* bndl;
NSString* auxName;
bndl = bundleBundle();
auxName = [[bndl infoDictionary] objectForKey:@"PyExecutableName"];
if (!auxName) {
auxName = @"python";
}
return [bndl pathForAuxiliaryExecutable:auxName];
}
static
NSArray *getPythonPathArray(NSDictionary *infoDictionary, NSString *resourcePath) {
NSMutableArray *pythonPathArray = [NSMutableArray arrayWithObject: resourcePath];
NSArray *pyResourcePackages = [infoDictionary objectForKey:@"PyResourcePackages"];
if (pyResourcePackages != nil) {
NSString *pkg;
NSEnumerator *pyResourcePackageEnumerator = [pyResourcePackages objectEnumerator];
while ((pkg = [pyResourcePackageEnumerator nextObject])) {
pkg = [pkg stringByExpandingTildeInPath];
if (![@"/" isEqualToString: [pkg substringToIndex:1]]) {
pkg = [resourcePath stringByAppendingPathComponent:pkg];
}
[pythonPathArray addObject:pkg];
}
}
return pythonPathArray;
}
static
NSString *getMainPyPath(NSDictionary *infoDictionary) {
NSArray *possibleMains = [infoDictionary objectForKey:@"PyMainFileNames"];
if ( !possibleMains )
possibleMains = [NSArray array];
// find main python file. __main__.py seems to be a standard, so we'll go ahead and add defaults.
possibleMains = [possibleMains arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:
@"__main__",
@"__realmain__",
@"Main",
nil]];
NSEnumerator *possibleMainsEnumerator = [possibleMains objectEnumerator];
NSString *mainPyPath = nil;
NSString *nextFileName = nil;
NSString *nextExtension = nil;
NSArray *extensions = [NSArray arrayWithObjects:@".py", @".pyc", @".pyo", @"", nil];
NSMutableArray *runtimeAttempts = [NSMutableArray array];
while ((nextFileName = [possibleMainsEnumerator nextObject])) {
NSEnumerator *nextExtensionEnumerator = [extensions objectEnumerator];
while ((nextExtension = [nextExtensionEnumerator nextObject])) {
[runtimeAttempts addObject:[nextFileName stringByAppendingString:nextExtension]];
}
}
possibleMainsEnumerator = [runtimeAttempts objectEnumerator];
while ((nextFileName = [possibleMainsEnumerator nextObject]) && !mainPyPath) {
mainPyPath = [bundleBundle() pathForResource:nextFileName ofType:nil];
}
if (!mainPyPath) {
NSString *components = [runtimeAttempts componentsJoinedByString:@"\r"];
report_error([ERR_NOPYTHONSCRIPT stringByAppendingString:components]);
}
return mainPyPath;
}
int pyobjc_main(int argc, char * const *argv, char * const *envp) {
char* curenv;
char* curlocale;
NSDictionary *infoDictionary = [bundleBundle() infoDictionary];
if (getenv("PYTHONOPTIMIZE") != NULL) {
unsetenv("PYTHONOPTIMIZE");
}
if (getenv("PYTHONDEBUG") != NULL) {
unsetenv("PYTHONDEBUG");
}
if (getenv("PYTHONDONTWRITEBYTECODE") != NULL) {
unsetenv("PYTHONDONTWRITEBYTECODE");
}
if (getenv("PYTHONIOENCODING") != NULL) {
unsetenv("PYTHONIOENCODING");
}
if (getenv("PYTHONDUMPREFS") != NULL) {
unsetenv("PYTHONDUMPREFS");
}
if (getenv("PYTHONMALLOCSTATS") != NULL) {
unsetenv("PYTHONMALLOCSTATS");
}
/* Disable writing of bytecode files */
setenv("PYTHONDONTWRITEBYTECODE", "1", 1);
NSString *pyLocation = nil;
while (NSIsSymbolNameDefined("_Py_Initialize")) {
// Python is already in-process
NSSymbol sym = NSLookupAndBindSymbol("_Py_Initialize");
if (!sym) {
break;
}
NSModule mod = NSModuleForSymbol(sym);
if (!mod) {
break;
}
const char *python_dylib_path = NSLibraryNameForModule(mod);
if (python_dylib_path) {
pyLocation = [NSString stringWithUTF8String:python_dylib_path];
}
break;
}
NSArray *pyLocations = [infoDictionary objectForKey:@"PyRuntimeLocations"];
if (!pyLocation) {
// Python is not in-process
if (!pyLocations) {
return report_error(ERR_PYRUNTIMELOCATIONS);
}
pyLocation = getPythonLocation(pyLocations);
}
if (!pyLocation) {
NSString *components = [pyLocations componentsJoinedByString:@"\r\r"];
return report_script_error([ERR_NOPYTHONRUNTIME stringByAppendingString:components], nil, nil);
}
// Find our resource path and possible PYTHONPATH
NSString *resourcePath = [bundleBundle() resourcePath];
NSArray *pythonPathArray = getPythonPathArray(infoDictionary, resourcePath);
// find the main script
NSString *mainPyPath = getMainPyPath(infoDictionary);
if (!mainPyPath) {
// error already reported
return -1;
}
// Load the Python dylib (may have already been loaded, that is OK)
const struct mach_header *py_dylib = NSAddImage([pyLocation fileSystemRepresentation], PYMACAPP_NSIMAGEFLAGS);
if (!py_dylib) {
return report_linkEdit_error([pyLocation fileSystemRepresentation]);
}
// Load the symbols we need from Python. We avoid lookups of unicode methods because their
// names are mangled by Python (because of UCS2/UCS4 stuff) and looking them up reliably is
// problematic.
NSSymbol tmpSymbol;
#define LOOKUP_SYMBOL(NAME) \
tmpSymbol = NSLookupSymbolInImage(py_dylib, "_" #NAME, PYMACAPP_NSLOOKUPSYMBOLINIMAGEFLAGS)
#define LOOKUP_DEFINEADDRESS(NAME, ADDRESS) \
NAME ## Ptr NAME = (NAME ## Ptr)ADDRESS
#define LOOKUP_DEFINE(NAME) \
LOOKUP_DEFINEADDRESS(NAME, NSAddressOfSymbol(tmpSymbol))
#define LOOKUP(NAME) \
LOOKUP_SYMBOL(NAME); \
if ( !tmpSymbol ) \
return report_linkEdit_error(#NAME); \
LOOKUP_DEFINE(NAME)
#define OPT_LOOKUP(NAME) \
LOOKUP_SYMBOL(NAME); \
NAME ## Ptr NAME = NULL; \
if (tmpSymbol) { \
NAME = (NAME ## Ptr)NSAddressOfSymbol(tmpSymbol); \
}
LOOKUP_SYMBOL(Py_DecRef);
LOOKUP_DEFINEADDRESS(Py_DecRef, (tmpSymbol ? NSAddressOfSymbol(tmpSymbol) : &DefaultDecRef));
LOOKUP(Py_SetProgramName);
LOOKUP(Py_IsInitialized);
LOOKUP(Py_Initialize);
LOOKUP(PyErr_Clear);
LOOKUP(PyErr_Print);
LOOKUP(PyErr_Occurred);
LOOKUP(PyEval_ReleaseLock);
LOOKUP(PyGILState_Ensure);
LOOKUP(PyGILState_Release);
LOOKUP(PyEval_InitThreads);
LOOKUP(PyRun_File);
LOOKUP(PySys_GetObject);
LOOKUP(PySys_SetArgv);
LOOKUP(PyObject_Str);
LOOKUP(PyList_Insert);
LOOKUP(PyObject_GetAttrString);
LOOKUP(PyObject_CallMethod);
LOOKUP(PyImport_ImportModule);
LOOKUP(PyImport_AddModule);
LOOKUP(PyObject_SetItem);
LOOKUP(PyModule_AddStringConstant);
LOOKUP(PyModule_AddObject);
LOOKUP(PyModule_GetDict);
LOOKUP(PyThreadState_Swap);
OPT_LOOKUP(_Py_DecodeUTF8_surrogateescape);
/* PyBytes / PyString lookups depend of if we're on py3k or not */
PyBytes_AsStringPtr PyBytes_AsString = NULL;
PyBytes_FromStringPtr PyBytes_FromString = NULL;
LOOKUP_SYMBOL(PyBytes_AsString);
int isPy3k = tmpSymbol != NULL;
if (isPy3k) {
PyBytes_AsString = (PyBytes_AsStringPtr)NSAddressOfSymbol(tmpSymbol);
LOOKUP_SYMBOL(PyBytes_FromString);
PyBytes_FromString = (PyBytes_FromStringPtr)NSAddressOfSymbol(tmpSymbol);
}
else {
LOOKUP_SYMBOL(PyString_AsString);
PyBytes_AsString = (PyBytes_AsStringPtr)NSAddressOfSymbol(tmpSymbol);
LOOKUP_SYMBOL(PyString_FromString);
PyBytes_FromString = (PyBytes_FromStringPtr)NSAddressOfSymbol(tmpSymbol);
}
#undef LOOKUP
#undef LOOKUP_DEFINE
#undef LOOKUP_DEFINEADDRESS
#undef LOOKUP_SYMBOL
int was_initialized = Py_IsInitialized();
/*
* When apps are started from the Finder (or anywhere
* except from the terminal), the LANG and LC_* variables
* aren't set in the environment. This confuses Py_Initialize
* when it tries to import the codec for UTF-8,
* therefore explicitly set the locale.
*
* Also set the LC_CTYPE environment variable because Py_Initialize
* reset the locale information using the environment :-(
*/
if (isPy3k) {
curlocale = setlocale(LC_ALL, NULL);
if (curlocale != NULL) {
curlocale = strdup(curlocale);
if (curlocale == NULL) {
(void)report_error(ERR_CANNOT_SAVE_LOCALE);
return -1;
}
}
setlocale(LC_ALL, "en_US.UTF-8");
curenv = getenv("LC_CTYPE");
if (!curenv) {
setenv("LC_CTYPE", "en_US.UTF-8", 1);
}
}
// Set up the environment variables to be transferred
NSMutableDictionary *newEnviron = [NSMutableDictionary dictionary];
[newEnviron setObject:[NSString stringWithFormat:@"%p", bundleBundle()] forKey:@"PYOBJC_BUNDLE_ADDRESS"];
[newEnviron setObject:[NSString stringWithFormat:@"%p", bundleBundle()] forKey:[NSString
stringWithFormat:@"PYOBJC_BUNDLE_ADDRESS%ld", (long)getpid()]];
[newEnviron setObject:resourcePath forKey:@"RESOURCEPATH"];
NSMutableDictionary *oldEnviron = [NSMutableDictionary dictionary];
// bootstrap Python with information about how to find what it needs
// if it is not already initialized
if (!was_initialized) {
// $PREFIX/Python -> $PREFIX
NSString *pythonProgramName = [pyLocation stringByDeletingLastPathComponent];
NSString* interpreter = getPythonInterpreter(pyLocation);
struct stat sb;
if (lstat([interpreter fileSystemRepresentation], &sb) == 0) {
if(!((sb.st_mode & S_IFLNK) == S_IFLNK)) {
setenv("PYTHONHOME", [resourcePath fileSystemRepresentation], 1);
}
} else {
setenv("PYTHONHOME", [resourcePath fileSystemRepresentation], 1);
}
NSString *pyExecutableName = [infoDictionary objectForKey:@"PyExecutableName"];
if ( !pyExecutableName ) {
pyExecutableName = @"python";
}
pythonProgramName = [[pythonProgramName stringByAppendingPathComponent:@"bin"] stringByAppendingPathComponent:pyExecutableName];
wchar_t wPythonName[PATH_MAX+1];
if (isPy3k) {
mbstowcs(wPythonName, [pythonProgramName fileSystemRepresentation], PATH_MAX+1);
}
else {
const char *cPythonName = [pythonProgramName fileSystemRepresentation];
memcpy(wPythonName, cPythonName, strlen(cPythonName));
}
Py_SetProgramName(wPythonName);
}
// Set new environment variables and save older ones (for nested plugin loading)
NSEnumerator *envEnumerator = [newEnviron keyEnumerator];
NSString *envKey;
while ((envKey = [envEnumerator nextObject])) {
char *keyString = (char *)[envKey UTF8String];
char *oldValue = getenv(keyString);
if (oldValue) {
[oldEnviron setObject:[NSString stringWithUTF8String:oldValue] forKey:envKey];
}
setenv(keyString, (char *)[[newEnviron objectForKey:envKey] UTF8String], 1);
}
int rval = 0;
FILE *mainPyFile = NULL;
Py_Initialize();
PyEval_InitThreads();
if (isPy3k) {
/*
* Reset the environment and locale information
*/
setlocale(LC_CTYPE, curlocale);
free(curlocale);
if (!curenv) {
unsetenv("LC_CTYPE");
}
}
PyGILState_STATE gilState = PyGILState_Ensure();
if (was_initialized) {
// transfer path into existing Python process
PyObject *path = PySys_GetObject("path");
NSEnumerator *pathEnumerator = [pythonPathArray reverseObjectEnumerator];
NSString *curPath;
while ((curPath = [pathEnumerator nextObject])) {
PyObject *b = PyBytes_FromString([curPath UTF8String]);
PyObject *s = PyObject_CallMethod(b, "decode", "s", "utf-8");
PyList_Insert(path, 0, s);
Py_DecRef(b);Py_DecRef(s);
}
// transfer environment variables into existing Python process
PyObject *osModule = PyImport_ImportModule("os");
PyObject *pyenv = PyObject_GetAttrString(osModule, "environ");
Py_DecRef(osModule);
envEnumerator = [newEnviron keyEnumerator];
while ((envKey = [envEnumerator nextObject])) {
char *keyString = (char *)[envKey UTF8String];
PyObject *b_key = PyBytes_FromString(keyString);
PyObject *b_value = PyBytes_FromString(getenv(keyString));
PyObject *key = PyObject_CallMethod(b_key, "decode", "s", "utf-8");
PyObject *value = PyObject_CallMethod(b_value, "decode", "s", "utf-8");
PyObject_SetItem(pyenv, key, value);
Py_DecRef(b_key);Py_DecRef(key);
Py_DecRef(b_value);Py_DecRef(value);
}
Py_DecRef(pyenv);
}
char *c_mainPyPath = (char *)[mainPyPath fileSystemRepresentation];
mainPyFile = fopen(c_mainPyPath, "r");
if (!mainPyFile) {
rval = report_error([NSString stringWithFormat:@"Could not open main script %@",mainPyPath]);
goto cleanup;
}
if (!was_initialized) {
int i;
NSMutableData *data_argv = [NSMutableData dataWithCapacity:(sizeof(char *) * argc)];
char **argv_new = [data_argv mutableBytes];
if (isPy3k) {
argv_new[0] = (char*)_Py_DecodeUTF8_surrogateescape(c_mainPyPath, strlen(c_mainPyPath));
} else {
argv_new[0] = c_mainPyPath;
}
for (i = 1; i < argc; i++) {
if (isPy3k) {
argv_new[i] = (char*)_Py_DecodeUTF8_surrogateescape(argv[i], strlen(argv[i]));
} else {
argv_new[i] = argv[i];
}
}
argv_new[argc] = NULL;
PySys_SetArgv(argc, argv_new);
}
// create a unique moduleName by CFBundleIdentifier replacing . with _ and prepending __main__
NSString *moduleName = [NSString stringWithFormat:@"__main__%@", [[[infoDictionary objectForKey:@"CFBundleIdentifier"] componentsSeparatedByString:@"."] componentsJoinedByString:@"_"]];
PyObject *module = PyImport_AddModule((char *)[moduleName UTF8String]);
if (!module) {
rval = report_error([NSString stringWithFormat:@"Could not create module '%@'",moduleName]);
goto cleanup;
}
PyModule_AddStringConstant(module, "__file__", c_mainPyPath);
char * builtinsName = isPy3k ? "builtins" : "__builtin__";
PyObject *builtins = PyImport_ImportModule(builtinsName);
PyModule_AddObject(module, "__builtins__", builtins);
PyObject *module_dict = PyModule_GetDict(module);
if (PyErr_Occurred()) {
goto cleanup;
}
PyObject *res = PyRun_File(mainPyFile, c_mainPyPath, Py_file_input, module_dict, module_dict);
if (res) {
Py_DecRef(res);
}
cleanup:
// un-transfer the environment variables
envEnumerator = [newEnviron keyEnumerator];
while ((envKey = [envEnumerator nextObject])) {
char *keyString = (char *)[envKey UTF8String];
NSString *newValue = [oldEnviron objectForKey:envKey];
if (newValue) {
setenv(keyString, [newValue UTF8String], 1);
} else {
unsetenv(keyString);
}
}
if (mainPyFile) {
fclose(mainPyFile);
}
if (PyErr_Occurred()) {
rval = -1;
PyErr_Print();
}
while ( rval ) {
PyObject *exc = PySys_GetObject("last_type");
if ( !exc ) {
rval = report_error([NSString stringWithFormat:ERR_PYTHONEXCEPTION,"<<PyMacAppException>>","The exception went away?"]);
break;
}
PyObject *exceptionClassName = PyObject_GetAttrString(exc, "__name__");
if ( !exceptionClassName ) {
rval = report_error([NSString stringWithFormat:ERR_PYTHONEXCEPTION,"<<PyMacAppException>>","Could not get exception class name?"]);
break;
}
PyObject *v = PySys_GetObject("last_value");
PyObject *exceptionName = NULL;
if ( v )
exceptionName = PyObject_Str(v);
PyObject *b = PyObject_CallMethod(exceptionClassName, "encode", "s", "utf-8");
NSString *nsExceptionClassName = [NSString stringWithCString:PyBytes_AsString(b) encoding:NSUTF8StringEncoding];
Py_DecRef(exceptionClassName);Py_DecRef(b);
NSString *nsExceptionName;
if ( exceptionName ) {
PyObject *b = PyObject_CallMethod(exceptionName, "encode", "s", "utf-8");
nsExceptionName = [NSString stringWithCString:PyBytes_AsString(b) encoding:NSUTF8StringEncoding];
Py_DecRef(exceptionName);Py_DecRef(b);
} else {
nsExceptionName = @"";
}
rval = report_script_error([NSString stringWithFormat:ERR_PYTHONEXCEPTION, nsExceptionClassName, nsExceptionName], nsExceptionClassName, nsExceptionName);
break;
}
PyErr_Clear();
PyGILState_Release(gilState);
if (gilState == PyGILState_LOCKED) {
PyThreadState_Swap(NULL);
PyEval_ReleaseLock();
}
return rval;
}
static
void _py2app_bundle_load(void)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int argc = 1;
char * const argv[] = { (char *)bundlePath(), NULL };
char * const *envp = *_NSGetEnviron();
(void)pyobjc_main(argc, argv, envp);
[pool release];
}