36 lines
1.3 KiB
Python
36 lines
1.3 KiB
Python
"""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)
|