feat: Windows .bat support + settings64 env setup for Xilinx tools

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']
This commit is contained in:
2026-06-11 15:08:25 +08:00
parent 21acc16c8c
commit 32b201cf8e
2 changed files with 69 additions and 6 deletions
+2 -1
View File
@@ -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,
+63 -1
View File
@@ -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}"
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 ──────────────────────────────────────────────