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