Skip to content

Commit 0247c83

Browse files
author
Salvador Santoluctio
committed
nisyscfg auto-discovery, remove lv_path, PostGenerateBitfile --config fix
1 parent 3e626f3 commit 0247c83

9 files changed

Lines changed: 159 additions & 49 deletions

File tree

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ def pre_all(context):
6464
config = context.config
6565

6666
# Tools
67-
config.set_lv_path("C:/Program Files/National Instruments/LabVIEW 2024")
6867
config.set_vivado_tools_path("C:/NIFPGA/programs/Vivado2021_1")
6968
config.set_vivado_tcl_scripts_folder("../common/TCL")
7069

@@ -115,7 +114,6 @@ def pre_create_project(context):
115114

116115
| Setter | Description |
117116
| --- | --- |
118-
| `set_lv_path(value)` | LabVIEW installation root path. |
119117
| `set_vivado_tools_path(value)` | Vivado installation root containing bin/vivado(.bat). |
120118
| `set_vivado_tcl_scripts_folder(value)` | Folder with Vivado TCL Mako templates/scripts. |
121119
| `set_modelsim_tools_path(value)` | ModelSim installation root directory. |
@@ -256,7 +254,7 @@ The current CLI surface is defined in labview_fpga_hdl_tools/__main__.py.
256254
| launch-vivado | `vivado_tools_path`, `vivado_project_path` | Also requires existing project .xpr file. |
257255
| create-modelsim | `top_level_entity`, `hdl_file_lists`, `modelsim_tools_path` | Uses `modelsim_file_lists` if set, otherwise `hdl_file_lists`. |
258256
| launch-modelsim | `top_level_entity`, `modelsim_tools_path` | Requires existing ModelSim project directory (run create-modelsim first). |
259-
| create-lvbitx | `lv_path` | Uses `top_level_entity` to derive filenames. |
257+
| create-lvbitx | `top_level_entity` | Auto-discovers LabVIEW via nisyscfg. Uses `top_level_entity` to derive filenames. |
260258
| install-deps | `dependencies` | Does not use other settings. |
261259
| gen-guid | None | Does not use any settings. |
262260

labview_fpga_hdl_tools/common.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,6 @@ class FileConfiguration:
119119
skip_vivado: bool = False # Skip launching Vivado (validation only)
120120
skip_modelsim: bool = False # Skip launching ModelSim (validation only)
121121

122-
# ----- TOOL PATH SETTINGS (loaded from [Tools] section) -----
123-
lv_path: Optional[str] = None # Path to LabVIEW installation
124-
125122
# --- General Settings setters ---
126123

127124
def set_target_family(self, value):
@@ -138,10 +135,6 @@ def set_dependencies(self, value):
138135

139136
# --- Tool Settings setters ---
140137

141-
def set_lv_path(self, value):
142-
"""Set the LabVIEW installation path (resolved to absolute)."""
143-
self.lv_path = resolve_path(value)
144-
145138
# --- Vivado Project Settings setters ---
146139

147140
def set_top_level_entity(self, value):

labview_fpga_hdl_tools/create_lvbitx.py

Lines changed: 101 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,74 @@
55
# SPDX-License-Identifier: MIT
66
#
77
import os # For file and directory operations
8+
import re
89
import subprocess # For executing external programs
910

1011
from . import common # For shared utilities across tools
1112

1213

