Salome HOME
update CoreFlows
[tools/solverlab.git] / CoreFlows / cmake_files / FindPETSc.cmake
1 # - Try to find PETSc
2 # Once done this will define
3 #
4 #  PETSC_FOUND        - system has PETSc
5 #  PETSC_INCLUDES     - the PETSc include directories
6 #  PETSC_LIBRARIES    - Link these to use PETSc
7 #  PETSC_COMPILER     - Compiler used by PETSc, helpful to find a compatible MPI
8 #  PETSC_DEFINITIONS  - Compiler switches for using PETSc
9 #  PETSC_MPIEXEC      - Executable for running MPI programs
10 #  PETSC_VERSION      - Version string (MAJOR.MINOR.SUBMINOR)
11 #
12 #  Usage:
13 #  find_package(PETSc COMPONENTS CXX)  - required if build --with-clanguage=C++ --with-c-support=0
14 #  find_package(PETSc COMPONENTS C)    - standard behavior of checking build using a C compiler
15 #  find_package(PETSc)                 - same as above
16 #
17 # Setting these changes the behavior of the search
18 #  PETSC_DIR - directory in which PETSc resides
19 #  PETSC_ARCH - build architecture
20 #
21 # Redistribution and use is allowed according to the terms of the BSD license.
22 # For details see the accompanying COPYING-CMAKE-SCRIPTS file.
23 #
24
25 set(PETSC_VALID_COMPONENTS
26   C
27   CXX)
28
29 if(NOT PETSc_FIND_COMPONENTS)
30   set(PETSC_LANGUAGE_BINDINGS "C")
31 else()
32   # Right now, this is designed for compatability with the --with-clanguage option, so
33   # only allow one item in the components list.
34   list(LENGTH ${PETSc_FIND_COMPONENTS} components_length)
35   if(${components_length} GREATER 1)
36     message(FATAL_ERROR "Only one component for PETSc is allowed to be specified")
37   endif()
38   # This is a stub for allowing multiple components should that time ever come. Perhaps
39   # to also test Fortran bindings?
40   foreach(component ${PETSc_FIND_COMPONENTS})
41     list(FIND PETSC_VALID_COMPONENTS ${component} component_location)
42     if(${component_location} EQUAL -1)
43       message(FATAL_ERROR "\"${component}\" is not a valid PETSc component.")
44     else()
45       list(APPEND PETSC_LANGUAGE_BINDINGS ${component})
46     endif()
47   endforeach()
48 endif()
49
50 function (petsc_get_version)
51   if (EXISTS "${PETSC_DIR}/petscversion.h" OR EXISTS "${PETSC_DIR}/include/petscversion.h" OR EXISTS "${PETSC_DIR}/${PETSC_ARCH}/include/petscversion.h")
52     if (EXISTS "${PETSC_DIR}/include/petscversion.h")
53       file (STRINGS "${PETSC_DIR}/include/petscversion.h" vstrings REGEX "#define PETSC_VERSION_(RELEASE|MAJOR|MINOR|SUBMINOR|PATCH) ")
54     elseif( EXISTS "${PETSC_DIR}/${PETSC_ARCH}/include/petscversion.h" )
55       file (STRINGS "${PETSC_DIR}/${PETSC_ARCH}/include/petscversion.h" vstrings REGEX "#define PETSC_VERSION_(RELEASE|MAJOR|MINOR|SUBMINOR|PATCH) ")
56     else()
57       file (STRINGS "${PETSC_DIR}/petscversion.h" vstrings REGEX "#define PETSC_VERSION_(RELEASE|MAJOR|MINOR|SUBMINOR|PATCH) ")
58     endif()
59     foreach (line ${vstrings})
60       string (REGEX REPLACE " +" ";" fields ${line}) # break line into three fields (the first is always "#define")
61       list (GET fields 1 var)
62       list (GET fields 2 val)
63       set (${var} ${val} PARENT_SCOPE)
64       set (${var} ${val})         # Also in local scope so we have access below
65     endforeach ()
66
67     if (PETSC_VERSION_RELEASE)
68       set (PETSC_VERSION "${PETSC_VERSION_MAJOR}.${PETSC_VERSION_MINOR}.${PETSC_VERSION_SUBMINOR}p${PETSC_VERSION_PATCH}" PARENT_SCOPE)
69     else ()
70       # make dev version compare higher than any patch level of a released version
71       set (PETSC_VERSION "${PETSC_VERSION_MAJOR}.${PETSC_VERSION_MINOR}.${PETSC_VERSION_SUBMINOR}.99" PARENT_SCOPE)
72     endif ()
73   else ()
74     message (SEND_ERROR "PETSC_DIR can not be used, file ${PETSC_DIR}/include/petscversion.h does not exist")
75   endif ()
76 endfunction ()
77
78 find_path (PETSC_DIR include/petsc.h
79   HINTS ENV PETSC_DIR
80   PATHS
81   #RedHat paths
82   /usr/include/petsc
83   # Debian paths
84   /usr/lib/petscdir/3.12.4 /usr/lib/petscdir/3.12 #Ubuntu 20.04
85   /usr/lib/petscdir/3.7.6 /usr/lib/petscdir/3.7 #Ubuntu 18.04
86   /usr/lib/petscdir/3.6.2 /usr/lib/petscdir/3.6 #Ubuntu 16.04
87   /usr/lib/petscdir/3.5.1 /usr/lib/petscdir/3.5
88   /usr/lib/petscdir/3.4.2 /usr/lib/petscdir/3.4
89   /usr/lib/petscdir/3.3 /usr/lib/petscdir/3.2 /usr/lib/petscdir/3.1
90   /usr/lib/petscdir/3.0.0 /usr/lib/petscdir/2.3.3 /usr/lib/petscdir/2.3.2
91   # MacPorts path
92   /opt/local/lib/petsc
93   $ENV{HOME}/petsc
94   DOC "PETSc Directory")
95
96 find_program (MAKE_EXECUTABLE NAMES make gmake)
97
98 if (PETSC_DIR AND NOT PETSC_ARCH)
99   set (_petsc_arches
100     $ENV{PETSC_ARCH}                            # If set, use environment variable first
101     linux-gnu-c-debug linux-gnu-c-opt           # old Debian defaults (petsc compilation)
102     arch-linux-c-opt or arch-linux-c-debug      # new Debian defaults (petsc compilation)
103     x86_64-linux-gnu-real   i686-linux-gnu-real # Debian defaults (petsc system installation)
104     arch-linux2-c-opt or arch-linux2-c-debug    # old RedHat defaults (petsc compilation)
105     x86_64-redhat-linux-gnu i686-redhat-linux-gnu # RedHat defaults (petsc apt installation)
106     x86_64-unknown-linux-gnu i386-unknown-linux-gnu)
107   set (petscconf "NOTFOUND" CACHE FILEPATH "Cleared" FORCE)
108   foreach (arch ${_petsc_arches})
109     if (NOT PETSC_ARCH)
110       find_path (petscconf petscconf.h
111         HINTS ${PETSC_DIR}
112         PATH_SUFFIXES ${arch}/include bmake/${arch}
113         NO_DEFAULT_PATH)
114       if (petscconf)
115         set (PETSC_ARCH "${arch}" CACHE STRING "PETSc build architecture")
116       endif (petscconf)
117     endif (NOT PETSC_ARCH)
118   endforeach (arch)
119   set (petscconf "NOTFOUND" CACHE INTERNAL "Scratch variable" FORCE)
120 endif (PETSC_DIR AND NOT PETSC_ARCH)
121
122 set (petsc_slaves LIBRARIES_SYS LIBRARIES_VEC LIBRARIES_MAT LIBRARIES_DM LIBRARIES_KSP LIBRARIES_SNES LIBRARIES_TS
123   INCLUDE_DIR INCLUDE_CONF)
124 include (FindPackageMultipass)
125 find_package_multipass (PETSc petsc_config_current
126   STATES DIR ARCH
127   DEPENDENTS INCLUDES LIBRARIES COMPILER MPIEXEC ${petsc_slaves})
128
129 # Determine whether the PETSc layout is old-style (through 2.3.3) or
130 # new-style (>= 3.0.0)
131 if (EXISTS "${PETSC_DIR}/${PETSC_ARCH}/lib/petsc/conf/petscvariables") # > 3.5
132   set (petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules")
133   set (petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables")
134 elseif (EXISTS "${PETSC_DIR}/${PETSC_ARCH}/include/petscconf.h")   # > 2.3.3
135   set (petsc_conf_rules "${PETSC_DIR}/conf/rules")
136   set (petsc_conf_variables "${PETSC_DIR}/conf/variables")
137 elseif (EXISTS "${PETSC_DIR}/bmake/${PETSC_ARCH}/petscconf.h") # <= 2.3.3
138   set (petsc_conf_rules "${PETSC_DIR}/bmake/common/rules")
139   set (petsc_conf_variables "${PETSC_DIR}/bmake/common/variables")
140 elseif (PETSC_DIR)
141   message (SEND_ERROR "The pair PETSC_DIR=${PETSC_DIR} PETSC_ARCH=${PETSC_ARCH} do not specify a valid PETSc installation")
142 endif ()
143
144 if (petsc_conf_rules AND petsc_conf_variables AND NOT petsc_config_current)
145   petsc_get_version()
146
147   # Put variables into environment since they are needed to get
148   # configuration (petscvariables) in the PETSc makefile
149   set (ENV{PETSC_DIR} "${PETSC_DIR}")
150   set (ENV{PETSC_ARCH} "${PETSC_ARCH}")
151
152   # A temporary makefile to probe the PETSc configuration
153   set (petsc_config_makefile "${PROJECT_BINARY_DIR}/Makefile.petsc")
154   file (WRITE "${petsc_config_makefile}"
155 "## This file was autogenerated by FindPETSc.cmake
156 # PETSC_DIR  = ${PETSC_DIR}
157 # PETSC_ARCH = ${PETSC_ARCH}
158 include ${petsc_conf_rules}
159 include ${petsc_conf_variables}
160 show :
161 \t-@echo -n \${\${VARIABLE}}
162 ")
163
164   macro (PETSC_GET_VARIABLE name var)
165     set (${var} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE)
166     execute_process (COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} show VARIABLE=${name}
167       OUTPUT_VARIABLE ${var}
168       RESULT_VARIABLE petsc_return)
169   endmacro (PETSC_GET_VARIABLE)
170   petsc_get_variable (PETSC_LIB_DIR            petsc_lib_dir)
171   petsc_get_variable (PETSC_EXTERNAL_LIB_BASIC petsc_libs_external)
172   petsc_get_variable (PETSC_CCPPFLAGS          petsc_cpp_line)
173   petsc_get_variable (PETSC_INCLUDE            petsc_include)
174   petsc_get_variable (PCC                      petsc_cc)
175   petsc_get_variable (PCC_FLAGS                petsc_cc_flags)
176   petsc_get_variable (MPIEXEC                  petsc_mpiexec)
177   # We are done with the temporary Makefile, calling PETSC_GET_VARIABLE after this point is invalid!
178   file (REMOVE ${petsc_config_makefile})
179
180   include (ResolveCompilerPaths)
181   # Extract include paths and libraries from compile command line
182   resolve_includes (petsc_includes_all "${petsc_cpp_line}")
183
184   #on windows we need to make sure we're linking against the right
185   #runtime library
186   if (WIN32)
187     if (petsc_cc_flags MATCHES "-MT")
188       set(using_md False)
189       foreach(flag_var
190           CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
191           CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
192           CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
193           CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
194         if(${flag_var} MATCHES "/MD")
195           set(using_md True)
196         endif(${flag_var} MATCHES "/MD")
197       endforeach(flag_var)
198       if(${using_md} MATCHES "True")
199         message(WARNING "PETSc was built with /MT, but /MD is currently set.
200  See http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F")
201       endif(${using_md} MATCHES "True")
202     endif (petsc_cc_flags MATCHES "-MT")
203   endif (WIN32)
204
205   include (CorrectWindowsPaths)
206   convert_cygwin_path(petsc_lib_dir)
207   message (STATUS "petsc_lib_dir ${petsc_lib_dir}")
208
209   macro (PETSC_FIND_LIBRARY suffix name)
210     set (PETSC_LIBRARY_${suffix} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) # Clear any stale value, if we got here, we need to find it again
211     if (WIN32)
212       set (libname lib${name}) #windows expects "libfoo", linux expects "foo"
213     else (WIN32)
214       set (libname ${name})
215     endif (WIN32)
216     find_library (PETSC_LIBRARY_${suffix} NAMES ${libname} HINTS ${petsc_lib_dir} NO_DEFAULT_PATH)
217     set (PETSC_LIBRARIES_${suffix} "${PETSC_LIBRARY_${suffix}}")
218     mark_as_advanced (PETSC_LIBRARY_${suffix})
219   endmacro (PETSC_FIND_LIBRARY suffix name)
220
221   # Look for petscvec first, if it doesn't exist, we must be using single-library
222   petsc_find_library (VEC petscvec)
223   if (PETSC_LIBRARY_VEC)
224     petsc_find_library (SYS  "petscsys;petsc") # libpetscsys is called libpetsc prior to 3.1 (when single-library was introduced)
225     petsc_find_library (MAT  petscmat)
226     petsc_find_library (DM   petscdm)
227     petsc_find_library (KSP  petscksp)
228     petsc_find_library (SNES petscsnes)
229     petsc_find_library (TS   petscts)
230     macro (PETSC_JOIN libs deps)
231       list (APPEND PETSC_LIBRARIES_${libs} ${PETSC_LIBRARIES_${deps}})
232     endmacro (PETSC_JOIN libs deps)
233     petsc_join (VEC  SYS)
234     petsc_join (MAT  VEC)
235     petsc_join (DM   MAT)
236     petsc_join (KSP  DM)
237     petsc_join (SNES KSP)
238     petsc_join (TS   SNES)
239     petsc_join (ALL  TS)
240   else ()
241     set (PETSC_LIBRARY_VEC "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) # There is no libpetscvec
242     petsc_find_library (SINGLE petsc) #check existence of libpetsc.so
243     if (NOT PETSC_LIBRARY_SINGLE)
244       petsc_find_library (SINGLE petsc_real) #check existence of libpetsc_real.so
245     endif()
246     if (NOT PETSC_LIBRARY_SINGLE)
247       petsc_find_library (SINGLE petsc_complex) #check existence of libpetsc_complex.so
248     endif()
249     foreach (pkg SYS VEC MAT DM KSP SNES TS ALL)
250       set (PETSC_LIBRARIES_${pkg} "${PETSC_LIBRARY_SINGLE}")
251     endforeach ()
252   endif ()
253   if (PETSC_LIBRARY_TS)
254     message (STATUS "Recognized PETSc install with separate libraries for each package")
255   else ()
256     message (STATUS "Recognized PETSc install with single library for all packages")
257   endif ()
258
259   include(Check${PETSC_LANGUAGE_BINDINGS}SourceRuns)
260   macro (PETSC_TEST_RUNS includes libraries runs)
261     if(${PETSC_LANGUAGE_BINDINGS} STREQUAL "C")
262       set(_PETSC_ERR_FUNC "CHKERRQ(ierr)")
263     elseif(${PETSC_LANGUAGE_BINDINGS} STREQUAL "CXX")
264       set(_PETSC_ERR_FUNC "CHKERRXX(ierr)")
265     endif()
266     if (PETSC_VERSION VERSION_GREATER 3.1)
267       set (_PETSC_TSDestroy "TSDestroy(&ts)")
268     else ()
269       set (_PETSC_TSDestroy "TSDestroy(ts)")
270     endif ()
271
272     set(_PETSC_TEST_SOURCE "
273 static const char help[] = \"PETSc test program.\";
274 #include <petscts.h>
275 int main(int argc,char *argv[]) {
276   PetscErrorCode ierr;
277   TS ts;
278
279   ierr = PetscInitialize(&argc,&argv,0,help);${_PETSC_ERR_FUNC};
280   ierr = TSCreate(PETSC_COMM_WORLD,&ts);${_PETSC_ERR_FUNC};
281   ierr = TSSetFromOptions(ts);${_PETSC_ERR_FUNC};
282   ierr = ${_PETSC_TSDestroy};${_PETSC_ERR_FUNC};
283   ierr = PetscFinalize();${_PETSC_ERR_FUNC};
284   return 0;
285 }
286 ")
287     multipass_source_runs ("${includes}" "${libraries}" "${_PETSC_TEST_SOURCE}" ${runs} "${PETSC_LANGUAGE_BINDINGS}")
288     if (${${runs}})
289       set (PETSC_EXECUTABLE_RUNS "YES" CACHE BOOL
290         "Can the system successfully run a PETSc executable?  This variable can be manually set to \"YES\" to force CMake to accept a given PETSc configuration, but this will almost always result in a broken build.  If you change PETSC_DIR, PETSC_ARCH, or PETSC_CURRENT you would have to reset this variable." FORCE)
291     endif (${${runs}})
292   endmacro (PETSC_TEST_RUNS)
293
294
295   find_path (PETSC_INCLUDE_DIR petscts.h HINTS "${PETSC_DIR}" PATH_SUFFIXES include NO_DEFAULT_PATH)
296   find_path (PETSC_INCLUDE_CONF petscconf.h HINTS "${PETSC_DIR}" PATH_SUFFIXES "${PETSC_ARCH}/include" "bmake/${PETSC_ARCH}" NO_DEFAULT_PATH)
297   mark_as_advanced (PETSC_INCLUDE_DIR PETSC_INCLUDE_CONF)
298   set (petsc_includes_minimal ${PETSC_INCLUDE_CONF} ${PETSC_INCLUDE_DIR})
299
300   petsc_test_runs ("${petsc_includes_minimal}" "${PETSC_LIBRARIES_TS}" petsc_works_minimal)
301   if (petsc_works_minimal)
302     message (STATUS "Minimal PETSc includes and libraries work.  This probably means we are building with shared libs.")
303     set (petsc_includes_needed "${petsc_includes_minimal}")
304   else (petsc_works_minimal)     # Minimal includes fail, see if just adding full includes fixes it
305     petsc_test_runs ("${petsc_includes_all}" "${PETSC_LIBRARIES_TS}" petsc_works_allincludes)
306     if (petsc_works_allincludes) # It does, we just need all the includes (
307       message (STATUS "PETSc requires extra include paths, but links correctly with only interface libraries.  This is an unexpected configuration (but it seems to work fine).")
308       set (petsc_includes_needed ${petsc_includes_all})
309     else (petsc_works_allincludes) # We are going to need to link the external libs explicitly
310       resolve_libraries (petsc_libraries_external "${petsc_libs_external}")
311       foreach (pkg SYS VEC MAT DM KSP SNES TS ALL)
312         list (APPEND PETSC_LIBRARIES_${pkg}  ${petsc_libraries_external})
313       endforeach (pkg)
314       petsc_test_runs ("${petsc_includes_minimal}" "${PETSC_LIBRARIES_TS}" petsc_works_alllibraries)
315       if (petsc_works_alllibraries)
316          message (STATUS "PETSc only need minimal includes, but requires explicit linking to all dependencies.  This is expected when PETSc is built with static libraries.")
317         set (petsc_includes_needed ${petsc_includes_minimal})
318       else (petsc_works_alllibraries)
319         # It looks like we really need everything, should have listened to Matt
320         set (petsc_includes_needed ${petsc_includes_all})
321         petsc_test_runs ("${petsc_includes_all}" "${PETSC_LIBRARIES_TS}" petsc_works_all)
322         if (petsc_works_all) # We fail anyways
323           message (STATUS "PETSc requires extra include paths and explicit linking to all dependencies.  This probably means you have static libraries and something unexpected in PETSc headers.")
324         else (petsc_works_all) # We fail anyways
325           message (STATUS "PETSc could not be used, maybe the install is broken.")
326         endif (petsc_works_all)
327       endif (petsc_works_alllibraries)
328     endif (petsc_works_allincludes)
329   endif (petsc_works_minimal)
330
331   # We do an out-of-source build so __FILE__ will be an absolute path, hence __INSDIR__ is superfluous
332   if (${PETSC_VERSION} VERSION_LESS 3.1)
333     set (PETSC_DEFINITIONS "-D__SDIR__=\"\"" CACHE STRING "PETSc definitions" FORCE)
334   else ()
335     set (PETSC_DEFINITIONS "-D__INSDIR__=" CACHE STRING "PETSc definitions" FORCE)
336   endif ()
337   # Sometimes this can be used to assist FindMPI.cmake
338   set (PETSC_MPIEXEC ${petsc_mpiexec} CACHE FILEPATH "Executable for running PETSc MPI programs" FORCE)
339   set (PETSC_INCLUDES ${petsc_includes_needed} CACHE STRING "PETSc include path" FORCE)
340   set (PETSC_LIBRARIES ${PETSC_LIBRARIES_ALL} CACHE STRING "PETSc libraries" FORCE)
341   set (PETSC_COMPILER ${petsc_cc} CACHE FILEPATH "PETSc compiler" FORCE)
342   # Note that we have forced values for all these choices.  If you
343   # change these, you are telling the system to trust you that they
344   # work.  It is likely that you will end up with a broken build.
345   mark_as_advanced (PETSC_INCLUDES PETSC_LIBRARIES PETSC_COMPILER PETSC_DEFINITIONS PETSC_MPIEXEC PETSC_EXECUTABLE_RUNS)
346 endif ()
347
348 include (FindPackageHandleStandardArgs)
349 find_package_handle_standard_args (PETSc
350   "PETSc could not be found.  Be sure to set PETSC_DIR and PETSC_ARCH."
351   PETSC_INCLUDES PETSC_LIBRARIES PETSC_EXECUTABLE_RUNS)