From 51418b820f12392ebd60d8a1ded4a4ddcef1cf07 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 4 Jul 2026 06:59:54 +0530 Subject: [PATCH] Delay load slangc --- kitty/constants.py | 12 ++++++++++-- kitty/shaders/slang.py | 18 +++++++++--------- kitty_tests/__init__.py | 6 ++++++ kitty_tests/base.py | 3 ++- kitty_tests/check_build.py | 2 +- kitty_tests/main.py | 6 +++--- 6 files changed, 31 insertions(+), 16 deletions(-) diff --git a/kitty/constants.py b/kitty/constants.py index 5ea442bbe..8e331d688 100644 --- a/kitty/constants.py +++ b/kitty/constants.py @@ -35,7 +35,15 @@ kitty_run_data: dict[str, Any] = getattr(sys, 'kitty_run_data', {}) launched_by_launch_services = kitty_run_data.get('launched_by_launch_services', False) is_quick_access_terminal_app = kitty_run_data.get('is_quick_access_terminal_app', False) unserialize_launch_flag = 'kitty-unserialize-data=' -slangc = os.environ.get('SLANGC', 'slangc').split() +_slangc: tuple[str, ...] = () + + +def slangc() -> tuple[str, ...]: + global _slangc + if not _slangc: + from kitty.fast_data_types import Shlex + _slangc = tuple(Shlex(os.environ.get('SLANGC', 'slangc'), False)) + return _slangc if getattr(sys, 'frozen', False): @@ -64,7 +72,7 @@ if getattr(sys, 'frozen', False): return ans kitty_base_dir = get_frozen_base() if rpath := kitty_run_data.get('bundle_exe_dir'): - slangc = [os.path.join(rpath, 'slangc')] + _slangc = (os.path.join(rpath, 'slangc'),) del get_frozen_base, rpath else: kitty_base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) diff --git a/kitty/shaders/slang.py b/kitty/shaders/slang.py index 6a7086b79..71a2938c4 100644 --- a/kitty/shaders/slang.py +++ b/kitty/shaders/slang.py @@ -52,7 +52,7 @@ def self_mtime() -> float: @lru_cache(maxsize=2) def slangc_version() -> str: import subprocess - return subprocess.check_output(slangc + ['-version'], stderr=subprocess.STDOUT).decode().strip() + return subprocess.check_output(list(slangc()) + ['-version'], stderr=subprocess.STDOUT).decode().strip() def is_dir_slangc_version_ok(path: str) -> bool: @@ -332,7 +332,7 @@ class Command(NamedTuple): def commands_to_compile_dir_to_ir(sources: dict[str, SlangFile], src_dir: str, output_dirpath: str) -> Iterator[Command]: - cmdbase = list(slangc) + ['-warnings-as-errors', 'all'] + cmdbase = list(slangc()) + ['-warnings-as-errors', 'all'] for name, sfile in sources.items(): if sfile.should_compile_to_ir: parts = name.split('.') @@ -351,7 +351,7 @@ def commands_to_compile_dir_to_ir(sources: dict[str, SlangFile], src_dir: str, o def iter_entry_point_shaders( sources: dict[str, SlangFile], build_dir: str, dest_dir: str ) -> Iterator[tuple[str, str, str, list[str], SlangFile]]: - cmdbase = list(slangc) + ['-warnings-as-errors', 'all'] + cmdbase = list(slangc()) + ['-warnings-as-errors', 'all'] for name, sfile in sources.items(): if not sfile.entry_points: continue @@ -575,7 +575,7 @@ def create_specialisations(sources: dict[str, SlangFile], build_dir: str) -> Ite else: os.remove(dest) yield Command(needs_build, f'Compiling specialisation |{os.path.basename(dest)}| ...', - list(slangc) + [dest, '-o', dest + '-module']) + list(slangc()) + [dest, '-o', dest + '-module']) def compile_builtin_shaders(build_dir: str, dest_dir: str, parallel_run: ParallelRun) -> None: @@ -604,8 +604,8 @@ def compile_builtin_shaders(build_dir: str, dest_dir: str, parallel_run: Paralle def main() -> None: - if not shutil.which(slangc[0]): - raise SystemExit(f'The shader slang compiler ({slangc[0]}) not in PATH: {os.environ.get("PATH")}') + if not shutil.which(slangc()[0]): + raise SystemExit(f'The shader slang compiler ({slangc()[0]}) not in PATH: {os.environ.get("PATH")}') setup = runpy.run_path('setup.py') Command = setup['Command'] parallel_run = setup['parallel_run'] @@ -622,8 +622,8 @@ def main() -> None: def test_slang_build() -> None: import subprocess - if shutil.which(slangc[0]) is None: - raise AssertionError(f'The shader slang compiler ({slangc[0]}) not in PATH: {os.environ.get("PATH")}') + if shutil.which(slangc()[0]) is None: + raise AssertionError(f'The shader slang compiler ({slangc()[0]}) not in PATH: {os.environ.get("PATH")}') q = os.path.join(shaders_dir, 'graphics.spv') if not os.path.isfile(q): raise AssertionError(f'The compiled graphics shader {q} does not exist') @@ -634,7 +634,7 @@ def test_slang_build() -> None: [shader("vertex")] float4 main(uint vertex_id : SV_VertexID) : SV_Position { return float4(vertex_id, 1, 0, 1); } ''' - cp = subprocess.run(slangc + '-lang slang -entry main -stage vertex -target glsl -o /dev/stdout -- -'.split(), + cp = subprocess.run(list(slangc()) + '-lang slang -entry main -stage vertex -target glsl -o /dev/stdout -- -'.split(), input=src, capture_output=True) if cp.returncode != 0: raise AssertionError(f'Test compile of shader to GLSL failed with returncode: {cp.returncode} and stderr: {cp.stderr.decode()}') diff --git a/kitty_tests/__init__.py b/kitty_tests/__init__.py index e69de29bb..abfbf8d2c 100644 --- a/kitty_tests/__init__.py +++ b/kitty_tests/__init__.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python +# License: GPL v3 Copyright: 2016, Kovid Goyal + +import os + +is_ci = os.environ.get('CI') == 'true' diff --git a/kitty_tests/base.py b/kitty_tests/base.py index 8c2c4a602..61e624260 100644 --- a/kitty_tests/base.py +++ b/kitty_tests/base.py @@ -26,6 +26,8 @@ from kitty.types import MouseEvent from kitty.utils import read_screen_size from kitty.window import da1, decode_cmdline, process_remote_print, process_title_from_child +from . import is_ci + def parse_bytes(screen, data, dump_callback=None): data = memoryview(data) @@ -237,7 +239,6 @@ def filled_history_buf(ynum=5, xnum=5, cursor=Cursor()): return ans -is_ci = os.environ.get('CI') == 'true' max_attempts = 4 if is_ci else 2 sleep_duration = 4 if is_ci else 2 diff --git a/kitty_tests/check_build.py b/kitty_tests/check_build.py index aa9fad904..639671f0e 100644 --- a/kitty_tests/check_build.py +++ b/kitty_tests/check_build.py @@ -28,7 +28,7 @@ class TestBuild(BaseTest): self.assertTrue(os.access(exe, os.X_OK)) self.assertTrue(os.path.isfile(exe)) self.assertIn(str_version, subprocess.check_output([exe, '--version']).decode()) - self.assertTrue(shutil.which(slangc[0]), f'slang compiler: {slangc[0]} not found on PATH: {os.environ["PATH"]}') + self.assertTrue(shutil.which(slangc()[0]), f'slang compiler: {slangc()[0]} not found on PATH: {os.environ["PATH"]}') def test_loading_extensions(self) -> None: import kitty.fast_data_types as fdt diff --git a/kitty_tests/main.py b/kitty_tests/main.py index 2a15524ba..2b14d2eea 100644 --- a/kitty_tests/main.py +++ b/kitty_tests/main.py @@ -20,7 +20,7 @@ from typing import ( Optional, ) -from .base import BaseTest +from . import is_ci def contents(package: str) -> Iterator[str]: @@ -246,7 +246,7 @@ def run_python_tests(args: Any, go_proc: 'Optional[GoProc]' = None) -> None: def run_tests(report_env: bool = False) -> None: - report_env = report_env or BaseTest.is_ci + report_env = report_env or is_ci import argparse parser = argparse.ArgumentParser() @@ -304,7 +304,7 @@ def env_for_python_tests(report_env: bool = False) -> Iterator[None]: path = os.pathsep.join(x for x in paths if not x.startswith(current_home)) launcher_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'kitty', 'launcher') path = f'{launcher_dir}{os.pathsep}{path}' - print('Running under CI:', BaseTest.is_ci) + print('Running under CI:', is_ci) if report_env: print('Using PATH in test environment:', path) from kitty.fast_data_types import has_avx2, has_sse4_2