Skip to content

Commit d30dc55

Browse files
committed
Fix vswhere.exe discovery for non-default Visual Studio installations
Closes #1235 Signed-off-by: Aditya kumar singh <143548997+Adityakk9031@users.noreply.github.com>
1 parent 46b1773 commit d30dc55

File tree

3 files changed

+77
-10
lines changed

3 files changed

+77
-10
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@
113113
- Fix `BsrMatrix.notify_nnz_changed` sometimes failing to read the latest non-zero count from the `offsets` array.
114114
- `warp.fem`: Fix temporaries not being released promptly ([GH-1075](https://github.com/NVIDIA/warp/pull/1075)).
115115
- `warp.fem`: Fix uninitialized memory accesses in point-based function spaces with variable nodes per element.
116+
- Fix `vswhere.exe` discovery for non-default Visual Studio installations and standalone installs via
117+
package managers (Chocolatey, Scoop, winget) ([GH-1235](https://github.com/NVIDIA/warp/issues/1235)).
116118

117119
### Documentation
118120

build_lib.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,12 @@ def main(argv: list[str] | None = None) -> int:
502502
# attempt to find MSVC in environment (will set vcvars)
503503
args.host_compiler = build_dll.find_host_compiler()
504504
if not args.host_compiler:
505-
print("Warp build error: Could not find MSVC compiler")
505+
print(
506+
"Warp build error: Could not find MSVC compiler.\n"
507+
" Ensure Visual Studio 2019+ is installed with the 'Desktop development with C++' workload,\n"
508+
" or use --msvc-path and --sdk-path to specify custom toolchain locations.\n"
509+
" If Visual Studio is installed in a non-default location, adding vswhere.exe to PATH may help."
510+
)
506511
return 1
507512
else:
508513
args.host_compiler = build_dll.find_host_compiler()

warp/_src/build_dll.py

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,17 @@ def run_cmd(cmd):
5656
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
5757
# Print output even on success to show warnings
5858
if output:
59-
decoded_output = output.decode()
59+
decoded_output = output.decode("utf-8", errors="replace")
6060
if decoded_output.strip(): # Only print if not just whitespace
6161
# In parallel builds, associate output with its command for clarity
6262
# Use single print to avoid interleaving with other processes
6363
print(f"Output from: {cmd}\n{decoded_output}")
6464
return output
6565
except subprocess.CalledProcessError as e:
6666
# Single print to avoid interleaving in parallel builds
67-
print(f"Command failed with exit code {e.returncode}: {cmd}\nCommand output was:\n{e.output.decode()}")
67+
print(
68+
f"Command failed with exit code {e.returncode}: {cmd}\nCommand output was:\n{e.output.decode('utf-8', errors='replace')}"
69+
)
6870
raise e
6971

7072

@@ -96,6 +98,38 @@ def set_msvc_env(msvc_path, sdk_path):
9698
return os.path.join(msvc_path, "bin", "HostX64", "x64", "cl.exe")
9799

98100

101+
def _find_vswhere() -> str:
102+
"""Locate vswhere.exe using multiple discovery strategies.
103+
104+
Search order:
105+
1. ``PATH`` (covers Chocolatey, Scoop, winget, or manual installs)
106+
2. Default VS Installer location under ``%ProgramFiles(x86)%``
107+
3. Fallback under ``%ProgramFiles%`` (32-bit Windows or older setups)
108+
109+
Returns:
110+
Absolute path to vswhere.exe, or empty string if not found.
111+
"""
112+
path_result = shutil.which("vswhere.exe")
113+
if path_result:
114+
if verbose_cmd:
115+
print(f"Found vswhere.exe in PATH: {path_result}")
116+
return path_result
117+
118+
candidates = [
119+
os.path.expandvars(r"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"),
120+
os.path.expandvars(r"%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe"),
121+
]
122+
for candidate in candidates:
123+
if os.path.isfile(candidate):
124+
if verbose_cmd:
125+
print(f"Found vswhere.exe at: {candidate}")
126+
return candidate
127+
128+
if verbose_cmd:
129+
print("Warning: Could not locate vswhere.exe")
130+
return ""
131+
132+
99133
def find_host_compiler() -> str:
100134
"""Find the host C++ compiler.
101135
@@ -124,26 +158,52 @@ def find_host_compiler() -> str:
124158
if verbose_cmd:
125159
print("Warning: VS environment variables set but cl.exe not found, attempting auto-configuration")
126160

127-
vswhere_path = r"%ProgramFiles(x86)%/Microsoft Visual Studio/Installer/vswhere.exe"
128-
vswhere_path = os.path.expandvars(vswhere_path)
129-
if not os.path.exists(vswhere_path):
130-
return "" # Signal to caller that VS not found
161+
vswhere_path = _find_vswhere()
162+
if not vswhere_path:
163+
return "" # Signal to caller that vswhere.exe not found
131164

132-
vs_path = run_cmd(f'"{vswhere_path}" -latest -property installationPath').decode().rstrip()
165+
try:
166+
vs_path = (
167+
run_cmd(f'"{vswhere_path}" -latest -property installationPath')
168+
.decode("utf-8", errors="replace")
169+
.rstrip()
170+
)
171+
except subprocess.CalledProcessError:
172+
return "" # Signal to caller that vswhere command failed
173+
if not vs_path:
174+
if verbose_cmd:
175+
print("Warning: vswhere.exe found no Visual Studio installation")
176+
return ""
133177
vsvars_path = os.path.join(vs_path, "VC\\Auxiliary\\Build\\vcvars64.bat")
134178

135179
if not os.path.exists(vsvars_path):
136180
return "" # Signal to caller that VS environment script not found
137181

138-
output = run_cmd(f'"{vsvars_path}" && set').decode()
182+
try:
183+
output = run_cmd(f'"{vsvars_path}" && set').decode("utf-8", errors="replace")
184+
except subprocess.CalledProcessError:
185+
return "" # Signal to caller that VS environment script failed
139186

140187
for line in output.splitlines():
141188
pair = line.split("=", 1)
142189
if len(pair) >= 2:
143190
os.environ[pair[0]] = pair[1]
144191

145192
cl_path = shutil.which("cl.exe")
146-
cl_version = os.environ["VCToolsVersion"].split(".")
193+
if not cl_path:
194+
if verbose_cmd:
195+
print("Warning: cl.exe not found in PATH after running vcvars64.bat")
196+
return ""
197+
vc_tools_version = os.environ.get("VCToolsVersion", "")
198+
if not vc_tools_version:
199+
if verbose_cmd:
200+
print("Warning: VCToolsVersion not set after running vcvars64.bat")
201+
return ""
202+
cl_version = vc_tools_version.split(".")
203+
if len(cl_version) < 2:
204+
if verbose_cmd:
205+
print(f"Warning: Invalid VCToolsVersion format: {vc_tools_version}")
206+
return ""
147207

148208
# ensure at least VS2019 version, see list of MSVC versions here https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B
149209
cl_required_major = 14

0 commit comments

Comments
 (0)