#
# 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})
# 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)
# ##############################################################################
# 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_WALBERLA
"Build with waLBerla lattice-Boltzmann support" OFF)
option(ESPRESSO_BUILD_WITH_WALBERLA_AVX
"Build waLBerla lattice-Boltzmann with AVX vectorization" OFF)
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()
# 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_cpp_flags INTERFACE)
add_library(espresso::cpp_flags ALIAS espresso_cpp_flags)
set_target_properties(
espresso_cpp_flags PROPERTIES 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("IntelLLVM" 2023.1)
set(UNSUPPORTED_COMPILERS "Intel;MSVC")
foreach(LANG C CXX)
if(CMAKE_${LANG}_COMPILER_ID IN_LIST 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
#
if(ESPRESSO_BUILD_WITH_CUDA)
include(CheckLanguage)
enable_language(CUDA)
check_language(CUDA)
add_library(espresso_cuda_flags INTERFACE)
add_library(espresso::cuda_flags ALIAS espresso_cuda_flags)
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)
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_target_properties(
espresso_cuda_flags PROPERTIES 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.8...<3.1.0 REQUIRED)
find_program(IPYTHON_EXECUTABLE NAMES jupyter ipython3 ipython)
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")
endif()
#
# Compiler diagnostics
#
target_compile_options(
espresso_cpp_flags
INTERFACE
-Wall
-Wextra
-pedantic
# add extra warnings
$<$:-Wextern-initializer>
$<$:-Wrange-loop-analysis>
-Wfloat-conversion
$<$:-Wimplicit-float-conversion>
$<$:-Wunused-exception-parameter>
$<$:-Wmissing-variable-declarations>
$<$:-Wnon-c-typedef-for-linkage>
-Wdelete-non-virtual-dtor
-Wcast-qual
-Wcast-align
-Wunused-macros
-Wpointer-arith
-Winit-self
$<$:-Wformat-signedness>
$<$:-Wformat=2>
$<$:-Wduplicated-branches>
$<$:-Wshadow=compatible-local>
$<$:-Wshadow-field-in-constructor-modified>
# disable warnings from -Wall and -Wextra
-Wno-sign-compare
-Wno-unused-function
-Wno-unused-parameter
-Wno-array-bounds
$<$:-Wno-restrict>
$<$:-Wno-clobbered>
$<$:-Wno-cast-function-type>
$<$:-diag-disable=592>
$<$:-Wno-gnu-zero-variadic-macro-arguments>
$<$>:-Wno-implicit-fallthrough>
$<$>:-Wno-unused-private-field>
$<$,$>:-Wno-psabi>
$<$:-Wno-format-nonliteral>
$<$:-Wno-float-conversion>
$<$:$<$:-Wno-implicit-int-float-conversion>>
$<$:$<$:-Wno-implicit-float-conversion>>
$<$:-Wno-cast-qual>
# warnings are errors
$<$:-Werror>)
if(ESPRESSO_BUILD_WITH_CUDA)
target_compile_options(
espresso_cuda_flags
INTERFACE
-Wall
-Wextra
-Wno-sign-compare
-Wno-unused-parameter
$<$>:-Wno-implicit-fallthrough>
# disable warnings from -Wall and -Wextra
-Wno-array-bounds
# warnings are errors
$<$,$>:--Werror=all-warnings>
$<$,$>:-Werror>
)
endif()
#
# Code coverage
#
if(ESPRESSO_BUILD_WITH_COVERAGE)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
target_compile_options(
espresso_cpp_flags INTERFACE -g -fprofile-instr-generate
-fcoverage-mapping)
else()
target_compile_options(espresso_cpp_flags INTERFACE -g --coverage
-fprofile-abs-path)
target_link_libraries(espresso_cpp_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_cpp_flags INTERFACE -ffloat-store)
endif()
#
# 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)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O1")
target_compile_options(espresso_cpp_flags INTERFACE -fsanitize=address
-fno-omit-frame-pointer)
target_link_libraries(espresso_cpp_flags INTERFACE -fsanitize=address)
if(ESPRESSO_BUILD_WITH_CUDA)
target_link_libraries(espresso_cuda_flags INTERFACE -fsanitize=address)
endif()
endif()
if(ESPRESSO_BUILD_WITH_MSAN)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O1")
target_compile_options(espresso_cpp_flags INTERFACE -fsanitize=memory
-fno-omit-frame-pointer)
target_link_libraries(espresso_cpp_flags INTERFACE -fsanitize=memory)
if(ESPRESSO_BUILD_WITH_CUDA)
target_link_libraries(espresso_cuda_flags INTERFACE -fsanitize=memory)
endif()
endif()
if(ESPRESSO_BUILD_WITH_UBSAN)
target_compile_options(espresso_cpp_flags INTERFACE -fsanitize=undefined)
target_link_libraries(espresso_cpp_flags INTERFACE -fsanitize=undefined)
if(ESPRESSO_BUILD_WITH_CUDA)
target_link_libraries(espresso_cuda_flags INTERFACE -fsanitize=undefined)
endif()
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")
unset(SKIP_CLANG_TIDY_CHECKS)
unset(SKIP_CLANG_TIDY_CHECKS_CXX)
unset(SKIP_CLANG_TIDY_CHECKS_CUDA)
if(ESPRESSO_BUILD_WITH_CALIPER)
# Clang-Tidy sometimes emits diagnostics in code enclosed in `extern "C"`
# that are not always actionable, since they may rely on keywords only
# available in the C++ language. While some checks have an extra flag
# 'IgnoreExternC' to disable them inside C code, not all affected checks
# have been fixed yet. For an in-depth discussion on this topic, see
# https://github.com/llvm/llvm-project/issues/35272
list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-auto")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-nullptr")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-deprecated-headers")
endif()
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()
espresso_override_clang_tidy_checks(
ESPRESSO_CXX_CLANG_TIDY "${SKIP_CLANG_TIDY_CHECKS}"
"${SKIP_CLANG_TIDY_CHECKS_CXX}")
espresso_override_clang_tidy_checks(
ESPRESSO_CUDA_CLANG_TIDY "${SKIP_CLANG_TIDY_CHECKS}"
"${SKIP_CLANG_TIDY_CHECKS_CUDA}")
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)
install(TARGETS Heffte LIBRARY DESTINATION "${ESPRESSO_INSTALL_LIBDIR}")
if(ESPRESSO_BUILD_WITH_CLANG_TIDY)
set(ESPRESSO_HEFFTE_CXX_CLANG_TIDY "${ESPRESSO_CXX_CLANG_TIDY}")
set(ESPRESSO_HEFFTE_CUDA_CLANG_TIDY "${ESPRESSO_CUDA_CLANG_TIDY}")
unset(SKIP_CLANG_TIDY_CHECKS)
unset(SKIP_CLANG_TIDY_CHECKS_CXX)
unset(SKIP_CLANG_TIDY_CHECKS_CUDA)
# silence heFFTe diagnostics
list(APPEND SKIP_CLANG_TIDY_CHECKS "-bugprone-exception-escape")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-bugprone-narrowing-conversions")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-bugprone-branch-clone")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-loop-convert")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-override")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-auto")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-readability-else-after-return")
list(APPEND SKIP_CLANG_TIDY_CHECKS
"-readability-avoid-const-params-in-decls")
espresso_override_clang_tidy_checks(
ESPRESSO_HEFFTE_CXX_CLANG_TIDY "${SKIP_CLANG_TIDY_CHECKS}"
"${SKIP_CLANG_TIDY_CHECKS_CXX}")
espresso_override_clang_tidy_checks(
ESPRESSO_HEFFTE_CUDA_CLANG_TIDY "${SKIP_CLANG_TIDY_CHECKS}"
"${SKIP_CLANG_TIDY_CHECKS_CUDA}")
set(ESPRESSO_P3M_CXX_CLANG_TIDY "${ESPRESSO_HEFFTE_CXX_CLANG_TIDY}")
set(ESPRESSO_P3M_CUDA_CLANG_TIDY "${ESPRESSO_HEFFTE_CUDA_CLANG_TIDY}")
endif()
endif()
endif()
if(ESPRESSO_BUILD_WITH_SHARED_MEMORY_PARALLELISM)
find_package(OpenMP REQUIRED)
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()
if(ESPRESSO_BUILD_WITH_CLANG_TIDY)
# silence Kokkos and Cabana diagnostics
set(ESPRESSO_CABANA_CXX_CLANG_TIDY "${ESPRESSO_CXX_CLANG_TIDY}")
set(ESPRESSO_CABANA_CUDA_CLANG_TIDY "${ESPRESSO_CUDA_CLANG_TIDY}")
unset(SKIP_CLANG_TIDY_CHECKS)
unset(SKIP_CLANG_TIDY_CHECKS_CXX)
unset(SKIP_CLANG_TIDY_CHECKS_CUDA)
list(APPEND SKIP_CLANG_TIDY_CHECKS
"-bugprone-return-const-ref-from-parameter")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-bugprone-narrowing-conversions")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-bugprone-sizeof-expression")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-auto")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-override")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-bool-literals")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-equals-delete")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-equals-default")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-nullptr")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-pass-by-value")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-loop-convert")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-return-braced-init-list")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-readability-else-after-return")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-readability-non-const-parameter")
list(APPEND SKIP_CLANG_TIDY_CHECKS "-readability-simplify-boolean-expr")
list(APPEND SKIP_CLANG_TIDY_CHECKS
"-readability-avoid-const-params-in-decls")
list(APPEND SKIP_CLANG_TIDY_CHECKS
"-clang-analyzer-optin.performance.Padding")
list(APPEND SKIP_CLANG_TIDY_CHECKS
"-clang-analyzer-security.insecureAPI.strcpy")
espresso_override_clang_tidy_checks(
ESPRESSO_CABANA_CXX_CLANG_TIDY "${SKIP_CLANG_TIDY_CHECKS}"
"${SKIP_CLANG_TIDY_CHECKS_CXX}")
espresso_override_clang_tidy_checks(
ESPRESSO_CABANA_CUDA_CLANG_TIDY "${SKIP_CLANG_TIDY_CHECKS}"
"${SKIP_CLANG_TIDY_CHECKS_CUDA}")
if(ESPRESSO_BUILD_WITH_FFTW)
espresso_override_clang_tidy_checks(
ESPRESSO_P3M_CXX_CLANG_TIDY "${SKIP_CLANG_TIDY_CHECKS}"
"${SKIP_CLANG_TIDY_CHECKS_CXX}")
espresso_override_clang_tidy_checks(
ESPRESSO_P3M_CUDA_CLANG_TIDY "${SKIP_CLANG_TIDY_CHECKS}"
"${SKIP_CLANG_TIDY_CHECKS_CUDA}")
endif()
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 0103467 # v3.0.0-beta with patches
)
# 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_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()
# OpenMPI checks the number of processes against the number of CPUs
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")
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_cpp_flags INTERFACE)
add_library(espresso::tests::cpp_flags ALIAS espresso_tests_cpp_flags)
target_compile_options(espresso_tests_cpp_flags INTERFACE -Wno-unused-macros)
if(ESPRESSO_BUILD_WITH_COVERAGE)
target_compile_options(
espresso_tests_cpp_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 c69cb11d # v7.1 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_BENCHMARKS off CACHE BOOL "")
set(WALBERLA_BUILD_TOOLS off CACHE BOOL "")
set(WALBERLA_BUILD_TUTORIALS off CACHE BOOL "")
set(WALBERLA_BUILD_SHOWCASES off CACHE BOOL "")
set(WALBERLA_BUILD_DOC 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 ON)
set(CMAKE_SHARED_LIBRARY_PREFIX "lib")
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()
set(WALBERLA_LIBS_EXPORT
${WALBERLA_LIBS} lodepng walberla::boundary walberla::executiontree
walberla::geometry walberla::lbm walberla::timeloop)
# install all waLBerla shared objects
foreach(target_alias IN LISTS WALBERLA_LIBS_EXPORT)
string(REPLACE "::" "_" target_name ${target_alias})
get_target_property(target_type ${target_name} TYPE)
if(${target_type} STREQUAL "SHARED_LIBRARY")
install(TARGETS ${target_name}
LIBRARY DESTINATION "${ESPRESSO_INSTALL_LIBDIR}")
endif()
endforeach()
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}")
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, such as espresso::cpp_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)
set_target_properties(
${TARGET_NAME} PROPERTIES CXX_CLANG_TIDY "${ESPRESSO_CXX_CLANG_TIDY}")
set_target_properties(
${TARGET_NAME} PROPERTIES CUDA_CLANG_TIDY "${ESPRESSO_CUDA_CLANG_TIDY}")
endif()
endfunction()
#
# Subdirectories
#
add_subdirectory(doc)
add_subdirectory(src)
add_subdirectory(libs)
#
# Feature summary
#
include(FeatureSummary)
feature_summary(WHAT ALL)