fix(vitis): add xsct fallback for impact detection in Xilinx 2023.2
- vitis_checker: shutil.which() + xsct fallback for impact detection - flash_programmer: _get_impact_path now checks xsct as fallback - bitstream_programmer: _get_impact_path now checks xsct as fallback - GUI: show '(via xsct)' alias note when xsct replaces impact - ToolStatus: add 'alias' field for tracking which executable was found
This commit is contained in:
+14
-10
@@ -33,6 +33,7 @@ ProgressCallback = Callable[[str, str], None] | None
|
||||
def _get_impact_path(vitis_path: str) -> str | None:
|
||||
"""Find the impact executable path.
|
||||
|
||||
Tries 'impact' first, then falls back to 'xsct' (Xilinx 2023.2+).
|
||||
Uses shutil.which() for cross-platform compatibility,
|
||||
then falls back to common Vitis paths.
|
||||
|
||||
@@ -40,18 +41,21 @@ def _get_impact_path(vitis_path: str) -> str | None:
|
||||
vitis_path: Vitis installation path.
|
||||
|
||||
Returns:
|
||||
Path to impact executable, or None if not found.
|
||||
Path to impact or xsct executable, or None if not found.
|
||||
"""
|
||||
path = shutil.which("impact")
|
||||
if path:
|
||||
return path
|
||||
# Try shutil.which for impact, then xsct as fallback
|
||||
for tool in ("impact", "xsct"):
|
||||
path = shutil.which(tool)
|
||||
if path:
|
||||
return path
|
||||
if vitis_path:
|
||||
candidate = Path(vitis_path) / "bin" / "impact"
|
||||
if candidate.exists():
|
||||
return str(candidate)
|
||||
candidate = Path(vitis_path) / "bin" / "impact.exe"
|
||||
if candidate.exists():
|
||||
return str(candidate)
|
||||
bin_dir = Path(vitis_path) / "bin"
|
||||
if bin_dir.exists():
|
||||
for tool in ("impact", "xsct"):
|
||||
for ext in ("", ".exe"):
|
||||
candidate = bin_dir / f"{tool}{ext}"
|
||||
if candidate.exists():
|
||||
return str(candidate)
|
||||
common_paths = [
|
||||
"/opt/xilinx/bin/impact",
|
||||
os.path.expanduser("~/Xilinx/Vitis/bin/impact"),
|
||||
|
||||
+14
-11
@@ -75,6 +75,7 @@ def _run_command(
|
||||
def _get_impact_path(vitis_path: str) -> str | None:
|
||||
"""Find the impact executable path.
|
||||
|
||||
Tries 'impact' first, then falls back to 'xsct' (Xilinx 2023.2+).
|
||||
Uses shutil.which() for cross-platform compatibility,
|
||||
then falls back to common Vitis paths.
|
||||
|
||||
@@ -82,21 +83,23 @@ def _get_impact_path(vitis_path: str) -> str | None:
|
||||
vitis_path: Vitis installation path.
|
||||
|
||||
Returns:
|
||||
Path to impact executable, or None if not found.
|
||||
Path to impact or xsct executable, or None if not found.
|
||||
"""
|
||||
# Try shutil.which first (cross-platform)
|
||||
path = shutil.which("impact")
|
||||
if path:
|
||||
return path
|
||||
# Try shutil.which for impact, then xsct as fallback
|
||||
for tool in ("impact", "xsct"):
|
||||
path = shutil.which(tool)
|
||||
if path:
|
||||
return path
|
||||
|
||||
# Search in vitis_path/bin
|
||||
if vitis_path:
|
||||
candidate = Path(vitis_path) / "bin" / "impact"
|
||||
if candidate.exists():
|
||||
return str(candidate)
|
||||
candidate = Path(vitis_path) / "bin" / "impact.exe"
|
||||
if candidate.exists():
|
||||
return str(candidate)
|
||||
bin_dir = Path(vitis_path) / "bin"
|
||||
if bin_dir.exists():
|
||||
for tool in ("impact", "xsct"):
|
||||
for ext in ("", ".exe"):
|
||||
candidate = bin_dir / f"{tool}{ext}"
|
||||
if candidate.exists():
|
||||
return str(candidate)
|
||||
|
||||
# Common Vitis installation paths
|
||||
common_paths = [
|
||||
|
||||
@@ -487,7 +487,8 @@ class MainWindow(ctk.CTk):
|
||||
|
||||
for tool_name, tool_info in status_dict["tools"].items():
|
||||
if tool_info["found"]:
|
||||
self._log_message(f" ✓ {tool_name}: {tool_info['path']}")
|
||||
alias_note = f" (via {tool_info['alias']})" if tool_info.get("alias") and tool_info["alias"] != tool_name else ""
|
||||
self._log_message(f" ✓ {tool_name}: {tool_info['path']}{alias_note}")
|
||||
else:
|
||||
self._log_message(f" ✗ {tool_name}: {tool_info['error']}")
|
||||
|
||||
|
||||
+46
-24
@@ -8,8 +8,9 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import subprocess
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
@@ -25,6 +26,7 @@ class ToolStatus:
|
||||
path: str = ""
|
||||
version: str = ""
|
||||
error: str = ""
|
||||
alias: str = "" # Which alias was found (e.g. 'xsct' for 'impact')
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -55,10 +57,14 @@ def check_vitis(config: Config) -> VitisCheckResult:
|
||||
tools: dict[str, ToolStatus] = {}
|
||||
errors: list[str] = []
|
||||
|
||||
required_tools = ["bootgen", "impact"]
|
||||
# Xilinx tool aliases: map tool names to their possible executables
|
||||
tool_aliases: dict[str, list[str]] = {
|
||||
"bootgen": ["bootgen"],
|
||||
"impact": ["impact", "xsct"], # xsct can replace impact in newer versions
|
||||
}
|
||||
|
||||
for tool_name in required_tools:
|
||||
status = _check_tool(tool_name, vitis_path, system)
|
||||
for tool_name, aliases in tool_aliases.items():
|
||||
status = _check_tool(tool_name, aliases, vitis_path, system)
|
||||
tools[tool_name] = status
|
||||
if not status.found:
|
||||
errors.append(f"{tool_name}: {status.error or 'not found'}")
|
||||
@@ -73,46 +79,61 @@ def check_vitis(config: Config) -> VitisCheckResult:
|
||||
|
||||
|
||||
def _check_tool(
|
||||
tool_name: str, vitis_path: str, system: str
|
||||
tool_name: str, aliases: list[str], vitis_path: str, system: str
|
||||
) -> ToolStatus:
|
||||
"""Check if a single tool is available.
|
||||
|
||||
Uses shutil.which() for reliable PATH resolution, then falls back
|
||||
to scanning vitis_path/bin for each alias.
|
||||
|
||||
Args:
|
||||
tool_name: Name of the tool to check.
|
||||
tool_name: Canonical name of the tool (e.g. 'impact').
|
||||
aliases: List of possible executable names (e.g. ['impact', 'xsct']).
|
||||
vitis_path: Vitis installation path to search.
|
||||
system: Platform identifier (linux, windows, darwin).
|
||||
|
||||
Returns:
|
||||
ToolStatus with detection results.
|
||||
"""
|
||||
# Search in vitis_path/bin first, then system PATH
|
||||
search_dirs: list[str] = []
|
||||
if vitis_path:
|
||||
bin_dir = Path(vitis_path) / "bin"
|
||||
if bin_dir.exists():
|
||||
search_dirs.append(str(bin_dir))
|
||||
exec_suffix = ".exe" if system == "windows" else ""
|
||||
|
||||
# Add system PATH components
|
||||
path_env = os.environ.get("PATH", "")
|
||||
search_dirs.extend(path_env.split(os.pathsep))
|
||||
|
||||
exec_name = f"{tool_name}.exe" if system == "windows" else tool_name
|
||||
|
||||
for search_dir in search_dirs:
|
||||
candidate = Path(search_dir) / exec_name
|
||||
if candidate.exists() and candidate.is_file():
|
||||
version = _get_tool_version(str(candidate), tool_name, system)
|
||||
# 1. Try shutil.which() for each alias — most reliable PATH resolution
|
||||
for alias in aliases:
|
||||
found_path = shutil.which(f"{alias}{exec_suffix}")
|
||||
if found_path:
|
||||
version = _get_tool_version(found_path, tool_name, system)
|
||||
return ToolStatus(
|
||||
name=tool_name,
|
||||
found=True,
|
||||
path=str(candidate),
|
||||
path=found_path,
|
||||
version=version,
|
||||
alias=alias,
|
||||
)
|
||||
|
||||
# 2. Try vitis_path/bin for each alias
|
||||
if vitis_path:
|
||||
bin_dir = Path(vitis_path) / "bin"
|
||||
if bin_dir.exists():
|
||||
for alias in aliases:
|
||||
candidate = bin_dir / f"{alias}{exec_suffix}"
|
||||
if candidate.exists() and candidate.is_file():
|
||||
version = _get_tool_version(str(candidate), tool_name, system)
|
||||
return ToolStatus(
|
||||
name=tool_name,
|
||||
found=True,
|
||||
path=str(candidate),
|
||||
version=version,
|
||||
alias=alias,
|
||||
)
|
||||
|
||||
return ToolStatus(
|
||||
name=tool_name,
|
||||
found=False,
|
||||
error=f"Could not locate {exec_name} in PATH or {vitis_path}/bin",
|
||||
error=(
|
||||
f"Could not locate {', '.join(aliases)} in PATH or {vitis_path}/bin"
|
||||
if vitis_path
|
||||
else f"Could not locate {', '.join(aliases)} in PATH"
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -163,6 +184,7 @@ def get_tool_status_dict(result: VitisCheckResult) -> dict[str, Any]:
|
||||
"path": status.path,
|
||||
"version": status.version,
|
||||
"error": status.error,
|
||||
"alias": status.alias,
|
||||
}
|
||||
for name, status in result.tools.items()
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user