Fix malformed CUDA version macro check
[alexxy/gromacs.git] / cmake / gmxManageLinearAlgebraLibraries.cmake
1 # Helper macro for the function below. We treat BLAS and LAPACK the same
2 # way, so there's no reason to duplicate the logic for them
3 #
4 # MESSSAGE_TEXT variable is accumulated while checks for these
5 # libraries fail, but the message is only emitted if we are forced to
6 # fall back on the internal version.
7 #
8 # Arguments should be:
9 #     name                 "BLAS" or "LAPACK"
10 #     function_in_library  the name of a function to use in a linking test of that library
11 macro(manage_linear_algebra_library name function_in_library)
12     set(_library_was_found 0)
13     set(_find_quietly FALSE)
14     set(_user_var_changed FALSE)
15     if(NOT DEFINED GMX_EXTERNAL_${name} OR
16        (GMX_EXTERNAL_${name} AND NOT "${GMX_${name}_USER}" STREQUAL "${GMX_${name}_USER_PREV}"))
17         set(_user_var_changed TRUE)
18     endif()
19     if(DEFINED GMX_EXTERNAL_${name} AND NOT _user_var_changed)
20         set(_find_quietly TRUE)
21     endif()
22
23     # We could consider printing status messages at the beginning and
24     # end, which would require caching whether the previous provider
25     # was user/MKL/external/internal. It's possible (we do it for
26     # FFT), but the number of times the user changes these is pretty
27     # low, so let's solve that one in master branch when we have
28     # better CMake gear to support it.
29     if(GMX_EXTERNAL_${name} OR NOT DEFINED GMX_EXTERNAL_${name})
30         set(GMX_${name}_USER_PREV ${GMX_${name}_USER} CACHE INTERNAL
31             "Previous value of GMX_${name}_USER (to detect changes)" FORCE)
32         set(_message_text)
33         # Check for user-specified libraries if external libraries have
34         # been specified (which is the default).
35         if(GMX_${name}_USER)
36             set(_libraries_to_link ${GMX_${name}_USER})
37             set(_library_was_found 1)
38
39             if(NOT _find_quietly)
40                 set(CMAKE_REQUIRED_LIBRARIES ${GMX_${name}_USER})
41                 if(_user_var_changed)
42                     unset(_${name}_user_works CACHE)
43                 endif()
44                 message(STATUS "Checking that user ${name} library ${GMX_${name}_USER} works")
45                 check_function_exists(${function_in_library} _${name}_user_works)
46                 if(NOT _${name}_user_works)
47                     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.")
48                 endif()
49
50                 if(HAVE_LIBMKL)
51                     message(STATUS "MKL and GMX_${name}_USER were both specified. Using the latter for ${name}.")
52                 endif()
53             endif()
54         endif()
55
56         if(NOT _library_was_found AND HAVE_LIBMKL)
57             set(CMAKE_REQUIRED_LIBRARIES ${FFT_LINKER_FLAGS} ${FFT_LIBRARIES})
58             # This may also not work correctly if the user changes
59             # MKL_LIBRARIES after the first run. However,
60             # MKL_LIBRARIES is only needed for icc version < 11, or
61             # for trying to use MKL with a non-Intel compiler, and we
62             # can live with that for now.
63             check_function_exists(${function_in_library} _${name}_mkl_works)
64             if(_${name}_mkl_works)
65                 # If we ever need to compile with MKL linear algebra and
66                 # not with FFT supplied by MKL, uncomment the next line
67                 # (and probably tweak other things).
68 #                list(APPEND LINEAR_ALGEBRA_LIBRARIES ${FFT_LINKER_FLAGS} ${FFT_LIBRARIES})
69                 set(_library_was_found 1)
70             else()
71                 set(_message_text "Intel's MKL was specified, and it should provide ${name}, but it does not. ")
72             endif()
73         endif()
74
75         # If detection of ${name} has never run, or none of the preceding
76         # detection succeeded, try to detect ${name} in the CMake
77         # detection paths, etc.
78         if (NOT _library_was_found)
79             set(${name}_FIND_QUIETLY _find_quietly)
80             # Note that this finds all kinds of system libraries,
81             # including Apple's Accelerate Framework (and perhaps MKL for
82             # icc < 11).
83             find_package(${name})
84             if (${name}_FOUND)
85                 set(_libraries_to_link ${${name}_LIBRARIES})
86                 set(_library_was_found 1)
87             endif()
88         endif()
89
90         if (NOT _library_was_found AND NOT _find_quietly)
91             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.")
92         endif()
93     endif()
94
95     # Default behaviour is to try to use an external library, but fall
96     # back on the internal one if none is found.
97     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)")
98     mark_as_advanced(GMX_EXTERNAL_${name})
99     # Default behaviour is to use a library found on the system or in
100     # GROMACS. The user must actively set GMX_${name}_USER if they
101     # want to specify a library.
102     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)")
103     mark_as_advanced(GMX_${name}_USER)
104
105     if(GMX_EXTERNAL_${name})
106         if (NOT _library_was_found)
107             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.")
108         endif ()
109         # Actually trigger linking.
110         list(APPEND LINEAR_ALGEBRA_LIBRARIES ${_libraries_to_link})
111     else()
112         # Triggering the compilation of the internal version of the library is handled elsewhere.
113     endif()
114 endmacro()
115
116 # The default behaviour is to try to detect an "external" BLAS and/or
117 # LAPACK, perhaps provided by a vendor, use those if found, and
118 # otherwise fall back on the GROMACS internal implementations of
119 # these. If the libraries are not in a standard location, the user can
120 # indicate a search path with CMAKE_PREFIX_PATH.
121 #
122 # However, if we are using icc+mkl (so a build command that includes
123 # -mkl), then it is probably painful to try to link some other BLAS or
124 # LAPACK. In that case, we use the BLAS & LAPACK provided by MKL. In
125 # principle, we could offer a more configurable behaviour if/when
126 # there is need to (say) use vendor BLAS with MKL for FFTs.
127 #
128 # If the vendor BLAS and/or LAPACK have abnormal library names, then
129 # the default searching procedure will fail (e.g. Redmine #771). The
130 # GMX_(BLAS|LAPACK)_USER variables can be used to indicate the correct
131 # libraries. If these do not work, a warning is emitted and we try to
132 # use them anyway, assuming the user knows what they are doing.
133
134 # Inputs:
135 #     GMX_EXTERNAL_BLAS     user input about whether to detect BLAS
136 #     GMX_EXTERNAL_LAPACK   user input about whether to detect LAPACK
137 #     HAVE_LIBMKL           true if the build will link to MKL
138 #     FFT_LINKER_FLAGS      used iff HAVE_MKL
139 #     FFT_LIBRARIES         used iff HAVE_MKL
140 #     GMX_BLAS_USER         user input for BLAS libraries to use
141 #     GMX_LAPACK_USER       user input for LAPACK libraries to use
142 #
143 # This function sets the following cache variables:
144 #     GMX_EXTERNAL_BLAS     according to whether external BLAS is being used
145 #     GMX_EXTERNAL_LAPACK   according to whether external LAPACK is being used
146 #     GMX_BLAS_USER         off = use a system library;
147 #                           any other value = full path to the library to use
148 #     GMX_LAPACK_USER       off = use a system library;
149 #                           any other value = full path to the library to use
150 #
151 # This function sets the following variables in its parent scope:
152 #     LINEAR_ALGEBRA_LIBRARIES  will be set as required to add libraries required for linear algebra
153 #
154 function(gmxManageLinearAlgebraLibraries)
155     include(CheckFunctionExists)
156     # Probably not necessary to unset, but let's be clear about usage.
157     unset(LINEAR_ALGEBRA_LIBRARIES)
158
159     manage_linear_algebra_library(BLAS dgemm_)
160     set(BLAS_FIND_QUIETLY ON)
161     manage_linear_algebra_library(LAPACK cheev_)
162
163     # Propagate the new local value to the parent scope
164     set(LINEAR_ALGEBRA_LIBRARIES "${LINEAR_ALGEBRA_LIBRARIES}" PARENT_SCOPE)
165 endfunction()
166
167 gmxManageLinearAlgebraLibraries()