Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
64ab222
feat: build the host-side crates from cutile-rs
elibol Aug 20, 2026
9a8269e
ci: retire the departed host crates from the lanes; fmt; trybuild bas…
elibol Aug 20, 2026
92f22fe
examples: build against the shared host-side crates
elibol Aug 20, 2026
c31b627
examples: rustfmt over the import rewrites
elibol Aug 20, 2026
67fc45d
examples: sweep the nested workspaces too
elibol Aug 21, 2026
84e9530
examples: catch the aligned-assignment manifests the sweep missed
elibol Aug 21, 2026
37c3e7f
examples: finish the shared-crate switch for all ten failing lanes
elibol Aug 21, 2026
597100b
fix: keep tile interop on the tile async surface
nihalpasham Aug 21, 2026
be8d592
ci: back to CUDA 13.1.1, the shared bindings floor is 12.0 now
elibol Aug 21, 2026
d5c1134
build: pin the shared crates at the 12.8-floor revision
elibol Aug 22, 2026
15255d5
build: repin the shared crates at the #233 conflict-resolution head
elibol Aug 28, 2026
a291e3c
build: align example locks to one version per crate
elibol Aug 29, 2026
74548da
ci: detach the retired host crates and name them in the license guard
elibol Aug 29, 2026
01c20d6
build: repin the shared crates at aaf1364
elibol Aug 31, 2026
a2e4ef0
examples: convert the three examples added on main to the shared crates
elibol Aug 31, 2026
400cc5b
deps: track cutile-rs main for the shared host crates
elibol Sep 2, 2026
ecf70b4
deps: pin the shared host crates to cutile-rs v0.3.1
elibol Sep 3, 2026
48369e9
docs, scaffold: name the shared crates' simt surface everywhere users…
nihalpasham Sep 3, 2026
095b811
retire the local host crates for real; CI, licensing, and docs follow…
nihalpasham Sep 3, 2026
f79eec0
guards: host-API paths in docs and templates; shared host-crate pin p…
nihalpasham Sep 3, 2026
78ea549
oxide-artifacts: consume the crates.io release everywhere; the in-tre…
nihalpasham Sep 3, 2026
f023f82
deps: take the shared host crates from the crates.io 0.3.1 release
nihalpasham Sep 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 3 additions & 2 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# Low-level CUDA FFI changes require review from the cuda-bindings maintainer.
/crates/cuda-bindings/ @nihalpasham
# The raw CUDA FFI crate (cuda-bindings) is shared with cutile-rs and lives in
# NVlabs/cutile-rs since the host-crate migration; review ownership for it is
# declared there. No path in this repository currently needs a code owner.
21 changes: 4 additions & 17 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,25 +46,12 @@ jobs:
export LIBRARY_PATH="${sysroot}/lib:${LIBRARY_PATH:-}"
export LD_LIBRARY_PATH="${sysroot}/lib:${LD_LIBRARY_PATH:-}"

# See unit-tests.yml for the rationale: shadow the link-time libcuda
# stub as `libcuda.so.1` so any doctests that reference `cu*` symbols
# load on a GPU-less runner.
if [ -n "${CUDA_TOOLKIT_PATH:-}" ] && [ -f "${CUDA_TOOLKIT_PATH}/lib64/stubs/libcuda.so" ]; then
stub_shadow="${RUNNER_TEMP}/libcuda-stub"
mkdir -p "${stub_shadow}"
ln -sf "${CUDA_TOOLKIT_PATH}/lib64/stubs/libcuda.so" "${stub_shadow}/libcuda.so.1"
export LD_LIBRARY_PATH="${stub_shadow}:${LD_LIBRARY_PATH}"
fi

# Docs must build warning-free (RUSTDOCFLAGS=-D warnings above). The
# generated cuda-bindings crate keeps its CUDA doc comments but allows
# the rustdoc lints they trip (see crates/cuda-bindings/src/lib.rs).
# Docs must build warning-free (RUSTDOCFLAGS=-D warnings above).
cargo doc --no-deps --workspace

# Run doctests. cuda-bindings is excluded: its doctests come from
# bindgen-generated C doxygen comments, and its `doctest = false`
# (which `cargo test --doc` otherwise bypasses) signals that intent.
cargo test --doc --workspace --exclude cuda-bindings
# Run doctests. The shared cuda-bindings is not a workspace member,
# so nothing here reaches its bindgen-generated doc comments.
cargo test --doc --workspace

# `rustc-codegen-cuda` is its own [workspace] (it links against
# rustc-private dylibs), so `--workspace` above never reaches it. fmt,
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/examples-compile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ jobs:
- name: Example lockfiles resolve identical dependency versions
run: bash scripts/sync-example-locks.sh --check

