Skip to content

[fix] Let wheels resolve CUDA math libraries from pip packages - #76

Open
behnamasadi wants to merge 5 commits into
nvidia-isaac:mainfrom
behnamasadi:behnamasadi/wheel-cuda-math-libs
Open

[fix] Let wheels resolve CUDA math libraries from pip packages#76
behnamasadi wants to merge 5 commits into
nvidia-isaac:mainfrom
behnamasadi:behnamasadi/wheel-cuda-math-libs

Conversation

@behnamasadi

@behnamasadi behnamasadi commented Jul 29, 2026

Copy link
Copy Markdown

Fixes #70.

Wheels link against cuBLAS/cuSOLVER/cuSPARSE, exclude them during auditwheel repair, and neither bundle nor declare
them anywhere, so on a machine without a CUDA Toolkit installation pip install cuvslam-*.whl succeeds and
import cuvslam fails with ImportError: libcusolver.so.11: cannot open shared object file.

What this does

1. Declares the excluded libraries as extras (python/pyproject.toml)

[project.optional-dependencies]
cu12 = ["nvidia-cublas-cu12", "nvidia-cusolver-cu12", "nvidia-cusparse-cu12", "nvidia-nvjitlink-cu12"]
cu13 = ["nvidia-cublas>=13,<14", "nvidia-cusolver>=12,<13", "nvidia-cusparse>=12,<13", "nvidia-nvjitlink>=13,<14"]

Extras rather than hard dependencies, so the documented CUDA Toolkit prerequisite stays the default and the install
size does not change for existing users — pip install "cuvslam[cu12]" is opt-in for environments without a toolkit.
Happy to make them unconditional dependencies instead if you would rather the wheel be self-contained; that is a
one-line change.

Both extras ship in every wheel, since a wheel cannot vary its metadata by the CUDA major it was built for. From
CUDA 13 on, NVIDIA publishes these packages unsuffixed (nvidia-cublas 13.x, the -cu13 names on PyPI are 0.0.1
placeholders), hence the different naming and the major-version bounds in the cu13 list.

2. Makes the declaration actually work (python/_cuda_libs.py, python/__init__.py)

Declaring the packages is not sufficient on its own: pip installs them into <site-packages>/nvidia/<component>/lib,
which the dynamic loader does not search, and auditwheel repair overwrites the RPATH with $ORIGIN/../cuvslam.libs,
so an RPATH set at build time would not survive either. _cuda_libs.preload() therefore loads them by absolute path
with RTLD_GLOBAL before the extension module is imported, which registers their sonames so libcuvslam.so resolves
against them — no LD_LIBRARY_PATH needed. It is a no-op when the nvidia-* packages are not installed, so a system
CUDA Toolkit keeps working exactly as before.

When the libraries cannot be resolved at all, the ImportError now names both ways to provide them instead of only
the missing soname:

ImportError: libcusolver.so.11: cannot open shared object file: No such file or directory

PyCuVSLAM links against the CUDA math libraries (cuBLAS, cuSOLVER, cuSPARSE) but does not bundle them.
Provide them either by installing a CUDA Toolkit whose major version matches this wheel's cu12/cu13 tag, or by
installing the matching pip packages:
    pip install 'cuvslam[cu12]'   # CUDA 12 wheels
    pip install 'cuvslam[cu13]'   # CUDA 13 wheels

3. Closes the CI gap (scripts/verify_pycuvslam_wheel_in_docker.sh)

The existing wheel check runs in cuvslam:local, a CUDA devel image that provides those libraries system-wide, so it
cannot distinguish a wheel that declares its CUDA dependencies from one that silently relies on the toolkit being
present. The script now adds a second stage: install the built wheel with the extra matching its +cu12/+cu13
version tag into a clean venv, import it, and require via /proc/self/maps that cuBLAS/cuSOLVER/cuSPARSE were loaded
from <site-packages>/nvidia/... rather than from the image. No workflow changes — nightly.yml already calls this
script, so it picks the stage up automatically.

The stage runs on x86_64 only. The nvidia-* math library wheels are not published for aarch64, where the libraries
come from JetPack instead, so the script decides that from uname -m before installing anything and prints SKIPPED:
with the reason. Deciding it up front rather than from how pip fails matters: "No matching distribution" is also what a
broken extras declaration looks like, so on x86_64 every resolution failure fails the job.

