cmake_minimum_required (VERSION 3.4) # CMake utils list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") # Forbids in-source builds include(CheckNotInSources) #------------------------------------------------------ #----------------- Main configuration ----------------- #------------------------------------------------------ # custom variable allowing to define version suffixes such as -rc*, -beta*, ... set(PUGS_VERSION "0.4.1") # deduce PUGS_SHORT_VERSION using regex string(REGEX MATCH "^[0-9]+\.[0-9]+\.[0-9]+" PUGS_SHORT_VERSION ${PUGS_VERSION}) if("${PUGS_SHORT_VERSION}" STREQUAL "") message(FATAL_ERROR "Unable to compute short version from PUGS_VERSION=${PUGS_VERSION}") endif() # set project version as PUGS_SHORT_VERSION project (Pugs VERSION ${PUGS_SHORT_VERSION}) #------------------------------------------------------ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) #------------------------------------------------------ set(PUGS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") set(PUGS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") # Change RelWithDebInfo to compile assertions SET("CMAKE_CXX_FLAGS_RELWITHDEBINFO" "-g -O2" CACHE STRING "Flags used by the compiler during release builds with debug info and assertions" FORCE ) SET("CMAKE_C_FLAGS_RELWITHDEBINFO" "-g -O2" CACHE STRING "Flags used by the compiler during release builds with debug info and assertions" FORCE ) # Add new build types set(CMAKE_CXX_FLAGS_COVERAGE "-g -O0 --coverage" CACHE STRING "Flags used by the C++ compiler during coverage builds." FORCE ) set(CMAKE_C_FLAGS_COVERAGE "-g -O0 --coverage" CACHE STRING "Flags used by the C compiler during coverage builds." FORCE ) set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "--coverage" CACHE STRING "Flags used for linking binaries during coverage builds." FORCE ) set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "--coverage" CACHE STRING "Flags used by the shared libraries linker during coverage builds." FORCE ) mark_as_advanced( CMAKE_CXX_FLAGS_COVERAGE CMAKE_C_FLAGS_COVERAGE CMAKE_EXE_LINKER_FLAGS_COVERAGE CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) if(CMAKE_BUILD_TYPE) string(REGEX MATCH "(Debug|Release|RelWithDebInfo|MinSizeRel|Coverage)" VALID_BUILD_TYPE "${CMAKE_BUILD_TYPE}") if(NOT VALID_BUILD_TYPE) message(FATAL_ERROR "Invalid CMAKE_BUILD_TYPE: '${CMAKE_BUILD_TYPE}'") endif() endif() # Default build type is RelWIthDebInfo if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build: Debug Release RelWithDebInfo MinSizeRel Coverage." FORCE) endif() #------------------------------------------------------ # Checks if compiler version is compatible with Pugs sources set(GNU_CXX_MIN_VERSION "7.0.0") set(CLANG_CXX_MIN_VERSION "5.0.0") # Pugs default compiler flags set(PUGS_CXX_FLAGS "${PUGS_CXX_FLAGS} -Wall -Wextra") if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "${GNU_CXX_MIN_VERSION}") message(FATAL_ERROR "Pugs build requires at least g++-${GNU_CXX_MIN_VERSION}") endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "${CLANG_CXX_MIN_VERSION}") message(FATAL_ERROR "Pugs build requires at least llvm/clang ++-${CLANG_CXX_MIN_VERSION}") endif() set(PUGS_CXX_FLAGS "${PUGS_CXX_FLAGS} -Wsign-compare -Wunused -Wunused-member-function -Wunused-private-field") endif() #------------------------------------------------------ # defaults use of MPI set(PUGS_ENABLE_MPI AUTO CACHE STRING "Choose one of: AUTO ON OFF") if (NOT PUGS_ENABLE_MPI MATCHES "^(AUTO|ON|OFF)$") message(FATAL_ERROR "PUGS_ENABLE_MPI='${PUGS_ENABLE_MPI}'. Must be set to one of AUTO, ON or OFF") endif() # checks for MPI if (PUGS_ENABLE_MPI MATCHES "^(AUTO|ON)$") find_package(MPI) endif() #------------------------------------------------------ # Search for ParMETIS if(${MPI_FOUND}) find_package(ParMETIS) if (NOT PARMETIS_LIBRARIES) if(PUGS_ENABLE_MPI MATCHES "^AUTO$") message(WARNING "MPI support deactivated: ParMETIS cannot be found!") unset(MPI_FOUND) unset(MPI_CXX_LINK_FLAGS) unset(MPI_CXX_LIBRARIES) else() message(FATAL_ERROR "MPI support requires ParMETIS which cannot be found!") endif() endif() endif() # ----------------------------------------------------- if (${MPI_FOUND}) set(PUGS_CXX_FLAGS "${PUGS_CXX_FLAGS} ${MPI_CXX_COMPILER_FLAGS}") include_directories(SYSTEM ${MPI_CXX_INCLUDE_DIRS}) elseif(PUGS_ENABLE_MPI STREQUAL "ON") message(FATAL_ERROR "Could not find MPI library while requested") endif() set(PUGS_HAS_MPI ${MPI_FOUND}) #------------------------------------------------------ # search for clang-format find_program(CLANG_FORMAT clang-format) if (CLANG_FORMAT) add_custom_target(clang-format COMMAND echo "running ${CLANG_FORMAT} ..." COMMAND ${CMAKE_COMMAND} -DPUGS_SOURCE_DIR="${PUGS_SOURCE_DIR}" -DCLANG_FORMAT="${CLANG_FORMAT}" -P ${PUGS_SOURCE_DIR}/cmake/ClangFormatProcess.cmake) else () message(WARNING "clang-format no found!") endif() #------------------------------------------------------ # setting Kokkos defaults to OpenMP when available include(FindOpenMP) if(${OPENMP_FOUND}) set(KOKKOS_ENABLE_OPENMP ON CACHE BOOL "") endif() # do not build ETI by default set(KOKKOS_ENABLE_EXPLICIT_INSTANTIATION OFF CACHE BOOL "") # do not use Kokkos deprecated code set(KOKKOS_ENABLE_DEPRECATED_CODE OFF CACHE BOOL "") # Kokkos compiler flags add_subdirectory(${PUGS_SOURCE_DIR}/packages/kokkos) include_directories(SYSTEM ${Kokkos_INCLUDE_DIRS_RET}) include(GetKokkosCompilerFlags) # do not pollute compilation with Kokkos internal warnings set_target_properties(kokkos PROPERTIES COMPILE_FLAGS "-w") # sets Kokkos debug flags when non release build if (CMAKE_BUILD_TYPE MATCHES "^Release$") set (KOKKOS_ENABLE_DEBUG OFF) else() set (KOKKOS_ENABLE_DEBUG ON) endif() # C++ 17 flags if(${CMAKE_VERSION} VERSION_LESS "3.8.0") message(WARNING "Please consider to switch to CMake >= 3.8") set(PUGS_CXX_FLAGS "${PUGS_CXX_FLAGS} -std=gnu++1z") if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") set(PUGS_CXX_FLAGS "${PUGS_CXX_FLAGS} -Wno-c++17-extensions") endif() else() set(CMAKE_CXX_STANDARD "17") endif() # Compiler flags set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PUGS_CXX_FLAGS}") # Add debug mode for Standard C++ library set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_GLIBCXX_DEBUG -D_LIBCPP_DEBUG=1 ${PUGS_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -D_GLIBCXX_DEBUG -D_LIBCPP_DEBUG=1 ${PUGS_CXX_FLAGS}") #------------------------------------------------------ # Rang (colors? Useless thus necessary!) include_directories(${PUGS_SOURCE_DIR}/packages/rang/include) # CLI11 include_directories(${PUGS_SOURCE_DIR}/packages/CLI11/include) # PGETL include_directories(${PUGS_SOURCE_DIR}/packages/PEGTL/include/tao) # Pugs src add_subdirectory(src) include_directories(src) include_directories(src/algebra) include_directories(src/language) include_directories(src/mesh) include_directories(src/output) include_directories(src/scheme) include_directories(src/utils) # Pugs generated sources include_directories(${PUGS_BINARY_DIR}/src/utils) # Pugs tests set(CATCH_MODULE_PATH "${PUGS_SOURCE_DIR}/packages/Catch2") include("${CATCH_MODULE_PATH}/contrib/ParseAndAddCatchTests.cmake") add_subdirectory("${CATCH_MODULE_PATH}") add_subdirectory(tests) enable_testing() add_custom_target(run_unit_tests COMMAND ${CMAKE_CTEST_COMMAND} -j ${PROCESSOR_COUNT} DEPENDS unit_tests mpi_unit_tests COMMENT "Executing unit tests." ) # unit tests coverage if("${CMAKE_BUILD_TYPE}" STREQUAL "Coverage") find_program(LCOV lcov) if(NOT LCOV) message(FATAL_ERROR "lcov not found, cannot perform coverage.") endif() if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") string(REGEX MATCH "^[0-9]+" GCC_VERSION "${CMAKE_CXX_COMPILER_VERSION}") find_program(GCOV_BIN NAMES gcov-${GCC_VERSION} gcov HINTS ${COMPILER_PATH}) elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") string(REGEX MATCH "^[0-9]+" LLVM_VERSION "${CMAKE_CXX_COMPILER_VERSION}") if(LLVM_VERSION VERSION_GREATER 7) find_program(LLVM_COV_BIN NAMES "llvm-cov-${LLVM_VERSION}" "llvm-cov" HINTS ${COMPILER_PATH}) mark_as_advanced(LLVM_COV_BIN) if (LLVM_COV_BIN) file(MAKE_DIRECTORY "${PUGS_BINARY_DIR}/tools/tmp") file(WRITE "${PUGS_BINARY_DIR}/tools/tmp/llvm-cov.sh" "#! /bin/sh\n") file(APPEND "${PUGS_BINARY_DIR}/tools/tmp/llvm-cov.sh" "'${LLVM_COV_BIN}' gcov \"\$@\"\n") file(COPY "${PUGS_BINARY_DIR}/tools/tmp/llvm-cov.sh" DESTINATION "${PUGS_BINARY_DIR}/tools" FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE) set(GCOV_BIN "${PUGS_BINARY_DIR}/tools/llvm-cov.sh") endif() endif() endif() if(NOT GCOV_BIN) message(FATAL_ERROR "Cannot find a proper gcov tool, cannot perform coverage.") endif() add_custom_target(coverage ALL # in coverage mode we do coverage! # Cleanup previously generated profiling data COMMAND ${LCOV} -q --gcov "${GCOV_BIN}" --base-directory "${PUGS_SOURCE_DIR}/src" --directory "${PUGS_BINARY_DIR}" --zerocounters # Initialize profiling data with zero coverage for every instrumented line of the project # This way the percentage of total lines covered will always be correct, even when not all source code files were loaded during the test(s) COMMAND ${LCOV} -q --gcov "${GCOV_BIN}" --base-directory "${PUGS_SOURCE_DIR}/src" --directory "${PUGS_BINARY_DIR}" --capture --initial --output-file coverage_base.info # Run tests COMMAND ${CMAKE_CTEST_COMMAND} -j ${PROCESSOR_COUNT} # Collect data from executions COMMAND ${LCOV} --gcov "${GCOV_BIN}" --base-directory "${PUGS_SOURCE_DIR}/src" --directory "${PUGS_BINARY_DIR}" --capture --output-file coverage_ctest.info # Combine base and ctest results COMMAND ${LCOV} --gcov "${GCOV_BIN}" -q --add-tracefile coverage_base.info --add-tracefile coverage_ctest.info --output-file coverage_full.info # Extract only project data (--no-capture or --remove options may be used to select collected data) COMMAND ${LCOV} --gcov "${GCOV_BIN}" -q --extract coverage_full.info "'${PUGS_SOURCE_DIR}/src/*'" --output-file coverage_extract.info # Remove unwanted stuff COMMAND ${LCOV} --gcov "${GCOV_BIN}" --remove coverage_extract.info --output-file coverage.info '${PUGS_SOURCE_DIR}/src/main.cpp' '${PUGS_SOURCE_DIR}/utils/BacktraceManager.*' COMMAND ${LCOV} --gcov "${GCOV_BIN}" --list coverage.info DEPENDS unit_tests mpi_unit_tests COMMENT "Running test coverage." WORKING_DIRECTORY "${PUGS_BINARY_DIR}" ) find_program(GENHTML genhtml) if(NOT GENHTML) message(WARNING "genhtml not found, cannot perform report-coverage.") else() add_custom_target(coverage-report ALL COMMAND ${CMAKE_COMMAND} -E remove_directory "${PUGS_BINARY_DIR}/coverage" COMMAND ${CMAKE_COMMAND} -E make_directory "${PUGS_BINARY_DIR}/coverage" COMMAND ${GENHTML} -q -o coverage -t "${CMAKE_PROJECT_NAME} test coverage" --ignore-errors source --legend --num-spaces 4 coverage.info DEPENDS coverage COMMENT "Building coverage html report." WORKING_DIRECTORY "${PUGS_BINARY_DIR}" ) endif() endif() # ----------------------------------------------------- link_libraries("-rdynamic") # ------------------- Source files -------------------- # Pugs binary add_executable( pugs src/main.cpp) # Libraries target_link_libraries( pugs PugsMesh PugsUtils PugsLanguage kokkos ${PARMETIS_LIBRARIES} ${MPI_CXX_LINK_FLAGS} ${MPI_CXX_LIBRARIES} )