14+
def _get_sw_attr(obj, names):
15+
"""Return the first non-empty string attribute from *names*, or empty string."""
16+
for name in names:
17+
value = getattr(obj, name, None)
18+
if value is not None:
19+
text = str(value).strip()
20+
if text:
21+
return text
22+
return ""
23+
24+
25+
def _find_createbitfile_exe():
26+
"""Auto-discover createBitfile.exe from the latest installed LabVIEW using nisyscfg.
27+
28+
Queries NI System Configuration for installed LabVIEW versions, then
29+
checks the standard installation directories for createBitfile.exe,
30+
preferring the latest version.
31+
32+
Returns:
33+
str or None: Absolute path to createBitfile.exe, or None if not found.
34+
"""
35+
try:
36+
import nisyscfg
37+
except ImportError:
38+
print("Warning: nisyscfg package not available, cannot auto-discover LabVIEW")
39+
return None
40+
41+
labview_years = set()
42+
try:
43+
with nisyscfg.Session() as session:
44+
for sw in session.get_installed_software_components():
45+
title = _get_sw_attr(sw, ["title", "display_name", "name", "product_name", "id"])
46+
if re.match(r"^(NI\s+)?LabVIEW\s+\d{4}", title, re.IGNORECASE):
47+
year_match = re.search(r"(\d{4})", title)
48+
if year_match:
49+
labview_years.add(int(year_match.group(1)))
50+
except Exception as exc:
51+
print(f"Warning: Failed to query NI System Configuration: {exc}")
52+
return None
53+
54+
if not labview_years:
55+
return None
56+
57+
# Try each LabVIEW version from latest to oldest
58+
program_files = os.environ.get("ProgramFiles", r"C:\Program Files")
59+
for year in sorted(labview_years, reverse=True):
60+
candidate = os.path.join(
61+
program_files,
62+
"National Instruments",
63+
f"LabVIEW {year}",
64+
"vi.lib",
65+
"rvi",
66+
"CDR",
67+
"createBitfile.exe",
68+
)
69+
if os.path.isfile(candidate):
70+
print(f"Found createBitfile.exe from LabVIEW {year}")
71+
return candidate
72+
73+
return None
74+
75+
1376
def _create_lv_bitfile(config=None):
1477
"""Create the LabVIEW FPGA .lvbitx file by executing the createBitfile.exe tool."""
1578
if os.name != "nt":
@@ -21,7 +84,22 @@ def _create_lv_bitfile(config=None):
2184
path_parts = [part.lower() for part in os.path.normpath(vivado_impl_folder).split(os.sep)]
2285
if "impl_1" not in path_parts:
2386
print(
24-
"WARNING: This function must be run from within the implementation folder of a Vivado project.\n(e.g. C:\\dev\\github\\flexrio\\targets\\pxie-7903\\VivadoProject\\MySasquatchProj.runs\\impl_1)"
87+
"\n"
88+
"************************************************************\n"
89+
"*** WARNING ***\n"
90+
"************************************************************\n"
91+
"* This function must be run from within the implementation\n"
92+
"* folder of a Vivado project.\n"
93+
"*\n"
94+
"* Expected CWD example:\n"
95+
"* C:\\dev\\flexrio\\targets\\pxie-7903\\VivadoProject\\MyProj.runs\\impl_1\n"
96+
"*\n"
97+
"* When called from that folder, use --config to\n"
98+
"* point back to the target's nihdlsettings.py:\n"
99+
"*\n"
100+
"* nihdl create-lvbitx --config=../../../nihdlsettings.py\n"
101+
"*\n"
102+
"************************************************************\n"
25103
)
26104

27105
# This script is run by a TCL script in Vivado after the bitstream is generated and the
@@ -33,19 +111,6 @@ def _create_lv_bitfile(config=None):
33111
if config is None:
34112
config = common.FileConfiguration()
35113

36-
# Check if LV path is set
37-
if config.lv_path is None:
38-
print("Error: LabVIEW path not set in configuration")
39-
return 1
40-
41-
# Construct path to createBitfile.exe
42-
createbitfile_exe = os.path.join(config.lv_path, "vi.lib", "rvi", "CDR", "createBitfile.exe")
43-
44-
# Check if the executable exists
45-
if not os.path.exists(createbitfile_exe):
46-
print(f"Error: createBitfile.exe not found at {createbitfile_exe}")
47-
return 1
48-
49114
# Determine path to CodeGenerationResults.lvtxt based on UseGeneratedLVWindowFiles setting
50115
if config.use_gen_lv_window_files:
51116
# Check if window folder is set
@@ -62,8 +127,14 @@ def _create_lv_bitfile(config=None):
62127
code_gen_results_path = os.path.join(window_folder, "CodeGenerationResults.lvtxt")
63128
else:
64129
print("Using default LV window files")
65-
# Use the path from configuration
66130
code_gen_results_path = config.code_generation_results_stub
131+
if code_gen_results_path is None:
132+
print("Error: code_generation_results_stub not set in configuration")
133+
return 1
134+
135+
if config.top_level_entity is None:
136+
print("Error: top_level_entity not set in configuration")
137+
return 1
67138

68139
print(f"LabVIEW code generation results path: {code_gen_results_path}")
69140

@@ -73,6 +144,21 @@ def _create_lv_bitfile(config=None):
73144
lvbitx_output_path = os.path.abspath(f"objects/bitfiles/{config.top_level_entity}.lvbitx")
74145
print(f"Output .lvbitx path: {lvbitx_output_path}")
75146

147+
# In skip_vivado mode, create a mock file without needing createBitfile.exe
148+
if config.skip_vivado:
149+
print("SKIP VIVADO: Validation successful, skipping createBitfile.exe launch")
150+
os.makedirs(os.path.dirname(lvbitx_output_path), exist_ok=True)
151+
with open(lvbitx_output_path, "w") as f:
152+
f.write("# Mock LVBITX file created for testing\n")
153+
print(f"Created mock LVBITX file at: {lvbitx_output_path}")
154+
return 0
155+
156+
# Auto-discover createBitfile.exe from the latest installed LabVIEW
157+
createbitfile_exe = _find_createbitfile_exe()
158+
if createbitfile_exe is None:
159+
print("Error: Could not find createBitfile.exe. Is LabVIEW installed?")
160+
return 1
161+
76162
# Create the directory for the new file if it doesn't exist
77163
os.makedirs(os.path.dirname(lvbitx_output_path), exist_ok=True)
78164