# Needed for cuda.h (bindgen in cuda-bindings) and the link-time
# libcuda.so stub. Same shape as unit-tests.yml / clippy.yml.
# Needed for cuda.h and curand.h: bindgen runs in the shared
# cuda-bindings build script. Same setup as unit-tests.yml / clippy.yml.
- name: Install CUDA toolkit
uses: Jimver/cuda-toolkit@v0.2.35
id: cuda-toolkit
Expand Down
51 changes: 51 additions & 0 deletions .github/workflows/status-guard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,54 @@ jobs:
# exactly the dependency this job exists to keep out of the graph.
- name: Verify a kernel-only crate builds with no host surface
run: bash scripts/check-device-only-build.sh

# cuda-bindings, cuda-core, and cuda-async are shared with cutile-rs. Their
# roots carry cutile's Tile API and the cuda-oxide surface lives under
# `simt`, so an old root path (`cuda_core::LaunchConfig`,
# `cuda_async::device_operation::...`) either fails to compile or binds the
# Tile-side type. Nothing compiles book, README, or `cargo oxide new`
# snippets, which is how some forty stale lines outlived the crate switch.
host-api-paths:
name: host API paths in docs and templates
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Clone repository
uses: actions/checkout@v4

# Reads sources only: no rustup, no cargo, no CUDA toolkit.
- name: Verify docs and templates spell the shared crates' simt paths
run: bash scripts/check-host-api-paths.sh

# The shared host-crate release is named once in the root workspace and
# copied into every example manifest and into the `cargo oxide new`
# templates. A drifted example resolves a second runtime and breaks the
# shared example build cache; a drifted scaffold hands each new project a
# runtime the generated code was not written against.
shared-crate-pin-parity:
name: shared host-crate pin parity
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Clone repository
uses: actions/checkout@v4

# Reads sources only: no rustup, no cargo, no CUDA toolkit.
- name: Verify every shared-crate pin agrees with the root workspace
run: bash scripts/check-shared-crate-pin.sh

# crates/oxide-artifacts is only the publish source now; the backend writes
# and the shared cuda-core reads through the crates.io release. An in-tree
# bump that is not published and repointed reaches no consumer, so the
# in-tree version, both manifests, and every lock must agree.
oxide-artifacts-parity:
name: oxide-artifacts release parity
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Clone repository
uses: actions/checkout@v4

# Reads sources only: no rustup, no cargo, no CUDA toolkit.
- name: Verify the in-tree crate matches the consumed release
run: bash scripts/check-oxide-artifacts-parity.sh
45 changes: 12 additions & 33 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ jobs:
# no live GPU. `needs_cuda: true` installs the CUDA toolkit for build-
# time bindgen (every crate that transitively depends on
# `cuda-bindings` needs `cuda.h` to compile). `test_args` overrides
# the default `--all-targets`, used by `cuda-core` to skip its
# GPU-only `tests/vmm_p2p.rs` integration test.
# the default `--all-targets` where a crate needs a narrower set.
#
# cuda-bindings, cuda-core, and cuda-async are the shared host-side
# crates from cutile-rs now; their unit tests run in cutile-rs CI.
#
# Crates intentionally not in this matrix:
# * `cuda-bindings` — generated sys bindings covered transitively.
# * `fuzzer` — differential-testing infra with no unit tests.
# * `rustc-codegen-cuda` — its own [workspace] that links against
# `rustc-private` dylibs; covered by the separate job below.
Expand Down Expand Up @@ -64,9 +65,10 @@ jobs:
- package: mir-transforms
- package: nvvm-transforms
# `default = []`, but every consumer turns the object features on:
# rustc-codegen-cuda and cuda-core take `object-write`, cuda-core
# also `object-read`. Testing the default set alone skips the eight
# ELF emit/extract tests that cover the configuration actually built.
# rustc-codegen-cuda takes `object-write`, and the shared cuda-core
# (cutile-rs, via its crates.io oxide-artifacts) takes `object-read`.
# Testing the default set alone skips the eight ELF emit/extract
# tests that cover the configuration actually built.
- package: oxide-artifacts
test_args: --all-targets --features object
- package: reserved-oxide-symbols
Expand All @@ -91,14 +93,6 @@ jobs:
# Running it on a runner with NO toolkit installed is the
# regression gate for issue #87.
- package: cargo-oxide
# async DeviceOperation pipeline; transitively pulls cuda-bindings
- package: cuda-async
needs_cuda: true
# CUDA driver wrappers; `--lib` skips the GPU-only VMM/P2P
# integration test in `tests/vmm_p2p.rs`.
- package: cuda-core
needs_cuda: true
test_args: --lib

steps:
- name: Clone repository
Expand Down Expand Up @@ -137,25 +131,10 @@ jobs:
export LIBRARY_PATH="${sysroot}/lib:${LIBRARY_PATH:-}"
export LD_LIBRARY_PATH="${sysroot}/lib:${LD_LIBRARY_PATH:-}"

