The CUDA Compatibility Matrix Is a Four-Dimensional Problem, and Conan Is Built to Handle It
Source: isocpp
Every year, the ISO C++ community survey returns with the same result: dependency management is the top complaint. For most C++ projects, this means fighting over versioned headers, finding prebuilt binaries, or writing CMake find modules from scratch. For AI and machine learning projects that use CUDA, the problem compounds in a way that ordinary package management tooling was not designed to handle.
A talk at using std::cpp 2026 frames the solution as “one source checkout, one command, identical builds on every platform” using Conan and CMake. That promise is worth unpacking, because the CUDA compatibility problem is more structurally complex than simply adding a dependency.
Why CUDA Is Not a Normal Dependency
Most C++ dependencies have a single version axis. You want Boost 1.84, or something compatible with it. Conan, vcpkg, and most other package managers model this reasonably well with semver ranges and constraint solvers.
CUDA has four axes.
CUDA Toolkit version. This is the version of the headers, compiler (nvcc), and runtime library you build against. Common current versions are 11.8, 12.0, 12.2, and 12.4, each with meaningfully different capabilities and requirements.
Minimum GPU driver version. CUDA 12.0 requires driver 525.60.13 or newer on Linux. CUDA 12.4 requires 550.54.14 or newer. If your target machine has driver 520, you cannot run CUDA 12.0 code on it regardless of what you compiled against.
GPU compute capability. A binary compiled targeting compute capability 8.6 (Ampere, RTX 30 series) will not run optimally on compute capability 8.9 (Ada, RTX 40 series) unless you also embed PTX intermediate representation for JIT recompilation, which incurs startup overhead. CUDA 12.x dropped support for compute capabilities below 5.0 (Maxwell), so anything older than a GTX 900 series GPU is out entirely.
Host compiler version. CUDA 12.0 on Linux requires GCC 6.0 through 12.x. GCC 13+ with CUDA 12.0 produces errors. On Windows, MSVC 2019 or 2022 is required; Clang works but with restrictions depending on the CUDA release.
These four dimensions interact. You cannot resolve them independently. When you pick CUDA 12.4, you have implicitly committed to a minimum driver version, a host compiler range, and a set of supported GPU architectures. This is the compatibility matrix that the talk addresses, and it is why CUDA dependency management breaks tools that handle simpler version graphs.
What Conan 2.x Brings to This Problem
Conan’s architecture revolves around profiles and settings. A profile captures everything about the target environment: OS, architecture, compiler identity and version, build type. In Conan 2.x, you can define custom settings in settings.yml to extend this model.
For CUDA, the idiomatic approach is to treat the CUDA toolkit version and target architecture as first-class options in the conanfile.py, and let profile selection drive those values:
from conan import ConanFile
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
class InferenceProject(ConanFile):
name = "inference-engine"
version = "1.0"
settings = "os", "compiler", "build_type", "arch"
options = {
"cuda_version": ["11.8", "12.0", "12.2", "12.4"],
"cuda_arch": ["ANY"],
}
default_options = {
"cuda_version": "12.2",
"cuda_arch": "80;86;89;90",
}
def layout(self):
cmake_layout(self)
def generate(self):
tc = CMakeToolchain(self)
tc.variables["CUDA_ARCHITECTURES"] = str(self.options.cuda_arch)
tc.variables["CUDA_TOOLKIT_VERSION"] = str(self.options.cuda_version)
tc.generate()
deps = CMakeDeps(self)
deps.generate()
The compatibility selection is encoded in the recipe, not scattered across CI scripts and Dockerfiles. Switching from CUDA 12.0 to 12.4 becomes a profile change rather than a search through environment variable declarations. More importantly, the options mechanism means Conan’s conflict resolver can flag incompatibilities. If a downstream dependency requires cuda_version=11.8 and yours requires 12.2, Conan surfaces that at install time rather than at runtime when a mislinked binary crashes or silently produces wrong results.
CMake’s Modern CUDA Support
On the CMake side, the key shift happened in version 3.18 with the introduction of CMAKE_CUDA_ARCHITECTURES and native first-class CUDA language support through enable_language(CUDA).
The legacy path was FindCUDA, a CMake module that accumulated workarounds for every quirk in CUDA’s build system since the late 2000s. It was deprecated in CMake 3.10 and should not appear in new projects.
The modern path looks like this:
cmake_minimum_required(VERSION 3.18)
project(inference-engine LANGUAGES CXX CUDA)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CUDA_STANDARD 17)
# CUDA_ARCHITECTURES can be injected by Conan via CMakeToolchain
if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
set(CMAKE_CUDA_ARCHITECTURES "80;86;89;90")
endif()
find_package(CUDAToolkit REQUIRED)
add_library(kernels STATIC src/attention.cu src/matmul.cu)
target_link_libraries(kernels PUBLIC CUDA::cudart CUDA::cublas)
add_executable(infer src/main.cpp)
target_link_libraries(infer PRIVATE kernels)
The CUDA::cudart and CUDA::cublas targets come from the CUDAToolkit module and correctly handle include directories, link paths, and RPATH on all platforms. This is the interface Conan’s generated CMakeToolchain expects.
Setting CMAKE_CUDA_ARCHITECTURES to native will detect the GPU on the current build machine and target it specifically. That is useful for developer workstations but wrong for CI environments where you need binaries that run across multiple GPU generations. The Conan options pattern passes the architecture list into CMake as a variable derived from the profile, so the decision lives in the profile rather than in the CMakeLists.txt.
Alternatives and Their Trade-Offs
vcpkg has official CUDA ports and integrates well with Visual Studio on Windows via its MSBuild and CMake toolchain integration. For Windows-first projects using MSVC, vcpkg is competitive. Its weakness is that CUDA-dependent ports have lower coverage than Conan Center Index, and the variant system is less expressive than Conan’s options and settings mechanism for modeling multi-dimensional compatibility.
Spack, developed at Lawrence Livermore National Laboratory, has the deepest CUDA support of any package manager. You can install hdf5 +cuda cuda_arch=80,86 and Spack propagates compatible CUDA settings down the entire dependency tree. It can also manage multiple CUDA versions simultaneously on a single machine. The trade-off is complexity: Spack is an HPC tool designed for managing software environments on clusters, and its operational model reflects that. It is not a natural fit for a developer workstation or a containerized CI pipeline where Conan’s profile-per-environment model is more ergonomic.
Hunter, the CMake-first package manager, no longer sees active maintenance and is not a viable choice for new projects.
The “One Command” Reality
The pitch of “one source checkout, one command, identical builds” is achievable, but it depends on careful upfront work. In practice, cross-platform CUDA CI requires:
- A Conan profile per target environment, such as Linux GCC 11 with CUDA 12.2, or Windows MSVC 2022 with CUDA 12.2.
- A base Docker image or CI runner with the correct CUDA toolkit installed, since Conan cannot install GPU drivers or the CUDA toolkit itself on fresh machines.
- Explicit
cuda_archselection that covers all GPU generations you target in production.
With those pieces in place, the developer-facing command collapses to:
conan install . --profile=linux-cuda-12.2 -b missing
cmake --preset conan-release
cmake --build --preset conan-release
The profiles live in the repository, which means the compatibility matrix is versioned alongside the code. New team members and CI agents receive the same constraints without manual configuration steps.
What This Approach Does Not Solve
Conan manages build-time dependencies and compile flags. It cannot verify at install time that the machine’s GPU driver is compatible with the CUDA version selected; that failure still happens at runtime. TensorRT and cuDNN, which each carry their own version matrices layered on top of CUDA, require separate Conan recipes that may not be available on Conan Center Index, pushing teams toward custom recipe authorship.
The broader point holds, though. Conan’s architecture, with its separation of profile, settings, and requirements, maps more naturally onto the CUDA compatibility matrix than simpler tools do. The alternative is encoding all of that in CI environment variables and Dockerfile ARG statements, which produces systems that are harder to reason about and harder to change when NVIDIA releases a new toolkit version.
For C++ AI development, where CUDA version churn is ongoing and GPU architectures are multiplying, having compatibility constraints expressed in code that Conan can resolve and validate is a meaningful improvement over the accumulated shell script approach that most teams currently maintain.