@@ -86,17 +172,6 @@ def _create_lv_bitfile(config=None):
86172

87173
print(f"Executing: {' '.join(cmd)}")
88174

89-
# In skip_vivado mode, stop here after validation
90-
if config.skip_vivado:
91-
print("SKIP VIVADO: Validation successful, skipping createBitfile.exe launch")
92-
93-
# Create a mock LVBITX file for testing
94-
os.makedirs(os.path.dirname(lvbitx_output_path), exist_ok=True)
95-
with open(lvbitx_output_path, "w") as f:
96-
f.write("# Mock LVBITX file created for testing\n")
97-
print(f"Created mock LVBITX file at: {lvbitx_output_path}")
98-
return 0
99-
100175
# Execute the command
101176
result = subprocess.run(cmd, capture_output=True, text=True, check=False)
102177

labview_fpga_hdl_tools/nihdlsettings_default.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def pre_all(context):
3636
Available setters (grouped by section):
3737
3838
Tools:
39-
set_lv_path, set_vivado_tools_path, set_vivado_tcl_scripts_folder,
39+
set_vivado_tools_path, set_vivado_tcl_scripts_folder,
4040
set_modelsim_tools_path, set_xilinx_sim_lib_path
4141
4242
General Settings:
@@ -85,7 +85,6 @@ def pre_all(context):
8585
config = context.config
8686

8787
# --- Tools ---
88-
config.set_lv_path("C:/Program Files/National Instruments/LabVIEW 2024")
8988
config.set_vivado_tools_path("C:/NIFPGA/programs/Vivado2021_1")
9089
config.set_vivado_tcl_scripts_folder("../common/TCL")
9190
# config.set_modelsim_tools_path("")

poetry.lock

Lines changed: 43 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
44

55
[tool.poetry]
66
name = "labview-fpga-hdl-tools"
7-
version = "0.4.1"
7+
version = "0.4.2"
88
description = "LabVIEW FPGA HDL Tools"
99
authors = [
1010
"Salvador Santolucito <salvador.santolucito@gmail.com>"
@@ -20,6 +20,7 @@ python = ">=3.8,<4.0"
2020
mako = ">=1.3.10"
2121
click = ">=8.1.8,<8.2"
2222
packaging = ">=21.0"
23+
nisyscfg = {version = ">=0.2.1", python = ">=3.9"}
2324
tomli = {version = ">=1.1.0", python = "<3.11"}
2425

2526
[tool.poetry.group.test.dependencies]
@@ -46,5 +47,9 @@ disallow_incomplete_defs = false
4647
module = "mako.*"
4748
ignore_missing_imports = true
4849

50+
[[tool.mypy.overrides]]
51+
module = "nisyscfg.*"
52+
ignore_missing_imports = true
53+
4954
[tool.bandit]
5055
exclude_dirs = ["tests"]

tests/test-project/targets/pxie-7903/TCL/PostGenerateBitfile.tcl

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@
44
set env(PYTHONPATH) ""
55
set env(PYTHONHOME) ""
66

7-
pwd
8-
9-
cd ../../../
10-
11-
pwd
12-
137
# Execute the Python script
14-
exec nihdl create-lvbitx
8+
# This TCL script runs from inside the Vivado impl_1 directory, so we point
9+
# --config back up to the target folder's nihdlsettings.py.
10+
exec nihdl create-lvbitx --config=../../../nihdlsettings.py

tests/test-project/targets/pxie-7903/badsettings.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ def pre_all(context):
66
config = context.config
77

88
# --- Tools ---
9-
config.set_lv_path("../../../bad_labview_path")
109
config.set_vivado_tools_path("../../../bad_vivado_path")
1110
# config.set_vivado_tcl_scripts_folder("")
1211
config.set_modelsim_tools_path("../../../bad_modelsim_path")

tests/test-project/targets/pxie-7903/nihdlsettings.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ def pre_all(context):
66
config = context.config
77

88
# --- Tools ---
9-
config.set_lv_path("../../../test-LabVIEW")
109
config.set_vivado_tools_path("../../../test-vivado")
1110
config.set_vivado_tcl_scripts_folder("TCL")
1211
config.set_modelsim_tools_path("../../../test-modelsim")
1312
# config.set_xilinx_sim_lib_path("")
1413

14+
# --- Runtime ---
15+
config.set_skip_vivado(True)
16+
config.set_skip_modelsim(True)
17+
1518
# --- General Settings ---
1619
config.set_target_family("FlexRIO")
1720
config.set_base_target("PXIe-7903")

0 commit comments

Comments
 (0)