# cuda-bindings emits `cargo:rustc-link-lib=dylib=cuda`, and the
# linker stamps the stub's SONAME (`libcuda.so.1`) into the test
# binary's DT_NEEDED. The CUDA dev sub-packages only ship the
# link-time stub named `libcuda.so`, with no `libcuda.so.1` alias.
# Binaries that actually reference `cu*` symbols (cuda-core,
# cuda-async) keep the NEEDED entry and fail to load at runtime
# on a GPU-less runner. Binaries whose `cu*` calls were pruned by
# `--as-needed` (e.g. cuda-host's tests) load fine without it.
# Create a writable shadow with the `libcuda.so.1` filename
# pointing at the stub, and prepend it to LD_LIBRARY_PATH. The
# stub returns errors for any real driver call, which is fine
# because the unit tests selected here never invoke one.
if [ -n "${CUDA_TOOLKIT_PATH:-}" ] && [ -f "${CUDA_TOOLKIT_PATH}/lib64/stubs/libcuda.so" ]; then
stub_shadow="${RUNNER_TEMP}/libcuda-stub"
mkdir -p "${stub_shadow}"
ln -sf "${CUDA_TOOLKIT_PATH}/lib64/stubs/libcuda.so" "${stub_shadow}/libcuda.so.1"
export LD_LIBRARY_PATH="${stub_shadow}:${LD_LIBRARY_PATH}"
fi

# No libcuda shadowing: the shared cuda-bindings (cutile-rs) loads
# libcuda at run time through libloading, so test binaries carry no
# DT_NEEDED on `libcuda.so.1` and load on a driverless runner. The
# tests that need a real driver are `#[ignore]`d.
cargo test -p ${{ matrix.package }} ${{ matrix.test_args || '--all-targets' }}

# End-to-end proof for issue #87: on this runner there is no CUDA
Expand Down
42 changes: 15 additions & 27 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,10 @@ workflows:
just check
```

It needs a CUDA toolkit, `cargo-deny`, and `python3` on `PATH`; it does not
need a GPU -- the CUDA-linked test packages shadow the toolkit's `libcuda` stub
when no driver is present. Individual recipes exist for each piece, and
It needs a CUDA toolkit (13.0 or newer, with the cuRAND headers), `cargo-deny`,
and `python3` on `PATH`; it does not need a GPU or a driver: the shared
`cuda-bindings` crate loads `libcuda` at run time, so test binaries load without
one. Individual recipes exist for each piece, and
`just --list` shows them with a one-line description each.

A few CI jobs deliberately stay outside `just check` -- ones that need the
Expand Down Expand Up @@ -209,30 +210,17 @@ that script.
`smoketest.sh`; CI runs it as the `status-guard / smoketest example contract`
job.

#### Running the driver-linked crates without a GPU

Most crates test on a machine with no GPU and no NVIDIA driver. `cuda-core`,
`cuda-host`, and `cuda-async` link the CUDA driver, so their test binaries need
`libcuda.so.1` at load time even when no test calls the driver:

```text
error while loading shared libraries: libcuda.so.1: cannot open shared object file
```

The toolkit ships only the link-time stub `libcuda.so`, with no `libcuda.so.1`
alias, while the linker stamps that SONAME into the binary. Point the loader at a
directory that supplies the name:

```bash
mkdir -p /tmp/libcuda-stub
ln -sf "$CUDA_TOOLKIT_PATH/lib64/stubs/libcuda.so" /tmp/libcuda-stub/libcuda.so.1
export LD_LIBRARY_PATH="/tmp/libcuda-stub:$LD_LIBRARY_PATH"
```

The stub only satisfies the loader; tests that need a real driver are already
`#[ignore]`d, so the suites run unchanged. `.github/workflows/unit-tests.yml`
does the same thing for CI and remains the source of truth for how those jobs
are configured.
#### Running the CUDA-dependent crates without a GPU

Most crates test on a machine with no GPU and no NVIDIA driver. `cuda-host`
and `cuda-macros` build against the shared `cuda-bindings` crate from
cutile-rs, which needs `cuda.h` and `curand.h` from a CUDA 13.0+ toolkit at
build time but loads `libcuda` at run time through `libloading`. The test
binaries therefore carry no `libcuda.so.1` dependency and load without a
driver; tests that need a real driver are `#[ignore]`d. A driver call made
without `libcuda` present fails with `CUDA_ERROR_NOT_INITIALIZED`, and the
error's `Display` names the library candidates the loader tried.
`.github/workflows/unit-tests.yml` runs the same suites on driverless runners.

### Dependencies

Expand Down
Loading
Loading