From 32b201cf8eeb72098d5acafd17c96fa0d7a94950 Mon Sep 17 00:00:00 2001 From: Jeremy Shen Date: Thu, 11 Jun 2026 15:08:25 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20Windows=20.bat=20support=20?= =?UTF-8?q?+=20settings64=20env=20setup=20for=20Xilinx=20tools?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tool discovery: - On Windows, scan .bat files in addition to .exe (Xilinx Windows tools use .bat wrappers, not .exe) - Prefer .exe over .bat when both exist (same version dir) Environment setup: - _find_settings_script(): walk up from bin/ to find settings64.sh/.bat - build_tool_command(): wrap Linux tool invocation with 'source settings64.sh' Windows .bat wrappers handle env internally, no extra wrapping needed - reboot_manager.py now uses build_tool_command() for proper env Example output (Linux): build_tool_command('/data/xilinx/Vitis/2023.2/bin/xsct', 'script.tcl') → ['bash', '-c', 'source .../settings64.sh && .../xsct script.tcl'] --- src/reboot_manager.py | 3 +- src/vitis_checker.py | 72 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 6 deletions(-) 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 ──────────────────────────────────────────────