One note on cost: the stage downloads roughly 700 MB of nvidia-* wheels per x86_64 wheel-building matrix entry. Easy
to drop if you would rather keep nightly lean.

4. Documents it (README.md) — the install-from-wheels section now states that a CUDA Toolkit installation and the
wheel's matching cu12/cu13 extra are the two alternatives for providing the CUDA math libraries, and shows the
extra applied to the downloaded wheel file.

Tests

python/test/test_cuda_libs.py (5 tests) covers discovery order, ignoring unrelated components in the nvidia
namespace, the no-pip-packages no-op path, termination when libraries are unloadable, and a regression guard that the
CUDA math libraries are in fact loaded once cuvslam imports.

The four helper tests load _cuda_libs.py standalone via importlib rather than importing cuvslam, and the
regression guard runs import cuvslam plus the /proc/self/maps check in a subprocess, so a cuvslam already
imported by another test cannot mask a regression in import-time preloading.

Verification

Verified against the released v17.0.0 cu12 wheel on a machine with no CUDA math libraries installed at all
(ldconfig -p | grep -c "libcusolver\|libcublas"0), Ubuntu 24.04, Python 3.12, RTX 3090:

  • Before: ImportError: libcusolver.so.11: cannot open shared object file — the original report.
  • After patching the wheel's __init__.py/_cuda_libs.py in place and pip install nvidia-{cublas,cusolver,cusparse,nvjitlink}-cu12:
    import cuvslam succeeds, get_version()17.0.0+57f42cc, and warm_up_gpu() runs, so the pip-provided
    libraries are usable and not merely loadable.
  • /proc/self/maps confirms cuBLAS, cuBLASLt, cuSOLVER, cuSPARSE and nvJitLink all resolve from
    site-packages/nvidia/*/lib, with libcudart still coming from the vendored cuvslam.libs/.
  • With the nvidia-* packages absent, the new ImportError message is produced.
  • The Python test suite passes against that patched wheel (53 tests; test_map/test_tracking were not run, they
    need scipy, which was not installed in the throwaway venv).
  • pip install "<wheel>[cu12]" was exercised against a wheel with the new metadata to confirm the extras resolve
    through a direct wheel path, which is the form the CI stage uses.
  • pre-commit run --files ... passes on all changed files.

The full nightly path (build wheel → new verify stage) has not been run here; it needs the cuvslam:local image and a
GPU builder.

The review round on top of that was verified separately: the four helper tests pass against a stub cuvslam package on
PYTHONPATH whose __init__.py raises, which is what confirms they no longer import the package, and the subprocess
guard fails on that stub with the child's traceback surfaced. bash -n is clean on the verify script.

Summary by CodeRabbit

  • New Features

    • Added CUDA 12 (cu12) and CUDA 13 (cu13) optional installation extras for required CUDA math libraries.
    • cuVSLAM now attempts to preload matching CUDA math libraries from pip-provided NVIDIA packages during import (when available).
  • Documentation

    • Rewrote wheel installation guidance to explain CUDA Toolkit vs. cu12/cu13 extras, including the required CUDA driver and Jetson notes.
    • Improved Docker wheel verification to re-install with the matching extra and validate expected libraries.
  • Tests

    • Added unit tests for library discovery/loading behavior and an import-time regression check.

libcuvslam.so links against cuBLAS, cuSOLVER and cuSPARSE, which are
excluded from the wheel during auditwheel repair and were neither
bundled nor declared anywhere. On a machine without a CUDA Toolkit
installation, `pip install cuvslam-*.whl` succeeds and `import cuvslam`
then fails with:

    ImportError: libcusolver.so.11: cannot open shared object file

Declare the missing libraries as cu12/cu13 extras so pip can provide
them, and load them from the nvidia-* pip layout before the extension
module is imported: pip installs them under <site-packages>/nvidia/*/lib,
which the dynamic loader does not search, so declaring them alone is not
enough. When they cannot be resolved at all, the ImportError now names
the two ways to provide them instead of just the missing soname.

The wheel verification script could not catch this because it runs in a
CUDA devel image that provides those libraries system-wide. It now also
installs the wheel with its CUDA extra into a clean environment and
requires that the loaded libraries are the pip-provided ones.

Fixes nvidia-isaac#70

Signed-off-by: behnam.asadi <behnam.asadi@gmail.com>
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

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

