From fb505c2f38fb4c0dbdd106e14668725bb330dfc4 Mon Sep 17 00:00:00 2001 From: Growl Date: Mon, 6 Jul 2026 17:24:41 +0800 Subject: [PATCH 1/8] Rewrite FindMKL.cmake --- CMakeLists.txt | 10 +- cmake/CollectBuildInfoVars.cmake | 2 +- cmake/modules/FindMKL.cmake | 337 ++++++++++++------ source/CMakeLists.txt | 9 +- .../source_base/test_parallel/CMakeLists.txt | 6 +- 5 files changed, 248 insertions(+), 116 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 05f29d1afeb..23d6a9a8456 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -335,6 +335,12 @@ if(DEBUG_INFO) endif() if(ENABLE_MPI) + if(NOT CMAKE_CROSSCOMPILING) + # FindMPI runs a probe executable to determine the MPI library version, + # which FindMKL.cmake uses to auto-detect the BLACS interface. + # When cross compiling, assume users know what they are doing. + set(MPI_DETERMINE_LIBRARY_VERSION TRUE) + endif() find_package(MPI COMPONENTS CXX REQUIRED) abacus_add_feature_definitions(__MPI) endif() @@ -542,9 +548,7 @@ if(USE_KML) find_package(KML REQUIRED COMPONENTS ${_kml_components}) abacus_add_feature_definitions(__KML) -elseif(MKLROOT) - set(MKL_INTERFACE lp64) - set(ENABLE_SCALAPACK ON) +elseif(MKLROOT OR MKL_ROOT) find_package(MKL REQUIRED) abacus_add_feature_definitions(__MKL) elseif(NOT USE_SW) diff --git a/cmake/CollectBuildInfoVars.cmake b/cmake/CollectBuildInfoVars.cmake index 79e925af1dc..792043227f0 100644 --- a/cmake/CollectBuildInfoVars.cmake +++ b/cmake/CollectBuildInfoVars.cmake @@ -165,7 +165,7 @@ else() set(ABACUS_ELPA_VERSION "no") endif() -if(MKLROOT) +if(MKL_FOUND) set(ABACUS_MKL_SUPPORT "yes (version unknown)") find_path(MKL_VERSION_HEADER mkl_version.h PATHS ${MKL_INCLUDE} NO_DEFAULT_PATH) if(MKL_VERSION_HEADER) diff --git a/cmake/modules/FindMKL.cmake b/cmake/modules/FindMKL.cmake index 5d8ccdcc9b4..6108148f151 100644 --- a/cmake/modules/FindMKL.cmake +++ b/cmake/modules/FindMKL.cmake @@ -1,129 +1,254 @@ -# - Find mkl -# Find the native MKL headers and libraries. +# Find the oneMKL components used by ABACUS. # -# MKL_INCLUDE - where to find mkl.h, etc. -# MKL_FOUND - True if mkl found. - -# find_package(MKL NO_MODULE) # try using official module first -if(NOT TARGET MKL::MKL) - -find_path(MKL_INCLUDE mkl_service.h HINTS ${MKLROOT}/include) - -find_library(MKL_CORE NAMES mkl_core HINTS ${MKLROOT}/lib ${MKLROOT}/lib/intel64) -if(CMAKE_CXX_COMPILER_ID MATCHES "Intel") - find_library(MKL_INTERFACE_LIB NAMES mkl_intel_lp64 HINTS ${MKLROOT}/lib ${MKLROOT}/lib/intel64) - find_library(MKL_THREAD NAMES mkl_intel_thread HINTS ${MKLROOT}/lib ${MKLROOT}/lib/intel64) - find_library(MKL_IOMP5 NAMES iomp5 - HINTS ENV CMPLR_ROOT - PATH_SUFFIXES lib lib/intel64 linux/compiler/lib/intel64_lin - ) +# ABACUS uses the LP64 BLAS/LAPACK, FFTW3 and, with MPI, BLACS/ScaLAPACK +# interfaces directly. This module therefore provides complete link closures: +# +# abacus::mkl BLAS, LAPACK and FFTW3 compatibility interfaces +# abacus::mkl_scalapack abacus::mkl plus BLACS, ScaLAPACK and MPI +# (available only when ENABLE_MPI is ON) +# +# Search roots: MKLROOT, MKL_ROOT, or the MKLROOT environment variable. +# +# Optional cache variables: +# MKL_LINK AUTO (default), static, or dynamic +# MKL_THREADING AUTO (default), sequential, gnu_thread, or intel_thread +# MKL_MPI AUTO (default), openmpi, intelmpi, or mpich +# + +include(FindPackageHandleStandardArgs) + +# Reuse targets configured by this module. ABACUS deliberately keeps its +# adapter targets separate from the provider-owned MKL:: namespace. +if(TARGET abacus::mkl) + set(MKL_LIBRARIES abacus::mkl) + if(ENABLE_MPI) + if(NOT TARGET abacus::mkl_scalapack) + message(FATAL_ERROR + "The existing ABACUS MKL configuration lacks abacus::mkl_scalapack " + "for an MPI build.") + endif() + set(MKL_LIBRARIES abacus::mkl_scalapack) + endif() + set(MKL_FOUND TRUE) + return() +endif() + +# ABACUS declares and calls LP64 Fortran-style symbols directly, so ILP64 is not +# ABI-compatible with its integer arguments. +if(DEFINED MKL_INTERFACE) + string(TOLOWER "${MKL_INTERFACE}" _mkl_integer_interface) + if(NOT _mkl_integer_interface STREQUAL "lp64") + message(FATAL_ERROR "ABACUS supports only MKL_INTERFACE=lp64.") + endif() +endif() + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(_mkl_interface_name mkl_gf_lp64) else() - find_library(MKL_INTERFACE_LIB NAMES mkl_gf_lp64 HINTS ${MKLROOT}/lib ${MKLROOT}/lib/intel64) - find_library(MKL_THREAD NAMES mkl_gnu_thread HINTS ${MKLROOT}/lib ${MKLROOT}/lib/intel64) - # With GCC we use system-installed GNU OpenMP + set(_mkl_interface_name mkl_intel_lp64) +endif() + +set(_mkl_root_hints "${MKLROOT}" "${MKL_ROOT}" "$ENV{MKLROOT}") +list(REMOVE_ITEM _mkl_root_hints "") +list(REMOVE_DUPLICATES _mkl_root_hints) + +set(MKL_LINK AUTO CACHE STRING "oneMKL link mode: AUTO, static, or dynamic") +set_property(CACHE MKL_LINK PROPERTY STRINGS AUTO static dynamic) +string(TOLOWER "${MKL_LINK}" _mkl_link) +if(NOT _mkl_link MATCHES "^(auto|static|dynamic)$") + message(FATAL_ERROR "MKL_LINK must be AUTO, static, or dynamic.") +endif() + +if(NOT DEFINED MKL_THREADING) + set(MKL_THREADING AUTO CACHE STRING + "oneMKL threading layer: AUTO, sequential, gnu_thread, or intel_thread") + set_property(CACHE MKL_THREADING PROPERTY STRINGS AUTO sequential gnu_thread intel_thread) +endif() +string(TOLOWER "${MKL_THREADING}" _mkl_threading) +if(_mkl_threading STREQUAL "auto") + set(_mkl_threading sequential) + if(USE_OPENMP) + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(_mkl_threading gnu_thread) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") + set(_mkl_threading intel_thread) + endif() + endif() +elseif(NOT _mkl_threading MATCHES "^(sequential|gnu_thread|intel_thread)$") + message(FATAL_ERROR "MKL_THREADING must be AUTO, sequential, gnu_thread, or intel_thread.") endif() if(ENABLE_MPI) - execute_process(COMMAND ${MPI_CXX_COMPILER} --showme:version - OUTPUT_VARIABLE MPI_VER_OUT - ERROR_VARIABLE MPI_VER_ERR) - if(MPI_VER_OUT MATCHES "Open MPI" OR MPI_VER_ERR MATCHES "Open MPI") - set(MKL_BLACS_LIB_NAME "mkl_blacs_openmpi_lp64") - else() - set(MKL_BLACS_LIB_NAME "mkl_blacs_intelmpi_lp64") + set(MKL_MPI AUTO CACHE STRING "oneMKL MPI interface: AUTO, openmpi, intelmpi, or mpich") + set_property(CACHE MKL_MPI PROPERTY STRINGS AUTO openmpi intelmpi mpich) + + string(TOLOWER "${MKL_MPI}" _mkl_mpi) + if(_mkl_mpi STREQUAL "auto") + if("${MPI_CXX_LIBRARY_VERSION_STRING}" MATCHES "Open MPI") + set(_mkl_mpi openmpi) + else() + set(_mkl_mpi intelmpi) + endif() + elseif(_mkl_mpi STREQUAL "mpich") + # MPICH uses Intel-MPI-compatible BLACS on Unix. + set(_mkl_mpi intelmpi) + elseif(NOT _mkl_mpi MATCHES "^(openmpi|intelmpi)$") + message(FATAL_ERROR "MKL_MPI must be AUTO, openmpi, intelmpi, or mpich.") endif() - find_library(MKL_SCALAPACK NAMES mkl_scalapack_lp64 HINTS ${MKLROOT}/lib ${MKLROOT}/lib/intel64) - find_library(MKL_BLACS NAMES ${MKL_BLACS_LIB_NAME} HINTS ${MKLROOT}/lib ${MKLROOT}/lib/intel64) + + set(_mkl_blacs_name mkl_blacs_${_mkl_mpi}_lp64) endif() -include(FindPackageHandleStandardArgs) -# handle the QUIETLY and REQUIRED arguments and set MKL_FOUND to TRUE -# if all listed variables are TRUE +# Re-run searches when a configuration axis or the selected MKL root changes. +# This avoids reusing a library cached for another link mode, threading layer, +# MPI ABI, or oneMKL installation. +set(_mkl_search_signature + "${_mkl_root_hints};${_mkl_link};${_mkl_interface_name};${_mkl_threading};${_mkl_blacs_name}" +) +if(DEFINED _MKL_SEARCH_SIGNATURE + AND NOT "${_MKL_SEARCH_SIGNATURE}" STREQUAL "${_mkl_search_signature}") + foreach( + _mkl_cache_var IN + ITEMS MKL_INCLUDE + MKL_FFTW_INCLUDE + MKL_INTERFACE_LIB + MKL_THREAD + MKL_CORE + MKL_SCALAPACK + MKL_BLACS) + unset(${_mkl_cache_var} CACHE) + endforeach() +endif() +set(_MKL_SEARCH_SIGNATURE "${_mkl_search_signature}" + CACHE INTERNAL "Configuration used for the current oneMKL search") +set(_mkl_saved_suffixes "${CMAKE_FIND_LIBRARY_SUFFIXES}") +if(_mkl_link STREQUAL "static") + set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") +elseif(_mkl_link STREQUAL "dynamic") + set(CMAKE_FIND_LIBRARY_SUFFIXES ".so") +endif() + +find_path(MKL_INCLUDE + NAMES mkl.h + HINTS ${_mkl_root_hints} + PATH_SUFFIXES include) +find_path(MKL_FFTW_INCLUDE + NAMES fftw3.h + HINTS ${_mkl_root_hints} + PATH_SUFFIXES include/fftw) +find_library(MKL_INTERFACE_LIB + NAMES ${_mkl_interface_name} + HINTS ${_mkl_root_hints} + PATH_SUFFIXES lib/intel64 lib) +find_library(MKL_THREAD + NAMES mkl_${_mkl_threading} + HINTS ${_mkl_root_hints} + PATH_SUFFIXES lib/intel64 lib) +find_library(MKL_CORE + NAMES mkl_core + HINTS ${_mkl_root_hints} + PATH_SUFFIXES lib/intel64 lib) if(ENABLE_MPI) - find_package_handle_standard_args(MKL DEFAULT_MSG MKL_INTERFACE_LIB MKL_THREAD MKL_CORE MKL_SCALAPACK MKL_BLACS MKL_INCLUDE) -else() - find_package_handle_standard_args(MKL MKL_INTERFACE_LIB MKL_THREAD MKL_CORE MKL_INCLUDE) + find_library(MKL_SCALAPACK + NAMES mkl_scalapack_lp64 + HINTS ${_mkl_root_hints} + PATH_SUFFIXES lib/intel64 lib) + find_library(MKL_BLACS + NAMES ${_mkl_blacs_name} + HINTS ${_mkl_root_hints} + PATH_SUFFIXES lib/intel64 lib) endif() +set(CMAKE_FIND_LIBRARY_SUFFIXES "${_mkl_saved_suffixes}") + +set(_mkl_required_vars MKL_INCLUDE MKL_FFTW_INCLUDE MKL_INTERFACE_LIB MKL_THREAD MKL_CORE) +if(ENABLE_MPI) + list(APPEND _mkl_required_vars MKL_SCALAPACK MKL_BLACS) +endif() +find_package_handle_standard_args(MKL REQUIRED_VARS ${_mkl_required_vars}) if(MKL_FOUND) - if(NOT TARGET MKL::INTERFACE_LIB) - add_library(MKL::INTERFACE_LIB UNKNOWN IMPORTED) - set_target_properties(MKL::INTERFACE_LIB PROPERTIES - IMPORTED_LOCATION "${MKL_INTERFACE_LIB}" - INTERFACE_INCLUDE_DIRECTORIES "${MKL_INCLUDE}") - endif() - if(NOT TARGET MKL::THREAD) - add_library(MKL::THREAD UNKNOWN IMPORTED) - set_target_properties(MKL::THREAD PROPERTIES - IMPORTED_LOCATION "${MKL_THREAD}" - INTERFACE_INCLUDE_DIRECTORIES "${MKL_INCLUDE}") - endif() - if(NOT TARGET MKL::CORE) - add_library(MKL::CORE UNKNOWN IMPORTED) - set_target_properties(MKL::CORE PROPERTIES - IMPORTED_LOCATION "${MKL_CORE}" - INTERFACE_INCLUDE_DIRECTORIES "${MKL_INCLUDE}") + set(_mkl_libraries ${MKL_INTERFACE_LIB} ${MKL_THREAD} ${MKL_CORE}) + if(ENABLE_MPI) + list(APPEND _mkl_libraries ${MKL_SCALAPACK} ${MKL_BLACS}) endif() - if(NOT TARGET MKL::MKL_SCALAPACK) - add_library(MKL::MKL_SCALAPACK UNKNOWN IMPORTED) - set_target_properties(MKL::MKL_SCALAPACK PROPERTIES - IMPORTED_LOCATION "${MKL_SCALAPACK}" - INTERFACE_INCLUDE_DIRECTORIES "${MKL_INCLUDE}") + set(_mkl_any_static FALSE) + set(_mkl_all_static TRUE) + foreach(_mkl_library IN LISTS _mkl_libraries) + if(_mkl_library MATCHES "\\.a$") + set(_mkl_any_static TRUE) + else() + set(_mkl_all_static FALSE) + endif() + endforeach() + if(_mkl_any_static AND NOT _mkl_all_static) + message( + FATAL_ERROR "The selected oneMKL libraries mix static and shared files. " + "Choose a consistent MKL_LINK mode or library set.") endif() - if(ENABLE_MPI AND NOT TARGET MKL::BLACS) - add_library(MKL::BLACS UNKNOWN IMPORTED) - set_target_properties(MKL::BLACS PROPERTIES - IMPORTED_LOCATION "${MKL_BLACS}" - INTERFACE_INCLUDE_DIRECTORIES "${MKL_INCLUDE}") + if(_mkl_link STREQUAL "static" AND NOT _mkl_all_static) + message(FATAL_ERROR "MKL_LINK=static did not select static oneMKL libraries.") + elseif(_mkl_link STREQUAL "dynamic" AND _mkl_all_static) + message(FATAL_ERROR "MKL_LINK=dynamic did not select shared oneMKL libraries.") endif() - if(MKL_IOMP5 AND NOT TARGET MKL::IOMP5) - add_library(MKL::IOMP5 UNKNOWN IMPORTED) - set_target_properties(MKL::IOMP5 PROPERTIES - IMPORTED_LOCATION "${MKL_IOMP5}") - endif() - add_library(MKL::MKL INTERFACE IMPORTED) - if (ENABLE_MPI) - set_property(TARGET MKL::MKL PROPERTY - INTERFACE_LINK_LIBRARIES - "-Wl,--start-group" - MKL::INTERFACE_LIB MKL::THREAD MKL::CORE MKL::MKL_SCALAPACK MKL::BLACS - "-Wl,--end-group" - ) - else() - set_property(TARGET MKL::MKL PROPERTY - INTERFACE_LINK_LIBRARIES - "-Wl,--start-group" - MKL::INTERFACE_LIB MKL::THREAD MKL::CORE - "-Wl,--end-group" - ) - endif() - if(TARGET MKL::IOMP5) - set_property(TARGET MKL::MKL APPEND PROPERTY - INTERFACE_LINK_LIBRARIES MKL::IOMP5) - endif() -endif() -if(ENABLE_MPI) - mark_as_advanced(MKL_INCLUDE MKL_INTERFACE_LIB MKL_THREAD MKL_CORE MKL_SCALAPACK MKL_BLACS) -else() - mark_as_advanced(MKL_INCLUDE MKL_INTERFACE_LIB MKL_THREAD MKL_CORE) -endif() + find_package(Threads REQUIRED) + set(_mkl_runtime Threads::Threads ${CMAKE_DL_LIBS}) + list(APPEND _mkl_runtime m) + if(NOT _mkl_threading STREQUAL "sequential") + find_package(OpenMP REQUIRED COMPONENTS CXX) + list(APPEND _mkl_runtime OpenMP::OpenMP_CXX) + endif() -endif() # MKL::MKL + function(_mkl_link_group output) + if(_mkl_all_static AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + list(JOIN ARGN "," _mkl_archives) + set(${output} "-Wl,--start-group,${_mkl_archives},--end-group" PARENT_SCOPE) + else() + set(${output} "${ARGN}" PARENT_SCOPE) + endif() + endfunction() + set(_mkl_base_archives ${MKL_INTERFACE_LIB} ${MKL_THREAD} ${MKL_CORE}) + _mkl_link_group(_mkl_base ${_mkl_base_archives}) + add_library(abacus_mkl INTERFACE) + add_library(abacus::mkl ALIAS abacus_mkl) + target_include_directories( + abacus_mkl + INTERFACE + "${MKL_INCLUDE}" + "${MKL_FFTW_INCLUDE}") + target_link_libraries(abacus_mkl INTERFACE ${_mkl_base} ${_mkl_runtime}) -# In oneAPI 2022, MKL_SCALAPACK might not be linked properly -if(NOT TARGET MKL::MKL_SCALAPACK) - find_library(MKL_SCALAPACK NAMES mkl_scalapack_lp64 HINTS ${MKLROOT}/lib ${MKLROOT}/lib/intel64) - message(STATUS "Found MKL_SCALAPACK: ${MKL_SCALAPACK}") - if(MKL_SCALAPACK) - # create an IMPORTED target that points to the discovered library file - add_library(MKL::MKL_SCALAPACK UNKNOWN IMPORTED) - set_target_properties(MKL::MKL_SCALAPACK PROPERTIES - IMPORTED_LOCATION "${MKL_SCALAPACK}" - INTERFACE_INCLUDE_DIRECTORIES "${MKL_INCLUDE}" - ) + if(ENABLE_MPI) + add_library(abacus_mkl_scalapack INTERFACE) + add_library(abacus::mkl_scalapack ALIAS abacus_mkl_scalapack) + target_include_directories( + abacus_mkl_scalapack + INTERFACE + "${MKL_INCLUDE}" + "${MKL_FFTW_INCLUDE}") + if(_mkl_all_static AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + _mkl_link_group(_mkl_cluster ${MKL_SCALAPACK} ${MKL_BLACS} ${_mkl_base_archives}) + target_link_libraries( + abacus_mkl_scalapack INTERFACE ${_mkl_cluster} MPI::MPI_CXX ${_mkl_runtime}) + else() + target_link_libraries( + abacus_mkl_scalapack INTERFACE + ${MKL_SCALAPACK} ${MKL_BLACS} abacus::mkl MPI::MPI_CXX) + endif() + set(MKL_LIBRARIES abacus::mkl_scalapack) + else() + set(MKL_LIBRARIES abacus::mkl) endif() endif() + +mark_as_advanced( + MKL_INCLUDE + MKL_FFTW_INCLUDE + MKL_INTERFACE_LIB + MKL_THREAD + MKL_CORE + MKL_SCALAPACK + MKL_BLACS) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 0337707b61a..6106f52fdfc 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -104,9 +104,8 @@ if(USE_KML) if(ENABLE_FLOAT_FFTW) list(APPEND _abacus_linalg_libs KML::FFTW3_FLOAT) endif() -elseif(MKLROOT) - list(APPEND _abacus_linalg_libs MKL::MKL) - list(APPEND _abacus_linalg_include_dirs ${MKL_INCLUDE} ${MKL_INCLUDE}/fftw) +elseif(MKL_FOUND) + list(APPEND _abacus_linalg_libs ${MKL_LIBRARIES}) if(CMAKE_CXX_COMPILER_ID MATCHES Intel) list(APPEND _abacus_linalg_libs ifcore) endif() @@ -177,6 +176,10 @@ foreach(_abacus_linalg_target IN ITEMS abacus_add_target_compile_requirements(${_abacus_linalg_target}) endforeach() +if(MKL_FOUND) + abacus_add_target_compile_requirements("${MKL_LIBRARIES}") +endif() + # ------------------------------------------------------------------------------ # Optional external feature libraries # ------------------------------------------------------------------------------ diff --git a/source/source_base/test_parallel/CMakeLists.txt b/source/source_base/test_parallel/CMakeLists.txt index e623826dd97..2c263888305 100644 --- a/source/source_base/test_parallel/CMakeLists.txt +++ b/source/source_base/test_parallel/CMakeLists.txt @@ -65,9 +65,9 @@ add_test(NAME MODULE_BASE_parallel_2d_test_para ) - # figure out the lib that provides BLACS - if(MKLROOT) - list(APPEND BLACS_LIB MKL::MKL) + # Select the same ScaLAPACK/BLACS provider as the main build. + if(MKL_FOUND) + set(BLACS_LIB ${MKL_LIBRARIES}) else() set(BLACS_LIB ScaLAPACK::ScaLAPACK) endif() From 9ff41d882d6f702d49470dda5fe05873caea0154 Mon Sep 17 00:00:00 2001 From: Growl Date: Wed, 8 Jul 2026 12:37:07 +0800 Subject: [PATCH 2/8] Report MKL BLACS interface; block mkl_threads with non-OpenMP build --- cmake/modules/FindMKL.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/modules/FindMKL.cmake b/cmake/modules/FindMKL.cmake index 6108148f151..aacb48ff369 100644 --- a/cmake/modules/FindMKL.cmake +++ b/cmake/modules/FindMKL.cmake @@ -97,6 +97,7 @@ if(ENABLE_MPI) endif() set(_mkl_blacs_name mkl_blacs_${_mkl_mpi}_lp64) + message(STATUS "oneMKL BLACS interface: ${_mkl_blacs_name}") endif() # Re-run searches when a configuration axis or the selected MKL root changes. @@ -192,10 +193,14 @@ if(MKL_FOUND) message(FATAL_ERROR "MKL_LINK=dynamic did not select shared oneMKL libraries.") endif() + # oneMKL requires pthread even with mkl_sequential find_package(Threads REQUIRED) set(_mkl_runtime Threads::Threads ${CMAKE_DL_LIBS}) list(APPEND _mkl_runtime m) if(NOT _mkl_threading STREQUAL "sequential") + if(NOT USE_OPENMP) + message(FATAL_ERROR "MKL_THREADING=${_mkl_threading} requires USE_OPENMP=ON.") + endif() find_package(OpenMP REQUIRED COMPONENTS CXX) list(APPEND _mkl_runtime OpenMP::OpenMP_CXX) endif() From ffd4a06cefa83cfce1cb2a8ab72bee515935615c Mon Sep 17 00:00:00 2001 From: Growl Date: Wed, 8 Jul 2026 13:08:59 +0800 Subject: [PATCH 3/8] Remove cache variable MKL_THREADING --- cmake/modules/FindMKL.cmake | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/cmake/modules/FindMKL.cmake b/cmake/modules/FindMKL.cmake index aacb48ff369..aa3e99beb59 100644 --- a/cmake/modules/FindMKL.cmake +++ b/cmake/modules/FindMKL.cmake @@ -11,7 +11,6 @@ # # Optional cache variables: # MKL_LINK AUTO (default), static, or dynamic -# MKL_THREADING AUTO (default), sequential, gnu_thread, or intel_thread # MKL_MPI AUTO (default), openmpi, intelmpi, or mpich # @@ -59,23 +58,15 @@ if(NOT _mkl_link MATCHES "^(auto|static|dynamic)$") message(FATAL_ERROR "MKL_LINK must be AUTO, static, or dynamic.") endif() -if(NOT DEFINED MKL_THREADING) - set(MKL_THREADING AUTO CACHE STRING - "oneMKL threading layer: AUTO, sequential, gnu_thread, or intel_thread") - set_property(CACHE MKL_THREADING PROPERTY STRINGS AUTO sequential gnu_thread intel_thread) -endif() -string(TOLOWER "${MKL_THREADING}" _mkl_threading) -if(_mkl_threading STREQUAL "auto") - set(_mkl_threading sequential) - if(USE_OPENMP) - if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(_mkl_threading gnu_thread) - elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") - set(_mkl_threading intel_thread) - endif() +# Keep MKL threading internal: derive it from ABACUS OpenMP support and the +# known compiler/runtime combinations. Unknown OpenMP runtimes use sequential MKL. +set(_mkl_threading sequential) +if(USE_OPENMP) + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(_mkl_threading gnu_thread) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Intel") + set(_mkl_threading intel_thread) endif() -elseif(NOT _mkl_threading MATCHES "^(sequential|gnu_thread|intel_thread)$") - message(FATAL_ERROR "MKL_THREADING must be AUTO, sequential, gnu_thread, or intel_thread.") endif() if(ENABLE_MPI) @@ -198,9 +189,6 @@ if(MKL_FOUND) set(_mkl_runtime Threads::Threads ${CMAKE_DL_LIBS}) list(APPEND _mkl_runtime m) if(NOT _mkl_threading STREQUAL "sequential") - if(NOT USE_OPENMP) - message(FATAL_ERROR "MKL_THREADING=${_mkl_threading} requires USE_OPENMP=ON.") - endif() find_package(OpenMP REQUIRED COMPONENTS CXX) list(APPEND _mkl_runtime OpenMP::OpenMP_CXX) endif() From 28ffd839ceb2be59e14e66fdbd514b1b51385323 Mon Sep 17 00:00:00 2001 From: Growl Date: Wed, 8 Jul 2026 13:59:21 +0800 Subject: [PATCH 4/8] Block MKL_BLACS auto-detection when cross-compiling --- cmake/modules/FindMKL.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/modules/FindMKL.cmake b/cmake/modules/FindMKL.cmake index aa3e99beb59..f74c350367b 100644 --- a/cmake/modules/FindMKL.cmake +++ b/cmake/modules/FindMKL.cmake @@ -75,6 +75,11 @@ if(ENABLE_MPI) string(TOLOWER "${MKL_MPI}" _mkl_mpi) if(_mkl_mpi STREQUAL "auto") + if(CMAKE_CROSSCOMPILING) + message( + FATAL_ERROR "CMake cannot auto-determine MKL-BLACS interface correctly with cross compiling. " + "Please manually pass -DMKL_MPI= flag to CMake.") + endif() if("${MPI_CXX_LIBRARY_VERSION_STRING}" MATCHES "Open MPI") set(_mkl_mpi openmpi) else() From f263a44896f44d5cf5074d99bdd36a538e18e215 Mon Sep 17 00:00:00 2001 From: Growl Date: Wed, 8 Jul 2026 14:17:40 +0800 Subject: [PATCH 5/8] Hide oneMKL internal result variables --- cmake/modules/FindMKL.cmake | 145 ++++++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 57 deletions(-) diff --git a/cmake/modules/FindMKL.cmake b/cmake/modules/FindMKL.cmake index f74c350367b..b89465dfb9a 100644 --- a/cmake/modules/FindMKL.cmake +++ b/cmake/modules/FindMKL.cmake @@ -96,28 +96,34 @@ if(ENABLE_MPI) message(STATUS "oneMKL BLACS interface: ${_mkl_blacs_name}") endif() -# Re-run searches when a configuration axis or the selected MKL root changes. -# This avoids reusing a library cached for another link mode, threading layer, -# MPI ABI, or oneMKL installation. -set(_mkl_search_signature - "${_mkl_root_hints};${_mkl_link};${_mkl_interface_name};${_mkl_threading};${_mkl_blacs_name}" -) -if(DEFINED _MKL_SEARCH_SIGNATURE - AND NOT "${_MKL_SEARCH_SIGNATURE}" STREQUAL "${_mkl_search_signature}") - foreach( - _mkl_cache_var IN - ITEMS MKL_INCLUDE - MKL_FFTW_INCLUDE - MKL_INTERFACE_LIB - MKL_THREAD - MKL_CORE - MKL_SCALAPACK - MKL_BLACS) - unset(${_mkl_cache_var} CACHE) - endforeach() -endif() -set(_MKL_SEARCH_SIGNATURE "${_mkl_search_signature}" - CACHE INTERNAL "Configuration used for the current oneMKL search") +# These are result variables of this finder, not user configuration inputs. +foreach(_mkl_result_var IN ITEMS + MKL_INCLUDE + MKL_FFTW_INCLUDE + MKL_INTERFACE_LIB + MKL_THREAD + MKL_CORE + MKL_SCALAPACK + MKL_BLACS) + if(DEFINED CACHE{${_mkl_result_var}}) + message(WARNING + "${_mkl_result_var} is an internal result of FindMKL.cmake and will be ignored.") + unset(${_mkl_result_var} CACHE) + endif() + unset(${_mkl_result_var}) +endforeach() + +foreach(_mkl_internal_var IN ITEMS + _abacus_mkl_include + _abacus_mkl_fftw_include + _abacus_mkl_interface_lib + _abacus_mkl_thread + _abacus_mkl_core + _abacus_mkl_scalapack + _abacus_mkl_blacs) + unset(${_mkl_internal_var}) + unset(${_mkl_internal_var} CACHE) +endforeach() set(_mkl_saved_suffixes "${CMAKE_FIND_LIBRARY_SUFFIXES}") if(_mkl_link STREQUAL "static") @@ -126,38 +132,63 @@ elseif(_mkl_link STREQUAL "dynamic") set(CMAKE_FIND_LIBRARY_SUFFIXES ".so") endif() -find_path(MKL_INCLUDE - NAMES mkl.h - HINTS ${_mkl_root_hints} - PATH_SUFFIXES include) -find_path(MKL_FFTW_INCLUDE - NAMES fftw3.h - HINTS ${_mkl_root_hints} - PATH_SUFFIXES include/fftw) -find_library(MKL_INTERFACE_LIB - NAMES ${_mkl_interface_name} - HINTS ${_mkl_root_hints} - PATH_SUFFIXES lib/intel64 lib) -find_library(MKL_THREAD - NAMES mkl_${_mkl_threading} - HINTS ${_mkl_root_hints} - PATH_SUFFIXES lib/intel64 lib) -find_library(MKL_CORE - NAMES mkl_core - HINTS ${_mkl_root_hints} - PATH_SUFFIXES lib/intel64 lib) +find_path(_abacus_mkl_include + NAMES mkl.h + PATHS ${_mkl_root_hints} + PATH_SUFFIXES include + NO_DEFAULT_PATH) + +find_path(_abacus_mkl_fftw_include + NAMES fftw3.h + PATHS ${_mkl_root_hints} + PATH_SUFFIXES include/fftw + NO_DEFAULT_PATH) + +find_library(_abacus_mkl_interface_lib + NAMES ${_mkl_interface_name} + PATHS ${_mkl_root_hints} + PATH_SUFFIXES lib/intel64 lib + NO_DEFAULT_PATH) + +find_library(_abacus_mkl_thread + NAMES mkl_${_mkl_threading} + PATHS ${_mkl_root_hints} + PATH_SUFFIXES lib/intel64 lib + NO_DEFAULT_PATH) + +find_library(_abacus_mkl_core + NAMES mkl_core + PATHS ${_mkl_root_hints} + PATH_SUFFIXES lib/intel64 lib + NO_DEFAULT_PATH) + if(ENABLE_MPI) - find_library(MKL_SCALAPACK - NAMES mkl_scalapack_lp64 - HINTS ${_mkl_root_hints} - PATH_SUFFIXES lib/intel64 lib) - find_library(MKL_BLACS - NAMES ${_mkl_blacs_name} - HINTS ${_mkl_root_hints} - PATH_SUFFIXES lib/intel64 lib) + find_library(_abacus_mkl_scalapack + NAMES mkl_scalapack_lp64 + PATHS ${_mkl_root_hints} + PATH_SUFFIXES lib/intel64 lib + NO_DEFAULT_PATH) + + find_library(_abacus_mkl_blacs + NAMES ${_mkl_blacs_name} + PATHS ${_mkl_root_hints} + PATH_SUFFIXES lib/intel64 lib + NO_DEFAULT_PATH) endif() + set(CMAKE_FIND_LIBRARY_SUFFIXES "${_mkl_saved_suffixes}") +set(MKL_INCLUDE "${_abacus_mkl_include}") +set(MKL_FFTW_INCLUDE "${_abacus_mkl_fftw_include}") +set(MKL_INTERFACE_LIB "${_abacus_mkl_interface_lib}") +set(MKL_THREAD "${_abacus_mkl_thread}") +set(MKL_CORE "${_abacus_mkl_core}") + +if(ENABLE_MPI) + set(MKL_SCALAPACK "${_abacus_mkl_scalapack}") + set(MKL_BLACS "${_abacus_mkl_blacs}") +endif() + set(_mkl_required_vars MKL_INCLUDE MKL_FFTW_INCLUDE MKL_INTERFACE_LIB MKL_THREAD MKL_CORE) if(ENABLE_MPI) list(APPEND _mkl_required_vars MKL_SCALAPACK MKL_BLACS) @@ -243,10 +274,10 @@ if(MKL_FOUND) endif() mark_as_advanced( - MKL_INCLUDE - MKL_FFTW_INCLUDE - MKL_INTERFACE_LIB - MKL_THREAD - MKL_CORE - MKL_SCALAPACK - MKL_BLACS) + _abacus_mkl_include + _abacus_mkl_fftw_include + _abacus_mkl_interface_lib + _abacus_mkl_thread + _abacus_mkl_core + _abacus_mkl_scalapack + _abacus_mkl_blacs) From c475041b143255dec3117c88758301106751b28a Mon Sep 17 00:00:00 2001 From: Growl Date: Wed, 8 Jul 2026 20:48:31 +0800 Subject: [PATCH 6/8] Use MKL_FOUND for oneMKL consumers --- CMakeLists.txt | 2 +- cmake/CollectBuildInfoVars.cmake | 4 ++-- python/pyabacus/src/ModuleNAO/CMakeLists.txt | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 23d6a9a8456..5c22f47c8e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -564,7 +564,7 @@ elseif(NOT USE_SW) endif() endif() -if(NOT USE_KML AND NOT MKLROOT AND NOT USE_SW) +if(NOT USE_KML AND NOT MKL_FOUND AND NOT USE_SW) find_package(FFTW3 REQUIRED) endif() diff --git a/cmake/CollectBuildInfoVars.cmake b/cmake/CollectBuildInfoVars.cmake index 792043227f0..5cf5f852489 100644 --- a/cmake/CollectBuildInfoVars.cmake +++ b/cmake/CollectBuildInfoVars.cmake @@ -190,9 +190,9 @@ else() set(ABACUS_LIBXC_VERSION "no") endif() -if(NOT USE_SW AND NOT MKLROOT AND FFTW3_VERSION) +if(NOT USE_SW AND NOT MKL_FOUND AND FFTW3_VERSION) set(ABACUS_FFTW_VERSION "yes (v${FFTW3_VERSION})") -elseif(NOT USE_SW AND NOT MKLROOT) +elseif(NOT USE_SW AND NOT MKL_FOUND) if(FFTW3_INCLUDE_DIR AND EXISTS "${FFTW3_INCLUDE_DIR}/fftw3.h") file(STRINGS "${FFTW3_INCLUDE_DIR}/fftw3.h" _fftw_ver_line REGEX "^#define[\t ]+FFTW_VERSION[\t ]+\"[^\"]+\"") if(_fftw_ver_line) diff --git a/python/pyabacus/src/ModuleNAO/CMakeLists.txt b/python/pyabacus/src/ModuleNAO/CMakeLists.txt index 2822ef9df6d..b8ee95319cf 100644 --- a/python/pyabacus/src/ModuleNAO/CMakeLists.txt +++ b/python/pyabacus/src/ModuleNAO/CMakeLists.txt @@ -26,7 +26,7 @@ add_library(naopack SHARED ) # link math_libs -if(MKLROOT) +if(MKL_FOUND) target_link_libraries(naopack MPI::MPI_CXX OpenMP::OpenMP_CXX @@ -52,4 +52,4 @@ target_compile_definitions(_nao_pack PRIVATE VERSION_INFO=${PROJECT_VERSION}) set_target_properties(naopack PROPERTIES INSTALL_RPATH "$ORIGIN") set_target_properties(_nao_pack PROPERTIES INSTALL_RPATH "$ORIGIN") -install(TARGETS _nao_pack naopack DESTINATION ${TARGET_PACK}/ModuleNAO) \ No newline at end of file +install(TARGETS _nao_pack naopack DESTINATION ${TARGET_PACK}/ModuleNAO) From a9904273d4ff5a846b74f682f871b76e18b861b6 Mon Sep 17 00:00:00 2001 From: Growl Date: Fri, 10 Jul 2026 12:30:10 +0800 Subject: [PATCH 7/8] CMake: Resolve DFT-D4 dependencies after math libraries --- .github/workflows/build_test_cmake.yml | 4 +- CMakeLists.txt | 78 +++++++++++++------------- cmake/modules/FindKML.cmake | 12 ++++ cmake/modules/FindMKL.cmake | 14 +++++ 4 files changed, 67 insertions(+), 41 deletions(-) diff --git a/.github/workflows/build_test_cmake.yml b/.github/workflows/build_test_cmake.yml index ea4ce366fd0..e9d9b1ab4f2 100644 --- a/.github/workflows/build_test_cmake.yml +++ b/.github/workflows/build_test_cmake.yml @@ -23,11 +23,11 @@ jobs: - tag: gnu external_toolchain_args: "" - build_args: "-DENABLE_LIBXC=ON -DENABLE_MLALGO=ON -DENABLE_LIBRI=ON" + build_args: "-DENABLE_LIBXC=ON -DENABLE_MLALGO=ON -DENABLE_LIBRI=ON -DENABLE_DFTD4=ON" name: "Build extra components with GNU toolchain" - tag: intel external_toolchain_args: "--with-intel" - build_args: "-DENABLE_LIBXC=ON -DENABLE_PEXSI=ON -DENABLE_MLALGO=ON -DENABLE_LIBRI=ON" + build_args: "-DENABLE_LIBXC=ON -DENABLE_PEXSI=ON -DENABLE_MLALGO=ON -DENABLE_LIBRI=ON -DENABLE_DFTD4=ON" name: "Build extra components with Intel toolchain" - tag: cuda diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c22f47c8e9..2514a2770e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -238,14 +238,10 @@ if(NOT DEFINED CMAKE_CXX_STANDARD) endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) +# Enable DFT-D4 languages before finding OpenMP. if(ENABLE_DFTD4) - # DFTD4 requires enabling C and Fortran to work enable_language(C) enable_language(Fortran) - # Avoid custom-lapack fallback when resolving DFT-D4 dependencies - find_package(BLAS REQUIRED) - find_package(LAPACK REQUIRED) - find_package(dftd4 4.2.0 REQUIRED) endif() macro(set_if_higher VARIABLE VALUE) @@ -363,6 +359,44 @@ if(USE_OPENMP) find_package(OpenMP REQUIRED) endif() +if(DEFINED ENV{MKLROOT} AND NOT DEFINED MKLROOT) + set(MKLROOT "$ENV{MKLROOT}") +endif() +if(USE_KML) + set(_kml_components BLAS LAPACK FFTW3) + if(ENABLE_MPI) + list(APPEND _kml_components ScaLAPACK) + endif() + if(ENABLE_FLOAT_FFTW) + list(APPEND _kml_components FFTW3_FLOAT) + endif() + + find_package(KML REQUIRED COMPONENTS ${_kml_components}) + abacus_add_feature_definitions(__KML) +elseif(MKLROOT OR MKL_ROOT) + find_package(MKL REQUIRED) + abacus_add_feature_definitions(__MKL) +elseif(NOT USE_SW) + find_package(Lapack REQUIRED) + # ScaLAPACK is a distributed-memory library and is only needed for the + # MPI build. A serial build (e.g. the native Windows serial version) + # must not require it. + if(ENABLE_MPI) + find_package(ScaLAPACK REQUIRED) + endif() + if(NOT CMAKE_CXX_COMPILER_ID MATCHES "GNU|Intel|Clang") + message(WARNING "Cannot determine the required Fortran runtime.") + endif() +endif() + +if(NOT USE_KML AND NOT MKL_FOUND AND NOT USE_SW) + find_package(FFTW3 REQUIRED) +endif() + +if(ENABLE_DFTD4) + find_package(dftd4 4.2.0 REQUIRED) +endif() + include(CheckLanguage) check_language(CUDA) if(CMAKE_CUDA_COMPILER) @@ -534,40 +568,6 @@ if(ENABLE_ASAN) add_link_options(-fsanitize=address) endif() -if(DEFINED ENV{MKLROOT} AND NOT DEFINED MKLROOT) - set(MKLROOT "$ENV{MKLROOT}") -endif() -if(USE_KML) - set(_kml_components BLAS LAPACK FFTW3) - if(ENABLE_MPI) - list(APPEND _kml_components ScaLAPACK) - endif() - if(ENABLE_FLOAT_FFTW) - list(APPEND _kml_components FFTW3_FLOAT) - endif() - - find_package(KML REQUIRED COMPONENTS ${_kml_components}) - abacus_add_feature_definitions(__KML) -elseif(MKLROOT OR MKL_ROOT) - find_package(MKL REQUIRED) - abacus_add_feature_definitions(__MKL) -elseif(NOT USE_SW) - find_package(Lapack REQUIRED) - # ScaLAPACK is a distributed-memory library and is only needed for the - # MPI build. A serial build (e.g. the native Windows serial version) - # must not require it. - if(ENABLE_MPI) - find_package(ScaLAPACK REQUIRED) - endif() - if(NOT CMAKE_CXX_COMPILER_ID MATCHES "GNU|Intel|Clang") - message(WARNING "Cannot determine the required Fortran runtime.") - endif() -endif() - -if(NOT USE_KML AND NOT MKL_FOUND AND NOT USE_SW) - find_package(FFTW3 REQUIRED) -endif() - if(ENABLE_FLOAT_FFTW) abacus_add_feature_definitions(__ENABLE_FLOAT_FFTW) endif() diff --git a/cmake/modules/FindKML.cmake b/cmake/modules/FindKML.cmake index 09301fe8e74..3952463a9e8 100644 --- a/cmake/modules/FindKML.cmake +++ b/cmake/modules/FindKML.cmake @@ -267,6 +267,18 @@ if(KML_FOUND) endif() endif() +# Compatibility with packages that consume the standard CMake math targets. +if(TARGET KML::BLAS AND NOT TARGET BLAS::BLAS) + add_library(BLAS::BLAS INTERFACE IMPORTED) + set_property(TARGET BLAS::BLAS PROPERTY + INTERFACE_LINK_LIBRARIES KML::BLAS) +endif() +if(TARGET KML::LAPACK AND NOT TARGET LAPACK::LAPACK) + add_library(LAPACK::LAPACK INTERFACE IMPORTED) + set_property(TARGET LAPACK::LAPACK PROPERTY + INTERFACE_LINK_LIBRARIES KML::LAPACK) +endif() + mark_as_advanced( KML_INCLUDE_DIR KML_RUNTIME_LIBRARY diff --git a/cmake/modules/FindMKL.cmake b/cmake/modules/FindMKL.cmake index b89465dfb9a..b9cda933470 100644 --- a/cmake/modules/FindMKL.cmake +++ b/cmake/modules/FindMKL.cmake @@ -273,6 +273,20 @@ if(MKL_FOUND) endif() endif() +# Compatibility with packages that consume the standard CMake math targets. +if(TARGET abacus::mkl) + if(NOT TARGET BLAS::BLAS) + add_library(BLAS::BLAS INTERFACE IMPORTED) + set_property(TARGET BLAS::BLAS PROPERTY + INTERFACE_LINK_LIBRARIES abacus::mkl) + endif() + if(NOT TARGET LAPACK::LAPACK) + add_library(LAPACK::LAPACK INTERFACE IMPORTED) + set_property(TARGET LAPACK::LAPACK PROPERTY + INTERFACE_LINK_LIBRARIES abacus::mkl) + endif() +endif() + mark_as_advanced( _abacus_mkl_include _abacus_mkl_fftw_include From cc120bab3982b1eb95f657616fd5816478e9da63 Mon Sep 17 00:00:00 2001 From: Growl Date: Fri, 10 Jul 2026 13:00:51 +0800 Subject: [PATCH 8/8] Move MKL-BLACS report into MKL_FOUND if clause --- cmake/modules/FindMKL.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/FindMKL.cmake b/cmake/modules/FindMKL.cmake index b9cda933470..5f1980e990f 100644 --- a/cmake/modules/FindMKL.cmake +++ b/cmake/modules/FindMKL.cmake @@ -93,7 +93,6 @@ if(ENABLE_MPI) endif() set(_mkl_blacs_name mkl_blacs_${_mkl_mpi}_lp64) - message(STATUS "oneMKL BLACS interface: ${_mkl_blacs_name}") endif() # These are result variables of this finder, not user configuration inputs. @@ -198,6 +197,7 @@ find_package_handle_standard_args(MKL REQUIRED_VARS ${_mkl_required_vars}) if(MKL_FOUND) set(_mkl_libraries ${MKL_INTERFACE_LIB} ${MKL_THREAD} ${MKL_CORE}) if(ENABLE_MPI) + message(STATUS "oneMKL BLACS interface: ${_mkl_blacs_name}") list(APPEND _mkl_libraries ${MKL_SCALAPACK} ${MKL_BLACS}) endif() set(_mkl_any_static FALSE)