# # Copyright (C) 2009-2025 The ESPResSo project # Copyright (C) 2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # # This file is part of ESPResSo. # # ESPResSo is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # ESPResSo is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # cmake_minimum_required(VERSION 3.27.6) cmake_policy(VERSION 3.27.6) message(STATUS "CMake version: ${CMAKE_VERSION}") # CMake modules/macros are in a subdirectory to keep this file cleaner set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # project info project( ESPResSo VERSION "5.0.0" LANGUAGES C CXX HOMEPAGE_URL "https://espressomd.org" DESCRIPTION "Extensible Simulation Package for Research on Soft Matter Systems") # programming language standards set(ESPRESSO_MINIMAL_C_STANDARD 11) set(ESPRESSO_MINIMAL_CXX_STANDARD 20) set(ESPRESSO_MINIMAL_CUDA_STANDARD 20) set(ESPRESSO_MINIMAL_CUDA_VERSION 12.0) include(FeatureSummary) include(GNUInstallDirs) include(ExternalProject) include(FetchContent) include(espresso_option_enum) include(espresso_enable_avx2_support) include(espresso_override_clang_tidy_checks) if(EXISTS "${PROJECT_BINARY_DIR}/CMakeLists.txt") message( FATAL_ERROR "${PROJECT_NAME} cannot be built in-place. Instead, create a build directory and run CMake from there. A new file 'CMakeCache.txt' and a new folder 'CMakeFiles' have just been created by CMake in the current folder and need to be removed." ) endif() # # CMake internal vars # # Select the build type espresso_option_enum( varname "CMAKE_BUILD_TYPE" help_text "build type" default_value "Release" possible_values "Debug;Release;RelWithDebInfo;MinSizeRel;Coverage;RelWithAssert") set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} -Og -g") set(CMAKE_CXX_FLAGS_RELWITHASSERT "${CMAKE_CXX_FLAGS_RELWITHASSERT} -O3 -g") # build targets as static libraries unless otherwise specified set(ESPRESSO_BUILD_SHARED_LIBS_DEFAULT OFF) set(BUILD_SHARED_LIBS ${ESPRESSO_BUILD_SHARED_LIBS_DEFAULT}) # shared objects require position-independent code in static libraries set(CMAKE_POSITION_INDEPENDENT_CODE ON) # On Mac OS X, first look for other packages, then frameworks set(CMAKE_FIND_FRAMEWORK LAST) # avoid applying patches twice with FetchContent set(FETCHCONTENT_UPDATES_DISCONNECTED ON) # customize default options based on basic information set(ESPRESSO_BUILD_WITH_WALBERLA_AVX_DEFAULT OFF) if(CMAKE_SYSTEM_PROCESSOR MATCHES "[xX]86") set(ESPRESSO_BUILD_WITH_WALBERLA_AVX_DEFAULT ON) endif() # ############################################################################## # User input options # ############################################################################## option(ESPRESSO_BUILD_WITH_PYTHON "Build with Python bindings" ON) option(ESPRESSO_BUILD_WITH_GSL "Build with GSL support" OFF) option(ESPRESSO_BUILD_WITH_FFTW "Build with FFTW support" ON) option(ESPRESSO_BUILD_WITH_CUDA "Build with GPU support" OFF) option(ESPRESSO_BUILD_WITH_HDF5 "Build with HDF5 support" OFF) option(ESPRESSO_BUILD_TESTS "Enable tests" ON) option(ESPRESSO_BUILD_WITH_SCAFACOS "Build with ScaFaCoS support" OFF) option(ESPRESSO_BUILD_WITH_STOKESIAN_DYNAMICS "Build with Stokesian Dynamics" OFF) option(ESPRESSO_BUILD_WITH_NLOPT "Build with NLopt support" OFF) option(ESPRESSO_BUILD_WITH_WALBERLA "Build with waLBerla support" ON) option(ESPRESSO_BUILD_WITH_WALBERLA_AVX "Build waLBerla kernels with AVX2 vectorization" ${ESPRESSO_BUILD_WITH_WALBERLA_AVX_DEFAULT}) option(ESPRESSO_BUILD_WITH_SHARED_MEMORY_PARALLELISM "Build with shared memory parallelism support" OFF) option(ESPRESSO_BUILD_BENCHMARKS "Enable benchmarks" OFF) option(ESPRESSO_BUILD_WITH_VALGRIND "Build with Valgrind instrumentation" OFF) option(ESPRESSO_BUILD_WITH_CALIPER "Build with Caliper instrumentation" OFF) option(ESPRESSO_BUILD_WITH_CPPCHECK "Run Cppcheck during compilation" OFF) option(ESPRESSO_BUILD_WITH_FPE "Build with floating-point exceptions instrumentation" OFF) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") option(ESPRESSO_BUILD_WITH_CLANG_TIDY "Run Clang-Tidy during compilation" OFF) endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU") option(ESPRESSO_BUILD_WITH_COVERAGE "Generate code coverage report for C++ code" OFF) option(ESPRESSO_BUILD_WITH_COVERAGE_PYTHON "Generate code coverage report for Python code" OFF) option(ESPRESSO_BUILD_WITH_ASAN "Build with address sanitizer" OFF) option(ESPRESSO_BUILD_WITH_UBSAN "Build with undefined behavior sanitizer" OFF) endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT APPLE) option( ESPRESSO_BUILD_WITH_MSAN "Build with memory sanitizer (experimental; requires a memory-sanitized Python interpreter)" OFF) endif() option( ESPRESSO_ADD_OMPI_SINGLETON_WARNING "Add a runtime warning in the pypresso script for NUMA architectures that aren't supported in singleton mode by Open MPI 4.x" ON) option(ESPRESSO_WARNINGS_ARE_ERRORS "Treat warnings as errors during compilation" OFF) option(ESPRESSO_BUILD_WITH_CCACHE "Use ccache compiler invocation." OFF) option(ESPRESSO_INSIDE_DOCKER "Set this to ON when running inside Docker." OFF) mark_as_advanced(ESPRESSO_INSIDE_DOCKER) set(ESPRESSO_TEST_TIMEOUT "300" CACHE STRING "Timeout in seconds for each testsuite test") if(ESPRESSO_BUILD_WITH_CCACHE) find_program(CCACHE_PROGRAM ccache REQUIRED) if(CCACHE_PROGRAM) message(STATUS "Found ccache: ${CCACHE_PROGRAM}") set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_PROGRAM}) set(CMAKE_CUDA_COMPILER_LAUNCHER ${CCACHE_PROGRAM}) endif() endif() set(ESPRESSO_NUMPY_SITEARCH "" CACHE FILEPATH "NumPy's third-party platform dependent installation directory") # Write compile commands to file, for various tools... set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # choose the name of the config file set(ESPRESSO_MYCONFIG_NAME "myconfig.hpp" CACHE STRING "Default name of the local config file") # Check which config file to use include(espresso_myconfig) # # Pretty function # include(CheckCXXSourceCompiles) # cross-platform macro to print the function name in error messages set(ESPRESSO_PRETTY_FUNCTION_EXTENSION __func__) # search for a supported compiler extension that prints the function name as # well as its list of arguments, return type and namespace foreach(func_name __PRETTY_FUNCTION__ __FUNCSIG__ __FUNCTION__) check_cxx_source_compiles( " #include int main() { std::string(${func_name}); } " result${func_name}) if(result${func_name}) set(ESPRESSO_PRETTY_FUNCTION_EXTENSION ${func_name}) break() endif(result${func_name}) endforeach() # # Compiler flags: must be added to all ESPResSo targets # add_library(espresso_compiler_flags INTERFACE) add_library(espresso::compiler_flags ALIAS espresso_compiler_flags) set_property( TARGET espresso_compiler_flags APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_${ESPRESSO_MINIMAL_CXX_STANDARD}) # # AVX2 support # include(CheckCXXCompilerFlag) add_library(espresso_avx_flags INTERFACE) add_library(espresso::avx_flags ALIAS espresso_avx_flags) # # C/C++ compiler # block(SCOPE_FOR VARIABLES) set(C_COMPILER_IS_OFFICIALLY_TESTED FALSE) set(CXX_COMPILER_IS_OFFICIALLY_TESTED FALSE) macro(espresso_minimal_compiler_version) foreach(LANG C CXX) if(CMAKE_${LANG}_COMPILER_ID STREQUAL "${ARGV0}") if(CMAKE_${LANG}_COMPILER_VERSION VERSION_GREATER_EQUAL "${ARGV1}") set(${LANG}_COMPILER_IS_OFFICIALLY_TESTED TRUE) else() message( FATAL_ERROR "Unsupported compiler ${CMAKE_${LANG}_COMPILER_ID} \ ${CMAKE_${LANG}_COMPILER_VERSION} (required version >= ${ARGV1})" ) endif() endif() endforeach() endmacro() espresso_minimal_compiler_version("GNU" 12.2.0) espresso_minimal_compiler_version("Clang" 18.1.0) espresso_minimal_compiler_version("AppleClang" 17.0.0) espresso_minimal_compiler_version("CrayClang" 17.0.0) espresso_minimal_compiler_version("IntelLLVM" 2023.1) set(ESPRESSO_UNSUPPORTED_COMPILERS "Intel;MSVC") foreach(LANG C CXX) if(CMAKE_${LANG}_COMPILER_ID IN_LIST ESPRESSO_UNSUPPORTED_COMPILERS) message(FATAL_ERROR "Unsupported compiler ${CMAKE_${LANG}_COMPILER_ID}") endif() if(NOT ${LANG}_COMPILER_IS_OFFICIALLY_TESTED) message( AUTHOR_WARNING "The ${CMAKE_${LANG}_COMPILER_ID} compiler isn't actively tested by ${PROJECT_NAME}; \ ${LANG} compiler flags defined by ${PROJECT_NAME}'s CMakeLists.txt might require tweaks" ) endif() endforeach() endblock() # # CUDA compiler # set(ESPRESSO_XCOMPILER "") set(ESPRESSO_PTXAS "") if(ESPRESSO_BUILD_WITH_CUDA) include(CheckLanguage) enable_language(CUDA) check_language(CUDA) find_package(CUDAToolkit ${ESPRESSO_MINIMAL_CUDA_VERSION} REQUIRED) if(NOT DEFINED ESPRESSO_CMAKE_CUDA_ARCHITECTURES) if("$ENV{CUDAARCHS}" STREQUAL "") # 1. sm_61: GTX-1000 series (Pascal) # 2. sm_75: RTX-2000 series (Turing) # 3. sm_86: RTX-3000 series (Ampere) # 4. sm_89: RTX-4000 series (Ada) # 5. sm_90: H100 series (Hopper) # 6. sm_120: RTX-5000 series (Blackwell) set(ESPRESSO_CUDA_ARCHITECTURES "75;86;89") else() set(ESPRESSO_CUDA_ARCHITECTURES "$ENV{CUDAARCHS}") endif() set(ESPRESSO_CMAKE_CUDA_ARCHITECTURES "${ESPRESSO_CUDA_ARCHITECTURES}" CACHE INTERNAL "") endif() set(CMAKE_CUDA_ARCHITECTURES "${ESPRESSO_CMAKE_CUDA_ARCHITECTURES}") cmake_path(GET CUDA_cuda_driver_LIBRARY PARENT_PATH ESPRESSO_LIBCUDA_RPATH) cmake_path(GET CUDA_cudart_LIBRARY PARENT_PATH ESPRESSO_LIBCUDART_RPATH) macro(espresso_add_cuda_rpaths) set(TARGET_NAME ${ARGV0}) set_property( TARGET ${TARGET_NAME} APPEND PROPERTY BUILD_RPATH "${ESPRESSO_LIBCUDA_RPATH}" "${ESPRESSO_LIBCUDART_RPATH}") set_property( TARGET ${TARGET_NAME} APPEND PROPERTY INSTALL_RPATH "${ESPRESSO_LIBCUDA_RPATH}" "${ESPRESSO_LIBCUDART_RPATH}") endmacro() if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") find_package(CUDACompilerNVCC ${ESPRESSO_MINIMAL_CUDA_VERSION} REQUIRED) set(ESPRESSO_XCOMPILER "$<$:-Xcompiler=>") set(ESPRESSO_PTXAS "$<$:-Xptxas=>") elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang") if(ESPRESSO_BUILD_WITH_COVERAGE) message( FATAL_ERROR "Cannot enable code coverage with Clang as the CUDA compiler") endif() find_package(CUDACompilerClang 18.1.0 REQUIRED) else() message(FATAL_ERROR "Unknown CUDA compiler '${CMAKE_CUDA_COMPILER_ID}'") endif() set_property( TARGET espresso_compiler_flags APPEND PROPERTY INTERFACE_COMPILE_FEATURES cuda_std_${ESPRESSO_MINIMAL_CUDA_STANDARD}) endif() # Python interpreter and Cython interface library if(ESPRESSO_BUILD_WITH_PYTHON) find_package(Python 3.11 REQUIRED COMPONENTS Interpreter Development NumPy) find_package(Cython 3.0.4...<3.2.0 REQUIRED) if(CYTHON_VERSION VERSION_LESS 3.0.8) message(WARNING "We strongly recommend using Cython 3.0.8 or later") endif() find_program(IPYTHON_EXECUTABLE NAMES jupyter ipython3 ipython) if(NOT DEFINED CACHE{ESPRESSO_NUMPY_SITEARCH} OR "$CACHE{ESPRESSO_NUMPY_SITEARCH}" STREQUAL "") # NumPy isn't necessarily installed in Python_SITEARCH. EasyBuild packages # NumPy within SciPy-bundle, for example. Cython needs to include NumPy's # parent directory to properly detect file numpy/__init__.pxd. block(SCOPE_FOR VARIABLES PROPAGATE ESPRESSO_NUMPY_SITEARCH) execute_process( COMMAND ${Python_EXECUTABLE} -c "import numpy;print(numpy.__file__)" OUTPUT_VARIABLE numpy_init_path ERROR_VARIABLE numpy_init_error RESULT_VARIABLE numpy_init_result) if(NOT ${numpy_init_result} EQUAL 0) message(FATAL_ERROR "Cannot import numpy:\n${numpy_init_error}") endif() cmake_path(GET numpy_init_path PARENT_PATH numpy_path) cmake_path(GET numpy_path PARENT_PATH numpy_sitearch) set(ESPRESSO_NUMPY_SITEARCH "${numpy_sitearch}" CACHE FILEPATH "NumPy's third-party platform dependent installation directory" FORCE) endblock() endif() endif() # # Installation folders # string(REGEX REPLACE "/+$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") # folder for binaries and wrapper scripts set(ESPRESSO_INSTALL_BINDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}") # folder for C++ and CUDA shared objects set(ESPRESSO_INSTALL_LIBDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") set(ESPRESSO_OLD_CMAKE_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}") # python site-packages, can be overriden with CMake options if(ESPRESSO_BUILD_WITH_PYTHON) if(NOT ESPRESSO_INSTALL_PYTHON) if(CMAKE_INSTALL_PREFIX STREQUAL "/") set(ESPRESSO_INSTALL_PYTHON "${Python_SITEARCH}") else() set(ESPRESSO_INSTALL_PYTHON "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/python${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}/site-packages" ) endif() endif() # override: package C++, CUDA and Cython shared objects together set(ESPRESSO_INSTALL_LIBDIR "${ESPRESSO_INSTALL_PYTHON}/espressomd") add_custom_target(espresso_packaging_dependencies) endif() # # Compiler diagnostics # # cmake-format: off target_compile_options( espresso_compiler_flags INTERFACE $<$:-Wall> $<$:-Wextra> $<$:-pedantic> # add extra warnings $<$:-Wfloat-conversion> $<$:-Wdelete-non-virtual-dtor> $<$:-Wnon-virtual-dtor> $<$:-Wcast-qual> $<$:-Wcast-align> $<$:-Wunused-macros> $<$:-Wpointer-arith> $<$:-Winit-self> $<$:-Wextern-initializer> $<$:-Wrange-loop-analysis> $<$:-Wnon-c-typedef-for-linkage> $<$:-Wshadow-uncaptured-local> $<$:-Wimplicit-float-conversion> $<$:-Wunused-exception-parameter> $<$:-Wmissing-variable-declarations> $<$:-Wctad-maybe-unsupported> $<$:-Wbuiltin-macro-redefined> $<$:-Wformat-signedness> $<$:-Wdiv-by-zero> $<$:-Wextra-semi> $<$:-Wexceptions> $<$:-Wdeprecated-declarations> $<$:-Wdeprecated-enum-enum-conversion> $<$:-Wdeprecated-enum-float-conversion> $<$:-Wformat=2> $<$:-Wbidi-chars> $<$:-Wcomma-subscript> $<$:-Wduplicated-branches> $<$:-Wshadow=compatible-local> $<$:-Wshadow-field-in-constructor-modified> # disable warnings from -Wall and -Wextra, as well as warnings triggered by third-party libraries $<$:-Wno-sign-compare> $<$:-Wno-unused-parameter> $<$:-Wno-array-bounds> $<$:-Wno-restrict> $<$:-Wno-cast-function-type> $<$:-diag-disable=592> $<$:-Wno-global-constructors> $<$,$>:-Wno-psabi> $<$,$>:-Wno-format-nonliteral> $<$,$>:-Wno-float-conversion> $<$,$>:-Wno-implicit-int-float-conversion> $<$,$>:-Wno-implicit-float-conversion> $<$,$>:-Wno-tautological-constant-compare> $<$,$>:-Wno-ctad-maybe-unsupported> $<$,$>:-Wno-extra-semi> $<$,$>:-Wno-extra-semi> $<$,$>:-Wno-extra-semi> $<$,$>:-Wno-cast-qual> $<$,$>:-Wno-old-style-cast> # warnings are errors $<$,$>:-Werror> $<$,$>:--Werror=all-warnings> $<$,$>:-Werror> # configurations for NVCC $<$,$>:-g -G> $<$,$>:-Xptxas=-O3 -Xcompiler=-O3 -DNDEBUG> $<$,$>:-Xptxas=-O2 -Xcompiler=-Os -DNDEBUG> $<$,$>:-Xptxas=-O2 -Xcompiler=-O2,-g -DNDEBUG> $<$,$>:-Xptxas=-O3 -Xcompiler=-Og,-g> $<$,$>:-Xptxas=-O3 -Xcompiler=-O3,-g> $<$,$>:-Xcompiler=-isysroot;-Xcompiler=${CMAKE_OSX_SYSROOT}> # configurations for LLVM $<$,$>:-g> $<$,$>:-O3 -DNDEBUG> $<$,$>:-O2 -DNDEBUG> $<$,$>:-O2 -g -DNDEBUG> $<$,$>:-Og -g> $<$,$>:-O3 -g> ) # cmake-format: on # # Code coverage # if(ESPRESSO_BUILD_WITH_COVERAGE) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|IntelLLVM") # cmake-format: off target_compile_options( espresso_compiler_flags INTERFACE $<$:-fprofile-instr-generate -fcoverage-mapping> ) # cmake-format: on else() # cmake-format: off target_compile_options( espresso_compiler_flags INTERFACE $<$:--coverage -fprofile-abs-path> $<$:-Xcompiler=--coverage,-fprofile-abs-path> # workaround for https://github.com/espressomd/espresso/issues/4943 $<$,$>:--coverage -fprofile-abs-path> ) # cmake-format: on target_link_libraries(espresso_compiler_flags INTERFACE gcov) endif() endif() # # Portability options # # prevent 80-bit arithmetic on old Intel processors if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_SIZEOF_VOID_P EQUAL 4 AND CMAKE_SYSTEM_PROCESSOR MATCHES "[xX]86") target_compile_options(espresso_compiler_flags INTERFACE $<$:-ffloat-store>) endif() # allow infinities target_compile_options( espresso_compiler_flags INTERFACE $<$:-fno-finite-math-only>) # # Sanitizers # if(ESPRESSO_BUILD_WITH_ASAN AND ESPRESSO_BUILD_WITH_MSAN) message( FATAL_ERROR "Address sanitizer and memory sanitizer cannot be enabled simultaneously") endif() if(ESPRESSO_BUILD_WITH_ASAN) target_compile_options( espresso_compiler_flags INTERFACE $<$:${ESPRESSO_XCOMPILER}-fsanitize=address> $<$:${ESPRESSO_XCOMPILER}-g> $<$:$<$>:${ESPRESSO_XCOMPILER}-O1>> $<$:-fno-omit-frame-pointer>) target_link_libraries( espresso_compiler_flags INTERFACE -fsanitize=address -g $<$>:${ESPRESSO_XCOMPILER}-O1>) endif() if(ESPRESSO_BUILD_WITH_MSAN) target_compile_options( espresso_compiler_flags INTERFACE $<$:${ESPRESSO_XCOMPILER}-fsanitize=memory> $<$:${ESPRESSO_XCOMPILER}-g> $<$:$<$>:${ESPRESSO_XCOMPILER}-O1>> $<$:-fno-omit-frame-pointer>) target_link_libraries( espresso_compiler_flags INTERFACE -fsanitize=memory -g $<$>:-O1>) endif() if(ESPRESSO_BUILD_WITH_UBSAN) target_compile_options( espresso_compiler_flags INTERFACE $<$:-fsanitize=undefined> $<$:${ESPRESSO_XCOMPILER}-g> $<$:$<$>:${ESPRESSO_XCOMPILER}-O1>> ) target_link_libraries( espresso_compiler_flags INTERFACE -fsanitize=undefined -g $<$>:-O1>) endif() # # Static analysis # if(ESPRESSO_BUILD_WITH_CLANG_TIDY) find_package(ClangTidy "${CMAKE_CXX_COMPILER_VERSION}" EXACT REQUIRED) set(ESPRESSO_CXX_CLANG_TIDY "${CLANG_TIDY_EXE}") set(ESPRESSO_CUDA_CLANG_TIDY "${CLANG_TIDY_EXE};--extra-arg=--cuda-host-only") block(SCOPE_FOR VARIABLES) if(ESPRESSO_BUILD_WITH_CUDA) # silence casts in cuda_runtime.h (for both C++ and CUDA source files) list(APPEND SKIP_CLANG_TIDY_CHECKS "-bugprone-casting-through-void") # silence nullptr dereference in cuda::thrust list(APPEND SKIP_CLANG_TIDY_CHECKS_CUDA "-clang-analyzer-core.NonNullParamChecker") endif() foreach(LANG CXX CUDA) espresso_override_clang_tidy_checks( ESPRESSO_${LANG}_CLANG_TIDY "${SKIP_CLANG_TIDY_CHECKS}" "${SKIP_CLANG_TIDY_CHECKS_${LANG}}") set(ESPRESSO_${LANG}_CLANG_TIDY "${ESPRESSO_${LANG}_CLANG_TIDY}" PARENT_SCOPE) endforeach() endblock() endif() if(ESPRESSO_BUILD_WITH_CPPCHECK) find_program(CMAKE_CXX_CPPCHECK NAMES cppcheck) if(NOT CMAKE_CXX_CPPCHECK) message(FATAL_ERROR "Could not find the program cppcheck.") endif() list(APPEND CMAKE_CXX_CPPCHECK "--enable=all" "--std=c++${CMAKE_CXX_STANDARD}" "--quiet" "--inline-suppr" "--suppressions-list=${CMAKE_CURRENT_SOURCE_DIR}/.cppcheck") if(ESPRESSO_WARNINGS_ARE_ERRORS) list(APPEND CMAKE_CXX_CPPCHECK "--error-exitcode=2") endif() endif() # # Libraries # if(ESPRESSO_BUILD_WITH_FFTW) if(ESPRESSO_BUILD_WITH_SHARED_MEMORY_PARALLELISM) list(APPEND FFTW3_COMPONENTS omp) endif() find_package(fftw3 REQUIRED COMPONENTS ${FFTW3_COMPONENTS}) if(NOT EXISTS ${FETCHCONTENT_BASE_DIR}/heffte-src) find_package(Heffte 2.4.1 QUIET) endif() if(NOT DEFINED Heffte_FOUND OR NOT ${Heffte_FOUND}) # cmake-format: off FetchContent_Declare( heffte GIT_REPOSITORY https://github.com/icl-utk-edu/heffte.git GIT_TAG v2.4.1 OVERRIDE_FIND_PACKAGE ) # cmake-format: on set(Heffte_ENABLE_FFTW ON CACHE BOOL "") if(ESPRESSO_BUILD_WITH_CUDA) set(Heffte_ENABLE_CUDA ON CACHE BOOL "") endif() set(BUILD_SHARED_LIBS ON) FetchContent_MakeAvailable(heffte) set(BUILD_SHARED_LIBS ${ESPRESSO_BUILD_SHARED_LIBS_DEFAULT}) foreach(HEFFTE_MODULE IN ITEMS FFTW CUDA) if(TARGET Heffte::${HEFFTE_MODULE}) set(Heffte_${HEFFTE_MODULE}_FOUND true) endif() endforeach() add_library(Heffte::Heffte INTERFACE IMPORTED GLOBAL) target_link_libraries(Heffte::Heffte INTERFACE Heffte) set_property(TARGET Heffte PROPERTY INSTALL_RPATH "") install(TARGETS Heffte LIBRARY DESTINATION "${ESPRESSO_INSTALL_LIBDIR}") endif() endif() if(ESPRESSO_BUILD_WITH_SHARED_MEMORY_PARALLELISM) find_package(OpenMP REQUIRED COMPONENTS CXX) if(NOT EXISTS ${FETCHCONTENT_BASE_DIR}/kokkos-src) find_package(Kokkos 4.3 QUIET) endif() if(NOT DEFINED Kokkos_FOUND OR NOT ${Kokkos_FOUND}) # cmake-format: off FetchContent_Declare( kokkos GIT_REPOSITORY https://github.com/kokkos/kokkos.git GIT_TAG 18b830e # version 4.6.1 with patches OVERRIDE_FIND_PACKAGE ) # cmake-format: on set(BUILD_SHARED_LIBS ON) set(CMAKE_SHARED_LIBRARY_PREFIX "lib") set(Kokkos_ENABLE_SERIAL ON CACHE BOOL "") set(Kokkos_ENABLE_OPENMP ON CACHE BOOL "") set(Kokkos_ENABLE_IMPL_VIEW_LEGACY ON CACHE BOOL "") set(Kokkos_ENABLE_COMPLEX_ALIGN ON CACHE BOOL "") set(Kokkos_ENABLE_AGGRESSIVE_VECTORIZATION ON CACHE BOOL "") set(Kokkos_ENABLE_HWLOC ON CACHE BOOL "") set(Kokkos_ARCH_NATIVE ON CACHE BOOL "") FetchContent_MakeAvailable(kokkos) set(BUILD_SHARED_LIBS ${ESPRESSO_BUILD_SHARED_LIBS_DEFAULT}) set(CMAKE_SHARED_LIBRARY_PREFIX "${ESPRESSO_SHARED_LIBRARY_PREFIX}") install(TARGETS kokkos LIBRARY DESTINATION "${ESPRESSO_INSTALL_LIBDIR}") # install all kokkos shared objects get_target_property(ESPRESSO_KOKKOS_LIBS kokkos INTERFACE_LINK_LIBRARIES) foreach(target_name IN LISTS ESPRESSO_KOKKOS_LIBS) get_target_property(target_type ${target_name} TYPE) if(${target_type} STREQUAL "SHARED_LIBRARY" AND ${target_name} MATCHES "^kokkos[a-zA-Z0-9_]+$") install(TARGETS ${target_name} LIBRARY DESTINATION "${ESPRESSO_INSTALL_LIBDIR}") endif() endforeach() endif() if(NOT EXISTS ${FETCHCONTENT_BASE_DIR}/cabana-src) find_package(Cabana 0.7.0 QUIET) endif() if(NOT DEFINED Cabana_FOUND OR NOT ${Cabana_FOUND}) # cmake-format: off FetchContent_Declare( cabana GIT_REPOSITORY https://github.com/ECP-copa/Cabana.git GIT_TAG e76c1a1 # 0.7.0 with patches PATCH_COMMAND patch -p0 < ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cabana.patch ) # cmake-format: on set(Cabana_REQUIRE_HEFFTE ${ESPRESSO_BUILD_WITH_FFTW} CACHE BOOL "") FetchContent_MakeAvailable(cabana) endif() endif() # We need the parallel hdf5 version! if(ESPRESSO_BUILD_WITH_HDF5) # The FindHDF5 function will fall back to the serial version if no parallel # version was found, and print to the CMake log that HDF5 was found. There is # no QUIET argument to override that message. This can be confusing to people # who are not familiar with the way hdf5 is distributed in Linux package # repositories (libhdf5-dev is the serial version). set(HDF5_PREFER_PARALLEL 1) find_package(HDF5 "1.8" REQUIRED COMPONENTS C) if(HDF5_FOUND) if(HDF5_IS_PARALLEL) add_feature_info(HDF5 ON "parallel") else() set(HDF5_FOUND FALSE) message(FATAL_ERROR "HDF5 parallel version not found.") endif() endif() add_library(hdf5 INTERFACE) target_link_libraries(hdf5 INTERFACE $) target_include_directories(hdf5 INTERFACE $) # cmake-format: off FetchContent_Declare( HighFive GIT_REPOSITORY https://github.com/highfive-devs/highfive.git GIT_TAG v3.2.0 ) # cmake-format: on FetchContent_MakeAvailable(HighFive) endif() if(ESPRESSO_BUILD_WITH_SCAFACOS) find_package(PkgConfig REQUIRED) pkg_check_modules(SCAFACOS scafacos REQUIRED) endif() if(ESPRESSO_BUILD_WITH_GSL) find_package(GSL REQUIRED) endif() if(ESPRESSO_BUILD_WITH_STOKESIAN_DYNAMICS) # cmake-format: off FetchContent_Declare( stokesian_dynamics GIT_REPOSITORY https://github.com/hmenke/espresso-stokesian-dynamics.git GIT_TAG 90f6de70d1c0ac9cf468f2fc90f9c601139e4c88 ) # cmake-format: on set(STOKESIAN_DYNAMICS 1) set(CMAKE_INSTALL_LIBDIR "${ESPRESSO_INSTALL_LIBDIR}") FetchContent_MakeAvailable(stokesian_dynamics) set(CMAKE_INSTALL_LIBDIR "${ESPRESSO_OLD_CMAKE_INSTALL_LIBDIR}") endif() if(ESPRESSO_BUILD_WITH_NLOPT) if(NOT EXISTS ${FETCHCONTENT_BASE_DIR}/nlopt-src) find_package(NLopt 2.7.1 QUIET) endif() if(NOT DEFINED NLopt_FOUND OR NOT ${NLopt_FOUND}) # cmake-format: off FetchContent_Declare( nlopt GIT_REPOSITORY https://github.com/stevengj/nlopt.git GIT_TAG v2.10.0 ) # cmake-format: on set(BUILD_SHARED_LIBS off) set(NLOPT_FORTRAN off CACHE BOOL "") set(NLOPT_PYTHON off CACHE BOOL "") set(NLOPT_OCTAVE off CACHE BOOL "") set(NLOPT_MATLAB off CACHE BOOL "") set(NLOPT_GUILE off CACHE BOOL "") set(NLOPT_JAVA off CACHE BOOL "") set(NLOPT_SWIG off CACHE BOOL "") set(NLOPT_LUKSAN off CACHE BOOL "") FetchContent_MakeAvailable(nlopt) set(BUILD_SHARED_LIBS ${ESPRESSO_BUILD_SHARED_LIBS_DEFAULT}) endif() endif() if(ESPRESSO_BUILD_WITH_VALGRIND) find_package(PkgConfig REQUIRED) pkg_check_modules(VALGRIND valgrind REQUIRED) if(VALGRIND_FOUND) message(STATUS "Found valgrind: ${VALGRIND_INCLUDE_DIRS}") endif() endif() # # MPI # find_package(MPI 3.0 REQUIRED) include(espresso_get_mpiexec_vendor) espresso_get_mpiexec_vendor() if(${ESPRESSO_MPIEXEC_VERSION} VERSION_GREATER_EQUAL ${ESPRESSO_MINIMAL_MPIEXEC_VERSION}) message( STATUS "Found ${ESPRESSO_MPIEXEC_VENDOR}: ${MPIEXEC} (found suitable version \"${ESPRESSO_MPIEXEC_VERSION}\", minimum required is \"${ESPRESSO_MINIMAL_MPIEXEC_VERSION}\")" ) else() message( FATAL_ERROR "Could not find a suitable ${ESPRESSO_MPIEXEC_VENDOR} implementation (found unsuitable version \"${ESPRESSO_MPIEXEC_VERSION}\", minimum required is \"${ESPRESSO_MINIMAL_MPIEXEC_VERSION}\")" ) endif() # MPIEXEC_PREFLAGS overrides set(ESPRESSO_MPIEXEC_PREFLAGS "") # Open MPI 4.x has a bug on NUMA archs that prevents running in singleton mode set(ESPRESSO_MPIEXEC_GUARD_SINGLETON_NUMA OFF) set(ESPRESSO_CPU_MODEL_NAME_OMPI_SINGLETON_NUMA_PATTERN "AMD (EPYC|Ryzen)") if("${ESPRESSO_MPIEXEC_VENDOR}" STREQUAL "OpenMPI") # OpenMPI checks the number of processes against the number of physical cores list(APPEND ESPRESSO_MPIEXEC_PREFLAGS "--oversubscribe") if(ESPRESSO_INSIDE_DOCKER) list(APPEND ESPRESSO_MPIEXEC_PREFLAGS "--bind-to" "none") endif() if(${ESPRESSO_MPIEXEC_VERSION} VERSION_LESS 5.0) if(NOT DEFINED ESPRESSO_CPU_MODEL_NAME) if(CMAKE_SYSTEM_NAME STREQUAL Linux) if(EXISTS /proc/cpuinfo) file(READ /proc/cpuinfo ESPRESSO_CPU_INFO) string(REGEX REPLACE ".*\n[Mm]odel name[ \t]*:[ \t]+([^\n]+).*" "\\1" ESPRESSO_CPU_MODEL_NAME_STRING "${ESPRESSO_CPU_INFO}") else() set(ESPRESSO_CPU_MODEL_NAME_STRING "__unreadable") endif() else() set(ESPRESSO_CPU_MODEL_NAME_STRING "__unaffected") endif() set(ESPRESSO_CPU_MODEL_NAME "${ESPRESSO_CPU_MODEL_NAME_STRING}" CACHE INTERNAL "") endif() if(ESPRESSO_CPU_MODEL_NAME MATCHES "^${ESPRESSO_CPU_MODEL_NAME_OMPI_SINGLETON_NUMA_PATTERN}") set(ESPRESSO_MPIEXEC_GUARD_SINGLETON_NUMA ON) endif() endif() endif() # OpenMPI cannot run two jobs in parallel in a Docker container, because the # same base folder is used to store the process ids of multiple jobs. Since the # base folder is deleted upon completion of a job, other jobs will fail when # attempting to create subdirectories in the base folder. # https://github.com/open-mpi/ompi/issues/8510 if("${ESPRESSO_MPIEXEC_VENDOR}" STREQUAL "OpenMPI" AND ESPRESSO_INSIDE_DOCKER) cmake_host_system_information(RESULT hostname QUERY HOSTNAME) function(espresso_set_mpiexec_tmpdir) set(ESPRESSO_MPIEXEC_TMPDIR --mca orte_tmpdir_base "/tmp/ompi.${hostname}.$ENV{USER}.${ARGV0}" PARENT_SCOPE) endfunction() else() function(espresso_set_mpiexec_tmpdir) set(ESPRESSO_MPIEXEC_TMPDIR "" PARENT_SCOPE) endfunction() endif() # # Boost # if(POLICY CMP0167) # use BoostConfig.cmake shipped with Boost 1.70+ instead of the one in CMake cmake_policy(SET CMP0167 NEW) endif() list(APPEND ESPRESSO_BOOST_COMPONENTS mpi serialization) if(ESPRESSO_BUILD_TESTS) list(APPEND ESPRESSO_BOOST_COMPONENTS unit_test_framework) endif() find_package(Boost 1.83.0 REQUIRED ${ESPRESSO_BOOST_COMPONENTS}) # # Paths # set(CMAKE_INSTALL_RPATH "${ESPRESSO_INSTALL_LIBDIR}") # # Packaging # # drop 'lib' prefix from all libraries set(ESPRESSO_SHARED_LIBRARY_PREFIX "") set(CMAKE_SHARED_LIBRARY_PREFIX "${ESPRESSO_SHARED_LIBRARY_PREFIX}") set(CMAKE_MACOSX_RPATH TRUE) # # Testing # if(ESPRESSO_BUILD_TESTS) enable_testing() add_custom_target(check) set(ESPRESSO_CTEST_ARGS "" CACHE STRING "Extra arguments to give to ctest calls (separated by semicolons)") set(ESPRESSO_TEST_NP "4" CACHE STRING "Maximal number of MPI ranks to use per test") add_library(espresso_tests_compiler_flags INTERFACE) add_library(espresso::tests::compiler_flags ALIAS espresso_tests_compiler_flags) target_compile_options(espresso_tests_compiler_flags INTERFACE -Wno-unused-macros) if(ESPRESSO_BUILD_WITH_COVERAGE) target_compile_options( espresso_tests_compiler_flags INTERFACE $<$:-fno-default-inline> $<$:-fno-elide-constructors>) endif() if(ESPRESSO_BUILD_WITH_PYTHON) add_subdirectory(testsuite) endif() endif() if(ESPRESSO_BUILD_BENCHMARKS) add_custom_target(benchmark) add_subdirectory(maintainer/benchmarks) endif() # # waLBerla # if(ESPRESSO_BUILD_WITH_WALBERLA) # cmake-format: off FetchContent_Declare( walberla GIT_REPOSITORY https://i10git.cs.fau.de/walberla/walberla.git GIT_TAG 17fc54c8 # v7.2 with patches ) # cmake-format: on string(REGEX REPLACE "([/\\]walberla)-src$" "\\1-build" walberla_BINARY_DIR "${walberla_SOURCE_DIR}") set(WALBERLA_BUILD_TESTS off CACHE BOOL "") set(WALBERLA_BUILD_TOOLS off CACHE BOOL "") set(WALBERLA_BUILD_BENCHMARKS off CACHE BOOL "") set(WALBERLA_BUILD_TUTORIALS off CACHE BOOL "") set(WALBERLA_BUILD_SHOWCASES off CACHE BOOL "") set(WALBERLA_BUILD_EXAMPLES off CACHE BOOL "") set(WALBERLA_BUILD_DOC off CACHE BOOL "") set(WALBERLA_BUILD_WITH_PYTHON off CACHE BOOL "") set(WALBERLA_LOGLEVEL "WARNING" CACHE STRING "") if(ESPRESSO_BUILD_WITH_CUDA) set(WALBERLA_BUILD_WITH_CUDA "on" CACHE BOOL "") if(NOT ESPRESSO_CUDA_COMPILER STREQUAL "clang") if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) message(FATAL_ERROR "variable CMAKE_CUDA_ARCHITECTURES is undefined") endif() endif() endif() set(WALBERLA_BUILD_WITH_FFTW off CACHE BOOL "") if(ESPRESSO_BUILD_WITH_SHARED_MEMORY_PARALLELISM) set(WALBERLA_BUILD_WITH_OPENMP on CACHE BOOL "") endif() set(WALBERLA_BUILD_WITH_FASTMATH off CACHE BOOL "") set(BUILD_SHARED_LIBS OFF) FetchContent_MakeAvailable(walberla) set(BUILD_SHARED_LIBS ${ESPRESSO_BUILD_SHARED_LIBS_DEFAULT}) set(CMAKE_SHARED_LIBRARY_PREFIX "${ESPRESSO_SHARED_LIBRARY_PREFIX}") set(WALBERLA_LIBS walberla::core walberla::domain_decomposition walberla::blockforest walberla::communication walberla::field walberla::stencil walberla::vtk) if(WALBERLA_BUILD_WITH_FFTW) list(APPEND WALBERLA_LIBS walberla::fft) endif() if(WALBERLA_BUILD_WITH_CUDA) list(APPEND WALBERLA_LIBS walberla::gpu) endif() if(ESPRESSO_BUILD_WITH_WALBERLA_AVX) function(espresso_avx_flags_callback COMPILER_AVX2_FLAG) target_compile_options( espresso_avx_flags INTERFACE $<$:${COMPILER_AVX2_FLAG}> -DESPRESSO_BUILD_WITH_AVX_KERNELS) endfunction() espresso_enable_avx2_support(espresso_avx_flags_callback) endif() endif() if(ESPRESSO_BUILD_WITH_CALIPER) # cmake-format: off FetchContent_Declare( caliper GIT_REPOSITORY https://github.com/LLNL/Caliper.git GIT_TAG v2.13.0 ) # cmake-format: on set(CALIPER_OPTION_PREFIX on CACHE BOOL "") set(CALIPER_WITH_MPI on CACHE BOOL "") set(CALIPER_WITH_NVTX off CACHE BOOL "") set(CALIPER_WITH_CUPTI off CACHE BOOL "") set(CALIPER_INSTALL_CONFIG off CACHE BOOL "") set(CALIPER_INSTALL_HEADERS off CACHE BOOL "") set(BUILD_SHARED_LIBS ON) set(CMAKE_INSTALL_LIBDIR "${ESPRESSO_INSTALL_LIBDIR}") set(CMAKE_SHARED_LIBRARY_PREFIX "lib") FetchContent_MakeAvailable(caliper) set(BUILD_SHARED_LIBS ${ESPRESSO_BUILD_SHARED_LIBS_DEFAULT}) set(CMAKE_INSTALL_LIBDIR "${ESPRESSO_OLD_CMAKE_INSTALL_LIBDIR}") set(CMAKE_SHARED_LIBRARY_PREFIX "${ESPRESSO_SHARED_LIBRARY_PREFIX}") target_compile_options( caliper-common PRIVATE $<$:-Wno-free-nonheap-object -Wno-deprecated-enum-enum-conversion -Wno-volatile>) endif() # # Set source file properties # function(espresso_set_common_target_properties) set(TARGET_NAME "${ARGV0}") get_target_property(TARGET_TYPE ${TARGET_NAME} TYPE) if(NOT TARGET_TYPE STREQUAL "INTERFACE_LIBRARY") # set non-transitive properties; transitive properties should be propagated # to dependent targets via INTERFACE targets, e.g. espresso::compiler_flags set_target_properties(${TARGET_NAME} PROPERTIES C_EXTENSIONS OFF) set_target_properties(${TARGET_NAME} PROPERTIES CXX_EXTENSIONS OFF) set_target_properties(${TARGET_NAME} PROPERTIES CUDA_EXTENSIONS OFF) if(ESPRESSO_BUILD_WITH_CLANG_TIDY) foreach(LANG CXX CUDA) set_target_properties( ${TARGET_NAME} PROPERTIES ${LANG}_CLANG_TIDY "${ESPRESSO_${LANG}_CLANG_TIDY}") endforeach() endif() if(ESPRESSO_BUILD_WITH_CUDA) if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA") set_target_properties(${TARGET_NAME} PROPERTIES CUDA_SEPARABLE_COMPILATION ON) elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang") set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE "CXX") endif() endif() endif() endfunction() # # Subdirectories # add_subdirectory(doc) add_subdirectory(src) add_subdirectory(libs) # # Feature summary # include(FeatureSummary) feature_summary(WHAT ALL)