Warning, /geant4/cmake/Modules/G4CMakeUtilities.cmake is written in an unsupported language. File is not indexed.
0001 #.rst:
0002 # G4CMakeUtilities
0003 # ----------------
0004 #
0005 # Extra functions and macros for encapsulating common tasks.
0006 #
0007
0008 #-----------------------------------------------------------------
0009 # License and Disclaimer
0010 #
0011 # The Geant4 software is copyright of the Copyright Holders of
0012 # the Geant4 Collaboration. It is provided under the terms and
0013 # conditions of the Geant4 Software License, included in the file
0014 # LICENSE and available at http://cern.ch/geant4/license . These
0015 # include a list of copyright holders.
0016 #
0017 # Neither the authors of this software system, nor their employing
0018 # institutes,nor the agencies providing financial support for this
0019 # work make any representation or warranty, express or implied,
0020 # regarding this software system or assume any liability for its
0021 # use. Please see the license in the file LICENSE and URL above
0022 # for the full disclaimer and the limitation of liability.
0023 #
0024 # This code implementation is the result of the scientific and
0025 # technical work of the GEANT4 collaboration.
0026 # By using, copying, modifying or distributing the software (or
0027 # any work based on the software) you agree to acknowledge its
0028 # use in resulting scientific publications, and indicate your
0029 # acceptance of all terms of the Geant4 Software license.
0030 #
0031 #-----------------------------------------------------------------
0032
0033 if(NOT __G4CMAKEUTILITIES_INCLUDED)
0034 set(__G4CMAKEUTILITIES_INCLUDED TRUE)
0035 else()
0036 return()
0037 endif()
0038
0039 #.rst:
0040 # Included Modules
0041 # ^^^^^^^^^^^^^^^^
0042 #
0043 # This module includes the following modules:
0044 include(CMakeDependentOption)
0045
0046 #-----------------------------------------------------------------------
0047 # CMAKE EXTENSIONS
0048 #-----------------------------------------------------------------------
0049 # macro set_ifnot(<var> <value>)
0050 # If variable var is not set, set its value to that provided
0051 #
0052 macro(set_ifnot _var _value)
0053 if(NOT ${_var})
0054 set(${_var} ${_value})
0055 endif()
0056 endmacro()
0057
0058 #-----------------------------------------------------------------------
0059 # function enum_option(<option>
0060 # VALUES <value1> ... <valueN>
0061 # TYPE <valuetype>
0062 # DOC <docstring>
0063 # [DEFAULT <elem>]
0064 # [CASE_INSENSITIVE])
0065 # Declare a cache variable <option> that can only take values
0066 # listed in VALUES. TYPE may be FILEPATH, PATH or STRING.
0067 # <docstring> should describe that option, and will appear in
0068 # the interactive CMake interfaces. If DEFAULT is provided,
0069 # <elem> will be taken as the zero-indexed element in VALUES
0070 # to which the value of <option> should default to if not
0071 # provided. Otherwise, the default is taken as the first
0072 # entry in VALUES. If CASE_INSENSITIVE is present, then
0073 # checks of the value of <option> against the allowed values
0074 # will ignore the case when performing string comparison.
0075 #
0076 function(enum_option _var)
0077 set(options CASE_INSENSITIVE)
0078 set(oneValueArgs DOC TYPE DEFAULT)
0079 set(multiValueArgs VALUES)
0080 cmake_parse_arguments(_ENUMOP "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
0081
0082 # - Validation as needed arguments
0083 if(NOT _ENUMOP_VALUES)
0084 message(FATAL_ERROR "enum_option must be called with non-empty VALUES\n(Called for enum_option '${_var}')")
0085 endif()
0086
0087 # - Set argument defaults as needed
0088 if(_ENUMOP_CASE_INSENSITIVE)
0089 set(_ci_values )
0090 foreach(_elem ${_ENUMOP_VALUES})
0091 string(TOLOWER "${_elem}" _ci_elem)
0092 list(APPEND _ci_values "${_ci_elem}")
0093 endforeach()
0094 set(_ENUMOP_VALUES ${_ci_values})
0095 endif()
0096
0097 set_ifnot(_ENUMOP_TYPE STRING)
0098 set_ifnot(_ENUMOP_DEFAULT 0)
0099 list(GET _ENUMOP_VALUES ${_ENUMOP_DEFAULT} _default)
0100
0101 if(NOT DEFINED ${_var})
0102 set(${_var} ${_default} CACHE ${_ENUMOP_TYPE} "${_ENUMOP_DOC} (${_ENUMOP_VALUES})")
0103 else()
0104 set(_var_tmp ${${_var}})
0105 if(_ENUMOP_CASE_INSENSITIVE)
0106 string(TOLOWER ${_var_tmp} _var_tmp)
0107 endif()
0108
0109 list(FIND _ENUMOP_VALUES ${_var_tmp} _elem)
0110 if(_elem LESS 0)
0111 message(FATAL_ERROR "Value '${${_var}}' for variable ${_var} is not allowed\nIt must be selected from the set: ${_ENUMOP_VALUES} (DEFAULT: ${_default})\n")
0112 else()
0113 # - convert to lowercase
0114 if(_ENUMOP_CASE_INSENSITIVE)
0115 set(${_var} ${_var_tmp} CACHE ${_ENUMOP_TYPE} "${_ENUMOP_DOC} (${_ENUMOP_VALUES})" FORCE)
0116 endif()
0117 endif()
0118 endif()
0119 set_property(CACHE ${_var} PROPERTY STRINGS ${_ENUMOP_VALUES})
0120 endfunction()
0121
0122 #-----------------------------------------------------------------------
0123 # GENERAL GEANT4
0124 #-----------------------------------------------------------------------
0125 # function geant4_add_feature(<NAME> <DOCSTRING>)
0126 # Add a Geant4 feature, whose activation is specified by the
0127 # existence of the variable <NAME>, to the list of enabled/disabled
0128 # features, plus a docstring describing the feature
0129 #
0130 function(geant4_add_feature _var _description)
0131 if(${_var})
0132 set_property(GLOBAL APPEND PROPERTY GEANT4_ENABLED_FEATURES ${_var})
0133 else()
0134 set_property(GLOBAL APPEND PROPERTY GEANT4_DISABLED_FEATURES ${_var})
0135 endif()
0136
0137 # Property name qualified by "G4" prefix so we can provide seperate
0138 # descriptions for CMake builtins we might expose (e.g. CXX_STANDARD)
0139 set_property(GLOBAL PROPERTY G4_${_var}_DESCRIPTION "${_description}")
0140 endfunction()
0141
0142 #-----------------------------------------------------------------------
0143 # function geant4_print_enabled_features()
0144 # Print enabled Geant4 features plus their docstrings.
0145 #
0146 function(geant4_print_enabled_features)
0147 set(_currentFeatureText "The following Geant4 features are enabled:")
0148 get_property(_enabledFeatures GLOBAL PROPERTY GEANT4_ENABLED_FEATURES)
0149
0150 foreach(_feature ${_enabledFeatures})
0151 set(_currentFeatureText "${_currentFeatureText}\n${_feature}")
0152
0153 get_property(_desc GLOBAL PROPERTY G4_${_feature}_DESCRIPTION)
0154
0155 if(_desc)
0156 set(_currentFeatureText "${_currentFeatureText}: ${_desc}")
0157 set(_desc NOTFOUND)
0158 endif(_desc)
0159 endforeach(_feature)
0160
0161 message(STATUS "${_currentFeatureText}\n")
0162 endfunction()
0163
0164 #-----------------------------------------------------------------------
0165 # GEANT4 DATASETS
0166 #-----------------------------------------------------------------------
0167 # function geant4_latest_version(<dir> <name> <output variable>)
0168 # Locate latest version of dataset <name> in <dir>, setting value
0169 # of output variable to the full path to the dataset
0170 #
0171 function(geant4_latest_version dir name var)
0172 file(GLOB files RELATIVE ${dir} ${dir}/${name}*)
0173 set(newer)
0174 foreach(file ${files})
0175 string(REPLACE ${name} "" version ${file})
0176 if("${version}" VERSION_GREATER "${newer}")
0177 set(newer ${version})
0178 endif()
0179 endforeach()
0180 set(${var} ${dir}/${name}${newer} PARENT_SCOPE)
0181 endfunction()
0182
0183 #-----------------------------------------------------------------------
0184 # GEANT4 EXTERNAL PACKAGE HELPERS
0185 #-----------------------------------------------------------------------
0186 # function geant4_save_package_variables(<title> <var1> ... <varN>)
0187 # Save variables <var1> ... <varN> under <title> for export to
0188 # build-time package settings file.
0189 #
0190 function(geant4_save_package_variables _title)
0191 get_property(__ep_titles GLOBAL PROPERTY GEANT4_EXPORT_PACKAGE_TITLES)
0192 if(NOT (${_title} IN_LIST __ep_titles))
0193 set_property(GLOBAL APPEND PROPERTY GEANT4_EXPORT_PACKAGE_TITLES ${_title})
0194 endif()
0195
0196 get_property(__exported_vars GLOBAL PROPERTY GEANT4_EXPORT_PACKAGE_${_title}_VARIABLES)
0197 foreach(__varname ${ARGN})
0198 if(NOT (${__varname} IN_LIST __exported_vars))
0199 # Some variables might be empty on certain systems. Only save those with a value
0200 if(${__varname})
0201 # TODO: Also check that the save variable is in the cache...
0202 # if(CACHE ...) only available from 3.14
0203 set_property(GLOBAL APPEND PROPERTY GEANT4_EXPORT_PACKAGE_${_title}_VARIABLES ${__varname})
0204 endif()
0205 endif()
0206 endforeach()
0207 endfunction()
0208
0209 # function geant4_export_package_variables(<file>)
0210 # Write saved package variables to <file>
0211 #
0212 function(geant4_export_package_variables _file)
0213 set(GEANT4_PACKAGE_SETTINGS )
0214 get_property(__g4_exports GLOBAL PROPERTY GEANT4_EXPORT_PACKAGE_TITLES)
0215
0216 foreach(__pkg_title ${__g4_exports})
0217 set(__local_build_setting "\n# ${__pkg_title} Build Time Settings")
0218 get_property(__pkg_vars GLOBAL PROPERTY GEANT4_EXPORT_PACKAGE_${__pkg_title}_VARIABLES)
0219
0220 foreach(__var ${__pkg_vars})
0221 get_property(__var_value CACHE ${__var} PROPERTY VALUE)
0222 get_property(__var_type CACHE ${__var} PROPERTY TYPE)
0223 get_property(__var_help CACHE ${__var} PROPERTY HELPSTRING)
0224 # Variable may not be in cache, only local (canonical case being EXPAT_LIBRARY since CMake 3.27)
0225 # We still need to account for these because they may be required to be in the CACHE at least set in
0226 # earlier versions.
0227 # 1. Variable may not be in cache, only local (canonical case being EXPAT_LIBRARY since CMake 3.27)
0228 # We still need to account for these because they may be required to be in the CACHE at least set in
0229 # earlier versions.
0230 # 2. Depending on CMake version, variable may be in cache but unitialized, here we want the local value
0231 if(((NOT __var_value) AND (NOT __var_type) AND (NOT __var_help)) OR (__var_type STREQUAL "UNINITIALIZED"))
0232 set(__var_value ${${__var}})
0233 # TODO: set type based on whether it looks like a bool or path, but PATH almost invariably what we save
0234 # Only important in cmake GUI and if value needs to be changed, which we don't if package cache is used
0235 set(__var_type PATH)
0236 set(__var_help "no documentation, not a cache value")
0237 endif()
0238
0239 list(APPEND __local_build_setting "geant4_set_and_check_package_variable(${__var} \"${__var_value}\" ${__var_type} \"${__var_help}\")")
0240 endforeach()
0241
0242 list(APPEND GEANT4_PACKAGE_SETTINGS ${__local_build_setting})
0243 endforeach()
0244
0245 string(REPLACE ";" "\n" GEANT4_PACKAGE_SETTINGS "${GEANT4_PACKAGE_SETTINGS}")
0246
0247 configure_file(${PROJECT_SOURCE_DIR}/cmake/Templates/Geant4PackageCache.cmake.in
0248 ${_file}
0249 @ONLY
0250 )
0251 endfunction()
0252
0253 #-----------------------------------------------------------------------
0254 # GEANT4 TESTING
0255 #-----------------------------------------------------------------------
0256 # function geant4_add_unit_tests(test1 test2 ... [dir1 ...]
0257 # INCLUDE_DIRS dir1 dir2 ...
0258 # LIBRARIES library1 library2 ...)
0259 #
0260 function(geant4_add_unit_tests)
0261 cmake_parse_arguments(ARG "" "" "INCLUDE_DIRS;LIBRARIES" ${ARGN})
0262
0263 foreach(incdir ${ARG_INCLUDE_DIRS})
0264 if(IS_ABSOLUTE ${incdir})
0265 include_directories(${incdir})
0266 else()
0267 include_directories(${PROJECT_SOURCE_DIR}/source/${incdir})
0268 endif()
0269 endforeach()
0270
0271 if(ARG_UNPARSED_ARGUMENTS)
0272 set(tnames ${ARG_UNPARSED_ARGUMENTS})
0273 else()
0274 set(tnames test*.cc)
0275 endif()
0276
0277 set(alltests)
0278 foreach(tname ${tnames})
0279 if(tname STREQUAL ".")
0280 set(tests ".")
0281 else()
0282 file(GLOB tests RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${tname})
0283 endif()
0284 set(alltests ${alltests} ${tests})
0285 endforeach()
0286
0287 if(NOT TARGET tests)
0288 add_custom_target(tests)
0289 endif()
0290
0291 foreach(test ${alltests})
0292 if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${test})
0293 file(GLOB sources ${test}/src/*.cc)
0294 include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/${test}/include)
0295 file(GLOB test ${test}/*.cc)
0296 else()
0297 set(sources)
0298 endif()
0299 get_filename_component(name ${test} NAME_WE)
0300 add_executable(${name} EXCLUDE_FROM_ALL ${test} ${sources})
0301 target_link_libraries(${name} ${ARG_LIBRARIES})
0302 set_target_properties(${name} PROPERTIES OUTPUT_NAME ${name})
0303 add_dependencies(tests ${name})
0304 add_test(NAME ${name} COMMAND ${name})
0305 set_property(TEST ${name} PROPERTY LABELS UnitTests)
0306 set_property(TEST ${name} PROPERTY TIMEOUT 60)
0307 endforeach()
0308 endfunction()