This page collects the engineering conventions that keep NVIDIA cuVS C APIs stable, predictable, and easy to use from downstream projects and language bindings. Start with the Contributor Guide, then use this page when designing public C APIs, C wrappers, or C-facing documentation.
Most C API changes can be developed directly in this repository. Cross-project work may also require a local RAFT build or a downstream project that consumes the installed NVIDIA cuVS C headers and shared libraries.
If source builds are not being used, install the local NVIDIA cuVS C artifacts into the consuming project’s environment before testing the downstream change.
Public C APIs should be thin, ABI-stable wrappers around NVIDIA cuVS implementation code. Keep C headers free of C++ types, templates, namespaces, exceptions, and RAII-only ownership patterns.
Expose only C-compatible types:
Prefer explicit create and destroy functions for every opaque object that owns memory or other resources.
The C API is the stable boundary used by downstream integrations and NVIDIA cuVS language bindings. Add new functions or fields before removing old ones, avoid changing the meaning of existing parameters, and keep ABI compatibility in mind when changing public structs or exported symbols.
Prefer stateless functions that take all required state explicitly:
Avoid APIs that hide global state, allocate persistent internal state without an owning handle, or require callers to understand C++ object lifetimes.
When a C API creates an index, model, resource, or parameter object, expose matching operations for lifecycle and persistence in the same API family:
Keep C wrappers thin. Validate inputs and translate handles at the boundary, but leave expensive work in the underlying NVIDIA cuVS implementation.
Avoid hidden host-device copies and hidden synchronization. If a wrapper needs to synchronize, document that behavior clearly.
C APIs should be safe to call from multiple host threads when each thread uses its own cuvsResources_t instance. Treat cuvsResources_t as the boundary for streams, memory resources, communication handles, and library handles.
Avoid mutable process-wide state in C wrappers. If shared state is unavoidable, make ownership and synchronization explicit.
C APIs should preserve the stream-ordering behavior of the underlying NVIDIA cuVS implementation. Do not add hidden synchronization only to simplify wrapper code.
When a C function accepts cuvsResources_t, use the stream and resources associated with that handle. Work queued by the caller before the API should complete before internal work starts, and work queued by the caller after the API returns should wait for internal work that affects the result.
Every successful create call that returns an owning handle should have a matching destroy call in examples and tests:
Destroy functions should tolerate cleanup after partial setup when practical, and examples should release resources in the reverse order they were acquired.
Multi-GPU C APIs generally use one of two execution strategies:
APIs may support either strategy or both, but they should document which resource handle users are expected to create. Use cuvsMultiGpuResourcesSetMemoryPool to configure an RMM memory pool across devices managed by a single-process multi-GPU resource. Continue to use cuvsStreamSet, cuvsStreamGet, and cuvsStreamSync for stream ownership and synchronization through the supplied opaque resource handle.
Single-GPU C APIs should not require communication libraries or multi-GPU setup.
C APIs may call implementations that use JIT link-time optimization, but the C wrapper should not duplicate JIT LTO policy or expose C++ implementation details. Keep runtime behavior documented at the API level when JIT compilation can affect first-call latency or cache behavior.
For runtime and cache behavior, see JIT Compilation. For implementation guidance, see Link-time Optimization.
NVIDIA cuVS uses pre-commit to run formatting, linting, spelling, and copyright checks. Install it with conda:
Run checks before committing:
Run the full suite across the repository when needed:
You can also install the git hook:
C headers and C wrapper implementation files are checked by the same formatting, spelling, Doxygen, and copyright hooks used by the rest of NVIDIA cuVS.
Run Doxygen checks for public C API documentation:
codespell catches spelling issues. To apply suggested fixes interactively, run:
Use #include <cuvs/...> for public NVIDIA cuVS C headers. Keep public C headers minimal and avoid including private C++ implementation headers from the public C interface.
RAPIDS pre-commit hooks check copyright headers on modified tracked files. To run that check manually:
Public C APIs need direct test coverage because downstream projects and language bindings rely on their runtime and ABI behavior. Prefer tests that exercise public entry points, lifecycle functions, error paths, and resource cleanup.
C APIs should return cuvsError_t and should not let C++ exceptions cross the C boundary. Translate implementation failures into C error values and make sure callers can retrieve useful diagnostic information when available.
Destroy functions should avoid throwing or failing in ways that make cleanup unsafe.
Public C APIs require user-facing Doxygen documentation. Document the purpose, parameters, return values, ownership rules, matching destroy functions, and any constraints that affect correct use.
C++ Guidelines