cmake_minimum_required (VERSION 3.10) # 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 "8.0.0") set(CLANG_CXX_MIN_VERSION "8.0.0") # Pugs default compiler flags set(PUGS_CXX_FLAGS "${PUGS_CXX_FLAGS} -Wall -Wextra -pedantic") 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() if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0.0") set(PUGS_STD_LINK_FLAGS "-lstdc++fs") endif() 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 ${CMAKE_COMMAND} -DPUGS_SOURCE_DIR="${PUGS_SOURCE_DIR}" -DCLANG_FORMAT="${CLANG_FORMAT}" -P ${PUGS_SOURCE_DIR}/cmake/ClangFormatProcess.cmake COMMENT "running ${CLANG_FORMAT} ...") else () message(WARNING "clang-format no found!") endif() #------------------------------------------------------ # search for clazy-standalone find_program(CLAZY_STANDALONE clazy-standalone) if (CLAZY_STANDALONE) add_custom_target(clazy-standalone COMMAND ${CMAKE_COMMAND} -DPUGS_SOURCE_DIR="${PUGS_SOURCE_DIR}" -DPUGS_BINARY_DIR="${PUGS_BINARY_DIR}" -DCLAZY_STANDALONE="${CLAZY_STANDALONE}" -P ${PUGS_SOURCE_DIR}/cmake/ClazyStandaloneProcess.cmake COMMENT "running ${CLAZY_STANDALONE} ..." ) else () message(WARNING "clazy-standalone no found!") endif() #------------------------------------------------------ # C++ 17 flags set(CMAKE_CXX_STANDARD "17") #------------------------------------------------------ # Kokkos configuration set(KOKKOS_SOURCE_DIR "${PUGS_SOURCE_DIR}/packages/kokkos") set(KOKKOS_BINARY_DIR "${PUGS_BINARY_DIR}/packages/kokkos") # setting Kokkos defaults to OpenMP when available find_package(OpenMP) if(OpenMP_CXX_FOUND) set(Kokkos_ENABLE_OPENMP ON CACHE BOOL "") endif() if("${Kokkos_ENABLE_OPENMP}" STREQUAL "ON") set(PUGS_CXX_FLAGS "${PUGS_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") set(OPENMP_LINK_FLAGS OpenMP::OpenMP_CXX) endif() add_subdirectory("${PUGS_SOURCE_DIR}/packages/kokkos") # set as SYSTEM for static analysis include_directories(SYSTEM ${KOKKOS_SOURCE_DIR}/core/src) include_directories(SYSTEM ${KOKKOS_SOURCE_DIR}/containers/src) include_directories(SYSTEM ${KOKKOS_BINARY_DIR}) set(PUGS_BUILD_KOKKOS_DEVICES "") if(${Kokkos_ENABLE_PTHREAD}) list(APPEND PUGS_BUILD_KOKKOS_DEVICES "Threads") endif() if(${Kokkos_ENABLE_CUDA}) list(APPEND PUGS_BUILD_KOKKOS_DEVICES "CUDA") endif() if(${Kokkos_ENABLE_QTHREADS}) list(APPEND PUGS_BUILD_KOKKOS_DEVICES "QThreads") endif() if(${Kokkos_ENABLE_HPX}) list(APPEND PUGS_BUILD_KOKKOS_DEVICES "HPX") endif() if(${Kokkos_ENABLE_OPENMP}) list(APPEND PUGS_BUILD_KOKKOS_DEVICES "OpenMP") endif() if(${Kokkos_ENABLE_OPENMPTARGET}) list(APPEND PUGS_BUILD_KOKKOS_DEVICES "OpenMPTarget") endif() if(${Kokkos_ENABLE_HWLOC}) list(APPEND PUGS_BUILD_KOKKOS_DEVICES "HWLoc") endif() if(${Kokkos_ENABLE_MPI}) list(APPEND PUGS_BUILD_KOKKOS_DEVICES "Kokkos/MPI") endif() if(${Kokkos_ENABLE_CUDA_UVM}) list(APPEND PUGS_BUILD_KOKKOS_DEVICES "CUDA UVM") endif() #------------------------------------------------------ # Compiler flags set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PUGS_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${PUGS_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${PUGS_CXX_FLAGS}") # Add debug mode for Standard C++ library (not for AppleClang since it is broken) if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_GLIBCXX_DEBUG -D_LIBCPP_DEBUG=1") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -D_GLIBCXX_DEBUG -D_LIBCPP_DEBUG=1") endif() #------------------------------------------------------ # Rang (colors? Useless thus necessary!) include_directories(${PUGS_SOURCE_DIR}/packages/rang/include) # CLI11 include_directories(${PUGS_SOURCE_DIR}/packages/CLI11/include) # PEGTL include_directories(SYSTEM ${PUGS_SOURCE_DIR}/packages/PEGTL/include/tao) # Pugs src add_subdirectory(${PUGS_SOURCE_DIR}/src) include_directories(${PUGS_SOURCE_DIR}/src) include_directories(${PUGS_BINARY_DIR}/src) # 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} 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() find_program(FASTCOV fastcov fastcov.py) if (FASTCOV AND (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "9")) add_custom_target(coverage ALL # in coverage mode we do coverage! # zero all counters COMMAND ${FASTCOV} -q -z # Run tests COMMAND ${CMAKE_CTEST_COMMAND} COMMAND ${FASTCOV} -q --gcov "${GCOV_BIN}" --include "${PUGS_SOURCE_DIR}/src" --exclude "${PUGS_SOURCE_DIR}/src/main.cpp" "${PUGS_SOURCE_DIR}/src/utils/BacktraceManager.*" --lcov -o coverage.info -n COMMAND ${LCOV} --gcov "${GCOV_BIN}" --list coverage.info DEPENDS unit_tests mpi_unit_tests COMMENT "Running test coverage." WORKING_DIRECTORY "${PUGS_BINARY_DIR}" ) else() 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_BINARY_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_BINARY_DIR}/src" --directory "${PUGS_BINARY_DIR}" --capture --initial --output-file coverage_base.info # Run tests COMMAND ${CMAKE_CTEST_COMMAND} # Collect data from executions COMMAND ${LCOV} --gcov "${GCOV_BIN}" --base-directory "${PUGS_BINARY_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}/src/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}" ) endif() 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} --demangle-cpp -q -o coverage -t "${CMAKE_PROJECT_NAME} test coverage" --ignore-errors source --legend --num-spaces 2 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 PugsLanguageAST PugsLanguageModules PugsLanguageAlgorithms PugsMesh PugsUtils PugsLanguageUtils kokkos ${PARMETIS_LIBRARIES} ${MPI_CXX_LINK_FLAGS} ${MPI_CXX_LIBRARIES} ${KOKKOS_CXX_FLAGS} ${OPENMP_LINK_FLAGS} ${PUGS_STD_LINK_FLAGS} stdc++fs ) # ---------------------- Doxygen ---------------------- include(PugsDoxygen) # ------------------- Installation -------------------- # temporary version workaround if(${CMAKE_VERSION} VERSION_LESS "3.13.0") install(TARGETS pugs RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) else() install(TARGETS pugs PugsMesh PugsUtils PugsLanguage RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) endif()