Salome HOME
649ae8e979f7a13968ee584d0450c45d2c4de47e
[tools/solverlab.git] / CDMATH / 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.7.6 /usr/lib/petscdir/3.7
85   /usr/lib/petscdir/3.6.2 /usr/lib/petscdir/3.6
86   /usr/lib/petscdir/3.5.1 /usr/lib/petscdir/3.5
87   /usr/lib/petscdir/3.4.2 /usr/lib/petscdir/3.4
88   /usr/lib/petscdir/3.3 /usr/lib/petscdir/3.2 /usr/lib/petscdir/3.1
89   /usr/lib/petscdir/3.0.0 /usr/lib/petscdir/2.3.3 /usr/lib/petscdir/2.3.2
90   # MacPorts path
91   /opt/local/lib/petsc
92   $ENV{HOME}/petsc
93   DOC "PETSc Directory")
94
95 find_program (MAKE_EXECUTABLE NAMES make gmake)
96
97 if (PETSC_DIR AND NOT PETSC_ARCH)
98   set (_petsc_arches
99     $ENV{PETSC_ARCH}                            # If set, use environment variable first
100     linux-gnu-c-debug linux-gnu-c-opt           # Debian defaults (petsc compilation)
101     x86_64-linux-gnu-real   i686-linux-gnu-real # Debian defaults (petsc system installation)
102     arch-linux2-c-opt or arch-linux2-c-debug    # RedHat defaults (petsc compilation)
103     x86_64-redhat-linux-gnu i686-redhat-linux-gnu # RedHat defaults (petsc apt installation)
104     x86_64-unknown-linux-gnu i386-unknown-linux-gnu)
105   set (petscconf "NOTFOUND" CACHE FILEPATH "Cleared" FORCE)
106   foreach (arch ${_petsc_arches})
107     if (NOT PETSC_ARCH)
108       find_path (petscconf petscconf.h
109         HINTS ${PETSC_DIR}
110         PATH_SUFFIXES ${arch}/include bmake/${arch}
111         NO_DEFAULT_PATH)
112       if (petscconf)
113         set (PETSC_ARCH "${arch}" CACHE STRING "PETSc build architecture")
114       endif (petscconf)
115     endif (NOT PETSC_ARCH)
116   endforeach (arch)
117   set (petscconf "NOTFOUND" CACHE INTERNAL "Scratch variable" FORCE)
118 endif (PETSC_DIR AND NOT PETSC_ARCH)
119
120 set (petsc_slaves LIBRARIES_SYS LIBRARIES_VEC LIBRARIES_MAT LIBRARIES_DM LIBRARIES_KSP LIBRARIES_SNES LIBRARIES_TS
121   INCLUDE_DIR INCLUDE_CONF)
122 include (FindPackageMultipass)
123 find_package_multipass (PETSc petsc_config_current
124   STATES DIR ARCH
125   DEPENDENTS INCLUDES LIBRARIES COMPILER MPIEXEC ${petsc_slaves})
126
127 # Determine whether the PETSc layout is old-style (through 2.3.3) or
128 # new-style (>= 3.0.0)
129 if (EXISTS "${PETSC_DIR}/${PETSC_ARCH}/lib/petsc/conf/petscvariables") # > 3.5
130   set (petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules")
131   set (petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables")
132 elseif (EXISTS "${PETSC_DIR}/${PETSC_ARCH}/include/petscconf.h")   # > 2.3.3
133   set (petsc_conf_rules "${PETSC_DIR}/conf/rules")
134   set (petsc_conf_variables "${PETSC_DIR}/conf/variables")
135 elseif (EXISTS "${PETSC_DIR}/bmake/${PETSC_ARCH}/petscconf.h") # <= 2.3.3
136   set (petsc_conf_rules "${PETSC_DIR}/bmake/common/rules")
137   set (petsc_conf_variables "${PETSC_DIR}/bmake/common/variables")
138 elseif (PETSC_DIR)
139   message (SEND_ERROR "The pair PETSC_DIR=${PETSC_DIR} PETSC_ARCH=${PETSC_ARCH} do not specify a valid PETSc installation")
140 endif ()
141
142 if (petsc_conf_rules AND petsc_conf_variables AND NOT petsc_config_current)
143   petsc_get_version()
144
145   # Put variables into environment since they are needed to get
146   # configuration (petscvariables) in the PETSc makefile
147   set (ENV{PETSC_DIR} "${PETSC_DIR}")
148   set (ENV{PETSC_ARCH} "${PETSC_ARCH}")
149
150   # A temporary makefile to probe the PETSc configuration
151   set (petsc_config_makefile "${PROJECT_BINARY_DIR}/Makefile.petsc")
152   file (WRITE "${petsc_config_makefile}"
153 "## This file was autogenerated by FindPETSc.cmake
154 # PETSC_DIR  = ${PETSC_DIR}
155 # PETSC_ARCH = ${PETSC_ARCH}
156 include ${petsc_conf_rules}
157 include ${petsc_conf_variables}
158 show :
159 \t-@echo -n \${\${VARIABLE}}
160 ")
161
162   macro (PETSC_GET_VARIABLE name var)
163     set (${var} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE)
164     execute_process (COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} show VARIABLE=${name}
165       OUTPUT_VARIABLE ${var}
166       RESULT_VARIABLE petsc_return)
167   endmacro (PETSC_GET_VARIABLE)
168   petsc_get_variable (PETSC_LIB_DIR            petsc_lib_dir)
169   petsc_get_variable (PETSC_EXTERNAL_LIB_BASIC petsc_libs_external)
170   petsc_get_variable (PETSC_CCPPFLAGS          petsc_cpp_line)
171   petsc_get_variable (PETSC_INCLUDE            petsc_include)
172   petsc_get_variable (PCC                      petsc_cc)
173   petsc_get_variable (PCC_FLAGS                petsc_cc_flags)
174   petsc_get_variable (MPIEXEC                  petsc_mpiexec)
175   # We are done with the temporary Makefile, calling PETSC_GET_VARIABLE after this point is invalid!
176   file (REMOVE ${petsc_config_makefile})
177
178   include (ResolveCompilerPaths)
179   # Extract include paths and libraries from compile command line
180   resolve_includes (petsc_includes_all "${petsc_cpp_line}")
181
182   #on windows we need to make sure we're linking against the right
183   #runtime library
184   if (WIN32)
185     if (petsc_cc_flags MATCHES "-MT")
186       set(using_md False)
187       foreach(flag_var
188           CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
189           CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
190           CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
191           CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
192         if(${flag_var} MATCHES "/MD")
193           set(using_md True)
194         endif(${flag_var} MATCHES "/MD")
195       endforeach(flag_var)
196       if(${using_md} MATCHES "True")
197         message(WARNING "PETSc was built with /MT, but /MD is currently set.
198  See http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F")
199       endif(${using_md} MATCHES "True")
200     endif (petsc_cc_flags MATCHES "-MT")
201   endif (WIN32)
202
203   include (CorrectWindowsPaths)
204   convert_cygwin_path(petsc_lib_dir)
205   message (STATUS "petsc_lib_dir ${petsc_lib_dir}")
206
207   macro (PETSC_FIND_LIBRARY suffix name)
208     set (PETSC_LIBRARY_${suffix} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) # Clear any stale value, if we got here, we need to find it again
209     if (WIN32)
210       set (libname lib${name}) #windows expects "libfoo", linux expects "foo"
211     else (WIN32)
212       set (libname ${name})
213     endif (WIN32)
214     find_library (PETSC_LIBRARY_${suffix} NAMES ${libname} HINTS ${petsc_lib_dir} NO_DEFAULT_PATH)
215     set (PETSC_LIBRARIES_${suffix} "${PETSC_LIBRARY_${suffix}}")
216     mark_as_advanced (PETSC_LIBRARY_${suffix})
217   endmacro (PETSC_FIND_LIBRARY suffix name)
218
219   # Look for petscvec first, if it doesn't exist, we must be using single-library
220   petsc_find_library (VEC petscvec)
221   if (PETSC_LIBRARY_VEC)
222     petsc_find_library (SYS  "petscsys;petsc") # libpetscsys is called libpetsc prior to 3.1 (when single-library was introduced)
223     petsc_find_library (MAT  petscmat)
224     petsc_find_library (DM   petscdm)
225     petsc_find_library (KSP  petscksp)
226     petsc_find_library (SNES petscsnes)
227     petsc_find_library (TS   petscts)
228     macro (PETSC_JOIN libs deps)
229       list (APPEND PETSC_LIBRARIES_${libs} ${PETSC_LIBRARIES_${deps}})
230     endmacro (PETSC_JOIN libs deps)
231     petsc_join (VEC  SYS)
232     petsc_join (MAT  VEC)
233     petsc_join (DM   MAT)
234     petsc_join (KSP  DM)
235     petsc_join (SNES KSP)
236     petsc_join (TS   SNES)
237     petsc_join (ALL  TS)
238   else ()
239     set (PETSC_LIBRARY_VEC "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) # There is no libpetscvec
240     petsc_find_library (SINGLE petsc) #check existence of libpetsc.so
241     if (NOT PETSC_LIBRARY_SINGLE)
242       petsc_find_library (SINGLE petsc_real) #check existence of libpetsc_real.so
243     endif()
244     if (NOT PETSC_LIBRARY_SINGLE)
245       petsc_find_library (SINGLE petsc_complex) #check existence of libpetsc_complex.so
246     endif()
247     foreach (pkg SYS VEC MAT DM KSP SNES TS ALL)
248       set (PETSC_LIBRARIES_${pkg} "${PETSC_LIBRARY_SINGLE}")
249     endforeach ()
250   endif ()
251   if (PETSC_LIBRARY_TS)
252     message (STATUS "Recognized PETSc install with separate libraries for each package")
253   else ()
254     message (STATUS "Recognized PETSc install with single library for all packages")
255   endif ()
256
257   include(Check${PETSC_LANGUAGE_BINDINGS}SourceRuns)
258   macro (PETSC_TEST_RUNS includes libraries runs)
259     if(${PETSC_LANGUAGE_BINDINGS} STREQUAL "C")
260       set(_PETSC_ERR_FUNC "CHKERRQ(ierr)")
261     elseif(${PETSC_LANGUAGE_BINDINGS} STREQUAL "CXX")
262       set(_PETSC_ERR_FUNC "CHKERRXX(ierr)")
263     endif()
264     if (PETSC_VERSION VERSION_GREATER 3.1)
265       set (_PETSC_TSDestroy "TSDestroy(&ts)")
266     else ()
267       set (_PETSC_TSDestroy "TSDestroy(ts)")
268     endif ()
269
270     set(_PETSC_TEST_SOURCE "
271 static const char help[] = \"PETSc test program.\";
272 #include <petscts.h>
273 int main(int argc,char *argv[]) {
274   PetscErrorCode ierr;
275   TS ts;
276
277   ierr = PetscInitialize(&argc,&argv,0,help);${_PETSC_ERR_FUNC};
278   ierr = TSCreate(PETSC_COMM_WORLD,&ts);${_PETSC_ERR_FUNC};
279   ierr = TSSetFromOptions(ts);${_PETSC_ERR_FUNC};
280   ierr = ${_PETSC_TSDestroy};${_PETSC_ERR_FUNC};
281   ierr = PetscFinalize();${_PETSC_ERR_FUNC};
282   return 0;
283 }
284 ")
285     multipass_source_runs ("${includes}" "${libraries}" "${_PETSC_TEST_SOURCE}" ${runs} "${PETSC_LANGUAGE_BINDINGS}")
286     if (${${runs}})
287       set (PETSC_EXECUTABLE_RUNS "YES" CACHE BOOL
288         "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)
289     endif (${${runs}})
290   endmacro (PETSC_TEST_RUNS)
291
292
293   find_path (PETSC_INCLUDE_DIR petscts.h HINTS "${PETSC_DIR}" PATH_SUFFIXES include NO_DEFAULT_PATH)
294   find_path (PETSC_INCLUDE_CONF petscconf.h HINTS "${PETSC_DIR}" PATH_SUFFIXES "${PETSC_ARCH}/include" "bmake/${PETSC_ARCH}" NO_DEFAULT_PATH)
295   mark_as_advanced (PETSC_INCLUDE_DIR PETSC_INCLUDE_CONF)
296   set (petsc_includes_minimal ${PETSC_INCLUDE_CONF} ${PETSC_INCLUDE_DIR})
297
298   petsc_test_runs ("${petsc_includes_minimal}" "${PETSC_LIBRARIES_TS}" petsc_works_minimal)
299   if (petsc_works_minimal)
300     message (STATUS "Minimal PETSc includes and libraries work.  This probably means we are building with shared libs.")
301     set (petsc_includes_needed "${petsc_includes_minimal}")
302   else (petsc_works_minimal)     # Minimal includes fail, see if just adding full includes fixes it
303     petsc_test_runs ("${petsc_includes_all}" "${PETSC_LIBRARIES_TS}" petsc_works_allincludes)
304     if (petsc_works_allincludes) # It does, we just need all the includes (
305       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).")
306       set (petsc_includes_needed ${petsc_includes_all})
307     else (petsc_works_allincludes) # We are going to need to link the external libs explicitly
308       resolve_libraries (petsc_libraries_external "${petsc_libs_external}")
309       foreach (pkg SYS VEC MAT DM KSP SNES TS ALL)
310         list (APPEND PETSC_LIBRARIES_${pkg}  ${petsc_libraries_external})
311       endforeach (pkg)
312       petsc_test_runs ("${petsc_includes_minimal}" "${PETSC_LIBRARIES_TS}" petsc_works_alllibraries)
313       if (petsc_works_alllibraries)
314          message (STATUS "PETSc only need minimal includes, but requires explicit linking to all dependencies.  This is expected when PETSc is built with static libraries.")
315         set (petsc_includes_needed ${petsc_includes_minimal})
316       else (petsc_works_alllibraries)
317         # It looks like we really need everything, should have listened to Matt
318         set (petsc_includes_needed ${petsc_includes_all})
319         petsc_test_runs ("${petsc_includes_all}" "${PETSC_LIBRARIES_TS}" petsc_works_all)
320         if (petsc_works_all) # We fail anyways
321           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.")
322         else (petsc_works_all) # We fail anyways
323           message (STATUS "PETSc could not be used, maybe the install is broken.")
324         endif (petsc_works_all)
325       endif (petsc_works_alllibraries)
326     endif (petsc_works_allincludes)
327   endif (petsc_works_minimal)
328
329   # We do an out-of-source build so __FILE__ will be an absolute path, hence __INSDIR__ is superfluous
330   if (${PETSC_VERSION} VERSION_LESS 3.1)
331     set (PETSC_DEFINITIONS "-D__SDIR__=\"\"" CACHE STRING "PETSc definitions" FORCE)
332   else ()
333     set (PETSC_DEFINITIONS "-D__INSDIR__=" CACHE STRING "PETSc definitions" FORCE)
334   endif ()
335   # Sometimes this can be used to assist FindMPI.cmake
336   set (PETSC_MPIEXEC ${petsc_mpiexec} CACHE FILEPATH "Executable for running PETSc MPI programs" FORCE)
337   set (PETSC_INCLUDES ${petsc_includes_needed} CACHE STRING "PETSc include path" FORCE)
338   set (PETSC_LIBRARIES ${PETSC_LIBRARIES_ALL} CACHE STRING "PETSc libraries" FORCE)
339   set (PETSC_COMPILER ${petsc_cc} CACHE FILEPATH "PETSc compiler" FORCE)
340   # Note that we have forced values for all these choices.  If you
341   # change these, you are telling the system to trust you that they
342   # work.  It is likely that you will end up with a broken build.
343   mark_as_advanced (PETSC_INCLUDES PETSC_LIBRARIES PETSC_COMPILER PETSC_DEFINITIONS PETSC_MPIEXEC PETSC_EXECUTABLE_RUNS)
344 endif ()
345
346 include (FindPackageHandleStandardArgs)
347 find_package_handle_standard_args (PETSc
348   "PETSc could not be found.  Be sure to set PETSC_DIR and PETSC_ARCH."
349   PETSC_INCLUDES PETSC_LIBRARIES PETSC_EXECUTABLE_RUNS)