diff --git a/cmake/Modules/FindCUQUANTUM.cmake b/cmake/Modules/FindCUQUANTUM.cmake index dc134ad93..abee325c9 100644 --- a/cmake/Modules/FindCUQUANTUM.cmake +++ b/cmake/Modules/FindCUQUANTUM.cmake @@ -49,6 +49,23 @@ 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) +# Report the directory a library was actually found in (mirrors FindCUTENSOR), +# rather than the earlier guessed ${CUQUANTUM_ROOT}/${CUTNLIB_DIR}. +if(CUQUANTUM_TENSORNET_LIB) + get_filename_component(CUQUANTUM_LIBRARY_DIRS "${CUQUANTUM_TENSORNET_LIB}" DIRECTORY) +endif() +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..738222484 100644 --- a/cmake/Modules/FindCUTENSOR.cmake +++ b/cmake/Modules/FindCUTENSOR.cmake @@ -27,22 +27,56 @@ else() endif() 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") -endif() +# Search both cuTENSOR library layouts: 2.x tarballs place the libraries +# directly under lib/, while older tarballs and apt use a per-CUDA-major +# subdir (lib/, e.g. lib/11, lib/12, lib/13). Listing both as +# find_library PATH_SUFFIXES resolves either layout for any CUDA major. The +# older minor-specific lib/10.2 and lib/11.0 special-cases were removed; the +# generic lib/ covers them (apt multiarch paths remain, issue #946). +# The CUDA-version floor is a separate policy decision (issue #962), enforced +# in CMakeLists.txt rather than gated here, so this finder stays policy-free. +set(CUTNLIB_DIR lib lib/${CUDAToolkit_VERSION_MAJOR}) -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}") + # CUTENSOR_MINOR may be absent/unmatched; default it to 0 rather than leaving + # CUTENSOR_VERSION malformed (e.g. "2."), which would break the VERSION_VAR + # comparison in find_package_handle_standard_args. + if(_cutensor_minor_line) + string(REGEX REPLACE ".*CUTENSOR_MINOR[ \t]+([0-9]+).*" "\\1" CUTENSOR_VERSION_MINOR "${_cutensor_minor_line}") + else() + set(CUTENSOR_VERSION_MINOR "0") + endif() + 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,24 @@ 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) +# 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}") +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 + VERSION_VAR CUTENSOR_VERSION)