The Apple build is working

This commit is contained in:
Kovid Goyal 2019-11-21 21:17:13 +05:30
parent 066ff4127b
commit 411da596b4
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
7 changed files with 133 additions and 410 deletions

View File

@ -37,20 +37,25 @@ QT_FRAMEWORKS = [x.replace('5', '') for x in QT_DLLS]
ENV = dict(
FONTCONFIG_PATH='@executable_path/../Resources/fonts',
FONTCONFIG_FILE='@executable_path/../Resources/fonts/fonts.conf',
PYTHONIOENCODING='UTF-8',
SSL_CERT_FILE='@executable_path/../Resources/resources/mozilla-ca-certs.pem',
)
APPNAME, VERSION = calibre_constants['appname'], calibre_constants['version']
basenames, main_modules, main_functions = calibre_constants['basenames'], calibre_constants['modules'], calibre_constants['functions']
def compile_launcher_lib(contents_dir, gcc, base):
def compile_launcher_lib(contents_dir, gcc, base, pyver):
print('\tCompiling calibre_launcher.dylib')
fd = join(contents_dir, 'Frameworks')
dest = join(fd, 'calibre-launcher.dylib')
env, env_vals = [], []
for key, val in ENV.items():
env.append(f'"{key}"'), env_vals.append(f'"{val}"')
env = ','.join(env)
env_vals = ','.join(env_vals)
dest = join(contents_dir, 'Frameworks', 'calibre-launcher.dylib')
src = join(base, 'util.c')
cmd = [gcc] + '-Wall -dynamiclib -std=gnu99'.split() + [src] + \
['-I' + base] + \
['-I' + base] + '-DPY_VERSION_MAJOR={} -DPY_VERSION_MINOR={}'.format(*pyver.split('.')).split() + \
[f'-DENV_VARS={env}', f'-DENV_VAR_VALS={env_vals}'] + \
['-I%s/python/Python.framework/Versions/Current/Headers' % PREFIX] + \
'-current_version 1.0 -compatibility_version 1.0'.split() + \
'-fvisibility=hidden -o'.split() + [dest] + \
@ -68,33 +73,19 @@ gcc = os.environ.get('CC', 'clang')
def compile_launchers(contents_dir, xprograms, pyver):
base = dirname(abspath(__file__))
lib = compile_launcher_lib(contents_dir, gcc, base)
with open(join(base, 'launcher.c'), 'rb') as f:
src = f.read().decode('utf-8')
env, env_vals = [], []
for key, val in ENV.items():
env.append('"%s"' % key)
env_vals.append('"%s"' % val)
env = ', '.join(env) + ', '
env_vals = ', '.join(env_vals) + ', '
src = src.replace('/*ENV_VARS*/', env)
src = src.replace('/*ENV_VAR_VALS*/', env_vals)
lib = compile_launcher_lib(contents_dir, gcc, base, pyver)
src = join(base, 'launcher.c')
programs = [lib]
for program, x in xprograms.items():
module, func, ptype = x
print('\tCompiling', program)
out = join(contents_dir, 'MacOS', program)
programs.append(out)
psrc = src.replace('**PROGRAM**', program)
psrc = psrc.replace('**MODULE**', module)
psrc = psrc.replace('**FUNCTION**', func)
psrc = psrc.replace('**PYVER**', pyver)
psrc = psrc.replace('**IS_GUI**', ('1' if ptype == 'gui' else '0'))
fsrc = '/tmp/%s.c' % program
with open(fsrc, 'wb') as f:
f.write(psrc.encode('utf-8'))
cmd = [gcc, '-Wall', '-I' + base, fsrc, lib, '-o', out,
'-headerpad_max_install_names']
is_gui = 'true' if ptype == 'gui' else 'false'
cmd = [
gcc, '-Wall', f'-DPROGRAM=L"{program}"', f'-DMODULE=L"{module}"', f'-DFUNCTION=L"{func}"', f'-DIS_GUI={is_gui}',
'-I' + base, src, lib, '-o', out, '-headerpad_max_install_names'
]
# print('\t'+' '.join(cmd))
sys.stdout.flush()
subprocess.check_call(cmd)
@ -194,9 +185,9 @@ class Freeze(object):
self.add_misc_libraries()
self.add_resources()
self.copy_site()
self.compile_py_modules()
self.copy_site()
self.create_exe()
if not test_launchers and not self.dont_strip:
self.strip_files()
@ -258,6 +249,8 @@ class Freeze(object):
for x, is_id in self.get_dependencies(path_to_lib):
if x.startswith('@rpath/Qt'):
yield x, x[len('@rpath/'):], is_id
elif x == 'libunrar.dylib' and not is_id:
yield x, x, is_id
else:
for y in (PREFIX + '/lib/', PREFIX + '/python/Python.framework/'):
if x.startswith(y):
@ -500,10 +493,10 @@ class Freeze(object):
@flush
def add_misc_libraries(self):
for x in (
'usb-1.0.0', 'mtp.9', 'chm.0', 'sqlite3.0', 'hunspell-1.7.0',
'icudata.64', 'icui18n.64', 'icuio.64', 'icuuc.64', 'hyphen.0',
'xslt.1', 'exslt.0', 'xml2.2', 'z.1', 'unrar', 'lzma.5',
'crypto.1.0.0', 'ssl.1.0.0', 'iconv.2', # 'ltdl.7'
'usb-1.0.0', 'mtp.9', 'chm.0', 'sqlite3.0', 'hunspell-1.7.0',
'icudata.64', 'icui18n.64', 'icuio.64', 'icuuc.64', 'hyphen.0',
'xslt.1', 'exslt.0', 'xml2.2', 'z.1', 'unrar', 'lzma.5',
'crypto.1.0.0', 'ssl.1.0.0', 'iconv.2', # 'ltdl.7'
):
print('\nAdding', x)
x = 'lib%s.dylib' % x

