Skip to content

Fix vswhere.exe discovery for non-default Visual Studio installations#1248

Open
Adityakk9031 wants to merge 1 commit intoNVIDIA:mainfrom
Adityakk9031:#1235
Open

Fix vswhere.exe discovery for non-default Visual Studio installations#1248
Adityakk9031 wants to merge 1 commit intoNVIDIA:mainfrom
Adityakk9031:#1235

Conversation

@Adityakk9031
Copy link
Contributor

@Adityakk9031 Adityakk9031 commented Feb 22, 2026

Description

This PR fixes an issue where vswhere.exe discovery would silently fail for non-default Visual Studio installations or when vswhere was installed via a standalone package manager (e.g., Chocolatey, Scoop, winget).

Changes:

  • Added a _find_vswhere() helper in warp/_src/build_dll.py with multi-strategy path discovery. It now searches PATH before falling back to the standard VS Installer paths under %ProgramFiles(x86)% and %ProgramFiles%.
  • Replaced the hardcoded path lookup in find_host_compiler() with a call to the new helper.
  • Improved the error message in build_lib.py when MSVC cannot be found. The message now mentions actionable workarounds, such as using the --msvc-path and --sdk-path flags or ensuring vswhere.exe is in the PATH.
  • Added an entry to CHANGELOG.md under the Fixed section.

Summary by CodeRabbit

  • Bug Fixes

    • More reliable Visual Studio/MSVC discovery for non-default and package-manager installations.
  • Improvements

    • Clearer, multi-line diagnostics when MSVC is not found, with actionable troubleshooting and custom toolchain options.
    • More robust handling and decoding of discovery outputs with additional verbose diagnostics for failure scenarios.
  • Documentation

    • Added changelog entry noting the discovery and messaging updates.

@copy-pr-bot
Copy link

copy-pr-bot bot commented Feb 22, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai
Copy link

coderabbitai bot commented Feb 22, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a PATH-first vswhere discovery helper used by MSVC detection with robust try/except and utf-8-with-replace decoding, updates MSVC-not-found messaging to a multiline instructional error, and adds an Unreleased changelog entry documenting the vswhere discovery fix.

Changes

Cohort / File(s) Summary
Changelog
CHANGELOG.md
Added Unreleased entry documenting fix to vswhere.exe discovery for non-default Visual Studio installations and package-manager-installed Visual Studio (Chocolatey, Scoop, winget).
MSVC error messaging
build_lib.py
Replaced terse "Could not find MSVC compiler" message with a multiline, instructional error explaining required Visual Studio workload, how to specify custom toolchains (--msvc-path, --sdk-path), and suggesting adding vswhere.exe to PATH.
vswhere discovery & MSVC detection
warp/_src/build_dll.py
Added def _find_vswhere() -> str to search PATH and common Program Files locations; switched find_host_compiler() to use it; wrapped vswhere and vcvars64.bat invocations in try/except; decode subprocess outputs with utf-8 replace; emit verbose diagnostics and return "" on failures.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor BuildScript as "build_dll.py"
  participant PATH as "PATH"
  participant Vswhere as "vswhere.exe"
  participant ProgramFiles as "ProgramFiles(x86)/ProgramFiles"
  participant VSEnv as "vcvars64.bat / Env"
  BuildScript->>PATH: check for vswhere.exe
  alt found in PATH
    PATH-->>BuildScript: path to vswhere.exe (rgba(0,128,0,0.5))
  else not found
    BuildScript->>ProgramFiles: check common Program Files locations
    ProgramFiles-->>BuildScript: path or not found (rgba(255,165,0,0.5))
  end
  BuildScript->>Vswhere: run vswhere -latest -property installationPath
  Vswhere-->>BuildScript: installationPath or error (rgba(0,128,255,0.5))
  alt installationPath present
    BuildScript->>VSEnv: run vcvars64.bat to load env
    VSEnv-->>BuildScript: env vars or error (rgba(0,0,128,0.5))
    BuildScript-->>BuildScript: verify MSVC version and return config
  else error / not found
    BuildScript-->>BuildScript: log verbose warning and return ""
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: fixing vswhere.exe discovery for non-default Visual Studio installations, which is the core objective of the PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link

greptile-apps bot commented Feb 22, 2026

Greptile Summary

This PR improves Visual Studio/MSVC discovery reliability for non-standard installations. The changes add a new _find_vswhere() helper that searches PATH before checking default VS Installer locations, allowing discovery of vswhere.exe installed via Chocolatey, Scoop, winget, or custom paths.

Key improvements:

  • Multi-strategy vswhere.exe discovery with PATH priority
  • Proper exception handling for subprocess calls (addresses previous review feedback)
  • Version string validation with length checks (addresses previous review feedback)
  • Enhanced error messages with actionable troubleshooting steps
  • UTF-8 decoding with error replacement for robustness

