pytorch/cmake/Modules/FindBLAS.cmake
Isuru Fernando 8f0998aafe Check F2C BLAS for OpenBLAS and other vendors (#143846)
This issue came from https://github.com/conda-forge/pytorch-cpu-feedstock/issues/180. MKL follows the F2C convention for returning single precision floats as doubles and uses the G77 convention for returning complex valued scalars. OpenBLAS does the opposite. There is a check for this already, but it's done only when the Generic BLAS vendor code path is used and this PR moves that code to `Dependencies.cmake` to make it work when the BLAS vendor is OpenBLAS and others

Pull Request resolved: https://github.com/pytorch/pytorch/pull/143846
Approved by: https://github.com/rgommers, https://github.com/atalman
2025-07-01 05:56:24 +00:00

349 lines
9.2 KiB
CMake

# - Find BLAS library
# This module finds an installed fortran library that implements the BLAS
# linear-algebra interface (see http://www.netlib.org/blas/).
# The list of libraries searched for is taken
# from the autoconf macro file, acx_blas.m4 (distributed at
# http://ac-archive.sourceforge.net/ac-archive/acx_blas.html).
#
# This module sets the following variables:
# BLAS_FOUND - set to true if a library implementing the BLAS interface is found.
# BLAS_INFO - name of the detected BLAS library.
# BLAS_F2C - set to true if following the f2c return convention
# BLAS_LIBRARIES - list of libraries to link against to use BLAS
# BLAS_INCLUDE_DIR - include directory
# Do nothing if BLAS was found before
IF(NOT BLAS_FOUND)
SET(BLAS_LIBRARIES)
SET(BLAS_INCLUDE_DIR)
SET(BLAS_INFO)
SET(BLAS_F2C)
SET(WITH_BLAS "" CACHE STRING "Blas type [accelerate/acml/atlas/blis/generic/goto/mkl/open/veclib]")
# Old FindBlas
INCLUDE(CheckCSourceRuns)
INCLUDE(CheckFortranFunctionExists)
INCLUDE(CheckFunctionExists)
MACRO(Check_Fortran_Libraries LIBRARIES _prefix _name _flags _list)
# This macro checks for the existence of the combination of fortran libraries
# given by _list. If the combination is found, this macro checks (using the
# Check_Fortran_Function_Exists macro) whether can link against that library
# combination using the name of a routine given by _name using the linker
# flags given by _flags. If the combination of libraries is found and passes
# the link test, LIBRARIES is set to the list of complete library paths that
# have been found. Otherwise, LIBRARIES is set to NOTFOUND.
# N.B. _prefix is the prefix applied to the names of all cached variables that
# are generated internally and marked advanced by this macro.
set(__list)
foreach(_elem ${_list})
if(__list)
set(__list "${__list} - ${_elem}")
else(__list)
set(__list "${_elem}")
endif(__list)
endforeach(_elem)
message(STATUS "Checking for [${__list}]")
set(_libraries_work TRUE)
set(${LIBRARIES})
set(_combined_name)
foreach(_library ${_list})
set(_combined_name ${_combined_name}_${_library})
if(_libraries_work)
if ( WIN32 )
find_library(${_prefix}_${_library}_LIBRARY
NAMES ${_library}
PATHS ENV LIB
PATHS ENV PATH )
endif ( WIN32 )
if ( APPLE )
find_library(${_prefix}_${_library}_LIBRARY
NAMES ${_library}
PATHS /usr/local/lib /usr/lib /usr/local/lib64 /usr/lib64 /opt/OpenBLAS/lib /usr/lib/aarch64-linux-gnu
ENV DYLD_LIBRARY_PATH )
else ( APPLE )
find_library(${_prefix}_${_library}_LIBRARY
NAMES ${_library}
PATHS /usr/local/lib /usr/lib /usr/local/lib64 /usr/lib64 /opt/OpenBLAS/lib /usr/lib/aarch64-linux-gnu ${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}
ENV LD_LIBRARY_PATH )
endif( APPLE )
mark_as_advanced(${_prefix}_${_library}_LIBRARY)
set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY})
set(_libraries_work ${${_prefix}_${_library}_LIBRARY})
MESSAGE(STATUS " Library ${_library}: ${${_prefix}_${_library}_LIBRARY}")
endif(_libraries_work)
endforeach(_library ${_list})
if(_libraries_work)
# Test this combination of libraries.
set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}})
if (CMAKE_Fortran_COMPILER_WORKS)
check_fortran_function_exists(${_name} ${_prefix}${_combined_name}_WORKS)
else (CMAKE_Fortran_COMPILER_WORKS)
check_function_exists("${_name}_" ${_prefix}${_combined_name}_WORKS)
endif(CMAKE_Fortran_COMPILER_WORKS)
set(CMAKE_REQUIRED_LIBRARIES)
mark_as_advanced(${_prefix}${_combined_name}_WORKS)
set(_libraries_work ${${_prefix}${_combined_name}_WORKS})
endif(_libraries_work)
if(NOT _libraries_work)
set(${LIBRARIES} NOTFOUND)
endif(NOT _libraries_work)
endmacro(Check_Fortran_Libraries)
# Intel MKL?
if((NOT BLAS_LIBRARIES)
AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "mkl")))
FIND_PACKAGE(MKL)
IF(MKL_FOUND)
SET(BLAS_INFO "mkl")
SET(BLAS_LIBRARIES ${MKL_LIBRARIES})
SET(BLAS_INCLUDE_DIR ${MKL_INCLUDE_DIR})
SET(BLAS_VERSION ${MKL_VERSION})
ENDIF(MKL_FOUND)
endif()
#BLIS?
if((NOT BLAS_LIBRARIES)
AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "blis")))
check_fortran_libraries(
BLAS_LIBRARIES
BLAS
sgemm
""
"blis")
if(BLAS_LIBRARIES)
set(BLAS_INFO "blis")
endif(BLAS_LIBRARIES)
endif()
# Apple BLAS library?
if((NOT BLAS_LIBRARIES)
AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "accelerate")))
check_fortran_libraries(
BLAS_LIBRARIES
BLAS
sgemm
""
"Accelerate")
if (BLAS_LIBRARIES)
set(BLAS_INFO "accelerate")
set(BLAS_IS_ACCELERATE 1)
endif(BLAS_LIBRARIES)
endif()
if((NOT BLAS_LIBRARIES)
AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "veclib")))
FIND_PACKAGE(vecLib)
if(vecLib_FOUND)
SET(BLAS_INFO "veclib")
else()
check_fortran_libraries(
BLAS_LIBRARIES
BLAS
sgemm
""
"vecLib")
if (BLAS_LIBRARIES)
set(BLAS_INFO "veclib")
endif(BLAS_LIBRARIES)
endif()
endif()
if((NOT BLAS_LIBRARIES)
AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "flexi")))
check_fortran_libraries(
BLAS_LIBRARIES
BLAS
sgemm
""
"flexiblas")
if(BLAS_LIBRARIES)
set(BLAS_INFO "flexi")
endif(BLAS_LIBRARIES)
endif()
if((NOT BLAS_LIBRARIES)
AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "open")))
check_fortran_libraries(
BLAS_LIBRARIES
BLAS
sgemm
""
"openblas")
if(BLAS_LIBRARIES)
set(BLAS_INFO "open")
endif(BLAS_LIBRARIES)
endif()
if((NOT BLAS_LIBRARIES)
AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "open")))
check_fortran_libraries(
BLAS_LIBRARIES
BLAS
sgemm
""
"openblas;pthread;m")
if(BLAS_LIBRARIES)
set(BLAS_INFO "open")
endif(BLAS_LIBRARIES)
endif()
if((NOT BLAS_LIBRARIES)
AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "open")))
check_fortran_libraries(
BLAS_LIBRARIES
BLAS
sgemm
""
"openblas;pthread;m;gomp")
if(BLAS_LIBRARIES)
set(BLAS_INFO "open")
endif(BLAS_LIBRARIES)
endif()
if((NOT BLAS_LIBRARIES) AND (WIN32)
AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "open")))
check_fortran_libraries(
BLAS_LIBRARIES
BLAS
sgemm
""
"libopenblas")
if(BLAS_LIBRARIES)
set(BLAS_INFO "open")
endif(BLAS_LIBRARIES)
endif()
if((NOT BLAS_LIBRARIES)
AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "goto")))
check_fortran_libraries(
BLAS_LIBRARIES
BLAS
sgemm
""
"goto2;gfortran")
if (BLAS_LIBRARIES)
set(BLAS_INFO "goto")
endif(BLAS_LIBRARIES)
endif()
if((NOT BLAS_LIBRARIES)
AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "goto")))
check_fortran_libraries(
BLAS_LIBRARIES
BLAS
sgemm
""
"goto2;gfortran;pthread")
if (BLAS_LIBRARIES)
set(BLAS_INFO "goto")
endif(BLAS_LIBRARIES)
endif()
if((NOT BLAS_LIBRARIES)
AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "acml")))
check_fortran_libraries(
BLAS_LIBRARIES
BLAS
sgemm
""
"acml;gfortran")
if (BLAS_LIBRARIES)
set(BLAS_INFO "acml")
endif(BLAS_LIBRARIES)
endif()
if((NOT BLAS_LIBRARIES)
AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "FLAME")))
# FLAME's blis library (https://github.com/flame/blis)
check_fortran_libraries(
BLAS_LIBRARIES
BLAS
sgemm
""
"blis")
if (BLAS_LIBRARIES)
set(BLAS_INFO "FLAME")
endif(BLAS_LIBRARIES)
endif()
# BLAS in ATLAS library? (http://math-atlas.sourceforge.net/)
if((NOT BLAS_LIBRARIES)
AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "atlas")))
FIND_PACKAGE(Atlas)
if(Atlas_FOUND)
SET(BLAS_INFO "atlas")
else()
check_fortran_libraries(
BLAS_LIBRARIES
BLAS
sgemm
""
"ptf77blas;atlas;gfortran")
if (BLAS_LIBRARIES)
set(BLAS_INFO "atlas")
endif(BLAS_LIBRARIES)
endif()
endif()
# Generic BLAS library?
if((NOT BLAS_LIBRARIES)
AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "generic")))
if(ENV{GENERIC_BLAS_LIBRARIES} STREQUAL "")
set(GENERIC_BLAS "blas")
else()
set(GENERIC_BLAS $ENV{GENERIC_BLAS_LIBRARIES})
endif()
check_fortran_libraries(
BLAS_LIBRARIES
BLAS
sgemm
""
"${GENERIC_BLAS}")
if (BLAS_LIBRARIES)
set(BLAS_INFO "generic")
endif(BLAS_LIBRARIES)
endif()
# Determine if blas was compiled with the f2c conventions
IF (BLAS_LIBRARIES)
include(cmake/BLAS_ABI.cmake)
endif(BLAS_LIBRARIES)
# epilogue
if(BLAS_LIBRARIES)
set(BLAS_FOUND TRUE)
else(BLAS_LIBRARIES)
set(BLAS_FOUND FALSE)
endif(BLAS_LIBRARIES)
IF (NOT BLAS_FOUND AND BLAS_FIND_REQUIRED)
message(FATAL_ERROR "Cannot find a library with BLAS API. Please specify library location.")
ENDIF(NOT BLAS_FOUND AND BLAS_FIND_REQUIRED)
IF(NOT BLAS_FIND_QUIETLY)
IF(BLAS_FOUND)
MESSAGE(STATUS "Found a library with BLAS API (${BLAS_INFO}). Full path: (${BLAS_LIBRARIES})")
ELSE(BLAS_FOUND)
MESSAGE(STATUS "Cannot find a library with BLAS API. Not using BLAS.")
ENDIF(BLAS_FOUND)
ENDIF(NOT BLAS_FIND_QUIETLY)
# Do nothing is BLAS was found before
ENDIF(NOT BLAS_FOUND)
# Blas has bfloat16 support?
IF(BLAS_LIBRARIES)
INCLUDE(CheckFunctionExists)
SET(CMAKE_REQUIRED_LIBRARIES ${BLAS_LIBRARIES})
check_function_exists("sbgemm_" BLAS_HAS_SBGEMM)
set(CMAKE_REQUIRED_LIBRARIES)
IF(BLAS_HAS_SBGEMM)
add_compile_options(-DBLAS_HAS_SBGEMM)
ENDIF(BLAS_HAS_SBGEMM)
ENDIF(BLAS_LIBRARIES)