Newer
Older
cmake_minimum_required(VERSION 3.19)
Sebastian Schmitt
committed
include(CMakeDependentOption)
# Make CUDA support throw errors if architectures remain unclear
cmake_policy(SET CMP0104 NEW)
file(READ VERSION FULL_VERSION_STRING)
string(STRIP "${FULL_VERSION_STRING}" FULL_VERSION_STRING)
string(REGEX MATCH "^[0-9]+(\\.[0-9]+)?(\\.[0-9]+)?(\\.[0-9]+)?" numeric_version "${FULL_VERSION_STRING}")
project(arbor VERSION ${numeric_version})
# Effectively adds '-fpic' flag to CXX_FLAGS. Needed for dynamic catalogues.
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
Benjamin Cumming
committed
# Turn on this option to force the compilers to produce color output when output is
# redirected from the terminal (e.g. when using ninja or a pager).
option(ARBDEV_COLOR "Always produce ANSI-colored output (GNU/Clang only)." OFF)
#----------------------------------------------------------
# Configure-time build options for Arbor:
#----------------------------------------------------------
set(ARB_ARCH "native" CACHE STRING "Target architecture for arbor libraries")
option(ARB_VECTORIZE "use explicit SIMD code in generated mechanisms" OFF)
# Use externally built modcc?
set(ARB_MODCC "" CACHE STRING "path to external modcc NMODL compiler")
# Use libunwind to generate stack traces on errors?
option(ARB_BACKTRACE "Enable stacktraces on assertion and exceptions (requires Boost)." OFF)
# Specify GPU build type
set(ARB_GPU "none" CACHE STRING "GPU backend and compiler configuration")
set_property(CACHE PROPERTY STRINGS "none" "cuda" "cuda-clang" "hip")
if(NOT ARB_GPU STREQUAL "none")
set(ARB_USE_GPU_DEP ON)
endif()
cmake_dependent_option(ARB_USE_GPU_RNG
"Use GPU generated random numbers (only cuda, not bitwise equal to CPU version)" OFF
"ARB_USE_GPU_DEP" OFF)
Sebastian Schmitt
committed
# Use bundled 3rd party libraries
option(ARB_USE_BUNDLED_LIBS "Use bundled 3rd party libraries" OFF)
# Optional additional CXX Flags used for all code that will run on the target
# CPU architecture. Recorded in installed target, for downstream dependencies
# to use.
# Useful, for example, when a user wants to compile with target-specific
# optimization flags.
set(ARB_CXX_FLAGS_TARGET "" CACHE STRING "Optional additional flags for compilation")
#----------------------------------------------------------
# Debug support
#----------------------------------------------------------
# Print builtin catalogue configuration while building
option(ARB_CAT_VERBOSE "Print catalogue build information" OFF)
mark_as_advanced(ARB_CAT_VERBOSE)
#----------------------------------------------------------
# Configure-time features for Arbor:
#----------------------------------------------------------
option(ARB_WITH_MPI "build with MPI support" OFF)
option(ARB_WITH_PROFILING "use built-in profiling" OFF)
option(ARB_WITH_ASSERTIONS "enable arb_assert() assertions in code" OFF)
#----------------------------------------------------------
# Python front end for Arbor:
#----------------------------------------------------------
option(ARB_WITH_PYTHON "enable Python front end" OFF)
#----------------------------------------------------------
# Global CMake configuration
#----------------------------------------------------------
# Include own CMake modules in search path, load common modules.
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
include(GitSubmodule) # required for check_git_submodule
include(ErrorTarget) # reguired for add_error_target
# Set release as the default build type (CMake default is debug.)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE release CACHE STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "debug" "release")
# Add CUDA as a language if GPU support requested. (This has to be set early so
# as to enable CUDA tests in generator expressions.)
if(ARB_GPU STREQUAL "cuda")
include(FindCUDAToolkit)
set(ARB_WITH_NVCC TRUE)
# CMake 3.18 and later set the default CUDA architecture for
# each target according to CMAKE_CUDA_ARCHITECTURES.
# This fixes nvcc picking up a wrong host compiler for linking, causing
# issues with outdated libraries, eg libstdc++ and std::filesystem. Must
# happen before all calls to enable_language(CUDA)
set(CMAKE_CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER})
# We _still_ need this otherwise CUDA symbols will not be exported
# from libarbor.a leading to linker errors when link external clients.
# Unit tests are NOT external enough. Re-review this somewhere in the
# future.
find_package(CUDA ${CUDAToolkit_VERSION_MAJOR} REQUIRED)
elseif(ARB_GPU STREQUAL "cuda-clang")
include(FindCUDAToolkit)
set(ARB_WITH_CUDA_CLANG TRUE)
elseif(ARB_GPU STREQUAL "hip")
set(ARB_WITH_HIP_CLANG TRUE)
endif()
if(ARB_WITH_NVCC OR ARB_WITH_CUDA_CLANG OR ARB_WITH_HIP_CLANG)
set(ARB_WITH_GPU TRUE)
# Build paths.
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# Generate a .json file with full compilation command for each file.
set(CMAKE_EXPORT_COMPILE_COMMANDS "YES")
# Detect and deprecate xlC.
include("CheckCompilerXLC")
# Compiler options common to library, examples, tests, etc.
include("CompilerOptions")
add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:${CXXOPT_WALL}>")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CUDA_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
#----------------------------------------------------------
#----------------------------------------------------------
# Note: any target dependency of arbor needs to be explicitly added
# to the 'export set', even the private ones, and this must be done
# in the same CMakeLists.txt in which the target is defined.
Thorsten Hater
committed
set(ARB_INSTALL_DATADIR ${CMAKE_INSTALL_DATAROOTDIR}/arbor)
# Interface library `arbor-config-defs` collects configure-time defines
# for arbor, arborenv, arborio, of the form ARB_HAVE_XXX. These
# defines should _not_ be used in any installed public headers.
add_library(arbor-config-defs INTERFACE)
install(TARGETS arbor-config-defs EXPORT arbor-targets)
# Interface library `arbor-private-deps` collects dependencies, options etc.
# for the arbor library.
add_library(arbor-private-deps INTERFACE)
target_link_libraries(arbor-private-deps INTERFACE arbor-config-defs ext-random123 ${CMAKE_DL_LIBS})
install(TARGETS arbor-private-deps EXPORT arbor-targets)
# Interface library `arborenv-private-deps` collects dependencies, options etc.
# for the arborenv library.
add_library(arborenv-private-deps INTERFACE)
target_link_libraries(arborenv-private-deps INTERFACE arbor-config-defs)
install(TARGETS arborenv-private-deps EXPORT arbor-targets)
# Interface library `arborio-private-deps` collects dependencies, options etc.
# for the arborio library.
add_library(arborio-private-deps INTERFACE)
target_link_libraries(arborio-private-deps INTERFACE arbor-config-defs)
install(TARGETS arborio-private-deps EXPORT arbor-targets)
# Interface library `arbor-public-deps` collects requirements for the
# users of the arbor library (e.g. mpi) that will become part
add_library(arbor-public-deps INTERFACE)
install(TARGETS arbor-public-deps EXPORT arbor-targets)
# Interface library `arborio-public-deps` collects requirements for the
# users of the arborio library (e.g. xml libs) that will become part
# of arborio's PUBLIC interface.
add_library(arborio-public-deps INTERFACE)
install(TARGETS arborio-public-deps EXPORT arborio-targets)
# Add scripts and supporting CMake for setting up external catalogues
install(PROGRAMS scripts/arbor-build-catalogue DESTINATION ${CMAKE_INSTALL_BINDIR})
install(FILES mechanisms/BuildModules.cmake DESTINATION ${ARB_INSTALL_DATADIR})
# External libraries in `ext` sub-directory: json, tinyopt and randon123.
# Creates interface libraries `ext-json`, `ext-tinyopt` and `ext-random123`
cmake_dependent_option(ARB_USE_BUNDLED_FMT "Use bundled FMT lib." ON "ARB_USE_BUNDLED_LIBS" OFF)
cmake_dependent_option(ARB_USE_BUNDLED_PUGIXML "Use bundled XML lib." ON "ARB_USE_BUNDLED_LIBS" OFF)
Sebastian Schmitt
committed
cmake_dependent_option(ARB_USE_BUNDLED_JSON "Use bundled Niels Lohmann's json library." ON "ARB_USE_BUNDLED_LIBS" OFF)
if(NOT ARB_USE_BUNDLED_JSON)
find_package(nlohmann_json)
set(json_library_name nlohmann_json::nlohmann_json)
else()
unset(nlohmann_json_DIR CACHE)
endif()
cmake_dependent_option(ARB_USE_BUNDLED_RANDOM123 "Use bundled Random123 lib." ON "ARB_USE_BUNDLED_LIBS" OFF)
add_library(ext-random123 INTERFACE)
if(NOT ARB_USE_BUNDLED_RANDOM123)
find_package(Random123 REQUIRED)
target_include_directories(ext-random123 INTERFACE ${RANDOM123_INCLUDE_DIR})
endif()
install(TARGETS ext-random123 EXPORT arbor-targets)
# Keep track of packages we need to add to the generated CMake config
# file for arbor.
set(arbor_export_dependencies)
# Keep track of which 'components' of arbor are included (this is
# currently just 'MPI' support and 'neuroml' for NeuroML support in
# libarborio.)
set(arbor_supported_components)
# Target microarchitecture for building arbor libraries, tests and examples
#---------------------------------------------------------------------------
# Set the full set of target flags in ARB_CXX_FLAGS_TARGET_FULL, which
# will include target-specific -march flags if ARB_ARCH is not "none".
if(ARB_ARCH STREQUAL "none")
set(ARB_CXX_FLAGS_TARGET_FULL ${ARB_CXX_FLAGS_TARGET})
else()
set_arch_target(ARB_CXXOPT_ARCH ${ARB_ARCH})
set(ARB_CXX_FLAGS_TARGET_FULL ${ARB_CXX_FLAGS_TARGET} ${ARB_CXXOPT_ARCH})
# Compile with `-fvisibility=hidden` to ensure that the symbols of the generated
# arbor static libraries are hidden from the dynamic symbol tables of any shared
# libraries that link against them.
list(APPEND ARB_CXX_FLAGS_TARGET_FULL
"$<$<BUILD_INTERFACE:$<COMPILE_LANGUAGE:CXX>>:-fvisibility=hidden>"
"$<$<BUILD_INTERFACE:$<COMPILE_LANGUAGE:CUDA>>:-Xcompiler=-fvisibility=hidden>")
separate_arguments(ARB_CXX_FLAGS_TARGET_FULL)
target_compile_options(arbor-private-deps INTERFACE ${ARB_CXX_FLAGS_TARGET_FULL})
target_compile_options(arborenv-private-deps INTERFACE ${ARB_CXX_FLAGS_TARGET_FULL})
target_compile_options(arborio-private-deps INTERFACE ${ARB_CXX_FLAGS_TARGET_FULL})
# Profiling and test features
#-----------------------------
if(ARB_WITH_PROFILING)
target_compile_definitions(arbor-config-defs INTERFACE ARB_HAVE_PROFILING)
endif()
if(ARB_WITH_ASSERTIONS)
target_compile_definitions(arbor-config-defs INTERFACE ARB_HAVE_ASSERTIONS)
# Python bindings
#----------------------------------------------------------
# The minimum version of Python supported by Arbor.
Brent Huisman
committed
set(arb_py_version 3.7.0)
Sebastian Schmitt
committed
if(DEFINED PYTHON_EXECUTABLE)
set(Python3_EXECUTABLE ${PYTHON_EXECUTABLE})
endif()
Sebastian Schmitt
committed
cmake_dependent_option(ARB_USE_BUNDLED_PYBIND11 "Use bundled pybind11" ON "ARB_WITH_PYTHON;ARB_USE_BUNDLED_LIBS" OFF)
Brent Huisman
committed
if(DEFINED ENV{CIBUILDWHEEL} AND (UNIX AND NOT APPLE))
find_package(Python3 ${arb_py_version} COMPONENTS Interpreter Development.Module REQUIRED)
else()
find_package(Python3 ${arb_py_version} COMPONENTS Interpreter Development REQUIRED)
endif()
else()
# If not building the Python module, the interpreter is still required
# to build some targets, e.g. when building the documentation.
find_package(Python3 ${arb_py_version} COMPONENTS Interpreter)
Sebastian Schmitt
committed
endif()
if(${Python3_FOUND})
set(PYTHON_EXECUTABLE "${Python3_EXECUTABLE}")
message(STATUS "PYTHON_EXECUTABLE: ${PYTHON_EXECUTABLE}")
# Threading model
#-----------------
find_package(Threads REQUIRED)
target_link_libraries(arbor-private-deps INTERFACE Threads::Threads)
list(APPEND arbor_export_dependencies "Threads")
target_compile_definitions(arbor-config-defs INTERFACE ARB_HAVE_MPI)
# target_compile_definitions(MPI::MPI_CXX INTERFACE MPICH_SKIP_MPICXX=1 OMPI_SKIP_MPICXX=1)
# target_link_libraries(arbor-public-deps INTERFACE MPI::MPI_CXX)
# CMake 3.9 does not allow us to add definitions to an import target.
# so wrap MPI::MPI_CXX in an interface library 'mpi-wrap' instead.
add_library(mpi-wrap INTERFACE)
target_link_libraries(mpi-wrap INTERFACE MPI::MPI_CXX)
target_compile_definitions(mpi-wrap INTERFACE MPICH_SKIP_MPICXX=1 OMPI_SKIP_MPICXX=1)
target_link_libraries(arbor-public-deps INTERFACE mpi-wrap)
install(TARGETS mpi-wrap EXPORT arbor-targets)
list(APPEND arbor_export_dependencies "MPI\;COMPONENTS\;CXX")
list(APPEND arbor_supported_components "MPI")
# CUDA support
#--------------
if(ARB_WITH_GPU)
if(ARB_WITH_NVCC OR ARB_WITH_CUDA_CLANG)
target_include_directories(arborenv-private-deps INTERFACE ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})
add_compile_options(
"$<$<COMPILE_LANGUAGE:CUDA>:-Xcudafe=--diag_suppress=integer_sign_change>"
"$<$<COMPILE_LANGUAGE:CUDA>:-Xcudafe=--diag_suppress=unsigned_compare_with_zero>")
endif()
if(ARB_WITH_NVCC)
target_compile_definitions(arbor-private-deps INTERFACE ARB_CUDA)
target_compile_definitions(arborenv-private-deps INTERFACE ARB_CUDA)
elseif(ARB_WITH_CUDA_CLANG)
set(clang_options_ -DARB_CUDA -xcuda --cuda-gpu-arch=sm_60 --cuda-gpu-arch=sm_70 --cuda-gpu-arch=sm_80 --cuda-path=${CUDA_TOOLKIT_ROOT_DIR})
target_compile_options(arbor-private-deps INTERFACE $<$<COMPILE_LANGUAGE:CXX>:${clang_options_}>)
target_compile_options(arborenv-private-deps INTERFACE $<$<COMPILE_LANGUAGE:CXX>:${clang_options_}>)
elseif(ARB_WITH_HIP_CLANG)
set(clang_options_ -DARB_HIP -xhip --amdgpu-target=gfx906 --amdgpu-target=gfx900)
target_compile_options(arbor-private-deps INTERFACE $<$<COMPILE_LANGUAGE:CXX>:${clang_options_}>)
target_compile_options(arborenv-private-deps INTERFACE $<$<COMPILE_LANGUAGE:CXX>:${clang_options_}>)
endif()
# Use boost::stacktrace if requested for pretty printing stack traces
#--------------------------------------------------------------------
if (ARB_BACKTRACE)
find_package(Boost REQUIRED
COMPONENTS stacktrace_basic
stacktrace_addr2line)
target_link_libraries(arbor-private-deps INTERFACE Boost::stacktrace_basic Boost::stacktrace_addr2line ${CMAKE_DL_LIBS})
target_compile_definitions(arbor-private-deps INTERFACE WITH_BACKTRACE)
#------------------------------------------------
if(ARB_MODCC)
find_program(modcc NAMES ${ARB_MODCC} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH REQUIRED)
if(NOT modcc)
message(FATAL_ERROR "Unable to find modcc executable.")
endif()
set(ARB_WITH_EXTERNAL_MODCC TRUE)
else()
set(modcc $<TARGET_FILE:modcc>)
set(ARB_WITH_EXTERNAL_MODCC FALSE)
endif()
set(ARB_MODCC_FLAGS)
if(ARB_VECTORIZE)
list(APPEND ARB_MODCC_FLAGS "--simd")
endif()
# Random number creation
# -----------------------------------------------
if(ARB_USE_GPU_RNG AND (ARB_WITH_NVCC OR ARB_WITH_CUDA_CLANG))
set(ARB_USE_GPU_RNG_IMPL TRUE)
else()
set(ARB_USE_GPU_RNG_IMPL FALSE)
endif()
#----------------------------------------------------------
# Set up install paths, permissions.
#----------------------------------------------------------
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
# Set up install paths according to GNU conventions.
#
# GNUInstallDirs picks (e.g.) `lib64` for the library install path on some
# systems where this is definitely not correct (e.g. Arch Linux). If there
# are cases where `lib` is inappropriate, we will have to incorporate special
# case behaviour here.
if(NOT CMAKE_INSTALL_LIBDIR)
set(CMAKE_INSTALL_LIBDIR lib)
endif()
include(GNUInstallDirs)
# Implicitly created directories require permissions to be set explicitly
# via this CMake variable.
#
# Note that this has no effect until CMake version 3.11.
set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
OWNER_READ
OWNER_WRITE
OWNER_EXECUTE
GROUP_READ
GROUP_EXECUTE
WORLD_READ
WORLD_EXECUTE)
# CMake versions 3.11 and 3.12 ignore this variable for directories
# implicitly created by install(DIRECTORY ...), which for us corresponds
# to our doc and include directories. Work-around by trying to install
# a non-existant file to these locations.
foreach(directory "${CMAKE_INSTALL_DOCDIR}" "${CMAKE_INSTALL_INCLUDEDIR}")
install(FILES _no_such_file_ OPTIONAL DESTINATION "${directory}")
endforeach()
#----------------------------------------------------------
# Configure targets in sub-directories.
#----------------------------------------------------------
add_subdirectory(arbor/include)
# arbor-sup:
add_subdirectory(sup)
# modcc, libmodcc:
add_subdirectory(modcc)
# arbor, arbor-private-headers:
add_subdirectory(arbor)
# arborenv, arborenv-public-headers:
add_subdirectory(arborenv)
# arborio, arborio-public-headers:
add_subdirectory(arborio)
# unit, unit-mpi, unit-local, unit-modcc
# html:
add_subdirectory(doc)
#----------------------------------------------------------
# Generate CMake config/version files for install.
#----------------------------------------------------------
# Note: each dependency for the arbor library target, private or otherwise,
# needs to add itself to the arbor-exports EXPORT target in the subdirectory
# in which they are defined, or none of this will work.
set(cmake_config_dir "${CMAKE_INSTALL_LIBDIR}/cmake/arbor")
install(EXPORT arbor-targets NAMESPACE arbor:: DESTINATION "${cmake_config_dir}")
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/arbor-config-version.cmake"
COMPATIBILITY SameMajorVersion)
# Template file will use contents of arbor_export_dependencies to include the
# required `find_dependency` statements, and arbor_supported_components will
# be used to check feature support.
#
# To avoid CMake users of the installed arbor library conditionally requiring
# that they add CUDA to their project language, explicitly munge the import
# language and library dependencies on the installed target if ARB_WITH_GPU
# is set, via the variables arbor_override_import_lang and arbor_add_import_libs.
# arbor_build_config records our build type in a way compatible with the
# generated export cmake files.
set(arbor_build_config NOCONFIG)
if(CMAKE_BUILD_TYPE)
string(TOUPPER "${CMAKE_BUILD_TYPE}" arbor_build_config)
endif()
set(arbor_override_import_lang)
set(arbor_add_import_libs)
set(arborenv_add_import_libs)
if(ARB_WITH_GPU)
set(arbor_override_import_lang CXX)
set(arbor_add_import_libs ${CUDA_LIBRARIES})
set(arborenv_add_import_libs ${CUDA_LIBRARIES})
# (We remove old generated one so that the generation happens every time we run cmake.)
file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/arbor-config.cmake")
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/arbor-config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/arbor-config.cmake"
@ONLY)
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/arbor-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/arbor-config-version.cmake"
DESTINATION "${cmake_config_dir}")