"""Portable process setup and classification for the native compiler driver. MinGW maps different CreateProcess failures to ENOENT. That text does not prove the compiler/subprogram is missing; never treat a C diagnostic as a launch retry. """ from __future__ import annotations import os from pathlib import Path import re import shutil IS_WINDOWS = os.name == 'nt' LAUNCH_RETRY_DELAYS = (0.05, 0.1, 0.2, 0.35, 0.5) def command_environment(executable: str) -> dict[str, str] | None: if not IS_WINDOWS: return None # Preserve the Linux toolchain and environment unchanged. env = os.environ.copy() path_key = next((key for key in env if key.upper() == 'PATH'), 'PATH') directory = str(Path(shutil.which(executable) or executable).resolve().parent) env[path_key] = directory + os.pathsep + env.get(path_key, '') return env def is_driver_launch_failure(stderr: str) -> bool: # GCC 8 emits "gcc.exe: error: CreateProcess: ..."; other releases add # "cannot execute 'cc1':". Anchor the driver diagnostic, not source text. return IS_WINDOWS and bool(re.search( r'(?im)^(?:[^\r\n]*[/\\])?[\w.+-]*gcc(?:\.exe)?: (?:fatal )?error: (?:cannot execute [^\r\n]*: )?CreateProcess:', stderr)) def is_transient_process_error(exc: OSError) -> bool: return IS_WINDOWS and getattr(exc, 'winerror', None) in (5, 32, 1450, 1455)