The package declares CUDA 12 and CUDA 13 extras, preloads pip-provided CUDA math libraries during import, reports installation guidance for missing libraries, and verifies wheel behavior through unit tests and Docker checks.

Changes

CUDA dependency resolution

Layer / File(s) Summary
CUDA wheel dependency contract
python/pyproject.toml, README.md
Adds cu12 and cu13 optional dependencies and documents CUDA Toolkit and wheel-extra installation paths.
CUDA library discovery and preload
python/_cuda_libs.py, python/CMakeLists.txt
Adds ordered discovery and global preloading of pip-installed CUDA libraries, and includes the helper in packaged files.
Import integration and diagnostics
python/__init__.py
Preloads CUDA libraries before importing the extension and appends installation guidance to missing-library errors.
Runtime and wheel validation
python/test/test_cuda_libs.py, scripts/verify_pycuvslam_wheel_in_docker.sh
Tests library discovery and import behavior, and verifies CUDA-extra installation and runtime mappings from a wheel.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Installer
  participant cuvslam
  participant _cuda_libs
  participant CUDA libraries
  Installer->>cuvslam: Install wheel with cu12/cu13 extra
  cuvslam->>_cuda_libs: preload()
  _cuda_libs->>CUDA libraries: Discover and load nvidia-* shared objects
  cuvslam->>cuvslam: Import libcuvslam.so
Loading

Suggested reviewers: hrabeti-nvidia, slepichev, vikuznetsov-nvidia

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: resolving CUDA math libraries from pip packages for wheels.
Linked Issues check ✅ Passed The changes meet issue #70 by adding CUDA 12/13 extras, preloading pip libs, improving import guidance, and adding clean-wheel verification.
Out of Scope Changes check ✅ Passed The modified files stay focused on CUDA library packaging, import behavior, docs, tests, and verification, with no clear unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@python/test/test_cuda_libs.py`:
- Line 19: Update the tests around the module-level cuvslam import and the
import-side-effect assertion to run import cuvslam plus the /proc/self/maps
check in a fresh subprocess, preventing prior initialization from masking
regressions. Load _cuda_libs.py independently for the helper unit tests, and
keep those tests separate from the subprocess-based import validation.

In `@README.md`:
- Around line 127-133: Update the CUDA dependency instructions in README.md to
clearly state that users need either the matching CUDA Toolkit installation or
the wheel’s matching pip extra. Replace the generic package install commands
with the local-wheel installation form already demonstrated by the existing
example near the referenced lines, using the appropriate cu12 or cu13 extra.

In `@scripts/verify_pycuvslam_wheel_in_docker.sh`:
- Around line 112-116: The CUDA extra installation check in the wheel
verification script must not treat “No matching distribution” as a successful
verification. Remove the broad grep-based exit 0 from the pip failure path so
dependency-resolution failures fail the job; handle intentionally unsupported
architectures only through an explicit, narrowly scoped CI or matrix skip before
the pip install check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 8d178e7a-55e6-4e38-85ea-1d57c93518d4

📥 Commits

Reviewing files that changed from the base of the PR and between 7d2463f and 077f30b.

📒 Files selected for processing (7)
  • README.md
  • python/CMakeLists.txt
  • python/__init__.py
  • python/_cuda_libs.py
  • python/pyproject.toml
  • python/test/test_cuda_libs.py
  • scripts/verify_pycuvslam_wheel_in_docker.sh

Comment thread python/test/test_cuda_libs.py Outdated
Comment thread README.md Outdated
Comment thread scripts/verify_pycuvslam_wheel_in_docker.sh Outdated
Do not let a failed extra resolution pass wheel verification: "No matching
distribution" is what a broken extras declaration looks like too. Decide from
the architecture, before the install, that the nvidia-* math library wheels are
x86_64-only, and let every pip failure fail the job.

Run the import-time preload regression guard in a subprocess. The test module
imported cuvslam at module level, which ran preload() before the assertion, so
the guard could not fail. Load _cuda_libs.py standalone for the helper tests.

State in README.md that a CUDA Toolkit installation and the wheel's cu12/cu13
extra are alternatives, and drop "pip install cuvslam[cu12]", which resolves
against PyPI rather than the downloaded wheel.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@python/test/test_cuda_libs.py`:
- Around line 108-109: Add a scoped Ruff suppression comment for S603 to the
subprocess.run invocation in the import-side-effect probe, documenting that this
intentional call uses fixed values and preventing the lint failure.

