can provide performance enhancements for \gromacs{} when doing
normal-mode analysis or covariance analysis. For simplicity, the text
below will refer only to \blas{}, but the same options are available
-for \lapack{}. By default, the \cmake{} optionv
-\verb+GMX_EXTERNAL_BLAS+ is on, which triggers \cmake{} to search for
-\blas{}. If one is found, then it is used. Otherwise, \cmake{} falls
-back on internal versions provided in the \gromacs{} source. These are
-fine for normal use. If you need to specify a non-standard path to
-search, use \verb+-DCMAKE_PREFIX_PATH=/path/to/search+.
+for \lapack{}. By default, CMake will search for \blas{}, use it if it
+is found, and otherwise fall back on a version of \blas{} internal to
+\gromacs{}. The \cmake{} option \verb+GMX_EXTERNAL_BLAS+ will be set
+accordingly. The internal versions are fine for normal use. If you
+need to specify a non-standard path to search, use
+\verb+-DCMAKE_PREFIX_PATH=/path/to/search+. If you need to specify a
+library with a non-standard name (e.g. ESSL on AIX), then set
+\verb+-DGMX_BLAS_USER=/path/to/reach/lib/libwhatever.a+.
If you are using Intel's \mkl{} for \fft{}, then the \blas{} and
-\lapack{} it provides are used automatically.
+\lapack{} it provides are used automatically. This could be
+over-ridden with \verb+GMX_BLAS_USER+, etc.
On Apple platforms where the Accelerate Framework is available, these
-will be automatically used for \blas{} and \lapack{}.
+will be automatically used for \blas{} and \lapack{}. This could be
+over-ridden with \verb+GMX_BLAS_USER+, etc.
\subsection{Native GPU acceleration}
If you have the \cuda{} Software Development Kit installed, you can
--- /dev/null
+# Helper macro for the function below. We treat BLAS and LAPACK the same
+# way, so there's no reason to duplicate the logic for them
+#
+# MESSSAGE_TEXT variable is accumulated while checks for these
+# libraries fail, but the message is only emitted if we are forced to
+# fall back on the internal version.
+#
+# Arguments should be:
+# name "BLAS" or "LAPACK"
+# function_in_library the name of a function to use in a linking test of that library
+macro(manage_linear_algebra_library name function_in_library)
+ set(_library_was_found 0)
+ set(_find_quietly FALSE)
+ set(_user_var_changed FALSE)
+ if(NOT DEFINED GMX_EXTERNAL_${name} OR
+ (GMX_EXTERNAL_${name} AND NOT "${GMX_${name}_USER}" STREQUAL "${GMX_${name}_USER_PREV}"))
+ set(_user_var_changed TRUE)
+ endif()
+ if(DEFINED GMX_EXTERNAL_${name} AND NOT _user_var_changed)
+ set(_find_quietly TRUE)
+ endif()
+
+ # We could consider printing status messages at the beginning and
+ # end, which would require caching whether the previous provider
+ # was user/MKL/external/internal. It's possible (we do it for
+ # FFT), but the number of times the user changes these is pretty
+ # low, so let's solve that one in master branch when we have
+ # better CMake gear to support it.
+ if(GMX_EXTERNAL_${name} OR NOT DEFINED GMX_EXTERNAL_${name})
+ set(GMX_${name}_USER_PREV ${GMX_${name}_USER} CACHE INTERNAL
+ "Previous value of GMX_${name}_USER (to detect changes)" FORCE)
+ set(_message_text)
+ # Check for user-specified libraries if external libraries have
+ # been specified (which is the default).
+ if(GMX_${name}_USER)
+ set(_libraries_to_link ${GMX_${name}_USER})
+ set(_library_was_found 1)
+
+ if(NOT _find_quietly)
+ set(CMAKE_REQUIRED_LIBRARIES ${GMX_${name}_USER})
+ if(_user_var_changed)
+ unset(_${name}_user_works CACHE)
+ endif()
+ message(STATUS "Checking that user ${name} library ${GMX_${name}_USER} works")
+ check_function_exists(${function_in_library} _${name}_user_works)
+ if(NOT _${name}_user_works)
+ message(WARNING "GMX_${name}_USER library ${GMX_${name}_USER} was specified, but it may not provide ${name}. We are proceeding by assuming you know what you are doing and that linking F77-style to this library will work.")
+ endif()
+
+ if(HAVE_LIBMKL)
+ message(STATUS "MKL and GMX_${name}_USER were both specified. Using the latter for ${name}.")
+ endif()
+ endif()
+ endif()
+
+ if(NOT _library_was_found AND HAVE_LIBMKL)
+ set(CMAKE_REQUIRED_LIBRARIES ${FFT_LINKER_FLAGS} ${FFT_LIBRARIES})
+ # This may also not work correctly if the user changes
+ # MKL_LIBRARIES after the first run. However,
+ # MKL_LIBRARIES is only needed for icc version < 11, or
+ # for trying to use MKL with a non-Intel compiler, and we
+ # can live with that for now.
+ check_function_exists(${function_in_library} _${name}_mkl_works)
+ if(_${name}_mkl_works)
+ # If we ever need to compile with MKL linear algebra and
+ # not with FFT supplied by MKL, uncomment the next line
+ # (and probably tweak other things).
+# list(APPEND LINEAR_ALGEBRA_LIBRARIES ${FFT_LINKER_FLAGS} ${FFT_LIBRARIES})
+ set(_library_was_found 1)
+ else()
+ set(_message_text "Intel's MKL was specified, and it should provide ${name}, but it does not. ")
+ endif()
+ endif()
+
+ # If detection of ${name} has never run, or none of the preceding
+ # detection succeeded, try to detect ${name} in the CMake
+ # detection paths, etc.
+ if (NOT _library_was_found)
+ set(${name}_FIND_QUIETLY _find_quietly)
+ # Note that this finds all kinds of system libraries,
+ # including Apple's Accelerate Framework (and perhaps MKL for
+ # icc < 11).
+ find_package(${name})
+ if (${name}_FOUND)
+ set(_libraries_to_link ${${name}_LIBRARIES})
+ set(_library_was_found 1)
+ endif()
+ endif()
+
+ if (NOT _library_was_found AND NOT _find_quietly)
+ message("${_message_text}A ${name} library was not found by CMake in the paths available to it. Falling back on the GROMACS internal version of the ${name} library instead. This is fine for normal usage.")
+ endif()
+ endif()
+
+ # Default behaviour is to try to use an external library, but fall
+ # back on the internal one if none is found.
+ set(GMX_EXTERNAL_${name} ${_library_was_found} CACHE BOOL "Use a ${name} library that is external to GROMACS if possible (ON), or the internal GROMACS one (OFF)")
+ mark_as_advanced(GMX_EXTERNAL_${name})
+ # Default behaviour is to use a library found on the system or in
+ # GROMACS. The user must actively set GMX_${name}_USER if they
+ # want to specify a library.
+ set(GMX_${name}_USER "" CACHE BOOL "Use a ${name} library found on the system (OFF), or a ${name} library supplied by the user (any other value, which is a full path to that ${name} library)")
+ mark_as_advanced(GMX_${name}_USER)
+
+ if(GMX_EXTERNAL_${name})
+ if (NOT _library_was_found)
+ message(FATAL_ERROR "You have set GMX_EXTERNAL_${name}=ON to instruct GROMACS to use an external ${name} library, but no external library could be detected.")
+ endif ()
+ # Actually trigger linking.
+ list(APPEND LINEAR_ALGEBRA_LIBRARIES ${_libraries_to_link})
+ else()
+ # Triggering the compilation of the internal version of the library is handled elsewhere.
+ endif()
+endmacro()
+
+# The default behaviour is to try to detect an "external" BLAS and/or
+# LAPACK, perhaps provided by a vendor, use those if found, and
+# otherwise fall back on the GROMACS internal implementations of
+# these. If the libraries are not in a standard location, the user can
+# indicate a search path with CMAKE_PREFIX_PATH.
+#
+# However, if we are using icc+mkl (so a build command that includes
+# -mkl), then it is probably painful to try to link some other BLAS or
+# LAPACK. In that case, we use the BLAS & LAPACK provided by MKL. In
+# principle, we could offer a more configurable behaviour if/when
+# there is need to (say) use vendor BLAS with MKL for FFTs.
+#
+# If the vendor BLAS and/or LAPACK have abnormal library names, then
+# the default searching procedure will fail (e.g. Redmine #771). The
+# GMX_(BLAS|LAPACK)_USER variables can be used to indicate the correct
+# libraries. If these do not work, a warning is emitted and we try to
+# use them anyway, assuming the user knows what they are doing.
+
+# Inputs:
+# GMX_EXTERNAL_BLAS user input about whether to detect BLAS
+# GMX_EXTERNAL_LAPACK user input about whether to detect LAPACK
+# HAVE_LIBMKL true if the build will link to MKL
+# FFT_LINKER_FLAGS used iff HAVE_MKL
+# FFT_LIBRARIES used iff HAVE_MKL
+# GMX_BLAS_USER user input for BLAS libraries to use
+# GMX_LAPACK_USER user input for LAPACK libraries to use
+#
+# This function sets the following cache variables:
+# GMX_EXTERNAL_BLAS according to whether external BLAS is being used
+# GMX_EXTERNAL_LAPACK according to whether external LAPACK is being used
+# GMX_BLAS_USER off = use a system library;
+# any other value = full path to the library to use
+# GMX_LAPACK_USER off = use a system library;
+# any other value = full path to the library to use
+#
+# This function sets the following variables in its parent scope:
+# LINEAR_ALGEBRA_LIBRARIES will be set as required to add libraries required for linear algebra
+#
+function(gmxManageLinearAlgebraLibraries)
+ include(CheckFunctionExists)
+ # Probably not necessary to unset, but let's be clear about usage.
+ unset(LINEAR_ALGEBRA_LIBRARIES)
+
+ manage_linear_algebra_library(BLAS dgemm_)
+ set(BLAS_FIND_QUIETLY ON)
+ manage_linear_algebra_library(LAPACK cheev_)
+
+ # Propagate the new local value to the parent scope
+ set(LINEAR_ALGEBRA_LIBRARIES "${LINEAR_ALGEBRA_LIBRARIES}" PARENT_SCOPE)
+endfunction()
+
+gmxManageLinearAlgebraLibraries()