From 47a5a2e8055947bbe448db4ced5a119d4119ca41 Mon Sep 17 00:00:00 2001 From: Pietro Incardona <incardon@mpi-cbg.de> Date: Fri, 15 Feb 2019 14:43:14 +0100 Subject: [PATCH] Fixing configure script for numerics only compilation --- CMakeLists.txt | 86 ++++-- cmake_modules/CorrectWindowsPaths.cmake | 14 + cmake_modules/FindEigen3.cmake | 108 +++++++ cmake_modules/FindLibHilbert.cmake | 99 +++++++ cmake_modules/FindMetis.cmake | 187 ++++++++++++ cmake_modules/FindPETSc.cmake | 349 +++++++++++++++++++++++ cmake_modules/FindPackageMultipass.cmake | 106 +++++++ cmake_modules/FindParMetis.cmake | 164 +++++++++++ cmake_modules/FindSuiteSparse.cmake | 272 ++++++++++++++++++ cmake_modules/FindTinyObjLoader.cmake | 99 +++++++ cmake_modules/ResolveCompilerPaths.cmake | 105 +++++++ 11 files changed, 1573 insertions(+), 16 deletions(-) create mode 100644 cmake_modules/CorrectWindowsPaths.cmake create mode 100644 cmake_modules/FindEigen3.cmake create mode 100644 cmake_modules/FindLibHilbert.cmake create mode 100644 cmake_modules/FindMetis.cmake create mode 100644 cmake_modules/FindPETSc.cmake create mode 100644 cmake_modules/FindPackageMultipass.cmake create mode 100644 cmake_modules/FindParMetis.cmake create mode 100644 cmake_modules/FindSuiteSparse.cmake create mode 100644 cmake_modules/FindTinyObjLoader.cmake create mode 100644 cmake_modules/ResolveCompilerPaths.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index ec1a590e..c916ef96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,9 @@ cmake_minimum_required(VERSION 3.8 FATAL_ERROR) -project(openfpm_numerics LANGUAGES C CXX) +project(openfpm_pdata LANGUAGES C CXX) +enable_testing() -list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/CMakeFiles/) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake_modules/) set(BOOST_INCLUDE ${Boost_INCLUDE_DIR} CACHE PATH "Include directory for BOOST") set(PETSC_ROOT CACHE PATH "If compiling with linear algebra indicate the PETSC root directory") @@ -12,6 +13,8 @@ set(LIBHILBERT_ROOT CACHE PATH "LibHilbert root path") set(HDF5_ROOT CACHE PATH "HDF5 root path") set(EIGEN3_ROOT CACHE PATH "Eigen3 include path") set(LIBHILBERT_ROOT CACHE PATH "LibHilbert root path") +set(SUITESPARSE_ROOT CACHE PATH "The suitesparse root path") +set(TINYOBJLOADER_ROOT CACHE PATH "TinyObjLoader library path") set(SE_CLASS1 CACHE BOOL "Activate compilation with SE_CLASS1") set(SE_CLASS2 CACHE BOOL "Activate compilation with SE_CLASS2") set(SE_CLASS3 CACHE BOOL "Activate compilation with SE_CLASS3") @@ -21,26 +24,46 @@ set(ENV{HDF5_ROOT} ${HDF5_ROOT}) set(ENV{EIGEN3_ROOT} ${EIGEN3_ROOT}) set(METIS_DIR ${METIS_ROOT}) set(PARMETIS_DIR ${PARMETIS_ROOT}) - -set(ENV{PATH} "$ENV{PATH}:${HDF5_ROOT}/bin") -set(HDF5_PREFER_PARALLEL TRUE) +set(OPENBLAS_ROOT CACHE PATH "Root path for blas library") +set(SuiteSparse_ROOT ${SUITESPARSE_ROOT}) set (CMAKE_CXX_STANDARD 11) set (CMAKE_CUDA_STANDARD 11) +if (OPENBLAS_ROOT) + set(ENV{LD_LIBRARY_PATH} "$ENV{LD_LIBRARY_PATH}:${OPENBLAS_ROOT}/lib") + set(ENV{DYLD_LIBRARY_PATH} "$ENV{DYLD_LIBRARY_PATH}:${OPENBLAS_ROOT}/lib") +endif() + +set(ENV{PATH} "$ENV{PATH}:${HDF5_ROOT}/bin") +set(HDF5_PREFER_PARALLEL TRUE) + if(ENABLE_GPU) enable_language(CUDA) find_package(CUDA) + + if (CUDA_VERSION_MAJOR EQUAL 9 AND CUDA_VERSION_MINOR EQUAL 2) + message("CUDA is compatible") + else() + message(FATAL_ERROR "CUDA is incompatible, version 9.2 is only supported") + endif() + endif() -find_package(Boost 1.66.0 REQUIRED COMPONENTS unit_test_framework iostreams program_options) -find_package(MPI REQUIRED) + +find_package(Boost 1.68.0 COMPONENTS unit_test_framework iostreams program_options) +find_package(MPI) find_package(PETSc) -find_package(HDF5 REQUIRED) +find_package(HDF5) find_package(Eigen3) -find_package(LibHilbert REQUIRED) -find_package(Metis REQUIRED) -find_package(ParMetis REQUIRED) +find_package(LibHilbert) +find_package(Metis) +find_package(ParMetis) +find_package(TinyObjLoader ) +find_package(BLAS) +find_package(LAPACK) +find_package(Eigen3) +find_package(SuiteSparse OPTIONAL_COMPONENTS UMFPACK) if(PROFILE_WITH_SCOREP) set(CMAKE_CXX_COMPILER_LAUNCHER "scorep") @@ -51,7 +74,7 @@ endif() if(CUDA_FOUND) set(OPENFPM_INIT_FILE "initialize/initialize_wrapper_cuda.cu") else() - set(OPENFPM_INIT_FILE "initialize/initialize_wrapper_cuda.cpp") + set(OPENFPM_INIT_FILE "initialize/initialize_wrapper_cpu.cpp") endif() ###### CONFIG.h FILE ###### @@ -68,6 +91,14 @@ if(SE_CLASS3) set(DEFINE_SE_CLASS3 "#define SE_CLASS3") endif() +if(PETSC_FOUND) + set(DEFINE_HAVE_PETSC "#define HAVE_PETSC") +endif() + +if(SCAN_COVERTY) + set(DEFINE_SCAN_COVERTY "#define COVERTY_SCAN") +endif() + if(CUDA_FOUND) set(DEFINE_CUDA_GPU "#define CUDA_GPU") endif() @@ -75,18 +106,21 @@ endif() if (METIS_FOUND) set(DEFINE_HAVE_METIS "#define HAVE_METIS 1") else() + file(WRITE error_code "201") message( FATAL_ERROR "Metis is required in order to install OpenFPM" ) endif() if (PARMETIS_FOUND) set(DEFINE_HAVE_PARMETIS "#define HAVE_PARMETIS 1") else() + file(WRITE error_code "208") message( FATAL_ERROR "ParMetis is required in order to install OpenFPM") endif() if(MPI_FOUND) set(DEFINE_HAVE_MPI "#define HAVE_MPI") else() + file(WRITE error_code "200") message( FATAL_ERROR "MPI is required in order to install OpenFPM" ) endif() @@ -96,6 +130,7 @@ if (Boost_FOUND) set(DEFINE_HAVE_BOOST_PROGRAM_OPTIONS "#define HAVE_BOOST_PROGRAM_OPTIONS") set(DEFINE_HAVE_BOOST_UNIT_TEST_FRAMEWORK "#define HAVE_BOOST_UNIT_TEST_FRAMEWORK") else() + file(WRITE error_code "202") message( FATAL_ERROR "BOOST is required in order to install OpenFPM" ) endif() @@ -103,25 +138,44 @@ if(HDF5_FOUND) if (HDF5_IS_PARALLEL) set(DEFINE_HAVE_HDF5 "#define HAVE_HDF5") else() - message( STATUS "HDF5 found ${HDF5_INCLUDE_DIRS} does not have parallel support, OpenFPM require it" ) + file(WRITE error_code "207") + message( FATAL_ERROR "HDF5 found ${HDF5_INCLUDE_DIRS} does not have parallel support, OpenFPM require it" ) endif() else() + file(WRITE error_code "207") message( FATAL_ERROR "HDF5 with parallel support is required in order to install OpenFPM" ) endif() -if(EIGEN_FOUND) +if(EIGEN3_FOUND) set(DEFINE_HAVE_EIGEN "#define HAVE_EIGEN") endif() if(LIBHILBERT_FOUND) set(DEFINE_HAVE_LIBHILBERT "#define HAVE_LIBHILBERT 1") else() + file(WRITE error_code "210") message( FATAL_ERROR "LibHilbert is required in order to install OpenFPM") endif() -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config/config_cmake.h.in ${CMAKE_CURRENT_SOURCE_DIR}/src/config/config.h) +if(SUITESPARSE_FOUND AND SuiteSparse_UMFPACK_FOUND) + set(DEFINE_HAVE_SUITESPARSE "#define HAVE_SUITESPARSE") +endif() -include_directories(SYSTEM ${MPI_INCLUDE_PATH}) +if(APPLE) + set(DEFINE_HAVE_OSX "#define HAVE_OSX") +endif() + +if(TINYOBJLOADER_FOUND) + set(DEFINE_HAVE_TINYOBJLOADER "#define HAVE_TINYOBJLOADER 1") +endif() + +file(WRITE error_code "0") +file(WRITE cuda_lib "${CUDA_cudart_static_LIBRARY} ${CUDA_cudadevrt_LIBRARY}") +file(WRITE cuda_include "-I${CUDA_INCLUDE_DIRS}") +file(WRITE mpi_include "-I${MPI_C_INCLUDE_DIRS}") +file(WRITE mpi_libs "${MPI_C_LINK_FLAGS} ${MPI_C_LIBRARIES}") + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config/config_cmake.h.in ${CMAKE_CURRENT_SOURCE_DIR}/src/config/config.h) add_subdirectory (src) diff --git a/cmake_modules/CorrectWindowsPaths.cmake b/cmake_modules/CorrectWindowsPaths.cmake new file mode 100644 index 00000000..09bcdd67 --- /dev/null +++ b/cmake_modules/CorrectWindowsPaths.cmake @@ -0,0 +1,14 @@ +# CorrectWindowsPaths - this module defines one macro +# +# CONVERT_CYGWIN_PATH( PATH ) +# This uses the command cygpath (provided by cygwin) to convert +# unix-style paths into paths useable by cmake on windows + +macro (CONVERT_CYGWIN_PATH _path) + if (WIN32) + EXECUTE_PROCESS(COMMAND cygpath.exe -m ${${_path}} + OUTPUT_VARIABLE ${_path}) + string (STRIP ${${_path}} ${_path}) + endif (WIN32) +endmacro (CONVERT_CYGWIN_PATH) + diff --git a/cmake_modules/FindEigen3.cmake b/cmake_modules/FindEigen3.cmake new file mode 100644 index 00000000..a2857c10 --- /dev/null +++ b/cmake_modules/FindEigen3.cmake @@ -0,0 +1,108 @@ +# - Try to find Eigen3 lib +# +# This module supports requiring a minimum version, e.g. you can do +# find_package(Eigen3 3.1.2) +# to require version 3.1.2 or newer of Eigen3. +# +# Once done this will define +# +# EIGEN3_FOUND - system has eigen lib with correct version +# EIGEN3_INCLUDE_DIR - the eigen include directory +# EIGEN3_VERSION - eigen version +# +# and the following imported target: +# +# Eigen3::Eigen - The header-only Eigen library +# +# This module reads hints about search locations from +# the following environment variables: +# +# EIGEN3_ROOT +# EIGEN3_ROOT_DIR + +# Copyright (c) 2006, 2007 Montel Laurent, <montel@kde.org> +# Copyright (c) 2008, 2009 Gael Guennebaud, <g.gael@free.fr> +# Copyright (c) 2009 Benoit Jacob <jacob.benoit.1@gmail.com> +# Redistribution and use is allowed according to the terms of the 2-clause BSD license. + +if(NOT Eigen3_FIND_VERSION) + if(NOT Eigen3_FIND_VERSION_MAJOR) + set(Eigen3_FIND_VERSION_MAJOR 2) + endif(NOT Eigen3_FIND_VERSION_MAJOR) + if(NOT Eigen3_FIND_VERSION_MINOR) + set(Eigen3_FIND_VERSION_MINOR 91) + endif(NOT Eigen3_FIND_VERSION_MINOR) + if(NOT Eigen3_FIND_VERSION_PATCH) + set(Eigen3_FIND_VERSION_PATCH 0) + endif(NOT Eigen3_FIND_VERSION_PATCH) + + set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}") +endif(NOT Eigen3_FIND_VERSION) + +macro(_eigen3_check_version) + file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) + + string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}") + set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}") + set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}") + set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}") + + set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION}) + if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK FALSE) + else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK TRUE) + endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + + if(NOT EIGEN3_VERSION_OK) + + message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, " + "but at least version ${Eigen3_FIND_VERSION} is required") + endif(NOT EIGEN3_VERSION_OK) +endmacro(_eigen3_check_version) + +if (EIGEN3_INCLUDE_DIR) + + # in cache already + _eigen3_check_version() + set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) + set(Eigen3_FOUND ${EIGEN3_VERSION_OK}) + +else (EIGEN3_INCLUDE_DIR) + + # search first if an Eigen3Config.cmake is available in the system, + # if successful this would set EIGEN3_INCLUDE_DIR and the rest of + # the script will work as usual + find_package(Eigen3 ${Eigen3_FIND_VERSION} NO_MODULE QUIET) + + if(NOT EIGEN3_INCLUDE_DIR) + find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library + HINTS + ENV EIGEN3_ROOT + ENV EIGEN3_ROOT_DIR + PATHS + ${CMAKE_INSTALL_PREFIX}/include + ${KDE4_INCLUDE_DIR} + PATH_SUFFIXES eigen3 eigen + ) + endif(NOT EIGEN3_INCLUDE_DIR) + + if(EIGEN3_INCLUDE_DIR) + _eigen3_check_version() + endif(EIGEN3_INCLUDE_DIR) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK) + + mark_as_advanced(EIGEN3_INCLUDE_DIR) + +endif(EIGEN3_INCLUDE_DIR) + +if(EIGEN3_FOUND AND NOT TARGET Eigen3::Eigen) + add_library(Eigen3::Eigen INTERFACE IMPORTED) + set_target_properties(Eigen3::Eigen PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${EIGEN3_INCLUDE_DIR}") +endif() + diff --git a/cmake_modules/FindLibHilbert.cmake b/cmake_modules/FindLibHilbert.cmake new file mode 100644 index 00000000..572dea52 --- /dev/null +++ b/cmake_modules/FindLibHilbert.cmake @@ -0,0 +1,99 @@ +# - Try to find LibHilbert +# Once done this will define +# +# LIBHILBERT_FOUND - system has LibHilbert +# LIBHILBERT_INCLUDE_DIRS - include directories for PETSc +# LIBHILBERT_LIBRARY_DIRS - library directories for PETSc +# LIBHILBERT_LIBRARIES - libraries for PETSc +# +#============================================================================= +# Copyright (C) 2010-2016 Pietro Incardona +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + + +if (LIBHILBERT_FOUND) + return() +endif() + +add_library(libhilbert INTERFACE IMPORTED) + +# Add libraries (static) +set(_libs "-L${LIBHILBERT_ROOT}/lib -llibhilbert") +set_property(TARGET libhilbert PROPERTY INTERFACE_LINK_LIBRARIES "${_libs}") + + +# Create LibHilbert test program +set(LIBHILBERT_TEST_LIB_CPP + "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/libhilbert_test_lib.cpp") + + +file(WRITE ${LIBHILBERT_TEST_LIB_CPP} " +extern \"C\" +{ +#include \"hilbertKey.h\" +} + int main() +{ + //An integer to handle errors + int err; + + //Array to handle output + uint64_t nextCoord[2]; + + //Get the coordinates of the next cell + getIntCoordFromHKey(nextCoord, 4, 2, 0, &err); + + return 0; +} +") + +# Try to run test program (static linking) +try_run( + LIBHILBERT_TEST_LIB_EXITCODE + LIBHILBERT_TEST_LIB_COMPILED + ${CMAKE_CURRENT_BINARY_DIR} + ${LIBHILBERT_TEST_LIB_CPP} + CMAKE_FLAGS + "-DINCLUDE_DIRECTORIES:STRING=${LIBHILBERT_ROOT}/include" + "-DLINK_LIBRARIES:STRING=${LIBHILBERT_ROOT}/lib" + LINK_LIBRARIES libhilbert m + COMPILE_OUTPUT_VARIABLE LIBHILBERT_TEST_LIB_COMPILE_OUTPUT + RUN_OUTPUT_VARIABLE LIBHILBERT_TEST_LIB_OUTPUT) + +if (LIBHILBERT_TEST_LIB_COMPILED AND LIBHILBERT_TEST_LIB_EXITCODE EQUAL 0) + message(STATUS "Test LibHilbert_TEST_RUNS static linking - Success") + set(LIBHILBERT_TEST_RUNS TRUE) + set(LIBHILBERT_FOUND TRUE) + set(LIBHILBERT_INCLUDE_DIRS ${LIBHILBERT_ROOT}/include) + set(LIBHILBERT_LIBRARY_DIRS ${LIBHILBERT_ROOT}/lib) + set(LIBHILBERT_LIBRARIES -llibhilbert) +else() + message(STATUS "Test LibHilbert_TEST_RUNS static linking - Failed") + set(LIBHILBERT_TEST_RUNS FALSE) +endif() + diff --git a/cmake_modules/FindMetis.cmake b/cmake_modules/FindMetis.cmake new file mode 100644 index 00000000..cab0b085 --- /dev/null +++ b/cmake_modules/FindMetis.cmake @@ -0,0 +1,187 @@ +# -*- mode: cmake -*- +# +# METIS Find Module for Femus +# Shamelessly stolen from Amanzi open source code https://software.lanl.gov/ascem/trac +# +# Usage: +# Control the search through METIS_DIR or setting environment variable +# METIS_ROOT to the METIS installation prefix. +# +# This module does not search default paths! +# +# Following variables are set: +# METIS_FOUND (BOOL) Flag indicating if METIS was found +# METIS_INCLUDE_DIR (PATH) Path to the METIS include file +# METIS_INCLUDE_DIRS (LIST) List of all required include files +# METIS_LIBRARY_DIR (PATH) Path to the METIS library +# METIS_LIBRARY (FILE) METIS library +# METIS_LIBRARIES (LIST) List of all required METIS libraries +# +# ############################################################################# + +# Standard CMake modules see CMAKE_ROOT/Modules +include(FindPackageHandleStandardArgs) + +# Amanzi CMake functions see <root>/tools/cmake for source +#include(PrintVariable) + +if ( METIS_LIBRARIES AND METIS_INCLUDE_DIRS ) + + # Do nothing. Variables are set. No need to search again + +else(METIS_LIBRARIES AND METIS_INCLUDE_DIRS) + + # Cache variables + if(METIS_DIR) + set(METIS_DIR "${METIS_DIR}" CACHE PATH "Path to search for METIS include and library files") + endif() + + if(METIS_INCLUDE_DIR) + set(METIS_INCLUDE_DIR "${METIS_INCLUDE_DIR}" CACHE PATH "Path to search for METIS include files") + endif() + + if(METIS_LIBRARY_DIR) + set(METIS_LIBRARY_DIR "${METIS_LIBRARY_DIR}" CACHE PATH "Path to search for METIS library files") + endif() + + + # Search for include files + # Search order preference: + # (1) METIS_INCLUDE_DIR - check existence of path AND if the include files exist + # (2) METIS_DIR/<include> + # (3) Default CMake paths See cmake --html-help=out.html file for more information. + # + set(metis_inc_names "metis.h") + + if (METIS_INCLUDE_DIR) + + if (EXISTS "${METIS_INCLUDE_DIR}") + + find_path(metis_test_include_path + NAMES ${metis_inc_names} + HINTS ${METIS_INCLUDE_DIR} + NO_DEFAULT_PATH) + if(NOT metis_test_include_path) + message(SEND_ERROR "Can not locate ${metis_inc_names} in ${METIS_INCLUDE_DIR}") + endif() + set(METIS_INCLUDE_DIR "${metis_test_include_path}") + + else() + message(SEND_ERROR "METIS_INCLUDE_DIR=${METIS_INCLUDE_DIR} does not exist") + set(METIS_INCLUDE_DIR "METIS_INCLUDE_DIR-NOTFOUND") + endif() + + else() + +# Metis sometimes puts the include files in a subdir called Lib + + set(metis_inc_suffixes "include" "Lib") + if(METIS_DIR) + + if (EXISTS "${METIS_DIR}" ) + + find_path(METIS_INCLUDE_DIR + NAMES ${metis_inc_names} + HINTS ${METIS_DIR} + PATH_SUFFIXES ${metis_inc_suffixes} + NO_DEFAULT_PATH) + + else() + message(SEND_ERROR "METIS_DIR=${METIS_DIR} does not exist") + set(METIS_INCLUDE_DIR "METIS_INCLUDE_DIR-NOTFOUND") + endif() + + + else() + + find_path(METIS_INCLUDE_DIR + NAMES ${metis_inc_names} + PATH_SUFFIXES ${metis_inc_suffixes}) + + endif() + + endif() + + + # Search for libraries + # Search order preference: + # (1) METIS_LIBRARY_DIR - check existence of path AND if the library file exists + # (2) METIS_DIR/<lib,Lib> + # (3) Default CMake paths See cmake --html-help=out.html file for more information. + # + set(metis_lib_names "metis") + + + if (METIS_LIBRARY_DIR) + + if (EXISTS "${METIS_LIBRARY_DIR}") + + find_library(METIS_LIBRARY + NAMES ${metis_lib_names} + HINTS ${METIS_LIBRARY_DIR} + NO_DEFAULT_PATH) + else() + set(METIS_LIBRARY "METIS_LIBRARY-NOTFOUND") + endif() + + else() + + list(APPEND metis_lib_suffixes "lib" "Lib") + if(METIS_DIR) + + if (EXISTS "${METIS_DIR}" ) + + find_library(METIS_LIBRARY + NAMES ${metis_lib_names} + HINTS ${METIS_DIR} + PATH_SUFFIXES ${metis_lib_suffixes} + NO_DEFAULT_PATH) + + else() + set(METISLIBRARY "METIS_LIBRARY-NOTFOUND") + endif() + + + else() + + find_library(METIS_LIBRARY + NAMES ${metis_lib_names} + PATH_SUFFIXES ${metis_lib_suffixes}) + + endif() + + endif() + + if ( NOT METIS_LIBRARY ) + endif() + + + # Define prerequisite packages + set(METIS_INCLUDE_DIRS ${METIS_INCLUDE_DIR}) + set(METIS_LIBRARIES ${METIS_LIBRARY}) + + +endif(METIS_LIBRARIES AND METIS_INCLUDE_DIRS ) + +# Send useful message if everything is found +find_package_handle_standard_args(METIS DEFAULT_MSG + METIS_LIBRARIES + METIS_INCLUDE_DIRS) + +# find_package_handle_standard_args should set METIS_FOUND but it does not! +if ( METIS_LIBRARIES AND METIS_INCLUDE_DIRS) + set(METIS_FOUND TRUE) +else() + set(METIS_FOUND FALSE) +endif() + +# Define the version + +mark_as_advanced( + METIS_INCLUDE_DIR + METIS_INCLUDE_DIRS + METIS_LIBRARY + METIS_LIBRARIES + METIS_LIBRARY_DIR +) + diff --git a/cmake_modules/FindPETSc.cmake b/cmake_modules/FindPETSc.cmake new file mode 100644 index 00000000..f8ea15b6 --- /dev/null +++ b/cmake_modules/FindPETSc.cmake @@ -0,0 +1,349 @@ +# - Try to find PETSc +# Once done this will define +# +# PETSC_FOUND - system has PETSc +# PETSC_INCLUDES - the PETSc include directories +# PETSC_LIBRARIES - Link these to use PETSc +# PETSC_COMPILER - Compiler used by PETSc, helpful to find a compatible MPI +# PETSC_DEFINITIONS - Compiler switches for using PETSc +# PETSC_MPIEXEC - Executable for running MPI programs +# PETSC_VERSION - Version string (MAJOR.MINOR.SUBMINOR) +# +# Usage: +# find_package(PETSc COMPONENTS CXX) - required if build --with-clanguage=C++ --with-c-support=0 +# find_package(PETSc COMPONENTS C) - standard behavior of checking build using a C compiler +# find_package(PETSc) - same as above +# +# Setting these changes the behavior of the search +# PETSC_DIR - directory in which PETSc resides +# PETSC_ARCH - build architecture +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +cmake_policy(VERSION 3.3) + +set(PETSC_VALID_COMPONENTS + C + CXX) + +if(NOT PETSc_FIND_COMPONENTS) + get_property (_enabled_langs GLOBAL PROPERTY ENABLED_LANGUAGES) + if ("C" IN_LIST _enabled_langs) + set(PETSC_LANGUAGE_BINDINGS "C") + else () + set(PETSC_LANGUAGE_BINDINGS "CXX") + endif () +else() + # Right now, this is designed for compatability with the --with-clanguage option, so + # only allow one item in the components list. + list(LENGTH ${PETSc_FIND_COMPONENTS} components_length) + if(${components_length} GREATER 1) + message(FATAL_ERROR "Only one component for PETSc is allowed to be specified") + endif() + # This is a stub for allowing multiple components should that time ever come. Perhaps + # to also test Fortran bindings? + foreach(component ${PETSc_FIND_COMPONENTS}) + list(FIND PETSC_VALID_COMPONENTS ${component} component_location) + if(${component_location} EQUAL -1) + message(FATAL_ERROR "\"${component}\" is not a valid PETSc component.") + else() + list(APPEND PETSC_LANGUAGE_BINDINGS ${component}) + endif() + endforeach() +endif() + +function (petsc_get_version) + if (EXISTS "${PETSC_DIR}/include/petscversion.h") + file (STRINGS "${PETSC_DIR}/include/petscversion.h" vstrings REGEX "#define PETSC_VERSION_(RELEASE|MAJOR|MINOR|SUBMINOR|PATCH) ") + foreach (line ${vstrings}) + string (REGEX REPLACE " +" ";" fields ${line}) # break line into three fields (the first is always "#define") + list (GET fields 1 var) + list (GET fields 2 val) + set (${var} ${val} PARENT_SCOPE) + set (${var} ${val}) # Also in local scope so we have access below + endforeach () + if (PETSC_VERSION_RELEASE) + if ($(PETSC_VERSION_PATCH) GREATER 0) + set (PETSC_VERSION "${PETSC_VERSION_MAJOR}.${PETSC_VERSION_MINOR}.${PETSC_VERSION_SUBMINOR}p${PETSC_VERSION_PATCH}" CACHE INTERNAL "PETSc version") + else () + set (PETSC_VERSION "${PETSC_VERSION_MAJOR}.${PETSC_VERSION_MINOR}.${PETSC_VERSION_SUBMINOR}" CACHE INTERNAL "PETSc version") + endif () + else () + # make dev version compare higher than any patch level of a released version + set (PETSC_VERSION "${PETSC_VERSION_MAJOR}.${PETSC_VERSION_MINOR}.${PETSC_VERSION_SUBMINOR}.99" CACHE INTERNAL "PETSc version") + endif () + else () + message (SEND_ERROR "PETSC_DIR can not be used, ${PETSC_DIR}/include/petscversion.h does not exist") + endif () +endfunction () + +# Debian uses versioned paths e.g /usr/lib/petscdir/3.5/ +file (GLOB DEB_PATHS "/usr/lib/petscdir/*") + +find_path (PETSC_DIR include/petsc.h + HINTS ENV PETSC_DIR + PATHS + /usr/lib/petsc + # Debian paths + ${DEB_PATHS} + # Arch Linux path + /opt/petsc/linux-c-opt + # MacPorts path + /opt/local/lib/petsc + $ENV{HOME}/petsc + DOC "PETSc Directory") + +find_program (MAKE_EXECUTABLE NAMES make gmake) + +if (PETSC_DIR AND NOT PETSC_ARCH) + set (_petsc_arches + $ENV{PETSC_ARCH} # If set, use environment variable first + linux-gnu-c-debug linux-gnu-c-opt # Debian defaults + x86_64-unknown-linux-gnu i386-unknown-linux-gnu) + set (petscconf "NOTFOUND" CACHE FILEPATH "Cleared" FORCE) + foreach (arch ${_petsc_arches}) + if (NOT PETSC_ARCH) + find_path (petscconf petscconf.h + HINTS ${PETSC_DIR} + PATH_SUFFIXES ${arch}/include bmake/${arch} + NO_DEFAULT_PATH) + if (petscconf) + set (PETSC_ARCH "${arch}" CACHE STRING "PETSc build architecture") + endif (petscconf) + endif (NOT PETSC_ARCH) + endforeach (arch) + set (petscconf "NOTFOUND" CACHE INTERNAL "Scratch variable" FORCE) +endif (PETSC_DIR AND NOT PETSC_ARCH) + +set (petsc_slaves LIBRARIES_SYS LIBRARIES_VEC LIBRARIES_MAT LIBRARIES_DM LIBRARIES_KSP LIBRARIES_SNES LIBRARIES_TS + INCLUDE_DIR INCLUDE_CONF) +include (FindPackageMultipass) +find_package_multipass (PETSc petsc_config_current + STATES DIR ARCH + DEPENDENTS INCLUDES LIBRARIES COMPILER MPIEXEC ${petsc_slaves}) + +# Determine whether the PETSc layout is old-style (through 2.3.3) or +# new-style (>= 3.0.0) +if (EXISTS "${PETSC_DIR}/${PETSC_ARCH}/lib/petsc/conf/petscvariables") # > 3.5 + set (petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules") + set (petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables") +elseif (EXISTS "${PETSC_DIR}/${PETSC_ARCH}/include/petscconf.h") # > 2.3.3 + set (petsc_conf_rules "${PETSC_DIR}/conf/rules") + set (petsc_conf_variables "${PETSC_DIR}/conf/variables") +elseif (EXISTS "${PETSC_DIR}/bmake/${PETSC_ARCH}/petscconf.h") # <= 2.3.3 + set (petsc_conf_rules "${PETSC_DIR}/bmake/common/rules") + set (petsc_conf_variables "${PETSC_DIR}/bmake/common/variables") +elseif (PETSC_DIR) + message (SEND_ERROR "The pair PETSC_DIR=${PETSC_DIR} PETSC_ARCH=${PETSC_ARCH} do not specify a valid PETSc installation") +endif () + +if (petsc_conf_rules AND petsc_conf_variables AND NOT petsc_config_current) + petsc_get_version() + + # Put variables into environment since they are needed to get + # configuration (petscvariables) in the PETSc makefile + set (ENV{PETSC_DIR} "${PETSC_DIR}") + set (ENV{PETSC_ARCH} "${PETSC_ARCH}") + + # A temporary makefile to probe the PETSc configuration + set (petsc_config_makefile "${PROJECT_BINARY_DIR}/Makefile.petsc") + file (WRITE "${petsc_config_makefile}" +"## This file was autogenerated by FindPETSc.cmake +# PETSC_DIR = ${PETSC_DIR} +# PETSC_ARCH = ${PETSC_ARCH} +include ${petsc_conf_rules} +include ${petsc_conf_variables} +show : +\t-@echo -n \${\${VARIABLE}} +") + + macro (PETSC_GET_VARIABLE name var) + set (${var} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) + execute_process (COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} show VARIABLE=${name} + OUTPUT_VARIABLE ${var} + RESULT_VARIABLE petsc_return) + endmacro (PETSC_GET_VARIABLE) + petsc_get_variable (PETSC_LIB_DIR petsc_lib_dir) + petsc_get_variable (PETSC_EXTERNAL_LIB_BASIC petsc_libs_external) + petsc_get_variable (PETSC_CCPPFLAGS petsc_cpp_line) + petsc_get_variable (PETSC_INCLUDE petsc_include) + petsc_get_variable (PCC petsc_cc) + petsc_get_variable (PCC_FLAGS petsc_cc_flags) + petsc_get_variable (MPIEXEC petsc_mpiexec) + # We are done with the temporary Makefile, calling PETSC_GET_VARIABLE after this point is invalid! + file (REMOVE ${petsc_config_makefile}) + + execute_process(COMMAND ${MPI_C_COMPILER} --showme:compile OUTPUT_VARIABLE mpi_compile_options ERROR_VARIABLE mpi_compile_error) + set(petsc_cpp_line ${petsc_cpp_line} ${mpi_compile_options}) + + include (ResolveCompilerPaths) + # Extract include paths and libraries from compile command line + resolve_includes (petsc_includes_all "${petsc_cpp_line}") + + #on windows we need to make sure we're linking against the right + #runtime library + if (WIN32) + if (petsc_cc_flags MATCHES "-MT") + set(using_md False) + foreach(flag_var + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if(${flag_var} MATCHES "/MD") + set(using_md True) + endif(${flag_var} MATCHES "/MD") + endforeach(flag_var) + if(${using_md} MATCHES "True") + message(WARNING "PETSc was built with /MT, but /MD is currently set. + See http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F") + endif(${using_md} MATCHES "True") + endif (petsc_cc_flags MATCHES "-MT") + endif (WIN32) + + include (CorrectWindowsPaths) + convert_cygwin_path(petsc_lib_dir) + message (STATUS "petsc_lib_dir ${petsc_lib_dir}") + + macro (PETSC_FIND_LIBRARY suffix name) + set (PETSC_LIBRARY_${suffix} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) # Clear any stale value, if we got here, we need to find it again + if (WIN32) + set (libname lib${name}) #windows expects "libfoo", linux expects "foo" + else (WIN32) + set (libname ${name}) + endif (WIN32) + find_library (PETSC_LIBRARY_${suffix} NAMES ${libname} HINTS ${petsc_lib_dir} NO_DEFAULT_PATH) + set (PETSC_LIBRARIES_${suffix} "${PETSC_LIBRARY_${suffix}}") + mark_as_advanced (PETSC_LIBRARY_${suffix}) + endmacro (PETSC_FIND_LIBRARY suffix name) + + # Look for petscvec first, if it doesn't exist, we must be using single-library + petsc_find_library (VEC petscvec) + if (PETSC_LIBRARY_VEC) + petsc_find_library (SYS "petscsys;petsc") # libpetscsys is called libpetsc prior to 3.1 (when single-library was introduced) + petsc_find_library (MAT petscmat) + petsc_find_library (DM petscdm) + petsc_find_library (KSP petscksp) + petsc_find_library (SNES petscsnes) + petsc_find_library (TS petscts) + macro (PETSC_JOIN libs deps) + list (APPEND PETSC_LIBRARIES_${libs} ${PETSC_LIBRARIES_${deps}}) + endmacro (PETSC_JOIN libs deps) + petsc_join (VEC SYS) + petsc_join (MAT VEC) + petsc_join (DM MAT) + petsc_join (KSP DM) + petsc_join (SNES KSP) + petsc_join (TS SNES) + petsc_join (ALL TS) + else () + set (PETSC_LIBRARY_VEC "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) # There is no libpetscvec + petsc_find_library (SINGLE petsc) + # Debian 9/Ubuntu 16.04 uses _real and _complex extensions when using libraries in /usr/lib/petsc. + if (NOT PETSC_LIBRARY_SINGLE) + petsc_find_library (SINGLE petsc_real) + endif() + if (NOT PETSC_LIBRARY_SINGLE) + petsc_find_library (SINGLE petsc_complex) + endif() + foreach (pkg SYS VEC MAT DM KSP SNES TS ALL) + set (PETSC_LIBRARIES_${pkg} "${PETSC_LIBRARY_SINGLE}") + endforeach () + endif () + if (PETSC_LIBRARY_TS) + message (STATUS "Recognized PETSc install with separate libraries for each package") + else () + message (STATUS "Recognized PETSc install with single library for all packages") + endif () + + include(Check${PETSC_LANGUAGE_BINDINGS}SourceRuns) + macro (PETSC_TEST_RUNS includes libraries runs) + if (PETSC_VERSION VERSION_GREATER 3.1) + set (_PETSC_TSDestroy "TSDestroy(&ts)") + else () + set (_PETSC_TSDestroy "TSDestroy(ts)") + endif () + + set(_PETSC_TEST_SOURCE " +static const char help[] = \"PETSc test program.\"; +#include <petscts.h> +int main(int argc,char *argv[]) { + PetscErrorCode ierr; + TS ts; + + ierr = PetscInitialize(&argc,&argv,0,help);CHKERRQ(ierr); + ierr = TSCreate(PETSC_COMM_WORLD,&ts);CHKERRQ(ierr); + ierr = TSSetFromOptions(ts);CHKERRQ(ierr); + ierr = ${_PETSC_TSDestroy};CHKERRQ(ierr); + ierr = PetscFinalize();CHKERRQ(ierr); + return 0; +} +") + multipass_source_runs ("${includes}" "${libraries}" "${_PETSC_TEST_SOURCE}" ${runs} "${PETSC_LANGUAGE_BINDINGS}") + if (${${runs}}) + set (PETSC_EXECUTABLE_RUNS "YES" CACHE BOOL + "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) + endif (${${runs}}) + endmacro (PETSC_TEST_RUNS) + + + find_path (PETSC_INCLUDE_DIR petscts.h HINTS "${PETSC_DIR}" PATH_SUFFIXES include NO_DEFAULT_PATH) + find_path (PETSC_INCLUDE_CONF petscconf.h HINTS "${PETSC_DIR}" PATH_SUFFIXES "${PETSC_ARCH}/include" "bmake/${PETSC_ARCH}" NO_DEFAULT_PATH) + mark_as_advanced (PETSC_INCLUDE_DIR PETSC_INCLUDE_CONF) + set (petsc_includes_minimal ${PETSC_INCLUDE_CONF} ${PETSC_INCLUDE_DIR}) + + petsc_test_runs ("${petsc_includes_minimal}" "${PETSC_LIBRARIES_TS}" petsc_works_minimal) + if (petsc_works_minimal) + message (STATUS "Minimal PETSc includes and libraries work. This probably means we are building with shared libs.") + set (petsc_includes_needed "${petsc_includes_minimal}") + else (petsc_works_minimal) # Minimal includes fail, see if just adding full includes fixes it + petsc_test_runs ("${petsc_includes_all}" "${PETSC_LIBRARIES_TS}" petsc_works_allincludes) + if (petsc_works_allincludes) # It does, we just need all the includes ( + 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).") + set (petsc_includes_needed ${petsc_includes_all}) + else (petsc_works_allincludes) # We are going to need to link the external libs explicitly + resolve_libraries (petsc_libraries_external "${petsc_libs_external}") + foreach (pkg SYS VEC MAT DM KSP SNES TS ALL) + list (APPEND PETSC_LIBRARIES_${pkg} ${petsc_libraries_external}) + endforeach (pkg) + petsc_test_runs ("${petsc_includes_minimal}" "${PETSC_LIBRARIES_TS}" petsc_works_alllibraries) + if (petsc_works_alllibraries) + message (STATUS "PETSc only need minimal includes, but requires explicit linking to all dependencies. This is expected when PETSc is built with static libraries.") + set (petsc_includes_needed ${petsc_includes_minimal}) + else (petsc_works_alllibraries) + # It looks like we really need everything, should have listened to Matt + set (petsc_includes_needed ${petsc_includes_all}) + petsc_test_runs ("${petsc_includes_all}" "${PETSC_LIBRARIES_TS}" petsc_works_all) + if (petsc_works_all) # We fail anyways + 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.") + else (petsc_works_all) # We fail anyways + message (STATUS "PETSc could not be used, maybe the install is broken.") + endif (petsc_works_all) + endif (petsc_works_alllibraries) + endif (petsc_works_allincludes) + endif (petsc_works_minimal) + + # We do an out-of-source build so __FILE__ will be an absolute path, hence __INSDIR__ is superfluous + if (${PETSC_VERSION} VERSION_LESS 3.1) + set (PETSC_DEFINITIONS "-D__SDIR__=\"\"" CACHE STRING "PETSc definitions" FORCE) + else () + set (PETSC_DEFINITIONS "-D__INSDIR__=" CACHE STRING "PETSc definitions" FORCE) + endif () + # Sometimes this can be used to assist FindMPI.cmake + set (PETSC_MPIEXEC ${petsc_mpiexec} CACHE FILEPATH "Executable for running PETSc MPI programs" FORCE) + set (PETSC_INCLUDES ${petsc_includes_needed} CACHE STRING "PETSc include path" FORCE) + set (PETSC_LIBRARIES ${PETSC_LIBRARIES_ALL} CACHE STRING "PETSc libraries" FORCE) + set (PETSC_COMPILER ${petsc_cc} CACHE FILEPATH "PETSc compiler" FORCE) + # Note that we have forced values for all these choices. If you + # change these, you are telling the system to trust you that they + # work. It is likely that you will end up with a broken build. + mark_as_advanced (PETSC_INCLUDES PETSC_LIBRARIES PETSC_COMPILER PETSC_DEFINITIONS PETSC_MPIEXEC PETSC_EXECUTABLE_RUNS) +endif () + +include (FindPackageHandleStandardArgs) +find_package_handle_standard_args (PETSc + REQUIRED_VARS PETSC_INCLUDES PETSC_LIBRARIES PETSC_EXECUTABLE_RUNS + VERSION_VAR PETSC_VERSION + FAIL_MESSAGE "PETSc could not be found. Be sure to set PETSC_DIR and PETSC_ARCH.") diff --git a/cmake_modules/FindPackageMultipass.cmake b/cmake_modules/FindPackageMultipass.cmake new file mode 100644 index 00000000..fbf06a7f --- /dev/null +++ b/cmake_modules/FindPackageMultipass.cmake @@ -0,0 +1,106 @@ +# PackageMultipass - this module defines two macros +# +# FIND_PACKAGE_MULTIPASS (Name CURRENT +# STATES VAR0 VAR1 ... +# DEPENDENTS DEP0 DEP1 ...) +# +# This function creates a cache entry <UPPERCASED-Name>_CURRENT which +# the user can set to "NO" to trigger a reconfiguration of the package. +# The first time this function is called, the values of +# <UPPERCASED-Name>_VAR0, ... are saved. If <UPPERCASED-Name>_CURRENT +# is false or if any STATE has changed since the last time +# FIND_PACKAGE_MULTIPASS() was called, then CURRENT will be set to "NO", +# otherwise CURRENT will be "YES". IF not CURRENT, then +# <UPPERCASED-Name>_DEP0, ... will be FORCED to NOTFOUND. +# Example: +# find_path (FOO_DIR include/foo.h) +# FIND_PACKAGE_MULTIPASS (Foo foo_current +# STATES DIR +# DEPENDENTS INCLUDES LIBRARIES) +# if (NOT foo_current) +# # Make temporary files, run programs, etc, to determine FOO_INCLUDES and FOO_LIBRARIES +# endif (NOT foo_current) +# +# MULTIPASS_SOURCE_RUNS (Name INCLUDES LIBRARIES SOURCE RUNS LANGUAGE) +# Always runs the given test, use this when you need to re-run tests +# because parent variables have made old cache entries stale. The LANGUAGE +# variable is either C or CXX indicating which compiler the test should +# use. +# MULTIPASS_C_SOURCE_RUNS (Name INCLUDES LIBRARIES SOURCE RUNS) +# DEPRECATED! This is only included for backwards compatability. Use +# the more general MULTIPASS_SOURCE_RUNS instead. +# Always runs the given test, use this when you need to re-run tests +# because parent variables have made old cache entries stale. + +macro (FIND_PACKAGE_MULTIPASS _name _current) + string (TOUPPER ${_name} _NAME) + set (_args ${ARGV}) + list (REMOVE_AT _args 0 1) + + set (_states_current "YES") + list (GET _args 0 _cmd) + if (_cmd STREQUAL "STATES") + list (REMOVE_AT _args 0) + list (GET _args 0 _state) + while (_state AND NOT _state STREQUAL "DEPENDENTS") + # The name of the stored value for the given state + set (_stored_var PACKAGE_MULTIPASS_${_NAME}_${_state}) + if (NOT "${${_stored_var}}" STREQUAL "${${_NAME}_${_state}}") + set (_states_current "NO") + endif (NOT "${${_stored_var}}" STREQUAL "${${_NAME}_${_state}}") + set (${_stored_var} "${${_NAME}_${_state}}" CACHE INTERNAL "Stored state for ${_name}." FORCE) + list (REMOVE_AT _args 0) + list (GET _args 0 _state) + endwhile (_state AND NOT _state STREQUAL "DEPENDENTS") + endif (_cmd STREQUAL "STATES") + + set (_stored ${_NAME}_CURRENT) + if (NOT ${_stored}) + set (${_stored} "YES" CACHE BOOL "Is the configuration for ${_name} current? Set to \"NO\" to reconfigure." FORCE) + set (_states_current "NO") + endif (NOT ${_stored}) + + set (${_current} ${_states_current}) + if (NOT ${_current} AND PACKAGE_MULTIPASS_${_name}_CALLED) + message (STATUS "Clearing ${_name} dependent variables") + # Clear all the dependent variables so that the module can reset them + list (GET _args 0 _cmd) + if (_cmd STREQUAL "DEPENDENTS") + list (REMOVE_AT _args 0) + foreach (dep ${_args}) + set (${_NAME}_${dep} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) + endforeach (dep) + endif (_cmd STREQUAL "DEPENDENTS") + set (${_NAME}_FOUND "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) + endif () + set (PACKAGE_MULTIPASS_${name}_CALLED YES CACHE INTERNAL "Private" FORCE) +endmacro (FIND_PACKAGE_MULTIPASS) + + +macro (MULTIPASS_SOURCE_RUNS includes libraries source runs language) + include (Check${language}SourceRuns) + # This is a ridiculous hack. CHECK_${language}_SOURCE_* thinks that if the + # *name* of the return variable doesn't change, then the test does + # not need to be re-run. We keep an internal count which we + # increment to guarantee that every test name is unique. If we've + # gotten here, then the configuration has changed enough that the + # test *needs* to be rerun. + if (NOT MULTIPASS_TEST_COUNT) + set (MULTIPASS_TEST_COUNT 00) + endif (NOT MULTIPASS_TEST_COUNT) + math (EXPR _tmp "${MULTIPASS_TEST_COUNT} + 1") # Why can't I add to a cache variable? + set (MULTIPASS_TEST_COUNT ${_tmp} CACHE INTERNAL "Unique test ID") + set (testname MULTIPASS_TEST_${MULTIPASS_TEST_COUNT}_${runs}) + set (CMAKE_REQUIRED_INCLUDES ${includes}) + set (CMAKE_REQUIRED_LIBRARIES ${libraries}) + if(${language} STREQUAL "C") + check_c_source_runs ("${source}" ${testname}) + elseif(${language} STREQUAL "CXX") + check_cxx_source_runs ("${source}" ${testname}) + endif() + set (${runs} "${${testname}}") +endmacro (MULTIPASS_SOURCE_RUNS) + +macro (MULTIPASS_C_SOURCE_RUNS includes libraries source runs) + multipass_source_runs("${includes}" "${libraries}" "${source}" ${runs} "C") +endmacro (MULTIPASS_C_SOURCE_RUNS) diff --git a/cmake_modules/FindParMetis.cmake b/cmake_modules/FindParMetis.cmake new file mode 100644 index 00000000..7103dec7 --- /dev/null +++ b/cmake_modules/FindParMetis.cmake @@ -0,0 +1,164 @@ +# - Try to find ParMETIS +# Once done this will define +# +# PARMETIS_FOUND - system has ParMETIS +# PARMETIS_INCLUDE_DIRS - include directories for ParMETIS +# PARMETIS_LIBRARIES - libraries for ParMETIS +# +# Variables used by this module. They can change the default behaviour and +# need to be set before calling find_package: +# +# PARMETIS_DIR - Prefix directory of the ParMETIS installation +# PARMETIS_INCLUDE_DIR - Include directory of the ParMETIS installation +# (set only if different from ${PARMETIS_DIR}/include) +# PARMETIS_LIB_DIR - Library directory of the ParMETIS installation +# (set only if different from ${PARMETIS_DIR}/lib) +# PARMETIS_TEST_RUNS - Skip tests building and running a test +# executable linked against ParMETIS libraries +# PARMETIS_LIB_SUFFIX - Also search for non-standard library names with the +# given suffix appended + +#============================================================================= +# Copyright (C) 2010-2012 Garth N. Wells, Anders Logg, Johannes Ring +# and Florian Rathgeber. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + +if(NOT PARMETIS_INCLUDE_DIR) + find_path(PARMETIS_INCLUDE_DIR parmetis.h + HINTS ${PARMETIS_INCLUDE_DIR} ENV PARMETIS_INCLUDE_DIR ${PARMETIS_DIR} ENV PARMETIS_DIR + PATH_SUFFIXES include + DOC "Directory where the ParMETIS header files are located" + ) +endif() + +if(NOT METIS_INCLUDE_DIR) + find_path(METIS_INCLUDE_DIR metis.h + HINTS ${METIS_INCLUDE_DIR} ENV METIS_INCLUDE_DIR ${METIS_DIR} ENV METIS_DIR + PATH_SUFFIXES include + DOC "Directory where the METIS header files are located" + ) +endif() + +if(PARMETIS_LIBRARIES) + set(PARMETIS_LIBRARY ${PARMETIS_LIBRARIES}) +endif() +if(NOT PARMETIS_LIBRARY) + find_library(PARMETIS_LIBRARY + NAMES parmetis parmetis${PARMETIS_LIB_SUFFIX} + HINTS ${PARMETIS_LIB_DIR} ENV PARMETIS_LIB_DIR ${PARMETIS_DIR} ENV PARMETIS_DIR + PATH_SUFFIXES lib + DOC "Directory where the ParMETIS library is located" + ) +endif() + +if(METIS_LIBRARIES) + set(METIS_LIBRARY ${METIS_LIBRARIES}) +endif() +if(NOT METIS_LIBRARY) + find_library(METIS_LIBRARY + NAMES metis metis${PARMETIS_LIB_SUFFIX} + HINTS ${PARMETIS_LIB_DIR} ENV PARMETIS_LIB_DIR ${PARMETIS_DIR} ENV PARMETIS_DIR + PATH_SUFFIXES lib + DOC "Directory where the METIS library is located" + ) +endif() + +# Get ParMETIS version +if(NOT PARMETIS_VERSION_STRING AND PARMETIS_INCLUDE_DIR AND EXISTS "${PARMETIS_INCLUDE_DIR}/parmetis.h") + set(version_pattern "^#define[\t ]+PARMETIS_(MAJOR|MINOR)_VERSION[\t ]+([0-9\\.]+)$") + file(STRINGS "${PARMETIS_INCLUDE_DIR}/parmetis.h" parmetis_version REGEX ${version_pattern}) + + foreach(match ${parmetis_version}) + if(PARMETIS_VERSION_STRING) + set(PARMETIS_VERSION_STRING "${PARMETIS_VERSION_STRING}.") + endif() + string(REGEX REPLACE ${version_pattern} "${PARMETIS_VERSION_STRING}\\2" PARMETIS_VERSION_STRING ${match}) + set(PARMETIS_VERSION_${CMAKE_MATCH_1} ${CMAKE_MATCH_2}) + endforeach() + unset(parmetis_version) + unset(version_pattern) +endif() + +# Try compiling and running test program +if(PARMETIS_INCLUDE_DIR AND METIS_INCLUDE_DIR AND + PARMETIS_LIBRARY AND METIS_LIBRARY) + + # Test requires MPI + find_package(MPI QUIET REQUIRED) + + # Set flags for building test program + set(CMAKE_REQUIRED_FLAGS "${MPI_C_COMPILE_FLAGS}") + # Ideally this would be used, but it unfortunately is not supported + #set(CMAKE_REQUIRED_LINKER_FLAGS "${MPI_C_LINK_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}") + set(CMAKE_REQUIRED_INCLUDES + ${PARMETIS_INCLUDE_DIR} ${METIS_INCLUDE_DIR} ${MPI_C_INCLUDE_PATH}) + set(CMAKE_REQUIRED_LIBRARIES + ${PARMETIS_LIBRARY} ${METIS_LIBRARY} ${MPI_C_LIBRARIES}) + + # Build and run test program + include(CheckCSourceCompiles) + check_c_source_compiles(" +#include \"mpi.h\" +#define METIS_EXPORT +#include \"parmetis.h\" +int main( int argc, char* argv[] ) +{ + // FIXME: Find a simple but sensible test for ParMETIS + MPI_Init( &argc, &argv ); + MPI_Finalize(); + return 0; +} +" PARMETIS_TEST_RUNS) + + unset(CMAKE_REQUIRED_FLAGS) + #unset(CMAKE_REQUIRED_LINKER_FLAGS) + unset(CMAKE_REQUIRED_INCLUDES) + unset(CMAKE_REQUIRED_LIBRARIES) +endif() + +# Standard package handling +include(FindPackageHandleStandardArgs) +if(CMAKE_VERSION VERSION_GREATER 2.8.2) + find_package_handle_standard_args(ParMETIS + REQUIRED_VARS PARMETIS_LIBRARY PARMETIS_INCLUDE_DIR PARMETIS_TEST_RUNS + VERSION_VAR PARMETIS_VERSION_STRING) +else() + find_package_handle_standard_args(ParMETIS + REQUIRED_VARS PARMETIS_LIBRARY PARMETIS_INCLUDE_DIR PARMETIS_TEST_RUNS) +endif() + +if(PARMETIS_FOUND) + set(PARMETIS_LIBRARIES ${PARMETIS_LIBRARY} ${METIS_LIBRARY}) + set(PARMETIS_INCLUDE_DIRS ${PARMETIS_INCLUDE_DIR} ${METIS_INCLUDE_DIR}) +else() + unset(METIS_LIBRARY CACHE) + unset(METIS_INCLUDE_DIR CACHE) +endif() + +mark_as_advanced(PARMETIS_INCLUDE_DIR METIS_INCLUDE_DIR + PARMETIS_LIBRARY METIS_LIBRARY) + diff --git a/cmake_modules/FindSuiteSparse.cmake b/cmake_modules/FindSuiteSparse.cmake new file mode 100644 index 00000000..f5a2649a --- /dev/null +++ b/cmake_modules/FindSuiteSparse.cmake @@ -0,0 +1,272 @@ +# .. cmake_module:: +# +# Find the SuiteSparse libraries like UMFPACK or SPQR. +# +# Example which tries to find Suite Sparse's UMFPack component: +# +# :code:`find_package(SuiteSparse OPTIONAL_COMPONENTS UMFPACK)` +# +# `OPTIONAL_COMPONENTS` +# A list of components. Components are: +# AMD, BTF, CAMD, CCOLAMD, CHOLMOD, COLAMD, CXSPARSE, +# KLU, LDL, RBIO, SPQR, UMFPACK +# +# :ref:`SuiteSparse_ROOT` +# Path list to search for SuiteSparse +# +# Sets the following variables: +# +# :code:`SuiteSparse_FOUND` +# True if SuiteSparse was found. +# +# :code:`SuiteSparse_INCLUDE_DIRS` +# Path to the SuiteSparse include dirs. +# +# :code:`SuiteSparse_LIBRARIES` +# Name of the SuiteSparse libraries. +# +# :code:`SuiteSparse_<COMPONENT>_FOUND` +# Whether <COMPONENT> was found as part of SuiteSparse. +# +# .. cmake_variable:: SuiteSparse_ROOT +# +# You may set this variable to have :ref:`FindSuiteSparse` look +# for SuiteSparse in the given path before inspecting +# system paths. +# + +find_package(BLAS QUIET) + +# look for desired componenents +set(SUITESPARSE_COMPONENTS ${SuiteSparse_FIND_COMPONENTS}) + +# resolve inter-component dependencies +list(FIND SUITESPARSE_COMPONENTS "UMFPACK" WILL_USE_UMFPACK) +if(NOT WILL_USE_UMFPACK EQUAL -1) + list(APPEND SUITESPARSE_COMPONENTS AMD CHOLMOD) +endif() +list(FIND SUITESPARSE_COMPONENTS "CHOLMOD" WILL_USE_CHOLMOD) +if(NOT WILL_USE_CHOLMOD EQUAL -1) + list(APPEND SUITESPARSE_COMPONENTS AMD CAMD COLAMD CCOLAMD) +endif() + +if(SUITESPARSE_COMPONENTS) + list(REMOVE_DUPLICATES SUITESPARSE_COMPONENTS) +endif() + +# find SuiteSparse config: +# look for library at positions given by the user +find_library(SUITESPARSE_CONFIG_LIB + NAMES "suitesparseconfig" + PATHS ${SuiteSparse_ROOT} + PATH_SUFFIXES "lib" "lib32" "lib64" "Lib" + NO_DEFAULT_PATH +) +# now also include the default paths +find_library(SUITESPARSE_CONFIG_LIB + NAMES "suitesparseconfig" + PATH_SUFFIXES "lib" "lib32" "lib64" "Lib" +) + +#look for header files at positions given by the user +find_path(SUITESPARSE_INCLUDE_DIR + NAMES "SuiteSparse_config.h" + PATHS ${SuiteSparse_ROOT} + PATH_SUFFIXES "SuiteSparse_config" "SuiteSparse_config/include" "suitesparse" "include" "src" "SuiteSparse_config/Include" + NO_DEFAULT_PATH +) +#now also look for default paths +find_path(SUITESPARSE_INCLUDE_DIR + NAMES "SuiteSparse_config.h" + PATH_SUFFIXES "SuiteSparse_config" "SuiteSparse_config/include" "suitesparse" "include" "src" "SuiteSparse_config/Include" +) + +foreach(_component ${SUITESPARSE_COMPONENTS}) + string(TOLOWER ${_component} _componentLower) + + #look for library at positions given by the user + find_library(${_component}_LIBRARY + NAMES "${_componentLower}" + PATHS ${SuiteSparse_ROOT} + PATH_SUFFIXES "lib" "lib32" "lib64" "${_component}" "${_component}/Lib" + NO_DEFAULT_PATH + ) + #now also include the default paths + find_library(${_component}_LIBRARY + NAMES "${_componentLower}" + PATH_SUFFIXES "lib" "lib32" "lib64" "${_component}" "${_component}/Lib" + ) + + #look for header files at positions given by the user + find_path(${_component}_INCLUDE_DIR + NAMES "${_componentLower}.h" + PATHS ${SuiteSparse_ROOT} + PATH_SUFFIXES "${_componentLower}" "include/${_componentLower}" "suitesparse" "include" "src" "${_component}" "${_component}/Include" + NO_DEFAULT_PATH + ) + #now also look for default paths + find_path(${_component}_INCLUDE_DIR + NAMES "${_componentLower}.h" + PATH_SUFFIXES "${_componentLower}" "include/${_componentLower}" "suitesparse" "include" "${_component}" "${_component}/Include" + ) +endforeach() + +# SPQR has different header file name SuiteSparseQR.hpp +#look for header files at positions given by the user +find_path(SPQR_INCLUDE_DIR + NAMES "SuiteSparseQR.hpp" + PATHS ${SuiteSparse_ROOT} + PATH_SUFFIXES "spqr" "include/spqr" "suitesparse" "include" "src" "SPQR" "SPQR/Include" + NO_DEFAULT_PATH +) +#now also look for default paths +find_path(SPQR_INCLUDE_DIR + NAMES "SuiteSparseQR.hpp" + PATH_SUFFIXES "spqr" "include/spqr" "suitesparse" "include" "SPQR" "SPQR/Include" +) + +# resolve inter-modular dependencies + +# CHOLMOD requires AMD, COLAMD; CAMD and CCOLAMD are optional +if(CHOLMOD_LIBRARY) + if(NOT (AMD_LIBRARY AND COLAMD_LIBRARY)) + message(WARNING "CHOLMOD requires AMD and COLAMD which were not found, skipping the test.") + set(SuiteSparse_CHOLMOD_FOUND "CHOLMOD requires AMD and COLAMD-NOTFOUND") + endif() + + list(APPEND CHOLMOD_LIBRARY ${AMD_LIBRARY} ${COLAMD_LIBRARY}) + if(CAMD_LIBRARY) + list(APPEND CHOLMOD_LIBRARY ${CAMD_LIBRARY}) + endif() + if(CCOLAMD_LIBRARY) + list(APPEND CHOLMOD_LIBRARY ${CCOLAMD_LIBRARY}) + endif() + list(REVERSE CHOLMOD_LIBRARY) + # remove duplicates + list(REMOVE_DUPLICATES CHOLMOD_LIBRARY) + list(REVERSE CHOLMOD_LIBRARY) +endif() + +# UMFPack requires AMD, can depend on CHOLMOD +if(UMFPACK_LIBRARY) + # check wether cholmod was found + if(CHOLMOD_LIBRARY) + list(APPEND UMFPACK_LIBRARY ${CHOLMOD_LIBRARY}) + else() + list(APPEND UMFPACK_LIBRARY ${AMD_LIBRARY}) + endif() + list(REVERSE UMFPACK_LIBRARY) + # remove duplicates + list(REMOVE_DUPLICATES UMFPACK_LIBRARY) + list(REVERSE UMFPACK_LIBRARY) +endif() + +# check wether everything was found +foreach(_component ${SUITESPARSE_COMPONENTS}) + # variable used for component handling + if(${_component}_LIBRARY AND ${_component}_INCLUDE_DIR) + set(SuiteSparse_${_component}_FOUND TRUE) + else() + set(SuiteSparse_${_component}_FOUND FALSE) + endif() + set(HAVE_SUITESPARSE_${_component} ${SuiteSparse_${_component}_FOUND}) + if(SuiteSparse_${_component}_FOUND) + list(APPEND SUITESPARSE_INCLUDE_DIR "${${_component}_INCLUDE_DIR}") + list(APPEND SUITESPARSE_LIBRARY "${${_component}_LIBRARY}") + endif() + + mark_as_advanced( + HAVE_SUITESPARSE_${_component} + SuiteSparse_${_component}_FOUND + ${_component}_INCLUDE_DIR + ${_component}_LIBRARY) +endforeach() + +# check version, for SPQR we need at least SuiteSparse 4.3 +if(SuiteSparse_SPQR_FOUND) + include(CheckCSourceCompiles) + include(CMakePushCheckState) + cmake_push_check_state() + set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${SUITESPARSE_INCLUDE_DIR}) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${SUITESPARSE_LIBRARY}) + # check whether version is at least 4.3 + check_c_source_compiles(" + #include <SuiteSparse_config.h> + int main(void) + { + #ifndef SUITESPARSE_HAS_VERSION_FUNCTION + #error SuiteSparse <= 4.2.0 too old, required version 4.3 or newer for SPQR. + #endif + #if SUITESPARSE_VERSION <= 4003 + #error SuiteSparse too old, required version 4.3 or newer for SPQR. + #endif + return 0; + }" + SUITESPARSE_MIN_VERSION_4_3) + + if(NOT SUITESPARSE_MIN_VERSION_4_3) + set(SuiteSparse_SPQR_FOUND FALSE) + set(HAVE_SUITESPARSE_SPQR FALSE) + endif() + cmake_pop_check_state() +endif() + +list(APPEND SUITESPARSE_LIBRARY ${SUITESPARSE_CONFIG_LIB}) + +# make them unique +if(SUITESPARSE_INCLUDE_DIR) + list(REMOVE_DUPLICATES SUITESPARSE_INCLUDE_DIR) +endif() +if(SUITESPARSE_LIBRARY) + list(REVERSE SUITESPARSE_LIBRARY) + list(REMOVE_DUPLICATES SUITESPARSE_LIBRARY) + list(REVERSE SUITESPARSE_LIBRARY) +endif() + +# behave like a CMake module is supposed to behave +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + "SuiteSparse" + FOUND_VAR SuiteSparse_FOUND + REQUIRED_VARS + BLAS_FOUND + SUITESPARSE_INCLUDE_DIR + SUITESPARSE_LIBRARY + HANDLE_COMPONENTS +) + +mark_as_advanced( + SUITESPARSE_INCLUDE_DIR + SUITESPARSE_LIBRARY + SUITESPARSE_CONFIG_LIB + SUITESPARSE_MIN_VERSION_4_3 + WILL_USE_CHOLMOD + WILL_USE_UMFPACK) + +# if both headers and library are found, store results +if(SuiteSparse_FOUND) + set(SuiteSparse_LIBRARIES ${SUITESPARSE_LIBRARY}) + set(SuiteSparse_INCLUDE_DIRS ${SUITESPARSE_INCLUDE_DIR}) + # log result + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Determining location of SuiteSparse succeeded:\n" + "Include directory: ${SuiteSparse_INCLUDE_DIRS}\n" + "Library directory: ${SuiteSparse_LIBRARIES}\n\n") + set(SuiteSparse_COMPILER_FLAGS) + foreach(dir ${SuiteSparse_INCLUDE_DIRS}) + set(SuiteSparse_COMPILER_FLAGS "${SuiteSparse_COMPILER_FLAGS} -I${dir}/") + endforeach() +else() + # log errornous result + file(APPEND ${CMAKE_BINARY_DIR}${CMAKES_FILES_DIRECTORY}/CMakeError.log + "Determing location of SuiteSparse failed:\n" + "Include directory: ${SuiteSparse_INCLUDE_DIRS}\n" + "Library directory: ${SuiteSparse_LIBRARIES}\n\n") +endif() + +#set HAVE_SUITESPARSE for config.h +set(HAVE_SUITESPARSE ${SuiteSparse_FOUND}) +set(HAVE_UMFPACK ${SuiteSparse_UMFPACK_FOUND}) + + + diff --git a/cmake_modules/FindTinyObjLoader.cmake b/cmake_modules/FindTinyObjLoader.cmake new file mode 100644 index 00000000..98bdae4d --- /dev/null +++ b/cmake_modules/FindTinyObjLoader.cmake @@ -0,0 +1,99 @@ +# - Try to find LibHilbert +# Once done this will define +# +# TINYOBJLOADER_FOUND - system has LibHilbert +# TINYOBJLOADER_INCLUDE_DIRS - include directories for PETSc +# TINYOBJLOADER_LIBRARY_DIRS - library directories for PETSc +# TINYOBJLOADER_LIBRARIES - libraries for PETSc +# +#============================================================================= +# Copyright (C) 2010-2016 Pietro Incardona +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + + +if (TINYOBJLOADER_FOUND OR TARGET tinyobjloader) + return() +endif() + +add_library(tinyobjloader INTERFACE IMPORTED) + +# Add libraries (static) +set(_libs "-L${TINYOBJLOADER_ROOT}/lib64 -ltinyobjloader") +set_property(TARGET tinyobjloader PROPERTY INTERFACE_LINK_LIBRARIES "${_libs}") + + +# Create LibHilbert test program +set(TINYOBJLOADER_TEST_LIB_CPP + "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/tinyobjloader_test_lib.cpp") + + +file(WRITE ${TINYOBJLOADER_TEST_LIB_CPP} " +#define TINYOBJLOADER_IMPLEMENTATION +#include \"tiny_obj_loader.h\" + + +int main() +{ + std::string inputfile = \"null.obj\"; + tinyobj::attrib_t attrib; + std::vector<tinyobj::shape_t> shapes; + std::vector<tinyobj::material_t> materials; + + std::string err; + bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, inputfile.c_str()); + + return 0; +} +") + +# Try to run test program (static linking) +try_run( + TINYOBJLOADER_TEST_LIB_EXITCODE + TINYOBJLOADER_TEST_LIB_COMPILED + ${CMAKE_CURRENT_BINARY_DIR} + ${TINYOBJLOADER_TEST_LIB_CPP} + CMAKE_FLAGS + "-DINCLUDE_DIRECTORIES:STRING=${TINYOBJLOADER_ROOT}/include" + "-DLINK_LIBRARIES:STRING=${TINYOBJLOADER_ROOT}/lib" + LINK_LIBRARIES tinyobjloader + COMPILE_OUTPUT_VARIABLE TINYOBJLOADER_TEST_LIB_COMPILE_OUTPUT + RUN_OUTPUT_VARIABLE TINYOBJLOADER_TEST_LIB_OUTPUT) + + +if (TINYOBJLOADER_TEST_LIB_COMPILED AND TINYOBJLOADER_TEST_LIB_EXITCODE EQUAL 0) + message(STATUS "Test TinyObjLoader_TEST_RUNS static linking - Success") + set(TINYOBJLOADER_TEST_RUNS TRUE) + set(TINYOBJLOADER_FOUND TRUE) + set(TINYOBJLOADER_INCLUDE_DIRS ${TINYOBJLOADER_ROOT}/include) + set(TINYOBJLOADER_LIBRARY_DIRS ${TINYOBJLOADER_ROOT}/lib64) + set(TINYOBJLOADER_LIBRARIES -ltinyobjloader) +else() + message(STATUS "Test TinyObjLoader_TEST_RUNS static linking - Failed") + set(TINYOBJLOADER_TEST_RUNS FALSE) +endif() + diff --git a/cmake_modules/ResolveCompilerPaths.cmake b/cmake_modules/ResolveCompilerPaths.cmake new file mode 100644 index 00000000..54787fa3 --- /dev/null +++ b/cmake_modules/ResolveCompilerPaths.cmake @@ -0,0 +1,105 @@ +# ResolveCompilerPaths - this module defines two macros +# +# RESOLVE_LIBRARIES (XXX_LIBRARIES LINK_LINE) +# This macro is intended to be used by FindXXX.cmake modules. +# It parses a compiler link line and resolves all libraries +# (-lfoo) using the library path contexts (-L/path) in scope. +# The result in XXX_LIBRARIES is the list of fully resolved libs. +# Example: +# +# RESOLVE_LIBRARIES (FOO_LIBRARIES "-L/A -la -L/B -lb -lc -ld") +# +# will be resolved to +# +# FOO_LIBRARIES:STRING="/A/liba.so;/B/libb.so;/A/libc.so;/usr/lib/libd.so" +# +# if the filesystem looks like +# +# /A: liba.so libc.so +# /B: liba.so libb.so +# /usr/lib: liba.so libb.so libc.so libd.so +# +# and /usr/lib is a system directory. +# +# Note: If RESOLVE_LIBRARIES() resolves a link line differently from +# the native linker, there is a bug in this macro (please report it). +# +# RESOLVE_INCLUDES (XXX_INCLUDES INCLUDE_LINE) +# This macro is intended to be used by FindXXX.cmake modules. +# It parses a compile line and resolves all includes +# (-I/path/to/include) to a list of directories. Other flags are ignored. +# Example: +# +# RESOLVE_INCLUDES (FOO_INCLUDES "-I/A -DBAR='\"irrelevant -I/string here\"' -I/B") +# +# will be resolved to +# +# FOO_INCLUDES:STRING="/A;/B" +# +# assuming both directories exist. +# Note: as currently implemented, the -I/string will be picked up mistakenly (cry, cry) +include (CorrectWindowsPaths) + +macro (RESOLVE_LIBRARIES LIBS LINK_LINE) + string (REGEX MATCHALL "((-L|-l|-Wl)([^\" ]+|\"[^\"]+\")|[^\" ]+\\.(a|so|dll|lib))" _all_tokens "${LINK_LINE}") + set (_libs_found "") + set (_directory_list "") + foreach (token ${_all_tokens}) + if (token MATCHES "-L([^\" ]+|\"[^\"]+\")") + # If it's a library path, add it to the list + string (REGEX REPLACE "^-L" "" token ${token}) + string (REGEX REPLACE "//" "/" token ${token}) + convert_cygwin_path(token) + list (APPEND _directory_list ${token}) + elseif (token MATCHES "^(-l([^\" ]+|\"[^\"]+\")|[^\" ]+\\.(a|so|dll|lib))") + # It's a library, resolve the path by looking in the list and then (by default) in system directories + if (WIN32) #windows expects "libfoo", linux expects "foo" + string (REGEX REPLACE "^-l" "lib" token ${token}) + else (WIN32) + string (REGEX REPLACE "^-l" "" token ${token}) + endif (WIN32) + set (_root "") + if (token MATCHES "^/") # We have an absolute path + #separate into a path and a library name: + string (REGEX MATCH "[^/]*\\.(a|so|dll|lib)$" libname ${token}) + string (REGEX MATCH ".*[^${libname}$]" libpath ${token}) + convert_cygwin_path(libpath) + set (_directory_list ${_directory_list} ${libpath}) + set (token ${libname}) + endif (token MATCHES "^/") + set (_lib "NOTFOUND" CACHE FILEPATH "Cleared" FORCE) + find_library (_lib ${token} HINTS ${_directory_list} ${_root}) + if (_lib) + string (REPLACE "//" "/" _lib ${_lib}) + list (APPEND _libs_found ${_lib}) + else (_lib) + message (STATUS "Unable to find library ${token}") + endif (_lib) + endif (token MATCHES "-L([^\" ]+|\"[^\"]+\")") + endforeach (token) + set (_lib "NOTFOUND" CACHE INTERNAL "Scratch variable" FORCE) + # only the LAST occurence of each library is required since there should be no circular dependencies + if (_libs_found) + list (REVERSE _libs_found) + list (REMOVE_DUPLICATES _libs_found) + list (REVERSE _libs_found) + endif (_libs_found) + set (${LIBS} "${_libs_found}") +endmacro (RESOLVE_LIBRARIES) + +macro (RESOLVE_INCLUDES INCS COMPILE_LINE) + string (REGEX MATCHALL "-I([^\" ]+|\"[^\"]+\")" _all_tokens "${COMPILE_LINE}") + set (_incs_found "") + foreach (token ${_all_tokens}) + string (REGEX REPLACE "^-I" "" token ${token}) + string (REGEX REPLACE "//" "/" token ${token}) + convert_cygwin_path(token) + if (EXISTS ${token}) + list (APPEND _incs_found ${token}) + else (EXISTS ${token}) + message (STATUS "Include directory ${token} does not exist") + endif (EXISTS ${token}) + endforeach (token) + list (REMOVE_DUPLICATES _incs_found) + set (${INCS} "${_incs_found}") +endmacro (RESOLVE_INCLUDES) -- GitLab