In `@README.md`:
- Around line 124-130: Update the prerequisite documentation so the matching
cu12/cu13 pip-extra option is explicitly limited to x86_64 wheels. For supported
aarch64 Jetson wheels, direct users to JetPack or system-provided CUDA instead,
while retaining the CUDA Toolkit alternative and driver requirement where
applicable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: ca75e284-7095-409d-9760-7379c175d471

📥 Commits

Reviewing files that changed from the base of the PR and between 077f30b and d919069.

📒 Files selected for processing (3)
  • README.md
  • python/test/test_cuda_libs.py
  • scripts/verify_pycuvslam_wheel_in_docker.sh

Comment thread python/test/test_cuda_libs.py
Comment thread README.md Outdated
The nvidia-* CUDA math library wheels are published for aarch64 as well, so
"not published there" was the wrong reason to skip the check. The real one is
that the aarch64 wheels are SBSA builds while the aarch64 wheel matrix entries
are Jetson, where CUDA comes from JetPack. Say that in the script, and point
Jetson users in README.md at JetPack rather than at the extra.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
README.md (1)

144-146: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the matching CUDA extra here. pip install "$(echo cuvslam-*.whl)[cu12]" is hardcoded to cu12, so it won’t work for cu13 wheels. Show the tag-specific extra instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 144 - 146, Update the README installation example to
use the CUDA extra matching the wheel tag, rather than hardcoding [cu12]. Show
the tag-specific form so both cu12 and cu13 wheels are installed with their
corresponding extras.
scripts/verify_pycuvslam_wheel_in_docker.sh (1)

135-140: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Include nvJitLink in the provenance assertion.

The CUDA extras explicitly install nvidia-nvjitlink-*, but this check only requires cublas, cusolver, and cusparse paths. Since the Docker image provides system CUDA libraries, a missing pip-provided nvJitLink could be masked and let verification pass incorrectly. Add nvjitlink to the checked library set or derive the set from python/_cuda_libs.py.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/verify_pycuvslam_wheel_in_docker.sh` around lines 135 - 140, Extend
the unresolved-library set in the wheel provenance assertion to include
nvjitlink alongside cublas, cusolver, and cusparse, or reuse the authoritative
library list from _cuda_libs.py. Ensure missing pip-provided nvJitLink is
reported when system CUDA libraries mask its absence.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@README.md`:
- Around line 144-146: Update the README installation example to use the CUDA
extra matching the wheel tag, rather than hardcoding [cu12]. Show the
tag-specific form so both cu12 and cu13 wheels are installed with their
corresponding extras.

In `@scripts/verify_pycuvslam_wheel_in_docker.sh`:
- Around line 135-140: Extend the unresolved-library set in the wheel provenance
assertion to include nvjitlink alongside cublas, cusolver, and cusparse, or
reuse the authoritative library list from _cuda_libs.py. Ensure missing
pip-provided nvJitLink is reported when system CUDA libraries mask its absence.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 0b33ed4d-a808-4ece-b9fb-cc1ffed56f3f

📥 Commits

Reviewing files that changed from the base of the PR and between d919069 and d6e7ad6.

📒 Files selected for processing (2)
  • README.md
  • scripts/verify_pycuvslam_wheel_in_docker.sh

@behnamasadi

Copy link
Copy Markdown
Author

Both outside-diff findings are valid. Addressed, in one case for a different reason than the one given.

scripts/verify_pycuvslam_wheel_in_docker.sh — nvJitLink missing from the provenance assertion

Agreed, and the consequence is worse than "could be masked": it is guaranteed to be masked. The stage runs in
cuvslam:local, a CUDA devel image, so libnvJitLink.so is on the system loader path. Had nvidia-nvjitlink-* been
dropped from the extras, ctypes.CDLL on the pip cuSOLVER/cuSPARSE would still have succeeded by resolving nvJitLink
from the image, those two would have appeared in /proc/self/maps under site-packages/nvidia/..., and the stage
would have reported success for a wheel that fails on a user's machine without a toolkit — the exact scenario this
stage exists to rule out.

Taken the second option and derived the set from _cuda_libs.CUDA_COMPONENTS rather than extending the literal, so
a component added there is verified without anyone having to remember this script:

from cuvslam import _cuda_libs

nvidia_root = _cuda_libs.nvidia_root()
unresolved = [name for name in _cuda_libs.CUDA_COMPONENTS
              if os.path.join(nvidia_root, name, "lib") not in maps]

