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:
|
def _get_impact_path(vitis_path: str) -> str | None:
|
||||||
"""Find the impact executable path.
|
"""Find the impact executable path.
|
||||||
|
|
||||||
|
Tries 'impact' first, then falls back to 'xsct' (Xilinx 2023.2+).
|
||||||
Uses shutil.which() for cross-platform compatibility,
|
Uses shutil.which() for cross-platform compatibility,
|
||||||
then falls back to common Vitis paths.
|
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.
|
vitis_path: Vitis installation path.
|
||||||
|
|
||||||
Returns:
|
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")
|
# Try shutil.which for impact, then xsct as fallback
|
||||||
if path:
|
for tool in ("impact", "xsct"):
|
||||||
return path
|
path = shutil.which(tool)
|
||||||
|
if path:
|
||||||
|
return path
|
||||||
if vitis_path:
|
if vitis_path:
|
||||||
candidate = Path(vitis_path) / "bin" / "impact"
|
bin_dir = Path(vitis_path) / "bin"
|
||||||
if candidate.exists():
|
if bin_dir.exists():
|
||||||
return str(candidate)
|
for tool in ("impact", "xsct"):
|
||||||
candidate = Path(vitis_path) / "bin" / "impact.exe"
|
for ext in ("", ".exe"):
|
||||||
if candidate.exists():
|
candidate = bin_dir / f"{tool}{ext}"
|
||||||
return str(candidate)
|
if candidate.exists():
|
||||||
|
return str(candidate)
|
||||||
common_paths = [
|
common_paths = [
|
||||||
"/opt/xilinx/bin/impact",
|
"/opt/xilinx/bin/impact",
|
||||||
os.path.expanduser("~/Xilinx/Vitis/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:
|
def _get_impact_path(vitis_path: str) -> str | None:
|
||||||
"""Find the impact executable path.
|
"""Find the impact executable path.
|
||||||
|
|
||||||
|
Tries 'impact' first, then falls back to 'xsct' (Xilinx 2023.2+).
|
||||||
Uses shutil.which() for cross-platform compatibility,
|
Uses shutil.which() for cross-platform compatibility,
|
||||||
then falls back to common Vitis paths.
|
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.
|
vitis_path: Vitis installation path.
|
||||||
|
|
||||||
Returns:
|
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)
|
# Try shutil.which for impact, then xsct as fallback
|
||||||
path = shutil.which("impact")
|
for tool in ("impact", "xsct"):
|
||||||
if path:
|
path = shutil.which(tool)
|
||||||
return path
|
if path:
|
||||||
|
return path
|
||||||
|
|
||||||
# Search in vitis_path/bin
|
# Search in vitis_path/bin
|
||||||
if vitis_path:
|
if vitis_path:
|
||||||
candidate = Path(vitis_path) / "bin" / "impact"
|
bin_dir = Path(vitis_path) / "bin"
|
||||||
if candidate.exists():
|
if bin_dir.exists():
|
||||||
return str(candidate)
|
for tool in ("impact", "xsct"):
|
||||||
candidate = Path(vitis_path) / "bin" / "impact.exe"
|
for ext in ("", ".exe"):
|
||||||
if candidate.exists():
|
candidate = bin_dir / f"{tool}{ext}"
|
||||||
return str(candidate)
|
if candidate.exists():
|
||||||
|
return str(candidate)
|
||||||
|
|
||||||
# Common Vitis installation paths
|
# Common Vitis installation paths
|
||||||
common_paths = [
|
common_paths = [
|
||||||
|
|||||||
@@ -487,7 +487,8 @@ class MainWindow(ctk.CTk):
|
|||||||
|
|
||||||
for tool_name, tool_info in status_dict["tools"].items():
|
for tool_name, tool_info in status_dict["tools"].items():
|
||||||
if tool_info["found"]:
|
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:
|
else:
|
||||||
self._log_message(f" ✗ {tool_name}: {tool_info['error']}")
|
self._log_message(f" ✗ {tool_name}: {tool_info['error']}")
|
||||||
|
|
||||||
|
|||||||
+46
-24
@@ -8,8 +8,9 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass, field
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@@ -25,6 +26,7 @@ class ToolStatus:
|
|||||||
path: str = ""
|
path: str = ""
|
||||||
version: str = ""
|
version: str = ""
|
||||||
error: str = ""
|
error: str = ""
|
||||||
|
alias: str = "" # Which alias was found (e.g. 'xsct' for 'impact')
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -55,10 +57,14 @@ def check_vitis(config: Config) -> VitisCheckResult:
|
|||||||
tools: dict[str, ToolStatus] = {}
|
tools: dict[str, ToolStatus] = {}
|
||||||
errors: list[str] = []
|
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:
|
for tool_name, aliases in tool_aliases.items():
|
||||||
status = _check_tool(tool_name, vitis_path, system)
|
status = _check_tool(tool_name, aliases, vitis_path, system)
|
||||||
tools[tool_name] = status
|
tools[tool_name] = status
|
||||||
if not status.found:
|
if not status.found:
|
||||||
errors.append(f"{tool_name}: {status.error or 'not found'}")
|
errors.append(f"{tool_name}: {status.error or 'not found'}")
|
||||||
@@ -73,46 +79,61 @@ def check_vitis(config: Config) -> VitisCheckResult:
|
|||||||
|
|
||||||
|
|
||||||
def _check_tool(
|
def _check_tool(
|
||||||
tool_name: str, vitis_path: str, system: str
|
tool_name: str, aliases: list[str], vitis_path: str, system: str
|
||||||
) -> ToolStatus:
|
) -> ToolStatus:
|
||||||
"""Check if a single tool is available.
|
"""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:
|
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.
|
vitis_path: Vitis installation path to search.
|
||||||
system: Platform identifier (linux, windows, darwin).
|
system: Platform identifier (linux, windows, darwin).
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
ToolStatus with detection results.
|
ToolStatus with detection results.
|
||||||
"""
|
"""
|
||||||
# Search in vitis_path/bin first, then system PATH
|
exec_suffix = ".exe" if system == "windows" else ""
|
||||||
search_dirs: list[str] = []
|
|
||||||
if vitis_path:
|
|
||||||
bin_dir = Path(vitis_path) / "bin"
|
|
||||||
if bin_dir.exists():
|
|
||||||
search_dirs.append(str(bin_dir))
|
|
||||||
|
|
||||||
# Add system PATH components
|
# 1. Try shutil.which() for each alias — most reliable PATH resolution
|
||||||
path_env = os.environ.get("PATH", "")
|
for alias in aliases:
|
||||||
search_dirs.extend(path_env.split(os.pathsep))
|
found_path = shutil.which(f"{alias}{exec_suffix}")
|
||||||
|
if found_path:
|
||||||
exec_name = f"{tool_name}.exe" if system == "windows" else tool_name
|
version = _get_tool_version(found_path, tool_name, system)
|
||||||
|
|
||||||
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)
|
|
||||||
return ToolStatus(
|
return ToolStatus(
|
||||||
name=tool_name,
|
name=tool_name,
|
||||||
found=True,
|
found=True,
|
||||||
path=str(candidate),
|
path=found_path,
|
||||||
version=version,
|
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(
|
return ToolStatus(
|
||||||
name=tool_name,
|
name=tool_name,
|
||||||
found=False,
|
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,
|
"path": status.path,
|
||||||
"version": status.version,
|
"version": status.version,
|
||||||
"error": status.error,
|
"error": status.error,
|
||||||
|
"alias": status.alias,
|
||||||
}
|
}
|
||||||
for name, status in result.tools.items()
|
for name, status in result.tools.items()
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user