Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some quality-of-life CMake defaults #847

Merged
merged 5 commits into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 92 additions & 63 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ include(CMakeDependentOption)
include(CMakePackageConfigHelpers)

#----------------------------------------------------------------------------#
# OPTIONS
# MAIN OPTIONS
#----------------------------------------------------------------------------#

# NOTE: languages must be *first* because their settings affect the
Expand Down Expand Up @@ -59,49 +59,25 @@ option(CELERITAS_BUILD_DEMOS "Build Celeritas demonstration mini-apps"
${CELERITAS_USE_JSON})
option(CELERITAS_BUILD_TESTS "Build Celeritas unit tests" ON)

if(CMAKE_VERSION VERSION_LESS 3.13 AND CELERITAS_USE_CUDA AND CELERITAS_USE_MPI)
message(FATAL_ERROR "Celeritas requires CMake 3.13 or higher "
"when building with CUDA + MPI.")
endif()
if(CMAKE_VERSION VERSION_LESS 3.18 AND CELERITAS_USE_CUDA
AND CELERITAS_USE_VecGeom)
message(FATAL_ERROR "VecGeom+CUDA requires CMake 3.18 or higher to support "
"\"Separable compilation\".")
endif()
if(CMAKE_VERSION VERSION_LESS 3.18 AND CMAKE_CUDA_ARCHITECTURES)
message(FATAL_ERROR "The CMAKE_CUDA_ARCHITECTURES flag is not compatible "
"with this version of CMake. Set CMAKE_CUDA_FLAGS.")
endif()

if(CMAKE_VERSION VERSION_LESS 3.22 AND CELERITAS_USE_HIP)
message(WARNING "HIP support is immature; CMake 3.22+ is recommended.")
endif()
# Assertion handling
option(CELERITAS_DEBUG "Enable runtime assertions" ON)

# Library
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
if(NOT DEFINED CMAKE_INSTALL_RPATH_USE_LINK_PATH)
# Inform installed binaries of external library rpaths
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON)
endif()
if(BUILD_SHARED_LIBS AND NOT DEFINED CMAKE_INSTALL_RPATH)
# Inform installed binaries of internal library rpaths
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}")
# Secondary testing options
if(NOT CELERITAS_DEBUG OR CELERITAS_USE_VecGeom)
set(_default_lock ON)
else()
set(_default_lock OFF)
endif()
cmake_dependent_option(CELERITAS_TEST_RESOURCE_LOCK
"Only run one GPU-enabled test at a time" "${_default_lock}"
"CELERITAS_BUILD_TESTS" OFF
)

