Get the new bypy based freezing process working with linux builds
This commit is contained in:
parent
4cf73204a2
commit
9114bda24c
@ -7,12 +7,13 @@ import re
|
|||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
|
||||||
from bypy.constants import (
|
from bypy.constants import (
|
||||||
LIBDIR, PREFIX, PYTHON, SRC as KITTY_DIR, ismacos, worker_env
|
LIBDIR, PREFIX, PYTHON, SRC as KITTY_DIR, ismacos, worker_env
|
||||||
)
|
)
|
||||||
from bypy.utils import run_shell
|
from bypy.utils import run_shell, walk
|
||||||
|
|
||||||
|
|
||||||
def read_src_file(name):
|
def read_src_file(name):
|
||||||
@ -43,8 +44,34 @@ def run(*args, **extra_env):
|
|||||||
return subprocess.call(list(args), env=env, cwd=cwd)
|
return subprocess.call(list(args), env=env, cwd=cwd)
|
||||||
|
|
||||||
|
|
||||||
|
def build_frozen_launcher(extra_include_dirs):
|
||||||
|
inc_dirs = [f'--extra-include-dirs={x}' for x in extra_include_dirs]
|
||||||
|
cmd = [PYTHON, 'setup.py', '--prefix', build_frozen_launcher.prefix] + inc_dirs + ['build-frozen-launcher']
|
||||||
|
if run(*cmd, cwd=build_frozen_launcher.writeable_src_dir) != 0:
|
||||||
|
print('Building of frozen kitty launcher failed', file=sys.stderr)
|
||||||
|
os.chdir(KITTY_DIR)
|
||||||
|
run_shell()
|
||||||
|
raise SystemExit('Building of kitty launcher failed')
|
||||||
|
return build_frozen_launcher.writeable_src_dir
|
||||||
|
|
||||||
|
|
||||||
|
def check_build(kitty_exe):
|
||||||
|
with tempfile.TemporaryDirectory() as tdir:
|
||||||
|
env = {
|
||||||
|
'KITTY_CONFIG_DIRECTORY': os.path.join(tdir, 'conf'),
|
||||||
|
'KITTY_CACHE_DIRECTORY': os.path.join(tdir, 'cache')
|
||||||
|
}
|
||||||
|
[os.mkdir(x) for x in env.values()]
|
||||||
|
if subprocess.call([kitty_exe, '+runpy', 'from kitty.check_build import main; main()'], env=env) != 0:
|
||||||
|
print('Checking of kitty build failed', file=sys.stderr)
|
||||||
|
os.chdir(os.path.dirname(kitty_exe))
|
||||||
|
run_shell()
|
||||||
|
raise SystemExit('Checking of kitty build failed')
|
||||||
|
|
||||||
|
|
||||||
def build_c_extensions(ext_dir, args):
|
def build_c_extensions(ext_dir, args):
|
||||||
writeable_src_dir = os.path.join(ext_dir, 'src')
|
writeable_src_dir = os.path.join(ext_dir, 'src')
|
||||||
|
build_frozen_launcher.writeable_src_dir = writeable_src_dir
|
||||||
shutil.copytree(
|
shutil.copytree(
|
||||||
KITTY_DIR, writeable_src_dir, symlinks=True,
|
KITTY_DIR, writeable_src_dir, symlinks=True,
|
||||||
ignore=shutil.ignore_patterns('b', 'build', 'dist', '*_commands.json', '*.o'))
|
ignore=shutil.ignore_patterns('b', 'build', 'dist', '*_commands.json', '*.o'))
|
||||||
@ -58,11 +85,19 @@ def build_c_extensions(ext_dir, args):
|
|||||||
run_shell()
|
run_shell()
|
||||||
raise SystemExit('Building of kitty launcher failed')
|
raise SystemExit('Building of kitty launcher failed')
|
||||||
|
|
||||||
|
for x in walk(writeable_src_dir):
|
||||||
|
if x.rpartition('.') in ('o', 'so', 'dylib', 'pyd'):
|
||||||
|
os.unlink(x)
|
||||||
cmd = [PYTHON, 'setup.py']
|
cmd = [PYTHON, 'setup.py']
|
||||||
|
if run(*cmd, cwd=writeable_src_dir) != 0:
|
||||||
|
print('Building of kitty failed', file=sys.stderr)
|
||||||
|
os.chdir(KITTY_DIR)
|
||||||
|
run_shell()
|
||||||
|
raise SystemExit('Building of kitty package failed')
|
||||||
bundle = 'macos-freeze' if ismacos else 'linux-freeze'
|
bundle = 'macos-freeze' if ismacos else 'linux-freeze'
|
||||||
cmd.append(bundle)
|
cmd.append(bundle)
|
||||||
dest = kitty_constants['appname'] + ('.app' if ismacos else '')
|
dest = kitty_constants['appname'] + ('.app' if ismacos else '')
|
||||||
dest = os.path.join(ext_dir, dest)
|
dest = build_frozen_launcher.prefix = os.path.join(ext_dir, dest)
|
||||||
cmd += ['--prefix', dest]
|
cmd += ['--prefix', dest]
|
||||||
if run(*cmd, cwd=writeable_src_dir) != 0:
|
if run(*cmd, cwd=writeable_src_dir) != 0:
|
||||||
print('Building of kitty package failed', file=sys.stderr)
|
print('Building of kitty package failed', file=sys.stderr)
|
||||||
|
|||||||
@ -14,12 +14,14 @@ import time
|
|||||||
from bypy.constants import (
|
from bypy.constants import (
|
||||||
OUTPUT_DIR, PREFIX, is64bit, python_major_minor_version
|
OUTPUT_DIR, PREFIX, is64bit, python_major_minor_version
|
||||||
)
|
)
|
||||||
from bypy.utils import get_dll_path, py_compile, walk
|
from bypy.freeze import (
|
||||||
|
extract_extension_modules, freeze_python, path_to_freeze_dir
|
||||||
|
)
|
||||||
|
from bypy.utils import get_dll_path, mkdtemp, py_compile, walk
|
||||||
|
|
||||||
j = os.path.join
|
j = os.path.join
|
||||||
self_dir = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
arch = 'x86_64' if is64bit else 'i686'
|
arch = 'x86_64' if is64bit else 'i686'
|
||||||
|
self_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
py_ver = '.'.join(map(str, python_major_minor_version()))
|
py_ver = '.'.join(map(str, python_major_minor_version()))
|
||||||
iv = globals()['init_env']
|
iv = globals()['init_env']
|
||||||
kitty_constants = iv['kitty_constants']
|
kitty_constants = iv['kitty_constants']
|
||||||
@ -27,12 +29,8 @@ kitty_constants = iv['kitty_constants']
|
|||||||
|
|
||||||
def binary_includes():
|
def binary_includes():
|
||||||
return tuple(map(get_dll_path, (
|
return tuple(map(get_dll_path, (
|
||||||
'expat', 'sqlite3', 'ffi', 'z', 'lzma', 'png16', 'lcms2',
|
'expat', 'sqlite3', 'ffi', 'z', 'lzma', 'png16', 'lcms2', 'crypt',
|
||||||
|
'iconv', 'pcre', 'graphite2', 'glib-2.0', 'freetype',
|
||||||
# dont include freetype because fontconfig is closely coupled to it
|
|
||||||
# and also distros often patch freetype
|
|
||||||
# 'iconv.so.2', 'pcre.so.1', 'graphite2.so.3', 'glib-2.0.so.0', 'freetype.so.6',
|
|
||||||
|
|
||||||
'harfbuzz', 'xkbcommon', 'xkbcommon-x11',
|
'harfbuzz', 'xkbcommon', 'xkbcommon-x11',
|
||||||
'ncursesw', 'readline',
|
'ncursesw', 'readline',
|
||||||
))) + (
|
))) + (
|
||||||
@ -49,6 +47,7 @@ class Env:
|
|||||||
self.py_dir = j(self.lib_dir, 'python' + py_ver)
|
self.py_dir = j(self.lib_dir, 'python' + py_ver)
|
||||||
os.makedirs(self.py_dir)
|
os.makedirs(self.py_dir)
|
||||||
self.bin_dir = j(self.base, 'bin')
|
self.bin_dir = j(self.base, 'bin')
|
||||||
|
self.obj_dir = mkdtemp('launchers-')
|
||||||
|
|
||||||
|
|
||||||
def ignore_in_lib(base, items, ignored_dirs=None):
|
def ignore_in_lib(base, items, ignored_dirs=None):
|
||||||
@ -106,10 +105,30 @@ def copy_python(env):
|
|||||||
shutil.copy2(y, env.py_dir)
|
shutil.copy2(y, env.py_dir)
|
||||||
|
|
||||||
srcdir = j(srcdir, 'site-packages')
|
srcdir = j(srcdir, 'site-packages')
|
||||||
dest = j(env.py_dir, 'site-packages')
|
site_packages_dir = j(env.py_dir, 'site-packages')
|
||||||
import_site_packages(srcdir, dest)
|
import_site_packages(srcdir, site_packages_dir)
|
||||||
|
pdir = os.path.join(env.lib_dir, 'kitty-extensions')
|
||||||
|
os.makedirs(pdir, exist_ok=True)
|
||||||
|
kitty_dir = os.path.join(env.base, 'lib', 'kitty')
|
||||||
|
for x in ('kitty', 'kittens'):
|
||||||
|
dest = os.path.join(env.py_dir, x)
|
||||||
|
os.rename(os.path.join(kitty_dir, x), dest)
|
||||||
|
if x == 'kitty':
|
||||||
|
shutil.rmtree(os.path.join(dest, 'launcher'))
|
||||||
|
os.rename(os.path.join(kitty_dir, '__main__.py'), os.path.join(env.py_dir, 'kitty_main.py'))
|
||||||
|
shutil.rmtree(os.path.join(kitty_dir, '__pycache__'))
|
||||||
|
print('Extracting extension modules from', env.py_dir, 'to', pdir)
|
||||||
|
ext_map = extract_extension_modules(env.py_dir, pdir)
|
||||||
|
shutil.copy(os.path.join(os.path.dirname(self_dir), 'site.py'), os.path.join(env.py_dir, 'site.py'))
|
||||||
|
for q in walk(os.path.join(env.py_dir, 'kitty')):
|
||||||
|
if os.path.splitext(q)[1] not in ('.py', '.glsl'):
|
||||||
|
os.unlink(q)
|
||||||
py_compile(env.py_dir)
|
py_compile(env.py_dir)
|
||||||
py_compile(os.path.join(env.base, 'lib', 'kitty'))
|
freeze_python(env.py_dir, pdir, env.obj_dir, ext_map, develop_mode_env_var='KITTY_DEVELOP_FROM')
|
||||||
|
|
||||||
|
|
||||||
|
def build_launcher(env):
|
||||||
|
iv['build_frozen_launcher']([path_to_freeze_dir(), env.obj_dir])
|
||||||
|
|
||||||
|
|
||||||
def is_elf(path):
|
def is_elf(path):
|
||||||
@ -204,10 +223,12 @@ def main():
|
|||||||
env = Env(os.path.join(ext_dir, kitty_constants['appname']))
|
env = Env(os.path.join(ext_dir, kitty_constants['appname']))
|
||||||
copy_libs(env)
|
copy_libs(env)
|
||||||
copy_python(env)
|
copy_python(env)
|
||||||
|
build_launcher(env)
|
||||||
files = find_binaries(env)
|
files = find_binaries(env)
|
||||||
fix_permissions(files)
|
fix_permissions(files)
|
||||||
if not args.dont_strip:
|
if not args.dont_strip:
|
||||||
strip_binaries(files)
|
strip_binaries(files)
|
||||||
|
iv['check_build'](os.path.join(env.base, 'bin', 'kitty'))
|
||||||
create_tarfile(env, args.compression_level)
|
create_tarfile(env, args.compression_level)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
31
bypy/site.py
Normal file
31
bypy/site.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import builtins
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import _sitebuiltins
|
||||||
|
|
||||||
|
|
||||||
|
def set_quit():
|
||||||
|
eof = 'Ctrl-D (i.e. EOF)'
|
||||||
|
builtins.quit = _sitebuiltins.Quitter('quit', eof)
|
||||||
|
builtins.exit = _sitebuiltins.Quitter('exit', eof)
|
||||||
|
|
||||||
|
|
||||||
|
def set_helper():
|
||||||
|
builtins.help = _sitebuiltins._Helper()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
sys.argv[0] = sys.calibre_basename
|
||||||
|
set_helper()
|
||||||
|
set_quit()
|
||||||
|
mod = __import__(sys.calibre_module, fromlist=[1])
|
||||||
|
func = getattr(mod, sys.calibre_function)
|
||||||
|
return func()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@ -110,7 +110,6 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
"name": "xz",
|
"name": "xz",
|
||||||
"os": "macos,linux",
|
|
||||||
"unix": {
|
"unix": {
|
||||||
"filename": "xz-5.2.5.tar.gz",
|
"filename": "xz-5.2.5.tar.gz",
|
||||||
"hash": "sha256:f6f4910fd033078738bd82bfba4f49219d03b17eb0794eb91efbae419f4aba10",
|
"hash": "sha256:f6f4910fd033078738bd82bfba4f49219d03b17eb0794eb91efbae419f4aba10",
|
||||||
@ -118,6 +117,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "xcrypt",
|
||||||
|
"unix": {
|
||||||
|
"filename": "xcrypt-4.4.17.tar.gz",
|
||||||
|
"hash": "sha256:7665168d0409574a03f7b484682e68334764c29c21ca5df438955a381384ca07",
|
||||||
|
"urls": ["https://github.com/besser82/libxcrypt/archive/v4.4.17.tar.gz"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"unix": {
|
"unix": {
|
||||||
|
|||||||
52
kitty/check_build.py
Normal file
52
kitty/check_build.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
class TestBuild(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_exe(self) -> None:
|
||||||
|
from kitty.constants import kitty_exe
|
||||||
|
exe = kitty_exe()
|
||||||
|
self.assertTrue(os.access(exe, os.X_OK))
|
||||||
|
self.assertTrue(os.path.isfile(exe))
|
||||||
|
self.assertIn('kitty', os.path.basename(exe))
|
||||||
|
|
||||||
|
def test_loading_extensions(self) -> None:
|
||||||
|
import kitty.fast_data_types as fdt
|
||||||
|
from kittens.unicode_input import unicode_names
|
||||||
|
from kittens.choose import subseq_matcher
|
||||||
|
from kittens.diff import diff_speedup
|
||||||
|
del fdt, unicode_names, subseq_matcher, diff_speedup
|
||||||
|
|
||||||
|
def test_loading_shaders(self) -> None:
|
||||||
|
from kitty.utils import load_shaders
|
||||||
|
for name in 'cell border bgimage tint blit graphics'.split():
|
||||||
|
load_shaders(name)
|
||||||
|
|
||||||
|
def test_glfw_modules(self) -> None:
|
||||||
|
from kitty.constants import is_macos, glfw_path
|
||||||
|
modules = ('cocoa',) if is_macos else ('x11', 'wayland')
|
||||||
|
for name in modules:
|
||||||
|
path = glfw_path(name)
|
||||||
|
self.assertTrue(os.path.isfile(path))
|
||||||
|
self.assertTrue(os.access(path, os.X_OK))
|
||||||
|
|
||||||
|
def test_all_kitten_names(self) -> None:
|
||||||
|
from kittens.runner import all_kitten_names
|
||||||
|
names = all_kitten_names()
|
||||||
|
self.assertIn('diff', names)
|
||||||
|
self.assertIn('hints', names)
|
||||||
|
self.assertGreater(len(names), 8)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
tests = unittest.defaultTestLoader.loadTestsFromTestCase(TestBuild)
|
||||||
|
r = unittest.TextTestRunner(verbosity=4)
|
||||||
|
result = r.run(tests)
|
||||||
|
if result.errors or result.failures:
|
||||||
|
raise SystemExit(1)
|
||||||
@ -257,7 +257,7 @@ def load_config(
|
|||||||
try:
|
try:
|
||||||
with open(path, encoding='utf-8', errors='replace') as f:
|
with open(path, encoding='utf-8', errors='replace') as f:
|
||||||
vals = parse_config(f)
|
vals = parse_config(f)
|
||||||
except FileNotFoundError:
|
except (FileNotFoundError, PermissionError):
|
||||||
continue
|
continue
|
||||||
ans = merge_configs(ans, vals)
|
ans = merge_configs(ans, vals)
|
||||||
if overrides is not None:
|
if overrides is not None:
|
||||||
|
|||||||
@ -24,10 +24,12 @@ version: Version = Version(0, 19, 3)
|
|||||||
str_version: str = '.'.join(map(str, version))
|
str_version: str = '.'.join(map(str, version))
|
||||||
_plat = sys.platform.lower()
|
_plat = sys.platform.lower()
|
||||||
is_macos: bool = 'darwin' in _plat
|
is_macos: bool = 'darwin' in _plat
|
||||||
if hasattr(sys, 'kitty_base_dir'):
|
if getattr(sys, 'frozen', False):
|
||||||
kitty_base_dir: str = getattr(sys, 'kitty_base_dir')
|
extensions_dir: str = getattr(sys, 'kitty_extensions_dir')
|
||||||
|
kitty_base_dir = os.path.join(os.path.dirname(extensions_dir), 'kitty')
|
||||||
else:
|
else:
|
||||||
kitty_base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
kitty_base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
extensions_dir = os.path.join(kitty_base_dir, 'kitty')
|
||||||
|
|
||||||
|
|
||||||
@run_once
|
@run_once
|
||||||
@ -128,7 +130,8 @@ except KeyError:
|
|||||||
|
|
||||||
|
|
||||||
def glfw_path(module: str) -> str:
|
def glfw_path(module: str) -> str:
|
||||||
return os.path.join(kitty_base_dir, 'kitty', 'glfw-{}.so'.format(module))
|
prefix = 'kitty.' if getattr(sys, 'frozen', False) else ''
|
||||||
|
return os.path.join(extensions_dir, f'{prefix}glfw-{module}.so')
|
||||||
|
|
||||||
|
|
||||||
def detect_if_wayland_ok() -> bool:
|
def detect_if_wayland_ok() -> bool:
|
||||||
|
|||||||
132
launcher.c
132
launcher.c
@ -21,8 +21,8 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define MAX_ARGC 1024
|
|
||||||
#ifndef KITTY_LIB_PATH
|
#ifndef KITTY_LIB_PATH
|
||||||
#define KITTY_LIB_PATH "../.."
|
#define KITTY_LIB_PATH "../.."
|
||||||
#endif
|
#endif
|
||||||
@ -41,78 +41,83 @@ safe_realpath(const char* src, char *buf, size_t buf_sz) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void
|
static inline bool
|
||||||
set_xoptions(const wchar_t *exe_dir, const char *lc_ctype, bool from_source) {
|
set_xoptions(const char *exe_dir_c, const char *lc_ctype, bool from_source) {
|
||||||
|
wchar_t *exe_dir = Py_DecodeLocale(exe_dir_c, NULL);
|
||||||
|
if (exe_dir == NULL) { fprintf(stderr, "Fatal error: cannot decode exe_dir: %s\n", exe_dir_c); return false; }
|
||||||
wchar_t buf[PATH_MAX+1] = {0};
|
wchar_t buf[PATH_MAX+1] = {0};
|
||||||
swprintf(buf, PATH_MAX, L"bundle_exe_dir=%ls", exe_dir);
|
swprintf(buf, PATH_MAX, L"bundle_exe_dir=%ls", exe_dir);
|
||||||
PySys_AddXOption(buf);
|
PySys_AddXOption(buf);
|
||||||
|
PyMem_RawFree(exe_dir);
|
||||||
if (from_source) PySys_AddXOption(L"kitty_from_source=1");
|
if (from_source) PySys_AddXOption(L"kitty_from_source=1");
|
||||||
if (lc_ctype) {
|
if (lc_ctype) {
|
||||||
swprintf(buf, PATH_MAX, L"lc_ctype_before_python=%s", lc_ctype);
|
swprintf(buf, PATH_MAX, L"lc_ctype_before_python=%s", lc_ctype);
|
||||||
PySys_AddXOption(buf);
|
PySys_AddXOption(buf);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FOR_BUNDLE
|
typedef struct {
|
||||||
static int
|
const char *exe, *exe_dir, *lc_ctype, *lib_dir;
|
||||||
run_embedded(const char* exe_dir_, const char *libpath, int argc, wchar_t **argv, const char *lc_ctype) {
|
char **argv;
|
||||||
int num;
|
int argc;
|
||||||
Py_NoSiteFlag = 1;
|
} RunData;
|
||||||
Py_FrozenFlag = 1;
|
|
||||||
Py_IgnoreEnvironmentFlag = 1;
|
|
||||||
Py_DontWriteBytecodeFlag = 1;
|
|
||||||
Py_NoUserSiteDirectory = 1;
|
|
||||||
Py_IsolatedFlag = 1;
|
|
||||||
Py_SetProgramName(L"kitty");
|
|
||||||
|
|
||||||
int ret = 1;
|
#ifdef FOR_BUNDLE
|
||||||
wchar_t *exe_dir = Py_DecodeLocale(exe_dir_, NULL);
|
#include <bypy-freeze.h>
|
||||||
if (exe_dir == NULL) { fprintf(stderr, "Fatal error: cannot decode exe_dir\n"); return 1; }
|
|
||||||
wchar_t stdlib[PATH_MAX+1] = {0};
|
static int
|
||||||
|
run_embedded(const RunData run_data) {
|
||||||
|
bypy_pre_initialize_interpreter(false);
|
||||||
|
wchar_t extensions_dir[PATH_MAX+1] = {0}, python_home[PATH_MAX+1] = {0};
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
const char *python_relpath = "../Resources/Python/lib";
|
const char *python_relpath = "../Resources/Python/lib";
|
||||||
#else
|
#else
|
||||||
const char *python_relpath = "../" KITTY_LIB_DIR_NAME;
|
const char *python_relpath = "../" KITTY_LIB_DIR_NAME;
|
||||||
#endif
|
#endif
|
||||||
num = swprintf(stdlib, PATH_MAX, L"%ls/%s/python%s:%ls/%s/python%s/lib-dynload:%ls/%s/python%s/site-packages",
|
int num = swprintf(extensions_dir, PATH_MAX, L"%s/%s/kitty-extensions", run_data.exe_dir, python_relpath);
|
||||||
exe_dir, python_relpath, PYVER,
|
if (num < 0 || num >= PATH_MAX) { fprintf(stderr, "Failed to create path to extensions_dir: %s/%s\n", run_data.exe_dir, python_relpath); return 1; }
|
||||||
exe_dir, python_relpath, PYVER,
|
num = swprintf(python_home, PATH_MAX, L"%s/%s/python%s", run_data.exe_dir, python_relpath, PYVER);
|
||||||
exe_dir, python_relpath, PYVER
|
if (num < 0 || num >= PATH_MAX) { fprintf(stderr, "Failed to create path to python home: %s/%s\n", run_data.exe_dir, python_relpath); return 1; }
|
||||||
);
|
bypy_initialize_interpreter(L"kitty", python_home, L"kitty_main", extensions_dir, run_data.argc, run_data.argv);
|
||||||
if (num < 0 || num >= PATH_MAX) { fprintf(stderr, "Failed to create path to python stdlib\n"); return 1; }
|
if (!set_xoptions(run_data.exe_dir, run_data.lc_ctype, false)) return 1;
|
||||||
Py_SetPath(stdlib);
|
set_sys_bool("frozen", true);
|
||||||
Py_Initialize();
|
set_sys_string("kitty_extensions_dir", extensions_dir);
|
||||||
set_xoptions(exe_dir, lc_ctype, false);
|
return bypy_run_interpreter();
|
||||||
PyMem_RawFree(exe_dir);
|
|
||||||
PySys_SetArgvEx(argc - 1, argv + 1, 0);
|
|
||||||
PySys_SetObject("frozen", Py_True);
|
|
||||||
PyObject *kitty = PyUnicode_FromString(libpath);
|
|
||||||
if (kitty == NULL) { fprintf(stderr, "Failed to allocate python kitty lib object\n"); goto end; }
|
|
||||||
PyObject *runpy = PyImport_ImportModule("runpy");
|
|
||||||
if (runpy == NULL) { PyErr_Print(); fprintf(stderr, "Unable to import runpy\n"); Py_CLEAR(kitty); goto end; }
|
|
||||||
PyObject *run_name = PyUnicode_FromString("__main__");
|
|
||||||
if (run_name == NULL) { fprintf(stderr, "Failed to allocate run_name\n"); goto end; }
|
|
||||||
PyObject *res = PyObject_CallMethod(runpy, "run_path", "OOO", kitty, Py_None, run_name);
|
|
||||||
Py_CLEAR(runpy); Py_CLEAR(kitty); Py_CLEAR(run_name);
|
|
||||||
if (res == NULL) PyErr_Print();
|
|
||||||
else { ret = 0; Py_CLEAR(res); }
|
|
||||||
end:
|
|
||||||
if (Py_FinalizeEx() < 0) ret = 120;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static int
|
static int
|
||||||
run_embedded(const char* exe_dir_, const char *libpath, int argc, wchar_t **argv, const char *lc_ctype) {
|
free_argv(wchar_t **argv) {
|
||||||
(void)libpath;
|
wchar_t **p = argv;
|
||||||
wchar_t *exe_dir = Py_DecodeLocale(exe_dir_, NULL);
|
while (*p) { PyMem_RawFree(*p); p++; }
|
||||||
if (exe_dir == NULL) { fprintf(stderr, "Fatal error: cannot decode exe_dir: %s\n", exe_dir_); return 1; }
|
free(argv);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
run_embedded(const RunData run_data) {
|
||||||
bool from_source = false;
|
bool from_source = false;
|
||||||
#ifdef FROM_SOURCE
|
#ifdef FROM_SOURCE
|
||||||
from_source = true;
|
from_source = true;
|
||||||
#endif
|
#endif
|
||||||
set_xoptions(exe_dir, lc_ctype, from_source);
|
if (!set_xoptions(run_data.exe_dir, run_data.lc_ctype, from_source)) return 1;
|
||||||
PyMem_RawFree(exe_dir);
|
int argc = run_data.argc + 1;
|
||||||
return Py_Main(argc, argv);
|
wchar_t **argv = calloc(argc, sizeof(wchar_t*));
|
||||||
|
if (!argv) { fprintf(stderr, "Out of memory creating argv\n"); return 1; }
|
||||||
|
argv[0] = Py_DecodeLocale(run_data.exe, NULL);
|
||||||
|
if (!argv[0]) { fprintf(stderr, "Failed to decode path to exe\n"); return free_argv(argv); }
|
||||||
|
argv[1] = Py_DecodeLocale(run_data.lib_dir, NULL);
|
||||||
|
if (!argv[1]) { fprintf(stderr, "Failed to decode path to lib_dir\n"); return free_argv(argv); }
|
||||||
|
for (int i=1; i < run_data.argc; i++) {
|
||||||
|
argv[i+1] = Py_DecodeLocale(run_data.argv[i], NULL);
|
||||||
|
if (!argv[i+1]) { fprintf(stderr, "Failed to decode the command line argument: %s\n", run_data.argv[i]); return free_argv(argv); }
|
||||||
|
}
|
||||||
|
int ret = Py_Main(argc, argv);
|
||||||
|
// we cannot free argv properly as Py_Main odifies it
|
||||||
|
free(argv);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -180,41 +185,26 @@ read_exe_path(char *exe, size_t buf_sz) {
|
|||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
char exe[PATH_MAX+1] = {0};
|
char exe[PATH_MAX+1] = {0};
|
||||||
|
char exe_dir_buf[PATH_MAX+1] = {0};
|
||||||
const char *lc_ctype = NULL;
|
const char *lc_ctype = NULL;
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
lc_ctype = getenv("LC_CTYPE");
|
lc_ctype = getenv("LC_CTYPE");
|
||||||
#endif
|
#endif
|
||||||
if (!read_exe_path(exe, sizeof(exe))) return 1;
|
if (!read_exe_path(exe, sizeof(exe))) return 1;
|
||||||
|
strncpy(exe_dir_buf, exe, sizeof(exe_dir_buf));
|
||||||
char *exe_dir = dirname(exe);
|
char *exe_dir = dirname(exe_dir_buf);
|
||||||
int num, num_args, i, ret=0;
|
int num, ret=0;
|
||||||
char lib[PATH_MAX+1] = {0};
|
char lib[PATH_MAX+1] = {0};
|
||||||
char *final_argv[MAX_ARGC + 1] = {0};
|
|
||||||
wchar_t *argvw[MAX_ARGC + 1] = {0};
|
|
||||||
num = snprintf(lib, PATH_MAX, "%s/%s", exe_dir, KITTY_LIB_PATH);
|
num = snprintf(lib, PATH_MAX, "%s/%s", exe_dir, KITTY_LIB_PATH);
|
||||||
|
|
||||||
if (num < 0 || num >= PATH_MAX) { fprintf(stderr, "Failed to create path to kitty lib\n"); return 1; }
|
if (num < 0 || num >= PATH_MAX) { fprintf(stderr, "Failed to create path to kitty lib\n"); return 1; }
|
||||||
final_argv[0] = exe;
|
|
||||||
final_argv[1] = lib;
|
|
||||||
for (i = 1, num_args=2; i < argc && i + 1 <= MAX_ARGC; i++) {
|
|
||||||
final_argv[i+1] = argv[i];
|
|
||||||
num_args++;
|
|
||||||
}
|
|
||||||
#if PY_VERSION_HEX >= 0x03070000
|
#if PY_VERSION_HEX >= 0x03070000
|
||||||
// Always use UTF-8 mode, see https://github.com/kovidgoyal/kitty/issues/924
|
// Always use UTF-8 mode, see https://github.com/kovidgoyal/kitty/issues/924
|
||||||
Py_UTF8Mode = 1;
|
Py_UTF8Mode = 1;
|
||||||
#endif
|
#endif
|
||||||
for (i = 0; i < num_args; i++) {
|
|
||||||
argvw[i] = Py_DecodeLocale(final_argv[i], NULL);
|
|
||||||
if (argvw[i] == NULL) {
|
|
||||||
fprintf(stderr, "Fatal error: cannot decode argv[%d]\n", i);
|
|
||||||
ret = 1; goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (lc_ctype) lc_ctype = strdup(lc_ctype);
|
if (lc_ctype) lc_ctype = strdup(lc_ctype);
|
||||||
ret = run_embedded(exe_dir, lib, num_args, argvw, lc_ctype);
|
RunData run_data = {.exe = exe, .exe_dir = exe_dir, .lib_dir = lib, .argc = argc, .argv = argv, .lc_ctype = lc_ctype};
|
||||||
|
ret = run_embedded(run_data);
|
||||||
if (lc_ctype) free((void*)lc_ctype);
|
if (lc_ctype) free((void*)lc_ctype);
|
||||||
end:
|
|
||||||
for (i = 0; i < num_args; i++) { if(argvw[i]) PyMem_RawFree(argvw[i]); }
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
26
setup.py
26
setup.py
@ -69,6 +69,7 @@ class Options(argparse.Namespace):
|
|||||||
for_freeze: bool = False
|
for_freeze: bool = False
|
||||||
libdir_name: str = 'lib'
|
libdir_name: str = 'lib'
|
||||||
extra_logging: List[str] = []
|
extra_logging: List[str] = []
|
||||||
|
extra_include_dirs: List[str] = []
|
||||||
link_time_optimization: bool = 'KITTY_NO_LTO' not in os.environ
|
link_time_optimization: bool = 'KITTY_NO_LTO' not in os.environ
|
||||||
update_check_interval: float = 24
|
update_check_interval: float = 24
|
||||||
egl_library: Optional[str] = os.getenv('KITTY_EGL_LIBRARY')
|
egl_library: Optional[str] = os.getenv('KITTY_EGL_LIBRARY')
|
||||||
@ -259,7 +260,8 @@ def init_env(
|
|||||||
egl_library: Optional[str] = None,
|
egl_library: Optional[str] = None,
|
||||||
startup_notification_library: Optional[str] = None,
|
startup_notification_library: Optional[str] = None,
|
||||||
canberra_library: Optional[str] = None,
|
canberra_library: Optional[str] = None,
|
||||||
extra_logging: Iterable[str] = ()
|
extra_logging: Iterable[str] = (),
|
||||||
|
extra_include_dirs: Iterable[str] = (),
|
||||||
) -> Env:
|
) -> Env:
|
||||||
native_optimizations = native_optimizations and not sanitize and not debug
|
native_optimizations = native_optimizations and not sanitize and not debug
|
||||||
if native_optimizations and is_macos and is_arm:
|
if native_optimizations and is_macos and is_arm:
|
||||||
@ -344,6 +346,9 @@ def init_env(
|
|||||||
if desktop_libs != []:
|
if desktop_libs != []:
|
||||||
library_paths['kitty/desktop.c'] = desktop_libs
|
library_paths['kitty/desktop.c'] = desktop_libs
|
||||||
|
|
||||||
|
for path in extra_include_dirs:
|
||||||
|
cflags.append(f'-I{path}')
|
||||||
|
|
||||||
return Env(cc, cppflags, cflags, ldflags, library_paths, ccver=ccver)
|
return Env(cc, cppflags, cflags, ldflags, library_paths, ccver=ccver)
|
||||||
|
|
||||||
|
|
||||||
@ -745,7 +750,7 @@ def init_env_from_args(args: Options, native_optimizations: bool = False) -> Non
|
|||||||
env = init_env(
|
env = init_env(
|
||||||
args.debug, args.sanitize, native_optimizations, args.link_time_optimization, args.profile,
|
args.debug, args.sanitize, native_optimizations, args.link_time_optimization, args.profile,
|
||||||
args.egl_library, args.startup_notification_library, args.canberra_library,
|
args.egl_library, args.startup_notification_library, args.canberra_library,
|
||||||
args.extra_logging
|
args.extra_logging, args.extra_include_dirs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -797,6 +802,8 @@ def build_launcher(args: Options, launcher_dir: str = '.', bundle_type: str = 's
|
|||||||
cppflags += shlex.split(os.environ.get('CPPFLAGS', ''))
|
cppflags += shlex.split(os.environ.get('CPPFLAGS', ''))
|
||||||
cflags += shlex.split(os.environ.get('CFLAGS', ''))
|
cflags += shlex.split(os.environ.get('CFLAGS', ''))
|
||||||
ldflags = shlex.split(os.environ.get('LDFLAGS', ''))
|
ldflags = shlex.split(os.environ.get('LDFLAGS', ''))
|
||||||
|
for path in args.extra_include_dirs:
|
||||||
|
cflags.append(f'-I{path}')
|
||||||
if bundle_type == 'linux-freeze':
|
if bundle_type == 'linux-freeze':
|
||||||
ldflags += ['-Wl,-rpath,$ORIGIN/../lib']
|
ldflags += ['-Wl,-rpath,$ORIGIN/../lib']
|
||||||
os.makedirs(launcher_dir, exist_ok=True)
|
os.makedirs(launcher_dir, exist_ok=True)
|
||||||
@ -1026,7 +1033,8 @@ def package(args: Options, bundle_type: str) -> None:
|
|||||||
shutil.rmtree(libdir)
|
shutil.rmtree(libdir)
|
||||||
launcher_dir = os.path.join(ddir, 'bin')
|
launcher_dir = os.path.join(ddir, 'bin')
|
||||||
safe_makedirs(launcher_dir)
|
safe_makedirs(launcher_dir)
|
||||||
build_launcher(args, launcher_dir, bundle_type)
|
if not bundle_type.endswith('-freeze'): # freeze launcher is built separately
|
||||||
|
build_launcher(args, launcher_dir, bundle_type)
|
||||||
os.makedirs(os.path.join(libdir, 'logo'))
|
os.makedirs(os.path.join(libdir, 'logo'))
|
||||||
build_terminfo = runpy.run_path('build-terminfo', run_name='import_build') # type: ignore
|
build_terminfo = runpy.run_path('build-terminfo', run_name='import_build') # type: ignore
|
||||||
for x in (libdir, os.path.join(ddir, 'share')):
|
for x in (libdir, os.path.join(ddir, 'share')):
|
||||||
@ -1103,7 +1111,7 @@ def option_parser() -> argparse.ArgumentParser: # {{{
|
|||||||
'action',
|
'action',
|
||||||
nargs='?',
|
nargs='?',
|
||||||
default=Options.action,
|
default=Options.action,
|
||||||
choices='build test linux-package kitty.app linux-freeze macos-freeze build-launcher clean export-ci-bundles'.split(),
|
choices='build test linux-package kitty.app linux-freeze macos-freeze build-launcher build-frozen-launcher clean export-ci-bundles'.split(),
|
||||||
help='Action to perform (default is build)'
|
help='Action to perform (default is build)'
|
||||||
)
|
)
|
||||||
p.add_argument(
|
p.add_argument(
|
||||||
@ -1161,6 +1169,12 @@ def option_parser() -> argparse.ArgumentParser: # {{{
|
|||||||
help='Turn on extra logging for debugging in this build. Can be specified multiple times, to turn'
|
help='Turn on extra logging for debugging in this build. Can be specified multiple times, to turn'
|
||||||
' on different types of logging.'
|
' on different types of logging.'
|
||||||
)
|
)
|
||||||
|
p.add_argument(
|
||||||
|
'--extra-include-dirs',
|
||||||
|
action='append',
|
||||||
|
default=Options.extra_include_dirs,
|
||||||
|
help='Extra include directories to use while compiling'
|
||||||
|
)
|
||||||
p.add_argument(
|
p.add_argument(
|
||||||
'--update-check-interval',
|
'--update-check-interval',
|
||||||
type=float,
|
type=float,
|
||||||
@ -1226,6 +1240,10 @@ def main() -> None:
|
|||||||
elif args.action == 'build-launcher':
|
elif args.action == 'build-launcher':
|
||||||
init_env_from_args(args, False)
|
init_env_from_args(args, False)
|
||||||
build_launcher(args, launcher_dir=launcher_dir)
|
build_launcher(args, launcher_dir=launcher_dir)
|
||||||
|
elif args.action == 'build-frozen-launcher':
|
||||||
|
init_env_from_args(args, False)
|
||||||
|
bundle_type = ('macos' if is_macos else 'linux') + '-freeze'
|
||||||
|
build_launcher(args, launcher_dir=os.path.join(args.prefix, 'bin'), bundle_type=bundle_type)
|
||||||
elif args.action == 'linux-package':
|
elif args.action == 'linux-package':
|
||||||
build(args, native_optimizations=False)
|
build(args, native_optimizations=False)
|
||||||
package(args, bundle_type='linux-package')
|
package(args, bundle_type='linux-package')
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user