View File

@ -10,32 +10,8 @@
#define arraysz(x) (sizeof(x)/sizeof(x[0]))
// These variables must be filled in before compiling
static const char *ENV_VARS[] = { /*ENV_VARS*/ NULL };
static const char *ENV_VAR_VALS[] = { /*ENV_VAR_VALS*/ NULL};
static char PROGRAM[] = "**PROGRAM**";
static const char MODULE[] = "**MODULE**";
static const char FUNCTION[] = "**FUNCTION**";
static const char PYVER[] = "**PYVER**";
int
main(int argc, char* const *argv, const char **envp) {
char pathbuf[PROC_PIDPATHINFO_MAXSIZE], realpath_buf[PROC_PIDPATHINFO_MAXSIZE * 5];
pid_t pid = getpid();
int ret = proc_pidpath(pid, pathbuf, arraysz(pathbuf));
if (ret <= 0) fatal("failed to get executable path for current pid with error: %s", strerror(errno));
char *path = realpath(pathbuf, realpath_buf);
if (path == NULL) fatal("failed to get realpath for executable path with error: %s", strerror(errno));
// We re-exec using an absolute path because the Qt WebEngine sandbox does not work
// when running via symlink
const int is_gui = **IS_GUI**;
if (!is_gui && strcmp(PROGRAM, "calibre-parallel") != 0 && strcmp(argv[0], path) != 0) {
char* new_argv[1024] = {0};
new_argv[0] = path;
for (int i = 1; i < argc && i < arraysz(new_argv) - 1; i++) new_argv[i] = argv[i];
execv(path, new_argv);
}
return run(ENV_VARS, ENV_VAR_VALS, PROGRAM, MODULE, FUNCTION, PYVER, is_gui, argc, argv, envp, path);
main(int argc, char * const *argv) {
run(PROGRAM, MODULE, FUNCTION, IS_GUI, argc, argv);
return 0;
}

View File

@ -1,131 +1,14 @@
"""
Append module search paths for third-party packages to sys.path.
This is stripped down and customized for use in py2app applications
"""
import sys
import builtins
import os
def makepath(*paths):
dir = os.path.abspath(os.path.join(*paths))
return dir, os.path.normcase(dir)
def abs__file__():
"""Set all module __file__ attribute to an absolute path"""
for m in sys.modules.values():
if hasattr(m, '__loader__'):
continue # don't mess with a PEP 302-supplied __file__
try:
m.__file__ = os.path.abspath(m.__file__)
except AttributeError:
continue
# 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 dircase not 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 sitedircase not 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:
f = open(fullname)
except IOError:
return
while True:
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 dircase not in _dirs_in_sys_path and os.path.exists(dir):
sys.path.append(dir)
_dirs_in_sys_path[dircase] = 1
if reset:
_dirs_in_sys_path = None
# 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"):
sys.setdefaultencoding('utf-8')
del sys.setdefaultencoding
def run_entry_point():
bname, mod, func = sys.calibre_basename, sys.calibre_module, sys.calibre_function
sys.argv[0] = bname
pmod = __import__(mod, fromlist=[1], level=0)
return getattr(pmod, func)()
import sys
import _sitebuiltins
def read_user_env_vars():
try:
with open(os.path.expanduser('~/Library/Preferences/calibre/macos-env.txt'), 'rb') as f:
raw = f.read().decode('utf-8', 'replace')
except EnvironmentError as err:
except EnvironmentError:
return
for line in raw.splitlines():
if line.startswith('#'):
@ -136,52 +19,46 @@ def read_user_env_vars():
os.environ[key] = os.path.expandvars(os.path.expanduser(val))
def add_calibre_vars(base):
sys.frameworks_dir = os.path.join(os.path.dirname(base), 'Frameworks')
sys.resources_location = os.path.abspath(os.path.join(base, 'resources'))
sys.extensions_location = os.path.join(sys.frameworks_dir, 'plugins')
sys.binaries_path = os.path.join(os.path.dirname(base), 'MacOS')
try:
read_user_env_vars()
except Exception as err:
try:
sys.stderr.write('Failed to read user env vars with error: {}\n'.format(err))
sys.stderr.flush()
except Exception:
pass
dv = os.environ.get('CALIBRE_DEVELOP_FROM', None)
if dv and os.path.exists(dv):
sys.path.insert(0, os.path.abspath(dv))
def nuke_stdout():
# Redirect stdout, stdin and stderr to /dev/null
from calibre.constants import plugins
plugins['speedup'][0].detach(os.devnull)
def set_helper():
builtins.help = _sitebuiltins._Helper()
def set_quit():
eof = 'Ctrl-D (i.e. EOF)'
builtins.quit = _sitebuiltins.Quitter('quit', eof)
builtins.exit = _sitebuiltins.Quitter('exit', eof)
def main():
global __file__
sys.argv[0] = sys.calibre_basename
try:
read_user_env_vars()
except Exception as err:
try:
print('Failed to read user env vars with error:', err, file=sys.stderr)
sys.stderr.flush()
except Exception:
pass
# Needed on OS X <= 10.8, which passes -psn_... as a command line arg when
# starting via launch services
for arg in tuple(sys.argv[1:]):
if arg.startswith('-psn_'):
sys.argv.remove(arg)
base = sys.resourcepath
sys.frozen = 'macosx_app'
sys.new_app_bundle = True
abs__file__()
add_calibre_vars(base)
addsitedir(sys.site_packages)
if sys.calibre_is_gui_app and not (
dfv = os.environ.get('CALIBRE_DEVELOP_FROM')
if dfv and os.path.exists(dfv):
sys.path.insert(0, os.path.abspath(dfv))
set_helper()
set_quit()
if sys.gui_app and not (
sys.stdout.isatty() or sys.stderr.isatty() or sys.stdin.isatty()
):
nuke_stdout()
mod = __import__(sys.calibre_module, fromlist=[1])
func = getattr(mod, sys.calibre_function)
return func()
return run_entry_point()
if __name__ == '__main__':
main()

View File

@ -1,43 +1,25 @@
#include "util.h"
#include <stdlib.h>
#include <strings.h>
#include "../run-python.h"
#include <CoreFoundation/CoreFoundation.h>
#include <mach-o/dyld.h>
#include <Python.h>
#include <libproc.h>
#define EXPORT __attribute__((visibility("default")))
static const char *ERR_OOM = "Out of memory";
static int
report_error(const char *msg) {
fprintf(stderr, "%s\n", msg);
fflush(stderr);
return -1;
}
static int
report_code(const char *preamble, const char* msg, int code) {
fprintf(stderr, "%s: %s\n", preamble, msg);
fflush(stderr);
return code;
}
#define EXE "@executable_path/.."
static const char *env_vars[] = { ENV_VARS };
static const char *env_var_vals[] = { ENV_VAR_VALS };
static void
set_env_vars(const char **ENV_VARS, const char **ENV_VAR_VALS, const char* exe_path) {
int i = 0;
set_env_vars(const char* contents_path) {
char buf[3*PATH_MAX];
const char *env_var, *val;
while(1) {
env_var = ENV_VARS[i];
if (env_var == NULL) break;
val = ENV_VAR_VALS[i++];
if (strstr(val, EXE) == val && strlen(val) >= strlen(EXE)+1) {
strncpy(buf, exe_path, 3*PATH_MAX-150);
strncpy(buf+strlen(exe_path), val+strlen(EXE), 150);
for (size_t i = 0; i < arraysz(env_vars); i++) {
env_var = env_vars[i]; val = env_var_vals[i];
if (strstr(val, EXE) == val && strlen(val) >= sizeof(EXE)) {
snprintf(buf, sizeof(buf) - 1, "%s%s", contents_path, val + sizeof(EXE) - 1);
setenv(env_var, buf, 1);
} else
setenv(env_var, val, 1);
@ -45,168 +27,52 @@ set_env_vars(const char **ENV_VARS, const char **ENV_VAR_VALS, const char* exe_p
return;
}
void initialize_interpreter(const char **ENV_VARS, const char **ENV_VAR_VALS,
char *PROGRAM, const char *MODULE, const char *FUNCTION, const char *PYVER, int IS_GUI,
const char* exe_path, const char *rpath, int argc, char* const *argv) {
PyObject *pargv, *v;
int i;
Py_OptimizeFlag = 2;
Py_NoSiteFlag = 1;
Py_DontWriteBytecodeFlag = 1;
Py_IgnoreEnvironmentFlag = 1;
Py_NoUserSiteDirectory = 1;
Py_HashRandomizationFlag = 1;
//Py_VerboseFlag = 1;
//Py_DebugFlag = 1;
Py_SetProgramName(PROGRAM);
char pyhome[1000];
snprintf(pyhome, 1000, "%s/Python", rpath);
Py_SetPythonHome(pyhome);
set_env_vars(ENV_VARS, ENV_VAR_VALS, exe_path);
//printf("Path before Py_Initialize(): %s\r\n\n", Py_GetPath());
Py_Initialize();
char *dummy_argv[1] = {""};
PySys_SetArgv(1, dummy_argv);
//printf("Path after Py_Initialize(): %s\r\n\n", Py_GetPath());
char path[3000];
snprintf(path, 3000, "%s/lib/python%s:%s/lib/python%s/lib-dynload:%s/site-packages", pyhome, PYVER, pyhome, PYVER, pyhome);
PySys_SetPath(path);
//printf("Path set by me: %s\r\n\n", path);
PySys_SetObject("calibre_basename", PyBytes_FromString(PROGRAM));
PySys_SetObject("calibre_module", PyBytes_FromString(MODULE));
PySys_SetObject("calibre_function", PyBytes_FromString(FUNCTION));
PySys_SetObject("calibre_is_gui_app", ((IS_GUI) ? Py_True : Py_False));
PySys_SetObject("resourcepath", PyBytes_FromString(rpath));
snprintf(path, 3000, "%s/site-packages", pyhome);
PySys_SetObject("site_packages", PyBytes_FromString(pyhome));
pargv = PyList_New(argc);
if (pargv == NULL) exit(report_error(ERR_OOM));
for (i = 0; i < argc; i++) {
v = PyBytes_FromString(argv[i]);
if (v == NULL) exit(report_error(ERR_OOM));
PyList_SetItem(pargv, i, v);
}
PySys_SetObject("argv", pargv);
}
int pyobject_to_int(PyObject *res) {
int ret; PyObject *tmp;
tmp = PyNumber_Int(res);
if (tmp == NULL) ret = (PyObject_IsTrue(res)) ? 1 : 0;
else ret = (int)PyInt_AS_LONG(tmp);
return ret;
}
int handle_sysexit(PyObject *e) {
PyObject *code;
code = PyObject_GetAttrString(e, "code");
if (!code) return 0;
if (!PyInt_Check(code)) {
PyObject_Print(code, stderr, Py_PRINT_RAW);
fflush(stderr);
}
return pyobject_to_int(code);
}
int calibre_show_python_error(const char *preamble, int code) {
PyObject *exc, *val, *tb, *str;
int ret, issysexit = 0; char *i;
if (!PyErr_Occurred()) return code;
issysexit = PyErr_ExceptionMatches(PyExc_SystemExit);
PyErr_Fetch(&exc, &val, &tb);
if (exc != NULL) {
PyErr_NormalizeException(&exc, &val, &tb);
if (issysexit) {
return (val) ? handle_sysexit(val) : 0;
}
if (val != NULL) {
str = PyObject_Unicode(val);
if (str == NULL) {
PyErr_Clear();
str = PyObject_Str(val);
}
i = PyString_AsString(str);
ret = report_code(preamble, (i==NULL)?ERR_OOM:i, code);
if (tb != NULL) {
PyErr_Restore(exc, val, tb);
PyErr_Print();
}
return ret;
}
}
return report_code(preamble, "", code);
}
EXPORT
int
run(const char **ENV_VARS, const char **ENV_VAR_VALS, char *PROGRAM,
const char *MODULE, const char *FUNCTION, const char *PYVER,
int IS_GUI, int argc, char * const *argv, const char **envp, char *full_exe_path) {
char *t = NULL;
int ret = 0, i;
PyObject *site, *mainf, *res;
for (i = 0; i < 3; i++) {
t = rindex(full_exe_path, '/');
if (t == NULL) return report_error("Failed to determine bundle path.");
static void
get_paths() {
char pathbuf[PROC_PIDPATHINFO_MAXSIZE], realpath_buf[PROC_PIDPATHINFO_MAXSIZE * 5];
pid_t pid = getpid();
int ret = proc_pidpath(pid, pathbuf, sizeof(pathbuf));
if (ret <= 0) fatal("failed to get executable path for current pid with error: %s", strerror(errno));
char *path = realpath(pathbuf, realpath_buf);
if (path == NULL) fatal("failed to get realpath for executable path with error: %s", strerror(errno));
decode_char_buf(path, interpreter_data.exe_path);
for (unsigned i = 0; i < 3; i++) {
char *t = rindex(path, '/');
if (t == NULL) fatal("Failed to determine bundle path.");
>>>>>>> The Apple build is working
*t = '\0';
}
if (strstr(full_exe_path, "/calibre.app/Contents/") != NULL) {
if (strstr(path, "/calibre.app/Contents/") != NULL) {
// We are one of the duplicate executables created to workaround codesign's limitations
for (i = 0; i < 2; i++) {
t = rindex(full_exe_path, '/');
if (t == NULL) return report_error("Failed to resolve bundle path in dummy executable");
for (unsigned i = 0; i < 2; i++) {
char *t = rindex(path, '/');
if (t == NULL) fatal("Failed to resolve bundle path in dummy executable");
*t = '\0';
}
}
char rpath[PATH_MAX+1], exe_path[PATH_MAX+1];
snprintf(exe_path, PATH_MAX+1, "%s/Contents", full_exe_path);
snprintf(rpath, PATH_MAX+1, "%s/Resources", exe_path);
initialize_interpreter(ENV_VARS, ENV_VAR_VALS, PROGRAM, MODULE, FUNCTION, PYVER, IS_GUI,
exe_path, rpath, argc, argv);
site = PyImport_ImportModule("site");
if (site == NULL)
ret = calibre_show_python_error("Failed to import site module", -1);
else {
Py_XINCREF(site);
mainf = PyObject_GetAttrString(site, "main");
if (mainf == NULL || !PyCallable_Check(mainf))
ret = calibre_show_python_error("site module has no main function", -1);
else {
Py_XINCREF(mainf);
res = PyObject_CallObject(mainf, NULL);
if (res == NULL)
ret = calibre_show_python_error("Python function terminated unexpectedly", -1);
else {
}
}
}
PyErr_Clear();
Py_Finalize();
//printf("11111 Returning: %d\r\n", ret);
return ret;
#define cat_literal(func, path, literal) func(path, literal, arraysz(literal) - 1)
cat_literal(strncat, path, "/Contents");
set_env_vars(path);
decode_char_buf(path, interpreter_data.bundle_resource_path);
#define set_path(which, fmt, ...) swprintf(interpreter_data.which, arraysz(interpreter_data.which), fmt, interpreter_data.bundle_resource_path, __VA_ARGS__)
set_path(python_home_path, L"%ls/Resources/Python", NULL);
set_path(frameworks_path, L"%ls/Frameworks", NULL);
set_path(python_lib_path, L"%ls/Resources/Python/lib/python%d.%d", PY_VERSION_MAJOR, PY_VERSION_MINOR);
set_path(extensions_path, L"%ls/Frameworks/plugins", NULL);
set_path(resources_path, L"%ls/Resources/resources", NULL);
set_path(executables_path, L"%ls/MacOS", NULL);
#undef set_path
cat_literal(wcsncat, interpreter_data.bundle_resource_path, L"/Resources");
#undef cat_literal
}
EXPORT
void
run(const wchar_t *program, const wchar_t *module, const wchar_t *function, bool gui_app, int argc, char * const *argv) {
interpreter_data.argc = argc;
interpreter_data.argv = argv;
interpreter_data.basename = program; interpreter_data.module = module; interpreter_data.function = function;
pre_initialize_interpreter(gui_app);
get_paths();
run_interpreter();
}

View File

@ -1,5 +1,5 @@
#pragma once
#include <wchar.h>
#include <stdbool.h>
int run(const char **ENV_VARS, const char **ENV_VAR_VALS, char *PROGRAM,
const char *MODULE, const char *FUNCTION, const char *PYVER, int IS_GUI,
int argc, char *const *argv, const char **envp, char *full_exe_path);
void run(const wchar_t *program, const wchar_t *module, const wchar_t *function, bool is_gui, int argc, char * const *argv);

View File

@ -111,12 +111,15 @@ typedef struct {
size_t sys_paths_count;
wchar_t exe_path[PATH_MAX], python_home_path[PATH_MAX], python_lib_path[PATH_MAX];
wchar_t extensions_path[PATH_MAX], resources_path[PATH_MAX], executables_path[PATH_MAX];
#ifdef __APPLE__
wchar_t bundle_resource_path[PATH_MAX], frameworks_path[PATH_MAX];
#endif
const wchar_t *basename, *module, *function;
int argc;
char * const *argv;
} InterpreterData;
static InterpreterData interpreter_data = {0};
static InterpreterData interpreter_data = {{0}};
static wchar_t*
add_sys_path() {
@ -133,7 +136,12 @@ static void
add_sys_paths() {
swprintf(add_sys_path(), PATH_MAX, L"%ls", interpreter_data.python_lib_path);
swprintf(add_sys_path(), PATH_MAX, L"%ls/lib-dynload", interpreter_data.python_lib_path);
#ifdef __APPLE__
swprintf(add_sys_path(), PATH_MAX, L"%ls/Python/site-packages", interpreter_data.bundle_resource_path);
#else
swprintf(add_sys_path(), PATH_MAX, L"%ls/site-packages", interpreter_data.python_lib_path);
#endif
}
#endif
@ -176,6 +184,9 @@ run_interpreter() {
set_sys_string("resources_location", interpreter_data.resources_path);
set_sys_string("executables_location", interpreter_data.executables_path);
#ifdef __APPLE__
set_sys_string("resourcepath", interpreter_data.bundle_resource_path);
set_sys_string("frameworks_dir", interpreter_data.frameworks_path);
set_sys_bool("new_app_bundle", true);
#elif _WIN32
#else
set_sys_string("frozen_path", interpreter_data.executables_path);

View File

@ -58,7 +58,7 @@ class Worker(object):
return os.path.join(os.path.dirname(sys.executable),
e+'.exe' if isfrozen else 'Scripts\\%s.exe'%e)
if isosx:
return os.path.join(sys.binaries_path, e)
return os.path.join(sys.executables_location, e)
if isfrozen:
return os.path.join(sys.executables_location, e)
@ -73,13 +73,13 @@ class Worker(object):
def gui_executable(self):
if isosx and not hasattr(sys, 'running_from_setup'):
if self.job_name == 'ebook-viewer':
base = os.path.dirname(sys.binaries_path)
base = os.path.dirname(sys.executables_location)
return os.path.join(base, 'ebook-viewer.app/Contents/MacOS/', self.exe_name)
if self.job_name == 'ebook-edit':
base = os.path.dirname(sys.binaries_path)
base = os.path.dirname(sys.executables_location)
return os.path.join(base, 'ebook-viewer.app/Contents/ebook-edit.app/Contents/MacOS/', self.exe_name)
return os.path.join(sys.binaries_path, self.exe_name)
return os.path.join(sys.executables_location, self.exe_name)
return self.executable