# Build flags
option(CELERITAS_DEBUG "Enable runtime assertions" ON)
if(DEFINED CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE)
if(CELERITAS_DEBUG)
set(_default_build_type "Debug")
else()
set(_default_build_type "Release")
endif()
set(CMAKE_BUILD_TYPE "${_default_build_type}" CACHE STRING "Build type" FORCE)
message(STATUS "Set default CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
unset(_default_build_type)
endif()
#----------------------------------------------------------------------------#
# CELERITAS CORE IMPLEMENTATION OPTIONS
#----------------------------------------------------------------------------#

# Define CELERITAS_CORE_RNG option for random number generator selection
# CELERITAS_CORE_RNG: random number generator selection
celeritas_setup_option(CELERITAS_CORE_RNG xorwow)
celeritas_setup_option(CELERITAS_CORE_RNG cuRAND CELERITAS_USE_CUDA)
celeritas_setup_option(CELERITAS_CORE_RNG hipRAND CELERITAS_USE_HIP)
Expand All @@ -110,7 +86,7 @@ celeritas_setup_option(CELERITAS_CORE_RNG hipRAND CELERITAS_USE_HIP)
celeritas_define_options(CELERITAS_CORE_RNG
"Celeritas runtime random number generator")

# Runtime geometry selection: default to VecGeom if available
# CELERITAS_CORE_GEO: runtime geometry selection
if(CELERITAS_USE_VecGeom AND NOT CELERITAS_USE_HIP)
set(_allow_vecgeom TRUE)
else()
Expand All @@ -132,22 +108,83 @@ celeritas_setup_option(CELERITAS_CORE_GEO ORANGE)
celeritas_setup_option(CELERITAS_CORE_GEO Geant4 _allow_g4)
celeritas_define_options(CELERITAS_CORE_GEO "Celeritas runtime geometry")

if(NOT CELERITAS_DEBUG OR CELERITAS_USE_VecGeom)
set(_default_lock ON)
else()
set(_default_lock OFF)
#----------------------------------------------------------------------------#
# CMAKE VERSION CHECKS
#----------------------------------------------------------------------------#

if(CMAKE_VERSION VERSION_LESS 3.13 AND CELERITAS_USE_CUDA AND CELERITAS_USE_MPI)
message(FATAL_ERROR "Celeritas requires CMake 3.13 or higher "
"when building with CUDA + MPI.")
endif()
if(CMAKE_VERSION VERSION_LESS 3.18 AND CELERITAS_USE_CUDA
AND CELERITAS_USE_VecGeom)
message(FATAL_ERROR "VecGeom+CUDA requires CMake 3.18 or higher to support "
"\"Separable compilation\".")
endif()
if(CMAKE_VERSION VERSION_LESS 3.18 AND CMAKE_CUDA_ARCHITECTURES)
message(FATAL_ERROR "The CMAKE_CUDA_ARCHITECTURES flag is not compatible "
"with this version of CMake. Set CMAKE_CUDA_FLAGS.")
endif()
if(CMAKE_VERSION VERSION_LESS 3.22 AND CELERITAS_USE_HIP)
message(WARNING "HIP support is immature; CMake 3.22+ is recommended.")
endif()
cmake_dependent_option(CELERITAS_TEST_RESOURCE_LOCK
"Only run one GPU-enabled test at a time" "${_default_lock}"
"CELERITAS_BUILD_TESTS" OFF
)

if(NOT DEFINED CMAKE_CXX_STANDARD)
# Default CMake standard to C++17 for this directory and underneath
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_EXTENSIONS OFF)
#----------------------------------------------------------------------------#
# CMAKE INTRINSIC OPTIONS
#
# These are generally used to initialize properties on targets, and it's
# possible Celeritas is being built inside another project. Instead of saving
# these as cache variables (which change the defaults project-wide, including
# changing behavior of other code that was loaded before Celeritas) set them as
# local variables to be inherited underneath Celeritas.
#----------------------------------------------------------------------------#

### Configuration ###
celeritas_set_default(CMAKE_EXPORT_NO_PACKAGE_REGISTRY ON)
celeritas_set_default(CMAKE_FIND_USE_PACKAGE_REGISTRY FALSE)
celeritas_set_default(CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY FALSE)

