From 12a01a970a75be8c0ab3d5a251dd1e8dfbd2ef38 Mon Sep 17 00:00:00 2001 From: Pochung Chen Date: Sun, 28 Jun 2026 20:35:38 +0800 Subject: [PATCH 1/5] build: require GCC>=13 and CUDA 12/13 with early, actionable errors - Require GCC >= 13 for GNU host compilers (C++20), failing early with a message pointing to -DCMAKE_CXX_COMPILER. Clang/AppleClang unaffected. - Resolve CUDAToolkit before enable_language() and require CUDA >= 12.0 (device-side C++20 floor), explicitly supporting 12.x and 13.x: < 12 is a FATAL_ERROR, > 13 warns. - Emit an actionable error when no usable nvcc is found, explaining that enable_language(CUDA) only consults CMAKE_CUDA_COMPILER / CUDACXX / PATH (not the located toolkit libraries). Skipped when a compiler is pinned. - Choose the default CUDA architecture list per toolkit version: CUDA 13.0 removed offline support for compute capability < 7.5, so Volta sm_70 is only emitted for CUDA 12.x. - Report CUDA via the modern CUDAToolkit_* variables (+ nvcc path); the legacy CUDA_VERSION_STRING / CUDA_TOOLKIT_ROOT_DIR are unset by find_package(CUDAToolkit) and printed blank (#949). Co-Authored-By: Claude Opus 4.8 (1M context) --- CMakeLists.txt | 76 ++++++++++++++++++++++++++++++++++++--- CytnxBKNDCMakeLists.cmake | 11 ++++-- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fd914848..46d282269 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,19 +195,87 @@ option(DEV_MODE "Build testing dev_test.cpp with cytnx" OFF) # ##################################################################### project(CYTNX VERSION ${CYTNX_VERSION} LANGUAGES CXX C) +# ##################################################################### +# ## HOST COMPILER REQUIREMENT +# ##################################################################### +# Cytnx targets C++20 (CMAKE_CXX_STANDARD 20). The GCC floor is 13: earlier +# releases lack the C++20 library/feature support the codebase relies on. Only +# enforce this for GNU; Clang/AppleClang are validated separately on macOS. +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13) + message(FATAL_ERROR + "GCC >= 13 is required (C++20 support), but found GCC " + "${CMAKE_CXX_COMPILER_VERSION} at ${CMAKE_CXX_COMPILER}.\n" + "Install GCC 13+ and point CMake at it, e.g. " + "-DCMAKE_CXX_COMPILER=g++-13 (and -DCMAKE_C_COMPILER=gcc-13), " + "or set the CXX/CC environment variables.") +endif() + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) if(USE_CUDA) + # Resolve the CUDA toolkit up front (before enable_language) so we can both + # enforce the version requirement early and choose an architecture list the + # toolkit can actually compile. find_package(CUDAToolkit) does not require the + # CUDA language to be enabled; the later find_package in CytnxBKNDCMakeLists + # re-uses this cached result. + find_package(CUDAToolkit QUIET) + + # enable_language(CUDA) finds the compiler ONLY via CMAKE_CUDA_COMPILER, the + # CUDACXX environment variable, or nvcc on PATH -- it does not reuse the + # toolkit located above. Catch the "no usable nvcc" case here with an + # actionable message instead of CMake's terse "No CMAKE_CUDA_COMPILER could be + # found". Skip the check when the user pinned a compiler explicitly. + if(NOT CUDAToolkit_FOUND OR (NOT CUDAToolkit_NVCC_EXECUTABLE + AND NOT CMAKE_CUDA_COMPILER AND NOT DEFINED ENV{CUDACXX})) + message(FATAL_ERROR + "USE_CUDA is ON but no usable CUDA compiler (nvcc) could be found.\n" + "enable_language(CUDA) searches only CMAKE_CUDA_COMPILER, the CUDACXX " + "environment variable, and nvcc on PATH; it does not reuse the libraries " + "found by find_package(CUDAToolkit), so installed CUDA runtime/dev " + "packages alone are not enough.\n" + "Do one of the following, then delete the build directory (a stale " + "CMakeCache.txt caches the failed detection) and re-configure:\n" + " * pass -DCMAKE_CUDA_COMPILER=/path/to/nvcc " + "(e.g. /usr/local/cuda-12/bin/nvcc), or\n" + " * export CUDACXX=/path/to/nvcc, or\n" + " * put the CUDA bin directory first on PATH " + "(export PATH=/usr/local/cuda-12/bin:$PATH).") + endif() + + # CUDA requirement: >= 12.0, with 12.x and 13.x explicitly supported. The + # 12.0 floor comes from device-side C++20 (nvcc gained -std=c++20 in CUDA + # 12.0; 11.x tops out at C++17), matching CMAKE_CUDA_STANDARD 20. Fail early + # with an actionable message instead of a cryptic later C++20/arch error. + if(CUDAToolkit_VERSION_MAJOR LESS 12) + message(FATAL_ERROR + "CUDA Toolkit >= 12.0 is required (device-side C++20 support), but found " + "${CUDAToolkit_VERSION} at ${CUDAToolkit_BIN_DIR}.\n" + "Install CUDA 12 or 13 and select it with " + "-DCMAKE_CUDA_COMPILER=/path/to/cuda-12+/bin/nvcc (or set CUDACXX / put " + "the desired nvcc first on PATH).") + elseif(CUDAToolkit_VERSION_MAJOR GREATER 13) + message(WARNING + "CUDA Toolkit ${CUDAToolkit_VERSION} is newer than the versions Cytnx is " + "tested against (12.x and 13.x). The build will proceed; please report " + "any issues.") + endif() + message(STATUS " CUDA Toolkit: ${CUDAToolkit_VERSION} (supported: 12.x, 13.x)") + # Default to a portable fat binary unless the caller picked architectures via # -D, the cache, a preset's cacheVariables, or the CUDAARCHS environment # variable. This must run before enable_language(CUDA): afterwards # CMAKE_CUDA_ARCHITECTURES is never empty (CMake fills in its own default), so # the "not specified" case can no longer be detected. enable_language(CUDA) # reads CUDAARCHS on its own, so we only avoid shadowing it here, not copy it. - # The default embeds SASS for each supported real architecture (Volta sm_70 is - # the floor required by cuTENSOR/cuQuantum, up through Hopper sm_90) plus PTX - # of the newest (90-virtual) so the driver can JIT for newer/unknown GPUs. + # The default embeds SASS for each supported real architecture plus PTX of the + # newest (90-virtual) so the driver can JIT for newer/unknown GPUs. CUDA 13.0 + # removed offline support for compute capability < 7.5, so Volta sm_70 is only + # included for CUDA 12.x. if(NOT CMAKE_CUDA_ARCHITECTURES AND NOT DEFINED ENV{CUDAARCHS}) - set(CMAKE_CUDA_ARCHITECTURES 70-real 75-real 80-real 86-real 89-real 90-real 90-virtual) + if(CUDAToolkit_VERSION_MAJOR GREATER_EQUAL 13) + set(CMAKE_CUDA_ARCHITECTURES 75-real 80-real 86-real 89-real 90-real 90-virtual) + else() + set(CMAKE_CUDA_ARCHITECTURES 70-real 75-real 80-real 86-real 89-real 90-real 90-virtual) + endif() endif() enable_language(CUDA) # Disable generation of "--option-file" flag in compile_commands.json. diff --git a/CytnxBKNDCMakeLists.cmake b/CytnxBKNDCMakeLists.cmake index 9bfafb669..caa4b68ca 100644 --- a/CytnxBKNDCMakeLists.cmake +++ b/CytnxBKNDCMakeLists.cmake @@ -135,6 +135,9 @@ if(USE_CUDA) set(CYTNX_VARIANT_INFO "${CYTNX_VARIANT_INFO} UNI_CUDA") enable_language(CUDA) + # CUDA toolkit version is validated at the top level (CMakeLists.txt, before + # enable_language) so the architecture defaults can adapt to it; this call + # re-uses that cached result. find_package(CUDAToolkit REQUIRED) if(NOT DEFINED CMAKE_CUDA_STANDARD) set(CMAKE_CUDA_STANDARD 20) @@ -231,8 +234,12 @@ if(USE_CUDA) message( STATUS " Build CUDA Support: YES") - message( STATUS " - CUDA Version: ${CUDA_VERSION_STRING}") - message( STATUS " - CUDA Toolkit Root: ${CUDA_TOOLKIT_ROOT_DIR}") + # Use the modern CUDAToolkit_* variables: the legacy FindCUDA variables + # (CUDA_VERSION_STRING / CUDA_TOOLKIT_ROOT_DIR) are not set by + # find_package(CUDAToolkit) and would print blank. + message( STATUS " - CUDA Version: ${CUDAToolkit_VERSION}") + message( STATUS " - CUDA Toolkit bin dir: ${CUDAToolkit_BIN_DIR}") + message( STATUS " - CUDA compiler (nvcc): ${CMAKE_CUDA_COMPILER}") message( STATUS " - Internal macro switch: GPU/CUDA") FILE(APPEND "${CMAKE_BINARY_DIR}/cxxflags.tmp" "-DUNI_GPU\n" "") message( STATUS " - Cudatoolkit include dir: ${CUDAToolkit_INCLUDE_DIRS}") From 5436e8ba607b30e9b6337d45407dc7d2cc59b6f2 Mon Sep 17 00:00:00 2001 From: Pochung Chen Date: Sun, 28 Jun 2026 20:35:46 +0800 Subject: [PATCH 2/5] build(cmake): harden cuTENSOR/cuQuantum finders (#946) - FindCUTENSOR: remove dead lib/10.2 and lib/11 branches; derive the library subdir from the CUDA major version (lib/12, lib/13) instead of hardcoding 12; require cuTENSOR >= 2.0 by reading CUTENSOR_MAJOR/MINOR from the headers. - Derive CUTENSOR_FOUND / CUQUANTUM_FOUND from the actual find_library results via find_package_handle_standard_args instead of setting them TRUE unconditionally (which let a NOTFOUND silently pass the caller's REQUIRED check and link empty / "-NOTFOUND"). - FindCUQUANTUM: build CUQUANTUM_LIBRARIES conditionally (parity with FindCUTENSOR) so a missing lib does not appear as "...-NOTFOUND" on the link line. Co-Authored-By: Claude Opus 4.8 (1M context) --- cmake/Modules/FindCUQUANTUM.cmake | 18 +++++++-- cmake/Modules/FindCUTENSOR.cmake | 67 ++++++++++++++++++++++++++----- 2 files changed, 71 insertions(+), 14 deletions(-) diff --git a/cmake/Modules/FindCUQUANTUM.cmake b/cmake/Modules/FindCUQUANTUM.cmake index dc134ad93..057870fe1 100644 --- a/cmake/Modules/FindCUQUANTUM.cmake +++ b/cmake/Modules/FindCUQUANTUM.cmake @@ -49,6 +49,18 @@ find_library( ) message(STATUS "CUQUANTUM_TENSORNET_LIB: ${CUQUANTUM_TENSORNET_LIB}") message(STATUS "CUQUANTUM_CUSTATEVEC_LIB: ${CUQUANTUM_CUSTATEVEC_LIB}") -set(CUQUANTUM_LIBRARIES "${CUQUANTUM_TENSORNET_LIB};${CUQUANTUM_CUSTATEVEC_LIB}") -message(STATUS "ok") -set(CUQUANTUM_FOUND TRUE) +set(CUQUANTUM_LIBRARIES "") +if(CUQUANTUM_TENSORNET_LIB) + list(APPEND CUQUANTUM_LIBRARIES "${CUQUANTUM_TENSORNET_LIB}") +endif() +if(CUQUANTUM_CUSTATEVEC_LIB) + list(APPEND CUQUANTUM_LIBRARIES "${CUQUANTUM_CUSTATEVEC_LIB}") +endif() + +# CUQUANTUM_FOUND must reflect whether the libraries were actually located; +# both cuTensorNet and cuStateVec are linked, so both are required. Setting it +# unconditionally would let a NOTFOUND (e.g. an "...-NOTFOUND" entry on the link +# line) silently pass the caller's REQUIRED check. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CUQUANTUM + REQUIRED_VARS CUQUANTUM_TENSORNET_LIB CUQUANTUM_CUSTATEVEC_LIB CUQUANTUM_INCLUDE_DIRS) diff --git a/cmake/Modules/FindCUTENSOR.cmake b/cmake/Modules/FindCUTENSOR.cmake index f9d15e707..383a55b32 100644 --- a/cmake/Modules/FindCUTENSOR.cmake +++ b/cmake/Modules/FindCUTENSOR.cmake @@ -30,19 +30,53 @@ message(STATUS " cudaver: ${CUDAToolkit_VERSION_MAJOR}" ) if(EXISTS "${CUTENSOR_ROOT}/lib") set(CUTNLIB_DIR "lib/") endif() -if((${CUDAToolkit_VERSION_MAJOR} LESS_EQUAL 10)) - set(CUTNLIB_DIR "${CUTNLIB_DIR}10.2") -elseif((${CUDAToolkit_VERSION_MAJOR} GREATER_EQUAL 11) AND (${CUDAToolkit_VERSION_MAJOR} LESS 12) AND (${CUDAToolkit_VERSION_MINOR} LESS_EQUAL 0)) - set(CUTNLIB_DIR "${CUTNLIB_DIR}11.0") -elseif((${CUDAToolkit_VERSION_MAJOR} GREATER_EQUAL 11) AND (${CUDAToolkit_VERSION_MAJOR} LESS 12) AND (${CUDAToolkit_VERSION_MINOR} GREATER_EQUAL 1)) - set(CUTNLIB_DIR "${CUTNLIB_DIR}11") -elseif((${CUDAToolkit_VERSION_MAJOR} GREATER_EQUAL 12)) - set(CUTNLIB_DIR "${CUTNLIB_DIR}12") +# Cytnx requires CUDA >= 12 (enforced in CMakeLists.txt). Use the toolkit major +# version as the cuTENSOR library subdir (lib/12, lib/13, ...) so both CUDA 12 +# and 13 resolve correctly, matching the 1.x-tarball / apt version-subdir +# layout. The older lib/10.2 and lib/11 branches were removed as dead code. For +# the cuTENSOR 2.x flat lib/ layout and apt multiarch paths, see issue #946. +if(${CUDAToolkit_VERSION_MAJOR} GREATER_EQUAL 12) + set(CUTNLIB_DIR "${CUTNLIB_DIR}${CUDAToolkit_VERSION_MAJOR}") +else() + message(FATAL_ERROR + "cuTENSOR support requires CUDA >= 12, but CUDAToolkit_VERSION_MAJOR is " + "'${CUDAToolkit_VERSION_MAJOR}'.") endif() set(CUTENSOR_LIBRARY_DIRS ${CUTENSOR_ROOT}/${CUTNLIB_DIR}) set(CUTENSOR_INCLUDE_DIRS ${CUTENSOR_ROOT}/include) +# Require cuTENSOR >= 2.0. The version macros (CUTENSOR_MAJOR/MINOR/PATCH) live +# in cutensor.h (older releases) or cutensor/types.h (newer ones); read whichever +# defines them and fail early on the 1.x API, which Cytnx no longer supports. +set(_cutensor_version_header "") +foreach(_hdr "${CUTENSOR_INCLUDE_DIRS}/cutensor.h" "${CUTENSOR_INCLUDE_DIRS}/cutensor/types.h") + if(EXISTS "${_hdr}") + file(STRINGS "${_hdr}" _cutensor_major_line REGEX "^#define[ \t]+CUTENSOR_MAJOR[ \t]+[0-9]+") + if(_cutensor_major_line) + set(_cutensor_version_header "${_hdr}") + break() + endif() + endif() +endforeach() + +if(_cutensor_version_header) + file(STRINGS "${_cutensor_version_header}" _cutensor_minor_line REGEX "^#define[ \t]+CUTENSOR_MINOR[ \t]+[0-9]+") + string(REGEX REPLACE ".*CUTENSOR_MAJOR[ \t]+([0-9]+).*" "\\1" CUTENSOR_VERSION_MAJOR "${_cutensor_major_line}") + string(REGEX REPLACE ".*CUTENSOR_MINOR[ \t]+([0-9]+).*" "\\1" CUTENSOR_VERSION_MINOR "${_cutensor_minor_line}") + set(CUTENSOR_VERSION "${CUTENSOR_VERSION_MAJOR}.${CUTENSOR_VERSION_MINOR}") + message(STATUS "cuTENSOR version: ${CUTENSOR_VERSION} (from ${_cutensor_version_header})") + if(CUTENSOR_VERSION_MAJOR LESS 2) + message(FATAL_ERROR + "cuTENSOR >= 2.0 is required, but found ${CUTENSOR_VERSION} in " + "${CUTENSOR_ROOT}. Install cuTENSOR 2.x and point CUTENSOR_ROOT at it.") + endif() +else() + message(WARNING + "Could not determine the cuTENSOR version from headers under " + "${CUTENSOR_INCLUDE_DIRS}; Cytnx requires cuTENSOR >= 2.0.") +endif() + # set libs: find_library( CUTENSOR_LIB @@ -60,6 +94,17 @@ find_library( ) message(STATUS "CUTENSOR_LIB: ${CUTENSOR_LIB}") message(STATUS "CUTENSORMg_LIB: ${CUTENSORMg_LIB}") -set(CUTENSOR_LIBRARIES "${CUTENSOR_LIB};${CUTENSORMg_LIB}") -message(STATUS "ok") -set(CUTENSOR_FOUND TRUE) +set(CUTENSOR_LIBRARIES "") +if(CUTENSOR_LIB) + list(APPEND CUTENSOR_LIBRARIES "${CUTENSOR_LIB}") +endif() +if(CUTENSORMg_LIB) + list(APPEND CUTENSOR_LIBRARIES "${CUTENSORMg_LIB}") +endif() + +# CUTENSOR_FOUND must reflect whether the core library was actually located: +# the main cutensor lib is mandatory, cutensorMg is optional. Setting it +# unconditionally would let a NOTFOUND silently pass the caller's REQUIRED check. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CUTENSOR + REQUIRED_VARS CUTENSOR_LIB CUTENSOR_INCLUDE_DIRS) From de94f3f8cca5a13a857368c156050d754eef7c52 Mon Sep 17 00:00:00 2001 From: Pochung Chen Date: Sun, 28 Jun 2026 20:35:53 +0800 Subject: [PATCH 3/5] docs(install): document CUDA>=12 / cuTENSOR>=2.0 and LD_LIBRARY_PATH for tarballs - Update the CUDA dependency list: CUDA toolkit >= 12.0 (12.x/13.x) and cuTENSOR >= 2.0. - Add a prominent note that tarball installs of cuTENSOR/cuQuantum need both CUTENSOR_ROOT/CUQUANTUM_ROOT (build) and LD_LIBRARY_PATH (runtime), since tarball libraries are not registered with ldconfig (#948 workaround). Use $CUTENSOR_ROOT/lib (cuTENSOR 2.x layout), noting lib/ as legacy. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/source/adv_install.rst | 38 +++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/docs/source/adv_install.rst b/docs/source/adv_install.rst index 1e928d2cc..b9c507781 100644 --- a/docs/source/adv_install.rst +++ b/docs/source/adv_install.rst @@ -29,9 +29,9 @@ In addition, you might want to install the following optional dependencies if yo [CUDA] -* Nvidia cuda library v10+ +* Nvidia CUDA toolkit >= 12.0 (12.x and 13.x supported) * Nvidia cuDNN library -* Nvidia cuTensor library +* Nvidia cuTENSOR library >= 2.0 * Nvidia cuQuantum library @@ -155,6 +155,40 @@ Similarly, cuqauantum (compile option -DUSE_CUTENSOR=ON), requires: $conda install -c nvidia cuquantum +.. important:: + + **If you install cuTENSOR and/or cuQuantum from NVIDIA tarballs** + (instead of conda), you must configure two separate paths -- one for the + build and one for runtime: + + 1. **Build time** -- point CMake at the extracted directories so the + libraries are found during configuration: + + .. code-block:: shell + + $export CUTENSOR_ROOT=/path/to/libcutensor- + $export CUQUANTUM_ROOT=/path/to/cuquantum- + + 2. **Runtime** -- the dynamic loader must also find the shared libraries + when you ``import cytnx`` (or run a C++ binary). Tarball libraries live + outside the system loader's default search path, and unlike conda they + are **not** registered with ``ldconfig``, so add their library + directories to ``LD_LIBRARY_PATH``: + + .. code-block:: shell + + $export LD_LIBRARY_PATH=$CUTENSOR_ROOT/lib:$CUQUANTUM_ROOT/lib:$LD_LIBRARY_PATH + + For cuTENSOR 2.x tarballs the libraries sit directly under ``lib/``, so + the path above is sufficient. Older cuTENSOR 1.x tarballs instead use a + per-CUDA subdirectory (``lib/``, e.g. ``lib/12``); use that + path if you are on the legacy layout. If ``LD_LIBRARY_PATH`` is not set + up, importing/running Cytnx fails with ``error while loading shared + libraries: libcutensor.so... cannot open shared object file``, or + silently binds to a mismatched system copy of the library if one is + present. Add these ``export`` lines to your shell profile (e.g. + ``~/.bashrc``) to make them persistent. + **Option B. Install dependencies via system package manager** You can also choose to install dependencies directly from the system package manager, but one needs to carefully resolve the dependency path for cmake to capture them successfully. From fe7b181bf1a13b9873b5609ea183df89cb9fe9ad Mon Sep 17 00:00:00 2001 From: Pochung Chen Date: Sun, 28 Jun 2026 21:18:32 +0800 Subject: [PATCH 4/5] docs(install): explain choosing between CUDA 12 and 13 when both are installed Add a troubleshooting subsection covering the two things to pin when multiple CUDA toolkits are present: the build compiler (-DCMAKE_CUDA_COMPILER / CUDACXX / PATH, with the pip/scikit-build form) and the runtime libraries (LD_LIBRARY_PATH vs the ldconfig/apt copy). Notes that the configure output reports the resolved toolkit and that a stale CMakeCache.txt must be wiped. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/source/adv_install.rst | 55 +++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/docs/source/adv_install.rst b/docs/source/adv_install.rst index b9c507781..f71d7924e 100644 --- a/docs/source/adv_install.rst +++ b/docs/source/adv_install.rst @@ -379,6 +379,61 @@ In the case that Cytnx is installed locally from binary build, not from anaconda Build troubleshooting ************************************* +Choosing between CUDA 12 and CUDA 13 when both are installed +------------------------------------------------------------------------------------- + +Cytnx supports both CUDA 12.x and 13.x. If more than one CUDA toolkit is present +(for example CUDA 12 installed via ``apt`` and CUDA 13 unpacked under +``/usr/local/cuda-13``), you must select the one to build against; otherwise +CMake picks up whichever ``nvcc`` it finds first on ``PATH``, which may not be +the one you intended. There are two independent things to pin -- the **build** +toolkit and the **runtime** libraries. + +**1. Build time -- select the compiler.** ``enable_language(CUDA)`` finds the +compiler only from ``CMAKE_CUDA_COMPILER``, the ``CUDACXX`` environment +variable, or ``nvcc`` on ``PATH`` (it does *not* reuse the libraries found by +``find_package(CUDAToolkit)``). Point it at the toolkit you want -- the rest of +the toolkit (libraries, headers, version) is then derived from that ``nvcc``: + +.. code-block:: shell + + # Use CUDA 13: + $cmake -S . -B build -DUSE_CUDA=ON -DCMAKE_CUDA_COMPILER=/usr/local/cuda-13/bin/nvcc + + # ...or use CUDA 12: + $cmake -S . -B build -DUSE_CUDA=ON -DCMAKE_CUDA_COMPILER=/usr/local/cuda-12/bin/nvcc + +Equivalent alternatives are ``export CUDACXX=/usr/local/cuda-13/bin/nvcc`` or +putting the desired ``bin`` directory first on ``PATH`` +(``export PATH=/usr/local/cuda-13/bin:$PATH``). For the ``pip`` build, pass it +through scikit-build-core: + +.. code-block:: shell + + $pip install . --config-settings=cmake.args="-DUSE_CUDA=ON;-DCMAKE_CUDA_COMPILER=/usr/local/cuda-13/bin/nvcc" + +The configure output reports the resolved toolkit (``CUDA Version``, +``CUDA Toolkit bin dir``, ``CUDA compiler (nvcc)``) -- check these match the +version you intended. CMake caches the detected compiler, so if you previously +configured with the wrong one, delete the build directory before reconfiguring; +a stale ``CMakeCache.txt`` keeps the old choice. + +**2. Runtime -- match the shared libraries.** Selecting the compiler does not +control which CUDA runtime libraries are loaded at run time. The dynamic loader +resolves ``libcudart.so.`` (and cuTENSOR/cuQuantum, etc.) via +``LD_LIBRARY_PATH``, then the ``ldconfig`` cache. If a different major version is +registered with ``ldconfig`` (commonly the ``apt`` copy under +``/usr/lib/x86_64-linux-gnu``), it can be loaded instead of the toolkit you +built against, causing version-skew crashes. To force the matching runtime, put +its library directory first: + +.. code-block:: shell + + $export LD_LIBRARY_PATH=/usr/local/cuda-13/lib64:$LD_LIBRARY_PATH + +(Adjust the path to the toolkit you built against; append the cuTENSOR/cuQuantum +``lib`` directories too if you enabled them -- see the tarball note above.) + CUDA device link fails with ``elfLink linker library load error`` ------------------------------------------------------------------------------------- From 10b1536fb11bd254f24d52388d786aebdcfc4cde Mon Sep 17 00:00:00 2001 From: Pochung Chen Date: Mon, 29 Jun 2026 10:02:22 +0800 Subject: [PATCH 5/5] =?UTF-8?q?build(cmake):=20address=20review=20?= =?UTF-8?q?=E2=80=94=20find=20cuTENSOR=202.x=20flat=20lib/,=20modern=20ver?= =?UTF-8?q?sion=20checks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses inline review feedback on PR #950: - FindCUTENSOR: search both the cuTENSOR 2.x flat lib/ and the legacy lib/ layouts (find_library PATH_SUFFIXES), so the required 2.x layout actually resolves; derive CUTENSOR_LIBRARY_DIRS from the located library; reference CUDAToolkit_VERSION_MAJOR by name (no in-if() dereference); register VERSION_VAR CUTENSOR_VERSION with find_package_handle_standard_args. - CMakeLists: use CUDAToolkit_VERSION with VERSION_LESS/VERSION_GREATER_EQUAL instead of comparing the major component as an integer. - docs(adv_install): note FindCUTENSOR searches both layouts so the build-time and runtime cuTENSOR paths agree. Co-Authored-By: Claude Opus 4.8 (1M context) --- CMakeLists.txt | 6 +++--- cmake/Modules/FindCUTENSOR.cmake | 29 +++++++++++++++++------------ docs/source/adv_install.rst | 9 ++++++--- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 46d282269..6ab70455a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -245,14 +245,14 @@ if(USE_CUDA) # 12.0 floor comes from device-side C++20 (nvcc gained -std=c++20 in CUDA # 12.0; 11.x tops out at C++17), matching CMAKE_CUDA_STANDARD 20. Fail early # with an actionable message instead of a cryptic later C++20/arch error. - if(CUDAToolkit_VERSION_MAJOR LESS 12) + if(CUDAToolkit_VERSION VERSION_LESS 12.0) message(FATAL_ERROR "CUDA Toolkit >= 12.0 is required (device-side C++20 support), but found " "${CUDAToolkit_VERSION} at ${CUDAToolkit_BIN_DIR}.\n" "Install CUDA 12 or 13 and select it with " "-DCMAKE_CUDA_COMPILER=/path/to/cuda-12+/bin/nvcc (or set CUDACXX / put " "the desired nvcc first on PATH).") - elseif(CUDAToolkit_VERSION_MAJOR GREATER 13) + elseif(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 14.0) message(WARNING "CUDA Toolkit ${CUDAToolkit_VERSION} is newer than the versions Cytnx is " "tested against (12.x and 13.x). The build will proceed; please report " @@ -271,7 +271,7 @@ if(USE_CUDA) # removed offline support for compute capability < 7.5, so Volta sm_70 is only # included for CUDA 12.x. if(NOT CMAKE_CUDA_ARCHITECTURES AND NOT DEFINED ENV{CUDAARCHS}) - if(CUDAToolkit_VERSION_MAJOR GREATER_EQUAL 13) + if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 13.0) set(CMAKE_CUDA_ARCHITECTURES 75-real 80-real 86-real 89-real 90-real 90-virtual) else() set(CMAKE_CUDA_ARCHITECTURES 70-real 75-real 80-real 86-real 89-real 90-real 90-virtual) diff --git a/cmake/Modules/FindCUTENSOR.cmake b/cmake/Modules/FindCUTENSOR.cmake index 383a55b32..c789afeee 100644 --- a/cmake/Modules/FindCUTENSOR.cmake +++ b/cmake/Modules/FindCUTENSOR.cmake @@ -27,23 +27,21 @@ else() endif() message(STATUS " cudaver: ${CUDAToolkit_VERSION_MAJOR}" ) -if(EXISTS "${CUTENSOR_ROOT}/lib") - set(CUTNLIB_DIR "lib/") -endif() -# Cytnx requires CUDA >= 12 (enforced in CMakeLists.txt). Use the toolkit major -# version as the cuTENSOR library subdir (lib/12, lib/13, ...) so both CUDA 12 -# and 13 resolve correctly, matching the 1.x-tarball / apt version-subdir -# layout. The older lib/10.2 and lib/11 branches were removed as dead code. For -# the cuTENSOR 2.x flat lib/ layout and apt multiarch paths, see issue #946. -if(${CUDAToolkit_VERSION_MAJOR} GREATER_EQUAL 12) - set(CUTNLIB_DIR "${CUTNLIB_DIR}${CUDAToolkit_VERSION_MAJOR}") +# Cytnx requires CUDA >= 12 (enforced in CMakeLists.txt) and cuTENSOR >= 2.0. +# Search both library layouts: cuTENSOR 2.x tarballs place the libraries +# directly under lib/, while 1.x tarballs and apt use a per-CUDA subdir +# (lib/, e.g. lib/12, lib/13). Listing both as find_library +# PATH_SUFFIXES lets the supported 2.x flat layout and the legacy versioned +# layout resolve for both CUDA 12 and 13. The older lib/10.2 and lib/11 +# branches were removed as dead code; apt multiarch paths remain (issue #946). +if(CUDAToolkit_VERSION_MAJOR GREATER_EQUAL 12) + set(CUTNLIB_DIR lib lib/${CUDAToolkit_VERSION_MAJOR}) else() message(FATAL_ERROR "cuTENSOR support requires CUDA >= 12, but CUDAToolkit_VERSION_MAJOR is " "'${CUDAToolkit_VERSION_MAJOR}'.") endif() -set(CUTENSOR_LIBRARY_DIRS ${CUTENSOR_ROOT}/${CUTNLIB_DIR}) set(CUTENSOR_INCLUDE_DIRS ${CUTENSOR_ROOT}/include) # Require cuTENSOR >= 2.0. The version macros (CUTENSOR_MAJOR/MINOR/PATCH) live @@ -94,6 +92,12 @@ find_library( ) message(STATUS "CUTENSOR_LIB: ${CUTENSOR_LIB}") message(STATUS "CUTENSORMg_LIB: ${CUTENSORMg_LIB}") +# Report the directory the library was actually found in (flat lib/ or the +# versioned lib/) rather than guessing a subdir, so callers and runtime +# guidance reference the real location. +if(CUTENSOR_LIB) + get_filename_component(CUTENSOR_LIBRARY_DIRS "${CUTENSOR_LIB}" DIRECTORY) +endif() set(CUTENSOR_LIBRARIES "") if(CUTENSOR_LIB) list(APPEND CUTENSOR_LIBRARIES "${CUTENSOR_LIB}") @@ -107,4 +111,5 @@ endif() # unconditionally would let a NOTFOUND silently pass the caller's REQUIRED check. include(FindPackageHandleStandardArgs) find_package_handle_standard_args(CUTENSOR - REQUIRED_VARS CUTENSOR_LIB CUTENSOR_INCLUDE_DIRS) + REQUIRED_VARS CUTENSOR_LIB CUTENSOR_INCLUDE_DIRS + VERSION_VAR CUTENSOR_VERSION) diff --git a/docs/source/adv_install.rst b/docs/source/adv_install.rst index f71d7924e..f97fd19d0 100644 --- a/docs/source/adv_install.rst +++ b/docs/source/adv_install.rst @@ -180,9 +180,12 @@ Similarly, cuqauantum (compile option -DUSE_CUTENSOR=ON), requires: $export LD_LIBRARY_PATH=$CUTENSOR_ROOT/lib:$CUQUANTUM_ROOT/lib:$LD_LIBRARY_PATH For cuTENSOR 2.x tarballs the libraries sit directly under ``lib/``, so - the path above is sufficient. Older cuTENSOR 1.x tarballs instead use a - per-CUDA subdirectory (``lib/``, e.g. ``lib/12``); use that - path if you are on the legacy layout. If ``LD_LIBRARY_PATH`` is not set + the path above is sufficient at both build and runtime. Older cuTENSOR + 1.x tarballs instead use a per-CUDA subdirectory (``lib/``, + e.g. ``lib/12``); on that legacy layout point ``LD_LIBRARY_PATH`` at the + subdirectory. Cytnx's ``FindCUTENSOR`` searches both layouts at build + time, so the runtime path matches whichever one was found. If + ``LD_LIBRARY_PATH`` is not set up, importing/running Cytnx fails with ``error while loading shared libraries: libcutensor.so... cannot open shared object file``, or silently binds to a mismatched system copy of the library if one is