All previously identified issues have been addressed:

  • CalledProcessError is now caught specifically (lines 165-172, 182-185)
  • Version string indexing is guarded (lines 203-206)
  • Verbose diagnostics added for failure scenarios

Confidence Score: 5/5

  • Safe to merge with no blocking issues
  • All previously identified issues from the prior review have been properly addressed with specific exception handling, input validation, and robust error handling. The changes are well-scoped, improve reliability, and include helpful diagnostics.
  • No files require special attention

Important Files Changed

Filename Overview
CHANGELOG.md Added changelog entry documenting the vswhere.exe discovery fix for non-default VS installations
build_lib.py Improved error message with actionable troubleshooting steps when MSVC is not found
warp/_src/build_dll.py Added robust vswhere.exe discovery with PATH search priority, proper error handling, and improved diagnostics

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[find_host_compiler called] --> B{Windows?}
    B -->|No| C[Return CXX or g++]
    B -->|Yes| D{VS env configured?}
    D -->|Yes + cl.exe found| E[Return cl.exe path]
    D -->|No or cl.exe missing| F[Call _find_vswhere]
    F --> G{Check PATH}
    G -->|Found| H[Return vswhere path]
    G -->|Not found| I{Check ProgramFiles x86}
    I -->|Found| H
    I -->|Not found| J{Check ProgramFiles}
    J -->|Found| H
    J -->|Not found| K[Return empty string]
    H --> L[Run vswhere -latest]
    L -->|Success| M[Get VS install path]
    L -->|Failure| K
    M --> N[Run vcvars64.bat]
    N -->|Success| O[Set environment vars]
    N -->|Failure| K
    O --> P{Validate cl.exe}
    P -->|Found| Q{Check VCToolsVersion}
    P -->|Missing| K
    Q -->|Valid format| R{Version >= 14.29?}
    Q -->|Invalid| K
    R -->|Yes| E
    R -->|No| K
Loading

Last reviewed commit: d30dc55

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

if not vswhere_path:
return "" # Signal to caller that vswhere.exe not found

vs_path = run_cmd(f'"{vswhere_path}" -latest -property installationPath').decode().rstrip()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing error handling if vswhere command fails. run_cmd() raises CalledProcessError on failure (see line 68), which would crash here instead of gracefully returning empty string

Suggested change
vs_path = run_cmd(f'"{vswhere_path}" -latest -property installationPath').decode().rstrip()
try:
vs_path = run_cmd(f'"{vswhere_path}" -latest -property installationPath').decode().rstrip()
except subprocess.CalledProcessError:
return "" # Signal to caller that vswhere command failed

@greptile-apps
Copy link

greptile-apps bot commented Feb 22, 2026

Additional Comments (1)

warp/_src/build_dll.py
Missing error handling if vcvars64.bat command fails. run_cmd() raises CalledProcessError on failure, which would crash here

        try:
            output = run_cmd(f'"{vsvars_path}" && set').decode()
        except subprocess.CalledProcessError:
            return ""  # Signal to caller that vcvars64.bat failed

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
warp/_src/build_dll.py (1)

110-114: Nit: use "vswhere.exe" for consistency with other shutil.which calls in this file.

All other shutil.which calls in this file include the explicit .exe suffix (e.g., shutil.which("cl.exe") on Lines 149 and 176). On Windows, both forms resolve identically via PATHEXT, but the suffix makes the search target unambiguous.

✏️ Suggested change
-    path_result = shutil.which("vswhere")
+    path_result = shutil.which("vswhere.exe")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@warp/_src/build_dll.py` around lines 110 - 114, Update the shutil.which call
to search for "vswhere.exe" instead of "vswhere" to match the explicit .exe
convention used elsewhere (e.g., the other shutil.which("cl.exe") calls); locate
the call that assigns path_result = shutil.which("vswhere") and change the
search string to "vswhere.exe" while keeping the existing verbose_cmd print and
return behavior intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CHANGELOG.md`:
- Around line 116-118: Remove the implementation-detail sentence "The build
system now checks `PATH` before falling back to default locations" from the
CHANGELOG entry about vswhere.exe discovery (leave the user-facing fix sentence
about discovery failing for non-default or package-manager installs), or
consolidate it into the first sentence so the entry only states the user-visible
change and not internal behavior.

---