nvidia_root() is now called with no arguments, which is how preload() resolves it at import time, so the check
asserts against the same path production uses instead of recomputing it. The two sources stay independent in the way
that matters: _cuda_libs.py states what the wheel needs, pyproject.toml states what the extras deliver, and the
stage is what compares them. The failure message says cuvslam did not load instead of libcuvslam.so did not load,
since nvJitLink is pulled in by the preload rather than linked by libcuvslam.so directly.

README.md — the [cu12] example

The line already carried # (use the extra matching the wheel's tag: cu12 or cu13), so on the stated grounds this
would be a no-op. It is worth fixing on sharper grounds, though: a wheel cannot vary its metadata by CUDA major, so
both extras are declared in every wheel. pip install "<cu13 wheel>[cu12]" is therefore not an error and not
even a warning — pip resolves the extra and installs CUDA 12 math libraries against a CUDA 13 build. A wrong
copy-paste fails later, at import, with a mismatch that does not point back at the install command.

So the fix is not a generic placeholder, which is not copy-pasteable, but both commands with the hazard stated:

pip install cuvslam-*.whl
# ...or, without a CUDA Toolkit installation, with the CUDA math libraries from pip. Every wheel carries both
# extras, so pip accepts a mismatched one without an error and installs math libraries of the wrong CUDA major:
# pick the line matching the tag of the wheel downloaded above.
pip install "$(echo cuvslam-*.whl)[cu12]"   # cu12 wheels
pip install "$(echo cuvslam-*.whl)[cu13]"   # cu13 wheels

Verification: bash -n is clean on the script and the edited heredoc body compiles standalone; nvidia_root()
was checked against a simulated site-packages layout to confirm the no-argument form resolves to
<site-packages>/nvidia. The stage itself still needs the cuvslam:local image and a GPU builder, so it has not
been run end to end here.

Verify the pip provenance of every CUDA component the package declares, not
just cuBLAS/cuSOLVER/cuSPARSE. The stage runs in a CUDA devel image, so had
nvidia-nvjitlink-* been dropped from the extras, cuSOLVER and cuSPARSE would
still have loaded by resolving nvJitLink from the image and the check would
have passed for a wheel that fails without a toolkit. Deriving the set from
_cuda_libs.CUDA_COMPONENTS covers future components without a second edit
here, and resolving nvidia_root() the way preload() does asserts against the
path production actually uses.

Show both install extras in README.md. Every wheel declares both, since a
wheel cannot vary its metadata by CUDA major, so a mismatched extra is not an
error and installs math libraries of the wrong major silently.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 144-148: Update the README installation example so only the CUDA
extra matching the downloaded wheel tag is executable: comment out the
alternative cu12/cu13 command or replace both with one command that derives the
extra from the wheel tag. Preserve the guidance to select the matching CUDA
major and prevent copying the block from installing both extras.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 49ee8145-6b10-4800-8157-d4bb90f89b84

📥 Commits

Reviewing files that changed from the base of the PR and between d6e7ad6 and 6e8011d.

📒 Files selected for processing (2)
  • README.md
  • scripts/verify_pycuvslam_wheel_in_docker.sh

Comment thread README.md Outdated
Two active pip commands, one per CUDA major, meant copying the block whole
installed both extras and so both sets of math libraries. Reading the extra
off the wheel's own +cu12/+cu13 tag leaves one runnable command that cannot
be mismatched, using the same idiom the wheel verification script already
uses to pick the extra.
@behnamasadi

Copy link
Copy Markdown
Author

Valid, and it was a regression I introduced in the previous round: two active pip install lines make the block
install both extras when it is copied whole, which is the failure the change was meant to prevent, not a milder
version of it.

Fixed in 087b1b1, but not by commenting both out. That leaves nothing runnable and hands the reader back the same
choice that is the source of the error — the block would then be correct only for someone who already knows which
tag their wheel carries. Since the wheel filename states its CUDA major, the extra can be read off it, which removes
the class of mistake instead of documenting around it:

pip install cuvslam-*.whl
# ...or, without a CUDA Toolkit installation, with the CUDA math libraries from pip. The extra has to match the
# wheel's CUDA major: every wheel declares both cu12 and cu13, so pip accepts a mismatched one without an error
# and installs math libraries of the wrong major. Reading the extra off the wheel's own +cu12/+cu13 tag rather
# than typing it keeps the two in step:
wheel=$(echo cuvslam-*.whl)
pip install "$wheel[$(echo "$wheel" | grep -oE '\+cu[0-9]+' | tr -d '+')]"