### Build flags ###
# Default to debug or released based on value of CELERITAS_DEBUG
if(DEFINED CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE)
if(CELERITAS_DEBUG)
set(_default_build_type "Debug")
else()
set(_default_build_type "Release")
endif()
set(CMAKE_BUILD_TYPE "${_default_build_type}" CACHE STRING "Build type" FORCE)
message(STATUS "Set default CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
unset(_default_build_type)
endif()
# Default to using C++17 everywhere
celeritas_set_default(CMAKE_CXX_STANDARD 17)
celeritas_set_default(CMAKE_CXX_EXTENSIONS OFF)
if(CELERITAS_USE_CUDA)
# Default to setting CUDA C++ standard the same as C++
celeritas_set_default(CMAKE_CUDA_STANDARD ${CMAKE_CXX_STANDARD})
celeritas_set_default(CMAKE_CUDA_EXTENSIONS ${CMAKE_CXX_EXTENSIONS})
endif()

### Linking flags ###
# Default to building shared libraries (*not* a cache variable)
celeritas_set_default(BUILD_SHARED_LIBS ON)
sethrj marked this conversation as resolved.
Show resolved Hide resolved
# Inform installed binaries of external library rpaths
celeritas_set_default(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON)
if(BUILD_SHARED_LIBS)
# Inform installed binaries of internal library rpaths
celeritas_set_default(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}")
# Do not relink libs/binaries when dependent shared libs change
celeritas_set_default(CMAKE_LINK_DEPENDS_NO_SHARED ON)
endif()

### Installation flags ###
# When developing add checking for proper usage of `install(`
if(CELERITAS_DEBUG)
celeritas_set_default(CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION ON)
endif()
# Avoid printing details about already installed files
celeritas_set_default(CMAKE_INSTALL_MESSAGE LAZY)

#----------------------------------------------------------------------------#
# Output locations for Celeritas products (used by CeleritasLibrary.cmake,
# CeleritasUtils.cmake, install code below) will mirror the installation layout
Expand All @@ -168,15 +205,7 @@ if(CELERITAS_USE_CUDA)
# Use host compiler by default to ensure ABI consistency
set(CMAKE_CUDA_HOST_COMPILER "${CMAKE_CXX_COMPILER}" CACHE STRING
"Set to CMAKE_CXX_COMPILER by Celeritas CMakeLists")

enable_language(CUDA)

if(NOT DEFINED CMAKE_CUDA_STANDARD)
set(CMAKE_CUDA_STANDARD ${CMAKE_CXX_STANDARD})
set(CMAKE_CUDA_EXTENSIONS ${CMAKE_CXX_EXTENSIONS})
endif()
unset(CMAKE_CUDA_FLAGS_DEBUG_INIT)

find_package(CUDAToolkit REQUIRED QUIET)
elseif(CELERITAS_USE_HIP)
enable_language(HIP)
Expand Down Expand Up @@ -337,7 +366,7 @@ if(CELERITAS_USE_SWIG)
endif()

#----------------------------------------------------------------------------#
# TESTS
# UNIT TESTS
#----------------------------------------------------------------------------#

if(CELERITAS_BUILD_TESTS)
Expand All @@ -346,7 +375,7 @@ if(CELERITAS_BUILD_TESTS)
endif()

#----------------------------------------------------------------------------#
# DEMO/HELPER APPS
# APPLICATIONS AND BINARIES
#----------------------------------------------------------------------------#

add_subdirectory(app)
Expand Down
24 changes: 22 additions & 2 deletions cmake/CeleritasUtils.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ CMake configuration utility functions for Celeritas.
packages. If given, the ``<find_package>`` package name will searched for
instead of ``<package>``.

.. command:: celeritas_set_default

Set a locally-scoped value for the given variable if it is undefined.

.. command:: celeritas_check_python_module

Determine whether a given Python module is available with the current
Expand Down Expand Up @@ -195,6 +199,15 @@ endmacro()

#-----------------------------------------------------------------------------#

function(celeritas_set_default name value)
if(NOT DEFINED ${name})
message(VERBOSE "Celeritas: set default ${name}=${value}")
set(${name} "${value}" PARENT_SCOPE)
endif()
endfunction()

#-----------------------------------------------------------------------------#

function(celeritas_check_python_module varname module)
set(_cache_name CELERITAS_CHECK_PYTHON_MODULE_${module})
if(DEFINED ${_cache_name})
Expand Down Expand Up @@ -342,13 +355,15 @@ function(celeritas_define_options var doc)
set(${var} "" CACHE STRING "${doc}")
set_property(CACHE ${var} PROPERTY STRINGS "${${var}_OPTIONS}")

if("${${var}}" STREQUAL "")
set(_val "${${var}}")
if(_val STREQUAL "")
# Dynamic default option: set as core variable in parent scope
list(GET ${var}_OPTIONS 0 _default)
set(${var} "${_default}" PARENT_SCOPE)
set(_val "${_default}")
else()
# User-provided value: check against list
list(FIND ${var}_OPTIONS "${${var}}" _index)
list(FIND ${var}_OPTIONS "${_val}" _index)
if(_index EQUAL -1)
string(JOIN "," _optlist ${${var}_OPTIONS})
celeritas_error_incompatible_option(
Expand All @@ -357,6 +372,11 @@ function(celeritas_define_options var doc)
)
endif()
endif()
set(_last_var _LAST_${var})
if(NOT ${var} STREQUAL ${_last_var}) # compare *values* of variable names
message(STATUS "Set ${var}=${_val}")
set(${_last_var} "${_val}" CACHE INTERNAL "")
endif()
endfunction()

#-----------------------------------------------------------------------------#
Expand Down