1# - Find BLAS library 2# This module finds an installed fortran library that implements the BLAS 3# linear-algebra interface (see http://www.netlib.org/blas/). 4# The list of libraries searched for is taken 5# from the autoconf macro file, acx_blas.m4 (distributed at 6# http://ac-archive.sourceforge.net/ac-archive/acx_blas.html). 7# 8# This module sets the following variables: 9# BLAS_FOUND - set to true if a library implementing the BLAS interface is found. 10# BLAS_INFO - name of the detected BLAS library. 11# BLAS_F2C - set to true if following the f2c return convention 12# BLAS_LIBRARIES - list of libraries to link against to use BLAS 13# BLAS_INCLUDE_DIR - include directory 14 15# Do nothing if BLAS was found before 16IF(NOT BLAS_FOUND) 17 18SET(BLAS_LIBRARIES) 19SET(BLAS_INCLUDE_DIR) 20SET(BLAS_INFO) 21SET(BLAS_F2C) 22 23SET(WITH_BLAS "" CACHE STRING "Blas type [accelerate/acml/atlas/blis/generic/goto/mkl/open/veclib]") 24 25# Old FindBlas 26INCLUDE(CheckCSourceRuns) 27INCLUDE(CheckFortranFunctionExists) 28 29MACRO(Check_Fortran_Libraries LIBRARIES _prefix _name _flags _list) 30 # This macro checks for the existence of the combination of fortran libraries 31 # given by _list. If the combination is found, this macro checks (using the 32 # Check_Fortran_Function_Exists macro) whether can link against that library 33 # combination using the name of a routine given by _name using the linker 34 # flags given by _flags. If the combination of libraries is found and passes 35 # the link test, LIBRARIES is set to the list of complete library paths that 36 # have been found. Otherwise, LIBRARIES is set to NOTFOUND. 37 # N.B. _prefix is the prefix applied to the names of all cached variables that 38 # are generated internally and marked advanced by this macro. 39 40 set(__list) 41 foreach(_elem ${_list}) 42 if(__list) 43 set(__list "${__list} - ${_elem}") 44 else(__list) 45 set(__list "${_elem}") 46 endif(__list) 47 endforeach(_elem) 48 message(STATUS "Checking for [${__list}]") 49 50 set(_libraries_work TRUE) 51 set(${LIBRARIES}) 52 set(_combined_name) 53 foreach(_library ${_list}) 54 set(_combined_name ${_combined_name}_${_library}) 55 if(_libraries_work) 56 if ( WIN32 ) 57 find_library(${_prefix}_${_library}_LIBRARY 58 NAMES ${_library} 59 PATHS ENV LIB 60 PATHS ENV PATH ) 61 endif ( WIN32 ) 62 if ( APPLE ) 63 find_library(${_prefix}_${_library}_LIBRARY 64 NAMES ${_library} 65 PATHS /usr/local/lib /usr/lib /usr/local/lib64 /usr/lib64 /opt/OpenBLAS/lib /usr/lib/aarch64-linux-gnu 66 ENV DYLD_LIBRARY_PATH ) 67 else ( APPLE ) 68 find_library(${_prefix}_${_library}_LIBRARY 69 NAMES ${_library} 70 PATHS /usr/local/lib /usr/lib /usr/local/lib64 /usr/lib64 /opt/OpenBLAS/lib /usr/lib/aarch64-linux-gnu ${CMAKE_C_IMPLICIT_LINK_DIRECTORIES} 71 ENV LD_LIBRARY_PATH ) 72 endif( APPLE ) 73 mark_as_advanced(${_prefix}_${_library}_LIBRARY) 74 set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY}) 75 set(_libraries_work ${${_prefix}_${_library}_LIBRARY}) 76 MESSAGE(STATUS " Library ${_library}: ${${_prefix}_${_library}_LIBRARY}") 77 endif(_libraries_work) 78 endforeach(_library ${_list}) 79 if(_libraries_work) 80 # Test this combination of libraries. 81 set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}}) 82 if (CMAKE_Fortran_COMPILER_WORKS) 83 check_fortran_function_exists(${_name} ${_prefix}${_combined_name}_WORKS) 84 else (CMAKE_Fortran_COMPILER_WORKS) 85 check_function_exists("${_name}_" ${_prefix}${_combined_name}_WORKS) 86 endif(CMAKE_Fortran_COMPILER_WORKS) 87 set(CMAKE_REQUIRED_LIBRARIES) 88 mark_as_advanced(${_prefix}${_combined_name}_WORKS) 89 set(_libraries_work ${${_prefix}${_combined_name}_WORKS}) 90 endif(_libraries_work) 91 if(NOT _libraries_work) 92 set(${LIBRARIES} NOTFOUND) 93 endif(NOT _libraries_work) 94endmacro(Check_Fortran_Libraries) 95 96# Intel MKL? 97if((NOT BLAS_LIBRARIES) 98 AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "mkl"))) 99 FIND_PACKAGE(MKL) 100 IF(MKL_FOUND) 101 SET(BLAS_INFO "mkl") 102 SET(BLAS_LIBRARIES ${MKL_LIBRARIES}) 103 SET(BLAS_INCLUDE_DIR ${MKL_INCLUDE_DIR}) 104 SET(BLAS_VERSION ${MKL_VERSION}) 105 ENDIF(MKL_FOUND) 106endif() 107 108#BLIS? 109if((NOT BLAS_LIBRARIES) 110 AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "blis"))) 111 check_fortran_libraries( 112 BLAS_LIBRARIES 113 BLAS 114 sgemm 115 "" 116 "blis") 117 if(BLAS_LIBRARIES) 118 set(BLAS_INFO "blis") 119 endif(BLAS_LIBRARIES) 120endif() 121 122# Apple BLAS library? 123if((NOT BLAS_LIBRARIES) 124 AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "accelerate"))) 125 check_fortran_libraries( 126 BLAS_LIBRARIES 127 BLAS 128 sgemm 129 "" 130 "Accelerate") 131 if (BLAS_LIBRARIES) 132 set(BLAS_INFO "accelerate") 133 set(BLAS_IS_ACCELERATE 1) 134 endif(BLAS_LIBRARIES) 135endif() 136 137if((NOT BLAS_LIBRARIES) 138 AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "veclib"))) 139 FIND_PACKAGE(vecLib) 140 if(vecLib_FOUND) 141 SET(BLAS_INFO "veclib") 142 else() 143 check_fortran_libraries( 144 BLAS_LIBRARIES 145 BLAS 146 sgemm 147 "" 148 "vecLib") 149 if (BLAS_LIBRARIES) 150 set(BLAS_INFO "veclib") 151 endif(BLAS_LIBRARIES) 152 endif() 153endif() 154 155if((NOT BLAS_LIBRARIES) 156 AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "flexi"))) 157 check_fortran_libraries( 158 BLAS_LIBRARIES 159 BLAS 160 sgemm 161 "" 162 "flexiblas") 163 if(BLAS_LIBRARIES) 164 set(BLAS_INFO "flexi") 165 endif(BLAS_LIBRARIES) 166endif() 167 168if((NOT BLAS_LIBRARIES) 169 AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "open"))) 170 check_fortran_libraries( 171 BLAS_LIBRARIES 172 BLAS 173 sgemm 174 "" 175 "openblas") 176 if(BLAS_LIBRARIES) 177 set(BLAS_INFO "open") 178 endif(BLAS_LIBRARIES) 179endif() 180 181if((NOT BLAS_LIBRARIES) 182 AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "open"))) 183 check_fortran_libraries( 184 BLAS_LIBRARIES 185 BLAS 186 sgemm 187 "" 188 "openblas;pthread;m") 189 if(BLAS_LIBRARIES) 190 set(BLAS_INFO "open") 191 endif(BLAS_LIBRARIES) 192endif() 193 194if((NOT BLAS_LIBRARIES) 195 AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "open"))) 196 check_fortran_libraries( 197 BLAS_LIBRARIES 198 BLAS 199 sgemm 200 "" 201 "openblas;pthread;m;gomp") 202 if(BLAS_LIBRARIES) 203 set(BLAS_INFO "open") 204 endif(BLAS_LIBRARIES) 205endif() 206 207if((NOT BLAS_LIBRARIES) AND (WIN32) 208 AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "open"))) 209 check_fortran_libraries( 210 BLAS_LIBRARIES 211 BLAS 212 sgemm 213 "" 214 "libopenblas") 215 if(BLAS_LIBRARIES) 216 set(BLAS_INFO "open") 217 endif(BLAS_LIBRARIES) 218endif() 219 220if((NOT BLAS_LIBRARIES) 221 AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "goto"))) 222 check_fortran_libraries( 223 BLAS_LIBRARIES 224 BLAS 225 sgemm 226 "" 227 "goto2;gfortran") 228 if (BLAS_LIBRARIES) 229 set(BLAS_INFO "goto") 230 endif(BLAS_LIBRARIES) 231endif() 232 233if((NOT BLAS_LIBRARIES) 234 AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "goto"))) 235 check_fortran_libraries( 236 BLAS_LIBRARIES 237 BLAS 238 sgemm 239 "" 240 "goto2;gfortran;pthread") 241 if (BLAS_LIBRARIES) 242 set(BLAS_INFO "goto") 243 endif(BLAS_LIBRARIES) 244endif() 245 246if((NOT BLAS_LIBRARIES) 247 AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "acml"))) 248 check_fortran_libraries( 249 BLAS_LIBRARIES 250 BLAS 251 sgemm 252 "" 253 "acml;gfortran") 254 if (BLAS_LIBRARIES) 255 set(BLAS_INFO "acml") 256 endif(BLAS_LIBRARIES) 257endif() 258 259if((NOT BLAS_LIBRARIES) 260 AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "FLAME"))) 261 # FLAME's blis library (https://github.com/flame/blis) 262 check_fortran_libraries( 263 BLAS_LIBRARIES 264 BLAS 265 sgemm 266 "" 267 "blis") 268 if (BLAS_LIBRARIES) 269 set(BLAS_INFO "FLAME") 270 endif(BLAS_LIBRARIES) 271endif() 272 273# BLAS in ATLAS library? (http://math-atlas.sourceforge.net/) 274if((NOT BLAS_LIBRARIES) 275 AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "atlas"))) 276 FIND_PACKAGE(Atlas) 277 if(Atlas_FOUND) 278 SET(BLAS_INFO "atlas") 279 else() 280 check_fortran_libraries( 281 BLAS_LIBRARIES 282 BLAS 283 sgemm 284 "" 285 "ptf77blas;atlas;gfortran") 286 if (BLAS_LIBRARIES) 287 set(BLAS_INFO "atlas") 288 endif(BLAS_LIBRARIES) 289 endif() 290endif() 291 292# Generic BLAS library? 293if((NOT BLAS_LIBRARIES) 294 AND ((NOT WITH_BLAS) OR (WITH_BLAS STREQUAL "generic"))) 295 if(ENV{GENERIC_BLAS_LIBRARIES} STREQUAL "") 296 set(GENERIC_BLAS "blas") 297 else() 298 set(GENERIC_BLAS $ENV{GENERIC_BLAS_LIBRARIES}) 299 endif() 300 check_fortran_libraries( 301 BLAS_LIBRARIES 302 BLAS 303 sgemm 304 "" 305 "${GENERIC_BLAS}") 306 if (BLAS_LIBRARIES) 307 set(BLAS_INFO "generic") 308 endif(BLAS_LIBRARIES) 309endif() 310 311# Determine if blas was compiled with the f2c conventions 312IF (BLAS_LIBRARIES) 313 # Push host architecture when cross-compiling otherwise check would fail 314 # when cross-compiling for arm64 on x86_64 315 cmake_push_check_state(RESET) 316 if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_OSX_ARCHITECTURES MATCHES "^(x86_64|arm64)$") 317 list(APPEND CMAKE_REQUIRED_FLAGS "-arch ${CMAKE_HOST_SYSTEM_PROCESSOR}") 318 endif() 319 320# Set values through env variables if cross compiling 321 IF (CMAKE_CROSSCOMPILING) 322 IF("$ENV{PYTORCH_BLAS_F2C}" STREQUAL "ON") 323 SET(BLAS_F2C TRUE) 324 ELSE() 325 SET(BLAS_F2C FALSE) 326 ENDIF() 327 328 IF("$ENV{PYTORCH_BLAS_USE_CBLAS_DOT}" STREQUAL "ON") 329 SET(BLAS_USE_CBLAS_DOT TRUE) 330 ELSE() 331 SET(BLAS_USE_CBLAS_DOT FALSE) 332 ENDIF() 333 ELSE () 334 SET(CMAKE_REQUIRED_LIBRARIES ${BLAS_LIBRARIES}) 335 CHECK_C_SOURCE_RUNS(" 336 #include <stdlib.h> 337 #include <stdio.h> 338 float x[4] = { 1, 2, 3, 4 }; 339 float y[4] = { .1, .01, .001, .0001 }; 340 int four = 4; 341 int one = 1; 342 extern double sdot_(); 343 int main() { 344 int i; 345 double r = sdot_(&four, x, &one, y, &one); 346 exit((float)r != (float).1234); 347 }" BLAS_F2C_DOUBLE_WORKS ) 348 CHECK_C_SOURCE_RUNS(" 349 #include <stdlib.h> 350 #include <stdio.h> 351 float x[4] = { 1, 2, 3, 4 }; 352 float y[4] = { .1, .01, .001, .0001 }; 353 int four = 4; 354 int one = 1; 355 extern float sdot_(); 356 int main() { 357 int i; 358 double r = sdot_(&four, x, &one, y, &one); 359 exit((float)r != (float).1234); 360 }" BLAS_F2C_FLOAT_WORKS ) 361 IF (BLAS_F2C_DOUBLE_WORKS AND NOT BLAS_F2C_FLOAT_WORKS) 362 MESSAGE(STATUS "This BLAS uses the F2C return conventions") 363 SET(BLAS_F2C TRUE) 364 ELSE (BLAS_F2C_DOUBLE_WORKS AND NOT BLAS_F2C_FLOAT_WORKS) 365 SET(BLAS_F2C FALSE) 366 ENDIF(BLAS_F2C_DOUBLE_WORKS AND NOT BLAS_F2C_FLOAT_WORKS) 367 CHECK_C_SOURCE_RUNS(" 368 #include <stdlib.h> 369 #include <stdio.h> 370 float x[4] = { 1, 2, 3, 4 }; 371 float y[4] = { .1, .01, .001, .0001 }; 372 extern float cblas_sdot(); 373 int main() { 374 int i; 375 double r = cblas_sdot(4, x, 1, y, 1); 376 exit((float)r != (float).1234); 377 }" BLAS_USE_CBLAS_DOT ) 378 IF (BLAS_USE_CBLAS_DOT) 379 SET(BLAS_USE_CBLAS_DOT TRUE) 380 ELSE (BLAS_USE_CBLAS_DOT) 381 SET(BLAS_USE_CBLAS_DOT FALSE) 382 ENDIF(BLAS_USE_CBLAS_DOT) 383 SET(CMAKE_REQUIRED_LIBRARIES) 384 ENDIF(CMAKE_CROSSCOMPILING) 385 cmake_pop_check_state() 386ENDIF(BLAS_LIBRARIES) 387 388# epilogue 389 390if(BLAS_LIBRARIES) 391 set(BLAS_FOUND TRUE) 392else(BLAS_LIBRARIES) 393 set(BLAS_FOUND FALSE) 394endif(BLAS_LIBRARIES) 395 396IF (NOT BLAS_FOUND AND BLAS_FIND_REQUIRED) 397 message(FATAL_ERROR "Cannot find a library with BLAS API. Please specify library location.") 398ENDIF(NOT BLAS_FOUND AND BLAS_FIND_REQUIRED) 399IF(NOT BLAS_FIND_QUIETLY) 400 IF(BLAS_FOUND) 401 MESSAGE(STATUS "Found a library with BLAS API (${BLAS_INFO}). Full path: (${BLAS_LIBRARIES})") 402 ELSE(BLAS_FOUND) 403 MESSAGE(STATUS "Cannot find a library with BLAS API. Not using BLAS.") 404 ENDIF(BLAS_FOUND) 405ENDIF(NOT BLAS_FIND_QUIETLY) 406 407# Do nothing is BLAS was found before 408ENDIF(NOT BLAS_FOUND) 409 410# Blas has bfloat16 support? 411IF(BLAS_LIBRARIES) 412 INCLUDE(CheckFunctionExists) 413 SET(CMAKE_REQUIRED_LIBRARIES ${BLAS_LIBRARIES}) 414 check_function_exists("sbgemm_" BLAS_HAS_SBGEMM) 415 set(CMAKE_REQUIRED_LIBRARIES) 416 IF(BLAS_HAS_SBGEMM) 417 add_compile_options(-DBLAS_HAS_SBGEMM) 418 ENDIF(BLAS_HAS_SBGEMM) 419ENDIF(BLAS_LIBRARIES) 420