One runnable command, no way to mismatch it, and it is the same idiom
scripts/verify_pycuvslam_wheel_in_docker.sh already uses to pick the extra it verifies
(grep -oE "\+cu[0-9]+" | tr -d "+"), so the documented install path and the one CI exercises are derived the same
way rather than by two independent conventions.

Both remaining lines are safe to copy together: the second is a superset of the first, so running both installs the
package once and adds the extra.

Verification: run against cuvslam-17.0.0+cu13-cp312-abi3-manylinux_2_39_x86_64.whl, the expansion is
pip install "cuvslam-17.0.0+cu13-...whl[cu13]" — the extra follows the wheel rather than the example.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 148-149: Update the README installation command around wheel
discovery to require exactly one matching cuvslam wheel before deriving the CUDA
extra. Reject both no-match cases, including the literal glob, and multiple
matches; only then extract the CUDA suffix and pass the single wheel with its
extra to pip.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: f27807e8-553b-478f-aed9-201c84991a5f

📥 Commits

Reviewing files that changed from the base of the PR and between 6e8011d and 087b1b1.

📒 Files selected for processing (1)
  • README.md

Comment thread README.md
Comment on lines +148 to +149
wheel=$(echo cuvslam-*.whl)
pip install "$wheel[$(echo "$wheel" | grep -oE '\+cu[0-9]+' | tr -d '+')]"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant README section with line numbers.
sed -n '136,160p' README.md | cat -n

echo
echo '--- shell behavior probe ---'
tmpdir="$(mktemp -d)"
cd "$tmpdir"

# Case 1: no matches
printf 'case 1 (no matches)\n'
shopt -u nullglob
wheel=$(echo cuvslam-*.whl)
printf 'wheel=<%s>\n' "$wheel"
printf 'tags=<%s>\n' "$(grep -oE '\+cu[0-9]+' <<<"$wheel" | tr -d '+')"

# Case 2: one match
printf '\ncase 2 (one match)\n'
touch 'cuvslam-a+cu12.whl'
wheel=$(echo cuvslam-*.whl)
printf 'wheel=<%s>\n' "$wheel"
printf 'tags=<%s>\n' "$(grep -oE '\+cu[0-9]+' <<<"$wheel" | tr -d '+')"
printf 'pip arg=<%s>\n' "$wheel[$(grep -oE '\+cu[0-9]+' <<<"$wheel" | tr -d '+')]"

# Case 3: two matches
printf '\ncase 3 (two matches)\n'
touch 'cuvslam-b+cu13.whl'
wheel=$(echo cuvslam-*.whl)
printf 'wheel=<%s>\n' "$wheel"
printf 'tags raw:\n'
grep -oE '\+cu[0-9]+' <<<"$wheel" | cat -n
printf 'tags stripped:\n'
grep -oE '\+cu[0-9]+' <<<"$wheel" | tr -d '+' | cat -n
printf 'pip arg=<%s>\n' "$wheel[$(grep -oE '\+cu[0-9]+' <<<"$wheel" | tr -d '+')]"

Repository: nvidia-isaac/cuVSLAM

Length of output: 1787


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '140,155p' README.md | cat -n

Repository: nvidia-isaac/cuVSLAM

Length of output: 946


Require a single wheel match before deriving the CUDA extra. wheel=$(echo cuvslam-*.whl) can expand to the literal glob when nothing matches, or to multiple filenames when more than one wheel is present; in the latter case the grep output is concatenated into an invalid pip install argument. Guard for exactly one wheel before building the extra.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 148 - 149, Update the README installation command
around wheel discovery to require exactly one matching cuvslam wheel before
deriving the CUDA extra. Reject both no-match cases, including the literal glob,
and multiple matches; only then extract the CUDA suffix and pass the single
wheel with its extra to pip.

@behnamasadi

Copy link
Copy Markdown
Author

I think this PR needs some human review. @slepichev @vikuznetsov-nvidia @hrabeti-nvidia

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.

Python wheel links cuBLAS/cuSOLVER/cuSPARSE but neither bundles nor declares them — import cuvslam fails on a clean install

1 participant