Nitpick comments:
In `@warp/_src/build_dll.py`:
- Around line 110-114: Update the shutil.which call to search for "vswhere.exe"
instead of "vswhere" to match the explicit .exe convention used elsewhere (e.g.,
the other shutil.which("cl.exe") calls); locate the call that assigns
path_result = shutil.which("vswhere") and change the search string to
"vswhere.exe" while keeping the existing verbose_cmd print and return behavior
intact.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@warp/_src/build_dll.py`:
- Around line 163-175: The code around vs_path/vsvars_path uses
run_cmd(...).decode() without handling empty output or decode errors; update the
block using run_cmd to (1) decode with a safe strategy (e.g.,
output_bytes.decode("utf-8", errors="replace") or catch UnicodeDecodeError) when
calling run_cmd for vs_path and for output, and (2) explicitly check vs_path for
an empty string after decoding and return/log a clear diagnostic (instead of
silently returning "") so callers/users know VS wasn't found; reference the
vs_path variable, the vsvars_path (vcvars64.bat) construction, and the run_cmd
calls so you update both decode sites and add the empty-check for vs_path.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@warp/_src/build_dll.py`:
- Around line 163-166: The broad except that currently reads except
(subprocess.CalledProcessError, Exception) should be narrowed to explicitly
catch subprocess.CalledProcessError and UnicodeDecodeError (e.g., except
(subprocess.CalledProcessError, UnicodeDecodeError):) for both places handling
run_cmd output (the vs_path decode block and the later similar block), and, for
a longer-term fix, update run_cmd where it does e.output.decode() to use
errors="replace" so UnicodeDecodeError cannot escape (this lets callers safely
catch only subprocess.CalledProcessError later).

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

.decode("utf-8", errors="replace")
.rstrip()
)
except (subprocess.CalledProcessError, Exception):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching bare Exception is overly broad and may hide unexpected errors like KeyboardInterrupt or programming bugs. Consider catching only specific exceptions like subprocess.CalledProcessError, UnicodeDecodeError, and OSError

output = run_cmd(f'"{vsvars_path}" && set').decode()
try:
output = run_cmd(f'"{vsvars_path}" && set').decode("utf-8", errors="replace")
except (subprocess.CalledProcessError, Exception):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same broad exception handling issue - consider catching only specific exception types

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@warp/_src/build_dll.py`:
- Line 169: The current except clause except (subprocess.CalledProcessError,
Exception) in build_dll.py is a blind catch (BLE001) because Exception subsumes
CalledProcessError; change the handler to explicitly catch the intended
exception types (e.g., except subprocess.CalledProcessError as e: and, if
needed, except UnicodeDecodeError as e:) at both locations referenced, and
include the caught exception variable in the process/error handling. Also update
run_cmd (the function that does .decode()) to use .decode("utf-8",
errors="replace") as a long-term fix so callers can safely catch only
subprocess.CalledProcessError.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link

greptile-apps bot commented Feb 22, 2026

Additional Comments (1)

warp/_src/build_dll.py
Potential KeyError if VCToolsVersion not set by vcvars64.bat. Wrap in .get() or add existence check before accessing.

        cl_version = os.environ.get("VCToolsVersion", "").split(".")

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link

greptile-apps bot commented Feb 22, 2026

Additional Comments (1)

warp/_src/build_dll.py
cl_path may be None when returned

shutil.which("cl.exe") returns None when the executable is not found, but this value is returned directly at line 212 without a guard. The function's return type annotation is str, and callers in build_lib.py check if not args.host_compiler: which does catch None, so this won't crash at runtime — but it's a type-safety gap that could cause issues if a caller ever assumes a non-empty return is always a str.

This is a pre-existing issue (the original code had the same pattern), but since this PR reworked this section and added the VCToolsVersion guard, it would be a good opportunity to add a cl_path check:

        cl_path = shutil.which("cl.exe")
        if not cl_path:
            if verbose_cmd:
                print("Warning: cl.exe not found in PATH after running vcvars64.bat")
            return ""
        vc_tools_version = os.environ.get("VCToolsVersion", "")
        if not vc_tools_version:
            if verbose_cmd:
                print("Warning: VCToolsVersion not set after running vcvars64.bat")
            return ""
        cl_version = vc_tools_version.split(".")

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

        if int(cl_version[0]) < cl_required_major or (
            (int(cl_version[0]) == cl_required_major) and (int(cl_version[1]) < cl_required_minor)
        ):
            print(
                f"Warp: MSVC found but compiler version too old, found {cl_version[0]}.{cl_version[1]}, but must be {cl_required_major}.{cl_required_minor} or higher, kernel host compilation will be disabled."
            )
            return ""  # Signal to caller that version too old

        return cl_path

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Closes NVIDIA#1235

Signed-off-by: Aditya kumar singh <143548997+Adityakk9031@users.noreply.github.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@Adityakk9031
Copy link
Contributor Author

@shi-eric have a look

@Adityakk9031
Copy link
Contributor Author

@christophercrouzet please review it

@c0d1f1ed
Copy link
Contributor

This looks good to me. I'll see if we can get it into the 12.1 release.

@c0d1f1ed
Copy link
Contributor

/ok to test d30dc55

@c0d1f1ed
Copy link
Contributor

@Adityakk9031 Thanks for the MR. I don't have any strictly technical concerns with it, but it adds 67 lines of code so I just wanted to verify that it's worth the complexity. Could you detail the exact issue you encountered and why all of the changes in this MR are necessary to address it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants