diff --git a/src/reboot_manager.py b/src/reboot_manager.py index 9ca6fc4..3259fae 100644 --- a/src/reboot_manager.py +++ b/src/reboot_manager.py @@ -231,8 +231,9 @@ exit if callback: callback("progress", "Running JTAG system reset...") + from vitis_checker import build_tool_command result = subprocess.run( - [xsct, tcl_path], + build_tool_command(xsct, tcl_path), capture_output=True, text=True, timeout=30, diff --git a/src/vitis_checker.py b/src/vitis_checker.py index 877036b..683a969 100644 --- a/src/vitis_checker.py +++ b/src/vitis_checker.py @@ -110,6 +110,7 @@ def _scan_xilinx_root( """Scan xilinx_root for all installed versions of a tool. Searches under Vitis/*/bin/ and Vivado/*/bin/ for the executable. + On Windows also checks .bat wrappers in addition to .exe. Args: xilinx_root: Xilinx root directory (e.g., /data/xilinx, C:/Xilinx). @@ -124,6 +125,11 @@ def _scan_xilinx_root( if not xr.is_dir(): return results + # On Windows, also try .bat extension (Xilinx tools use .bat wrappers) + suffixes = [exec_suffix] + if exec_suffix == ".exe": + suffixes.append(".bat") + for product in _PRODUCT_DIRS: pdir = xr / product if not pdir.is_dir(): @@ -135,11 +141,13 @@ def _scan_xilinx_root( for ver_dir in entries: if not ver_dir.is_dir(): continue - candidate = ver_dir / "bin" / f"{exec_name}{exec_suffix}" - if candidate.is_file(): - v = _parse_version_tuple(ver_dir.name) - if v != (0,): - results.append((v, candidate, product)) + for sfx in suffixes: + candidate = ver_dir / "bin" / f"{exec_name}{sfx}" + if candidate.is_file(): + v = _parse_version_tuple(ver_dir.name) + if v != (0,): + results.append((v, candidate, product)) + break # Found for this version dir # Sort newest first (descending version tuple) results.sort(key=lambda x: x[0], reverse=True) return results @@ -237,6 +245,60 @@ def get_all_found_versions( ] +# ── Environment setup ──────────────────────────────────────────────── + + +def _find_settings_script(tool_path: str) -> str | None: + """Find the settings64 script for a Xilinx tool's version directory. + + Walks up from the tool's bin/ directory looking for + settings64.sh (Linux) or settings64.bat (Windows). + + Args: + tool_path: Absolute path to a Xilinx tool executable. + + Returns: + Path to settings64 script, or None if not found. + """ + p = Path(tool_path).resolve() + for parent in p.parents: + for name in ("settings64.sh", "settings64.bat"): + candidate = parent / name + if candidate.is_file(): + return str(candidate) + return None + + +def build_tool_command(tool_path: str, *args: str) -> list[str]: + """Build a subprocess-safe command with Xilinx environment setup. + + On Linux: sources settings64.sh before running the tool. + On Windows: .bat wrappers handle environment internally. + + Args: + tool_path: Path to the Xilinx tool executable. + *args: Arguments to pass to the tool. + + Returns: + Command list suitable for subprocess.run(). + """ + import shlex + + system = platform.system().lower() + + # Windows: .bat wrappers set up their own environment + if system == "windows": + return [tool_path, *args] + + # Linux: find settings64.sh and source it before running + settings = _find_settings_script(tool_path) + if not settings: + return [tool_path, *args] + + quoted = " ".join(shlex.quote(a) for a in [tool_path, *args]) + return ["bash", "-c", f"source {shlex.quote(settings)} && {quoted}"] + + # ── Public path getters ──────────────────────────────────────────────