mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
The Apple build is working
This commit is contained in:
parent
066ff4127b
commit
411da596b4
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user