Warning, /geant4/cmake/Modules/G4DeveloperAPI.cmake is written in an unsupported language. File is not indexed.
0001 #.rst:
0002 # G4DeveloperAPI
0003 # --------------
0004 #
0005 # .. code-block::cmake
0006 #
0007 # include(G4DeveloperAPI)
0008 #
0009 # CMake functions and macros for declaring and working with build
0010 # products of Geant4.
0011 #
0012
0013 #-----------------------------------------------------------------
0014 # License and Disclaimer
0015 #
0016 # The Geant4 software is copyright of the Copyright Holders of
0017 # the Geant4 Collaboration. It is provided under the terms and
0018 # conditions of the Geant4 Software License, included in the file
0019 # LICENSE and available at http://cern.ch/geant4/license . These
0020 # include a list of copyright holders.
0021 #
0022 # Neither the authors of this software system, nor their employing
0023 # institutes,nor the agencies providing financial support for this
0024 # work make any representation or warranty, express or implied,
0025 # regarding this software system or assume any liability for its
0026 # use. Please see the license in the file LICENSE and URL above
0027 # for the full disclaimer and the limitation of liability.
0028 #
0029 # This code implementation is the result of the scientific and
0030 # technical work of the GEANT4 collaboration.
0031 # By using, copying, modifying or distributing the software (or
0032 # any work based on the software) you agree to acknowledge its
0033 # use in resulting scientific publications, and indicate your
0034 # acceptance of all terms of the Geant4 Software license.
0035 #
0036 #-----------------------------------------------------------------
0037
0038 include_guard(DIRECTORY)
0039
0040 #-----------------------------------------------------------------------
0041 #-----------------------------------------------------------------------
0042 #.rst:
0043 # Module Commands
0044 # ^^^^^^^^^^^^^^^
0045 #
0046 # .. cmake:command:: geant4_add_module
0047 #
0048 # .. code-block:: cmake
0049 #
0050 # geant4_add_module(<name>
0051 # PUBLIC_HEADERS header1 [header2 ...]
0052 # PRIVATE_HEADERS header1 [header2 ..]
0053 # [SOURCES source1 [source2 ...]])
0054 #
0055 # Add a Geant4 module called ``<name>`` to the project, composed
0056 # of the source files listed in the ``PUBLIC_HEADERS``, ``PRIVATE_HEADERS``,
0057 # and ``SOURCES`` arguments. The ``<name>`` must be unique within the project.
0058 # The directory in which the module is added (i.e. ``CMAKE_CURRENT_LIST_DIR``
0059 # for the CMake script in which ``geant4_add_module`` is called) must contain:
0060 #
0061 # * An ``include`` subdirectory for the public headers
0062 # * A ``include/private`` subdirectory for the private headers
0063 # * A ``src`` subdirectory for source files if the module provides these
0064 #
0065 # Any module with only ``PUBLIC_HEADERS`` has its ``IS_INTERFACE`` property
0066 # set to ``TRUE``. This is for downstream use in composing and building end
0067 # targets appropriately.
0068 #
0069 # The ``PUBLIC_HEADERS`` argument must list the headers comprising the
0070 # public interface of the module. If a header is supplied as a relative path,
0071 # this is interpreted as being relative to the ``include`` subdirectory of the module.
0072 # Absolute paths may also be supplied, e.g. if headers are generated by the project.
0073 #
0074 # The ``PRIVATE_HEADERS`` argument must list the headers comprising any
0075 # interfaces that are implementation details of the module. If a header is supplied
0076 # as a relative path, this is interpreted as being relative to the ``include/private``
0077 # subdirectory of the module. Absolute paths may also be supplied, e.g. if headers
0078 # are generated by the project.
0079 #
0080 # The ``SOURCES`` argument should list any source files for the module.
0081 # If a source is is supplied as a relative path, this is interpreted as being
0082 # relative to the ``src`` subdirectory of the module. Absolute paths may
0083 # also be supplied, e.g. if sources are generated by the project.
0084 #
0085 function(geant4_add_module _name)
0086 __geant4_module_assert_not_exists(${_name})
0087 set_property(GLOBAL APPEND PROPERTY GEANT4_DEFINED_MODULES ${_name})
0088 cmake_parse_arguments(G4ADDMOD
0089 ""
0090 ""
0091 "PUBLIC_HEADERS;PRIVATE_HEADERS;SOURCES"
0092 ${ARGN}
0093 )
0094 __geant4_assert_no_unparsed_arguments(G4ADDMOD geant4_add_module)
0095
0096 # - Check required directory structure at definition point
0097 # Headers always
0098 if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/include")
0099 message(FATAL_ERROR "Missing required 'include' subdirectory for module '${_name}' at '${CMAKE_CURRENT_LIST_DIR}'")
0100 endif()
0101
0102 # Sources if defined
0103 if(G4ADDMOD_SOURCES AND (NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/src"))
0104 message(FATAL_ERROR "Missing required 'src' subdirectory for module '${_name}' at '${CMAKE_CURRENT_LIST_DIR}'")
0105 endif()
0106
0107 # Record where we're defined so we can pop the file into IDEs
0108 geant4_set_module_property(${_name} PROPERTY CMAKE_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}")
0109
0110 # Compose header/source lists
0111 geant4_module_sources(${_name}
0112 PUBLIC_HEADERS ${G4ADDMOD_PUBLIC_HEADERS}
0113 PRIVATE_HEADERS ${G4ADDMOD_PRIVATE_HEADERS}
0114 SOURCES ${G4ADDMOD_SOURCES})
0115
0116 # Set default usage requirements for this module, dependent on whether it is an INTERFACE or not
0117 # TODO: It's a hard error if a module is INTERFACE and has PRIVATE_HEADERS
0118 if(NOT G4ADDMOD_SOURCES)
0119 geant4_module_include_directories(${_name} INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>)
0120 geant4_set_module_property(${_name} PROPERTY IS_INTERFACE TRUE)
0121 else()
0122 # Set the default include directory for this module
0123 # Private header inclusions are, for now, dealt with at the target level (until we require CMake >=3.18)
0124 # - See set_source_files_properties for details
0125 geant4_module_include_directories(${_name} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>)
0126
0127 # Some compile definitions are still transported via directory level
0128 # "add_definitions" calls (primarily DLL exports)
0129 # These, if they exist, are equivalent to PRIVATE compile defs for the module (and hence library)
0130 # and hence are only added for compiled modules.
0131 get_directory_property(__local_compile_defs COMPILE_DEFINITIONS)
0132 geant4_module_compile_definitions(${_name} PRIVATE ${__local_compile_defs})
0133 endif()
0134
0135 # Backward compatibility shim for direct usage of build directory
0136 # Not all clients (esp. those using ROOT) may not fully support usage requirements
0137 # and expect GEANT4_INCLUDE_DIRS to be complete
0138 set_property(GLOBAL APPEND PROPERTY GEANT4_BUILDTREE_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/include")
0139 endfunction()
0140
0141 #-----------------------------------------------------------------------
0142 # .. cmake:command:: geant4_module_sources
0143 #
0144 # .. code-block:: cmake
0145 #
0146 # geant4_module_sources(<name>
0147 # PUBLIC_HEADERS header1 [header2 ...]
0148 # PRIVATE_HEADERS header1 [header2 ...]
0149 # [SOURCES source1 [source2 ...]])
0150 #
0151 # Append sources to a Geant4 module called ``<name>``, composed of the source
0152 # files listed in the ``PUBLIC_HEADERS`` and ``SOURCES`` arguments. The module
0153 # ``name`` must have already been created by the ``geant4_add_module`` command.
0154 #
0155 # The requirements on the ``PUBLIC_HEADERS`` and ``SOURCES`` arguments as the same
0156 # as for the ``geant4_add_module`` command. Intended for the use case of modules with
0157 # optional sources dependent on a configuration flag.
0158 #
0159 function(geant4_module_sources _name)
0160 __geant4_module_assert_exists(${_name})
0161 cmake_parse_arguments(G4MODSRCS
0162 ""
0163 ""
0164 "PUBLIC_HEADERS;PRIVATE_HEADERS;SOURCES"
0165 ${ARGN}
0166 )
0167 __geant4_assert_no_unparsed_arguments(G4MODSRCS geant4_module_sources)
0168
0169 # Restrict calls to the same CMake file as the original add
0170 # Ensures we don't mix up sources/get confused on paths given assumptions made
0171 geant4_get_module_property(__location ${_name} CMAKE_LIST_FILE)
0172 if(NOT ("${__location}" STREQUAL "${CMAKE_CURRENT_LIST_FILE}"))
0173 message(FATAL_ERROR "adding sources to module '${_name}' in '${CMAKE_CURRENT_LIST_FILE}', but module was defined in '${__location}'")
0174 endif()
0175
0176 # Append header/source lists to module
0177 set(__tmp_HEADERS)
0178 foreach(__elem ${G4MODSRCS_PUBLIC_HEADERS})
0179 if(IS_ABSOLUTE "${__elem}")
0180 list(APPEND __tmp_HEADERS "${__elem}")
0181 else()
0182 list(APPEND __tmp_HEADERS "${CMAKE_CURRENT_LIST_DIR}/include/${__elem}")
0183 endif()
0184 endforeach()
0185 geant4_set_module_property(${_name} APPEND PROPERTY PUBLIC_HEADERS ${__tmp_HEADERS})
0186
0187 set(__tmp_HEADERS)
0188 foreach(__elem ${G4MODSRCS_PRIVATE_HEADERS})
0189 if(IS_ABSOLUTE "${__elem}")
0190 list(APPEND __tmp_HEADERS "${__elem}")
0191 else()
0192 list(APPEND __tmp_HEADERS "${CMAKE_CURRENT_LIST_DIR}/include/private/${__elem}")
0193 endif()
0194 endforeach()
0195 geant4_set_module_property(${_name} APPEND PROPERTY PRIVATE_HEADERS ${__tmp_HEADERS})
0196
0197 set(__tmp_SOURCES)
0198 foreach(__elem ${G4MODSRCS_SOURCES})
0199 if(IS_ABSOLUTE "${__elem}")
0200 list(APPEND __tmp_SOURCES "${__elem}")
0201 else()
0202 list(APPEND __tmp_SOURCES "${CMAKE_CURRENT_LIST_DIR}/src/${__elem}")
0203 endif()
0204 endforeach()
0205 geant4_set_module_property(${_name} APPEND PROPERTY SOURCES ${__tmp_SOURCES})
0206 endfunction()
0207
0208 #-----------------------------------------------------------------------
0209 #.rst:
0210 # .. cmake:command:: geant4_module_include_directories
0211 #
0212 # .. code-block:: cmake
0213 #
0214 # geant4_module_include_directories(<module>
0215 # [PUBLIC pub1 [pub2 ...]
0216 # [PRIVATE pri1 [pri2 ...]
0217 # [INTERFACE int1 [int2 ...])
0218 #
0219 # Add include directories to given module. If the module is an ``INTERFACE``,
0220 # i.e. header-only, then only ``INTERFACE`` properties may be set.
0221 #
0222 function(geant4_module_include_directories _module)
0223 __geant4_module_assert_exists(${_module})
0224 cmake_parse_arguments(G4MODINCDIR
0225 ""
0226 ""
0227 "PUBLIC;PRIVATE;INTERFACE"
0228 ${ARGN}
0229 )
0230 __geant4_assert_no_unparsed_arguments(G4MODINCDIR geant4_module_include_directories)
0231
0232 # An interface module can only have interface requirements set
0233 geant4_get_module_property(__is_interface ${_module} IS_INTERFACE)
0234 if(__is_interface AND (G4MODINCDIR_PUBLIC OR G4MODINCDIR_PRIVATE))
0235 message(FATAL_ERROR "geant4_module_include_directories: may only set INTERFACE properties on header-only module ${_module}")
0236 endif()
0237
0238 foreach(_dir ${G4MODINCDIR_PUBLIC})
0239 geant4_set_module_property(${_module} APPEND PROPERTY PUBLIC_INCLUDE_DIRECTORIES ${_dir})
0240 endforeach()
0241
0242 foreach(_dir ${G4MODINCDIR_PRIVATE})
0243 geant4_set_module_property(${_module} APPEND PROPERTY PRIVATE_INCLUDE_DIRECTORIES ${_dir})
0244 endforeach()
0245
0246 foreach(_dir ${G4MODINCDIR_INTERFACE})
0247 geant4_set_module_property(${_module} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${_dir})
0248 endforeach()
0249 endfunction()
0250
0251 #-----------------------------------------------------------------------
0252 #.rst:
0253 # .. cmake:command:: geant4_module_link_libraries
0254 #
0255 # .. code-block:: cmake
0256 #
0257 # geant4_module_link_libraries(<module>
0258 # [PUBLIC pub1 [pub2 ...]
0259 # [PRIVATE pri1 [pri2 ...]
0260 # [INTERFACE int1 [int2 ...])
0261 #
0262 # Link ``<module>`` to given targets. If the module is an ``INTERFACE``,
0263 # i.e. header-only, then only ``INTERFACE`` properties may be set.
0264 #
0265 function(geant4_module_link_libraries _module)
0266 __geant4_module_assert_exists(${_module})
0267 cmake_parse_arguments(G4MODLINKLIB
0268 ""
0269 ""
0270 "PUBLIC;PRIVATE;INTERFACE"
0271 ${ARGN}
0272 )
0273 __geant4_assert_no_unparsed_arguments(G4MODLINKLIB geant4_module_link_libraries)
0274
0275 # An interface module can only have interface requirements set
0276 geant4_get_module_property(__is_interface ${_module} IS_INTERFACE)
0277 if(__is_interface AND (G4MODLINKLIB_PUBLIC OR G4MODLINKLIB_PRIVATE))
0278 message(FATAL_ERROR "geant4_module_link_libraries: may only set INTERFACE properties on header-only module ${_module}")
0279 endif()
0280
0281 foreach(_lib ${G4MODLINKLIB_PUBLIC})
0282 geant4_set_module_property(${_module} APPEND PROPERTY PUBLIC_LINK_LIBRARIES ${_lib})
0283 endforeach()
0284
0285 foreach(_lib ${G4MODLINKLIB_PRIVATE})
0286 geant4_set_module_property(${_module} APPEND PROPERTY PRIVATE_LINK_LIBRARIES ${_lib})
0287 endforeach()
0288
0289 foreach(_lib ${G4MODLINKLIB_INTERFACE})
0290 geant4_set_module_property(${_module} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${_lib})
0291 endforeach()
0292 endfunction()
0293
0294 #-----------------------------------------------------------------------
0295 #.rst:
0296 # .. cmake:command:: geant4_module_compile_definitions
0297 #
0298 # .. code-block:: cmake
0299 #
0300 # geant4_module_compile_definitions(<module>
0301 # [PUBLIC pub1 [pub2 ...]
0302 # [PRIVATE pri1 [pri2 ...]
0303 # [INTERFACE int1 [int2 ...])
0304 #
0305 # Add compile definitions for this module. If the module is an ``INTERFACE``,
0306 # i.e. header-only, then only ``INTERFACE`` properties may be set.
0307 #
0308 # Use cases:
0309 # 1. workarounds when a config header isn't suitable
0310 #
0311 # Needs care with DLLs if used for import/export declspecs
0312 # Application of specific defs to single files not considered
0313 # Expected that uses cases here minimal, and developers should
0314 # in that case use set_source_files_properties or similar
0315 # directly.
0316 #
0317 function(geant4_module_compile_definitions _module)
0318 __geant4_module_assert_exists(${_module})
0319 cmake_parse_arguments(G4MODCOMPILEDEF
0320 ""
0321 ""
0322 "PUBLIC;PRIVATE;INTERFACE"
0323 ${ARGN}
0324 )
0325 __geant4_assert_no_unparsed_arguments(G4MODCOMPILEDEF geant4_module_compile_definitions)
0326
0327 # An interface module can only have interface requirements set
0328 geant4_get_module_property(__is_interface ${_module} IS_INTERFACE)
0329 if(__is_interface AND (G4MODCOMPILEDEF_PUBLIC OR G4MODCOMPILEDEF_PRIVATE))
0330 message(FATAL_ERROR "geant4_module_compile_definitions: may only set INTERFACE properties on header-only module ${_module}")
0331 endif()
0332
0333 foreach(_def ${G4MODCOMPILEDEF_PUBLIC})
0334 geant4_set_module_property(${_module} APPEND PROPERTY PUBLIC_COMPILE_DEFINITIONS ${_def})
0335 endforeach()
0336
0337 foreach(_def ${G4MODCOMPILEDEF_PRIVATE})
0338 geant4_set_module_property(${_module} APPEND PROPERTY PRIVATE_COMPILE_DEFINITIONS ${_def})
0339 endforeach()
0340
0341 foreach(_def ${G4MODCOMPILEDEF_INTERFACE})
0342 geant4_set_module_property(${_module} APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS ${_def})
0343 endforeach()
0344 endfunction()
0345
0346 #-----------------------------------------------------------------------
0347 #.rst:
0348 # .. cmake:command:: geant4_get_modules
0349 #
0350 # .. code-block:: cmake
0351 #
0352 # geant4_get_modules(<result>)
0353 #
0354 # Store the list of currently defined modules in the variable ``<result>``.
0355 #
0356 function(geant4_get_modules _result)
0357 get_property(__tmp GLOBAL PROPERTY GEANT4_DEFINED_MODULES)
0358 set(${_result} ${__tmp} PARENT_SCOPE)
0359 endfunction()
0360
0361 #-----------------------------------------------------------------------
0362 #.rst:
0363 # .. cmake:command:: geant4_has_module
0364 #
0365 # .. code-block:: cmake
0366 #
0367 # geant4_has_module(<result> <name>)
0368 #
0369 # Set variable ``<result>`` to a boolean which will be true if the module
0370 # ``<name>`` is defined.
0371 #
0372 function(geant4_has_module _result _name)
0373 set(__exists FALSE)
0374
0375 geant4_get_modules(__tmp)
0376 if(__tmp)
0377 list(FIND __tmp ${_name} __index)
0378 if(__index GREATER -1)
0379 set(__exists TRUE)
0380 endif()
0381 endif()
0382
0383 set(${_result} ${__exists} PARENT_SCOPE)
0384 endfunction()
0385
0386 #-----------------------------------------------------------------------
0387 #.rst:
0388 # Module Properties
0389 # =================
0390 #
0391 # A Geant4 module stores its build and usage requirements in a series
0392 # of properties:
0393 #
0394 # * ``PUBLIC_HEADERS``
0395 # * ``PRIVATE_HEADERS``
0396 # * ``SOURCES``
0397 # * ``PRIVATE_COMPILE_DEFINITIONS``
0398 # * ``PUBLIC_COMPILE_DEFINITIONS``
0399 # * ``INTERFACE_COMPILE_DEFINITIONS``
0400 # * ``PRIVATE_INCLUDE_DIRECTORIES``
0401 # * ``PUBLIC_INCLUDE_DIRECTORIES``
0402 # * ``INTERFACE_INCLUDE_DIRECTORIES``
0403 # * ``PRIVATE_LINK_LIBRARIES``
0404 # * ``PUBLIC_LINK_LIBRARIES``
0405 # * ``INTERFACE_LINK_LIBRARIES``
0406 # * ``PARENT_TARGET``
0407 # * ``CMAKE_LIST_FILE``
0408 # * ``GLOBAL_DEPENDENCIES``
0409 # * ``IS_INTERFACE``
0410 #
0411 # The properties of a module may be queried and set using the following
0412 # commands.
0413
0414 #-----------------------------------------------------------------------
0415 #.rst:
0416 # .. cmake:command:: geant4_get_module_property
0417 #
0418 # .. code-block:: cmake
0419 #
0420 # geant4_get_module_property(<result> <module> <property>)
0421 #
0422 # Store value of property ``<property>`` for ``<module>`` in variable
0423 # ``<result>``.
0424 #
0425 # If ``<property>`` is not a valid module property, a FATAL_ERROR is
0426 # emitted.
0427 #
0428 function(geant4_get_module_property _output _module _propertyname)
0429 __geant4_module_assert_exists(${_module})
0430 __geant4_module_validate_property(${_propertyname})
0431 get_property(__result GLOBAL PROPERTY ${_module}_${_propertyname})
0432 set(${_output} ${__result} PARENT_SCOPE)
0433 endfunction()
0434
0435 #-----------------------------------------------------------------------
0436 #.rst:
0437 # .. cmake:command:: geant4_set_module_property
0438 #
0439 # .. code-block:: cmake
0440 #
0441 # geant4_set_module_property(<module>
0442 # [APPEND | APPEND_STRING]
0443 # PROPERTY <property> <value>)
0444 #
0445 # Set property ``<property>`` of module ``<module>`` to ``<value>``.
0446 #
0447 # If ``APPEND`` is supplied, ``<value>`` will be appended to any existing
0448 # value for the property as a list.
0449 #
0450 # If ``APPEND_STRING`` is supplied, ``<value>`` will be appended to any existing
0451 # value for the property as a string. This option is mutually exclusive with
0452 # ``APPEND``.
0453 #
0454 # If ``<property>`` is not a valid module property, a FATAL_ERROR is
0455 # emitted.
0456 #
0457 function(geant4_set_module_property _module)
0458 __geant4_module_assert_exists(${_module})
0459 cmake_parse_arguments(G4SMP
0460 "APPEND;APPEND_STRING"
0461 ""
0462 "PROPERTY"
0463 ${ARGN}
0464 )
0465 __geant4_assert_no_unparsed_arguments(G4SMP geant4_set_module_property)
0466
0467
0468 # Append/Append_string are mutually exclusive
0469 if(G4SMP_APPEND AND G4SMP_APPEND_STRING)
0470 message(FATAL_ERROR "geant4_set_module_property: cannot set both APPEND and APPEND_STRING")
0471 elseif(G4SMP_APPEND)
0472 set(G4SMP_APPEND_MODE "APPEND")
0473 elseif(G4SMP_APPEND_MODE)
0474 set(G4SMP_APPEND_MODE "APPEND_STRING")
0475 endif()
0476
0477 # First element of PROPERTY list is prop name
0478 list(GET G4SMP_PROPERTY 0 G4SMP_PROPERTY_NAME)
0479 if(NOT G4SMP_PROPERTY_NAME)
0480 message(FATAL_ERROR "geant4_set_module_property: Required PROPERTY argument is missing")
0481 endif()
0482
0483 __geant4_module_validate_property(${G4SMP_PROPERTY_NAME})
0484 # Remainder is arguments, so strip first element
0485 list(REMOVE_AT G4SMP_PROPERTY 0)
0486
0487 set_property(GLOBAL ${G4SMP_APPEND_MODE} PROPERTY ${_module}_${G4SMP_PROPERTY_NAME} ${G4SMP_PROPERTY})
0488 endfunction()
0489
0490 #-----------------------------------------------------------------------
0491 #-----------------------------------------------------------------------
0492 #.rst:
0493 # Category Commands
0494 # ^^^^^^^^^^^^^^^^^
0495 #
0496 # .. cmake:command:: geant4_add_category
0497 #
0498 # .. code-block:: cmake
0499 #
0500 # geant4_add_category(<name> MODULES <module> [<module> ...])
0501 #
0502 # Add a Geant4 category ``<name>`` to the project, composed of the modules
0503 # supplied in the ``MODULES`` list.
0504 #
0505 # Calling this function does not create an actual CMake library target.
0506 # Because modules declare dependencies on modules rather than libraries, we
0507 # defer creation of library targets to after creation of categories, which
0508 # allows resolution of module <-> category use. Additionally, category specific
0509 # actions such as install may be added.
0510 #
0511 function(geant4_add_category _name)
0512 __geant4_category_assert_not_exists(${_name})
0513 set_property(GLOBAL APPEND PROPERTY GEANT4_DEFINED_CATEGORIES ${_name})
0514 cmake_parse_arguments(G4ADDCAT
0515 ""
0516 ""
0517 "MODULES"
0518 ${ARGN}
0519 )
0520 # - Modules must not be empty (Could also just be ARGN)
0521 if(NOT G4ADDCAT_MODULES)
0522 message(FATAL_ERROR "geant4_add_category: Missing/empty 'MODULES' argument")
0523 endif()
0524
0525 # Default to an interface module, geant4_category_modules will update this if needed
0526 geant4_set_category_property(${_name} PROPERTY IS_INTERFACE TRUE)
0527
0528 # Compose Category from Modules
0529 geant4_category_modules(${_name} ${G4ADDCAT_MODULES})
0530
0531 # As we do not create a physical target, store the script in which we're called
0532 geant4_set_category_property(${_name} PROPERTY CMAKE_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}")
0533 endfunction()
0534
0535 #-----------------------------------------------------------------------
0536 #.rst:
0537 # .. cmake:command:: geant4_category_modules
0538 #
0539 # .. code-block:: cmake
0540 #
0541 # geant4_category_modules(<category> <module> [<module> ...])
0542 #
0543 # Add modules to category ``<category>``
0544 #
0545 function(geant4_category_modules _name)
0546 __geant4_category_assert_exists(${_name})
0547 # ARGN must not be empty
0548 if(NOT ARGN)
0549 message(FATAL_ERROR "no modules given to add to to category '${_name}'")
0550 endif()
0551
0552 # Need to track if any added module has source files. If so, must set IS_INTERFACE to false
0553 # Compose Category from Modules, accounting for potential interface-only composition
0554 geant4_get_category_property(__cat_is_interface ${_name} IS_INTERFACE)
0555 foreach(__g4module ${ARGN})
0556 # Module must not have been composed already (Might want to mark special case where module added twice into same category)
0557 geant4_get_module_property(_parent ${__g4module} PARENT_TARGET)
0558 if(_parent)
0559 message(FATAL_ERROR "trying to compose category '${_name}' using module '${__g4module}' which is already composed into category '${_parent}'")
0560 endif()
0561
0562 # Compose it
0563 geant4_set_module_property(${__g4module} PROPERTY PARENT_TARGET ${_name})
0564 geant4_set_category_property(${_name} APPEND PROPERTY MODULES ${__g4module})
0565
0566 geant4_get_module_property(_headers ${__g4module} PUBLIC_HEADERS)
0567 geant4_set_category_property(${_name} APPEND PROPERTY PUBLIC_HEADERS ${_headers})
0568
0569 # Is this module interface only?
0570 geant4_get_module_property(_is_interface ${__g4module} IS_INTERFACE)
0571 if(NOT _is_interface)
0572 set(__cat_is_interface FALSE)
0573 endif()
0574 endforeach()
0575 geant4_set_category_property(${_name} PROPERTY IS_INTERFACE ${__cat_is_interface})
0576 endfunction()
0577
0578 #-----------------------------------------------------------------------
0579 #.rst:
0580 # .. cmake:command:: geant4_get_categories
0581 #
0582 # .. code-block:: cmake
0583 #
0584 # geant4_get_categories(<result>)
0585 #
0586 # Store the list of currently defined categories in the variable ``<result>``.
0587 #
0588 function(geant4_get_categories _result)
0589 get_property(__tmp GLOBAL PROPERTY GEANT4_DEFINED_CATEGORIES)
0590 set(${_result} ${__tmp} PARENT_SCOPE)
0591 endfunction()
0592
0593 #-----------------------------------------------------------------------
0594 #.rst:
0595 # .. cmake:command:: geant4_has_category
0596 #
0597 # .. code-block:: cmake
0598 #
0599 # geant4_has_category(<result> <name>)
0600 #
0601 # Set variable ``<result>`` to a boolean which will be true if the category
0602 # ``<name>`` is defined.
0603 #
0604 function(geant4_has_category _result _name)
0605 set(__exists FALSE)
0606
0607 geant4_get_categories(__tmp)
0608 if(__tmp)
0609 list(FIND __tmp ${_name} __index)
0610 if(__index GREATER -1)
0611 set(__exists TRUE)
0612 endif()
0613 endif()
0614
0615 set(${_result} ${__exists} PARENT_SCOPE)
0616 endfunction()
0617
0618 #-----------------------------------------------------------------------
0619 #.rst:
0620 # Category Properties
0621 # ===================
0622 #
0623 # A Geant4 category stores its build and usage requirements in a series
0624 # of properties:
0625 #
0626 # * ``CMAKE_LIST_FILE``
0627 # * ``IS_INTERFACE``
0628 # * ``MODULES``
0629 # * ``PUBLIC_HEADERS``
0630 #
0631 # The properties of a category may be queried and set using the following
0632 # commands.
0633 #
0634
0635 #-----------------------------------------------------------------------
0636 #.rst:
0637 # .. cmake:command:: geant4_get_category_property
0638 #
0639 # .. code-block:: cmake
0640 #
0641 # geant4_get_category_property(<result> <category> <property>)
0642 #
0643 # Store value of property ``<property>`` for ``<module>`` in variable
0644 # ``<result>``.
0645 #
0646 # If ``<property>`` is not a valid module property, a FATAL_ERROR is
0647 # emitted.
0648 #
0649 function(geant4_get_category_property _output _category _propertyname)
0650 __geant4_category_assert_exists(${_category})
0651 __geant4_category_validate_property(${_propertyname})
0652 get_property(__result GLOBAL PROPERTY GEANT4_CATEGORY_${_category}_${_propertyname})
0653 set(${_output} ${__result} PARENT_SCOPE)
0654 endfunction()
0655
0656 #-----------------------------------------------------------------------
0657 #.rst:
0658 # .. cmake:command:: geant4_set_category_property
0659 #
0660 # .. code-block:: cmake
0661 #
0662 # geant4_set_category_property(<module>
0663 # [APPEND | APPEND_STRING]
0664 # PROPERTY <property> <value>)
0665 #
0666 # Set property ``<property>`` of category ``<category>`` to ``<value>``.
0667 #
0668 # If ``APPEND`` is supplied, ``<value>`` will be appended to any existing
0669 # value for the property as a list.
0670 #
0671 # If ``APPEND_STRING`` is supplied, ``<value>`` will be appended to any existing
0672 # value for the property as a string. This option is mutually exclusive with
0673 # ``APPEND``.
0674 #
0675 # If ``<property>`` is not a valid category property, a FATAL_ERROR is
0676 # emitted.
0677 #
0678 function(geant4_set_category_property _category)
0679 __geant4_category_assert_exists(${_category})
0680 cmake_parse_arguments(G4CMP
0681 "APPEND;APPEND_STRING"
0682 ""
0683 "PROPERTY"
0684 ${ARGN}
0685 )
0686 __geant4_assert_no_unparsed_arguments(G4CMP geant4_set_category_property)
0687
0688
0689 # Append/Append_string are mutually exclusive
0690 if(G4CMP_APPEND AND G4CMP_APPEND_STRING)
0691 message(FATAL_ERROR "geant4_set_category_property: cannot set both APPEND and APPEND_STRING")
0692 elseif(G4CMP_APPEND)
0693 set(G4CMP_APPEND_MODE "APPEND")
0694 elseif(G4CMP_APPEND_MODE)
0695 set(G4CMP_APPEND_MODE "APPEND_STRING")
0696 endif()
0697
0698 # First element of PROPERTY list is prop name
0699 list(GET G4CMP_PROPERTY 0 G4CMP_PROPERTY_NAME)
0700 if(NOT G4CMP_PROPERTY_NAME)
0701 message(FATAL_ERROR "geant4_set_category_property: Required PROPERTY argument is missing")
0702 endif()
0703
0704 __geant4_category_validate_property(${G4CMP_PROPERTY_NAME})
0705 # Remainder is arguments, so strip first element
0706 list(REMOVE_AT G4CMP_PROPERTY 0)
0707
0708 set_property(GLOBAL ${G4CMP_APPEND_MODE} PROPERTY GEANT4_CATEGORY_${_category}_${G4CMP_PROPERTY_NAME} ${G4CMP_PROPERTY})
0709 endfunction()
0710
0711
0712 #-----------------------------------------------------------------------
0713 #-----------------------------------------------------------------------
0714 #.rst:
0715 # External Library Commands
0716 # ^^^^^^^^^^^^^^^^^^^^^^^^^
0717 #
0718 # Geant4 provides internal copies of libraries that are required to build
0719 # the toolkit:
0720 #
0721 # - CLHEP
0722 # - PTL
0723 # - Expat
0724 # - ZLIB
0725 # - Tools
0726 #
0727 # Because these may have different build systems and source/header structures than
0728 # Geant4, the following commands help adapt their build and use to:
0729 #
0730 # - Provide shared and/or static library targets using the same settings as the
0731 # toolkit libraries (for example, C++ Standard)
0732 # - Use of these targets as other Geant4 libraries to allow consistent full static/full
0733 # shared linking
0734 #
0735
0736 #-----------------------------------------------------------------------
0737 #.rst:
0738 # .. cmake:command:: geant4_add_external_library
0739 #
0740 # .. code-block::
0741 #
0742 # geant4_add_external_library(NAME <name>
0743 # SOURCES source1 [source2 ...])
0744 #
0745 # Maintained for building external targets because we try and reuse their
0746 # upstream code/build layout as far as possible, but want to ensure the
0747 # targets are compiled in same way as toolkit libraries.
0748 #
0749 function(geant4_add_external_library)
0750 cmake_parse_arguments(G4GLOBLIB
0751 ""
0752 "NAME"
0753 "SOURCES"
0754 ${ARGN}
0755 )
0756 __geant4_assert_no_unparsed_arguments(G4GLOBLIB geant4_add_external_library)
0757
0758 # Only supported for externals G4clhep/G4expat/G4zlib, so an error if used elsewhere
0759 if(NOT (${G4GLOBLIB_NAME} MATCHES "G4clhep|G4expat|G4zlib"))
0760 message(FATAL_ERROR "geant4_add_external_library called for '${G4GLOBLIB_NAME}' in '${CMAKE_CURRENT_LIST_DIR}'")
0761 endif()
0762
0763 if(BUILD_SHARED_LIBS)
0764 add_library(${G4GLOBLIB_NAME} SHARED ${G4GLOBLIB_SOURCES})
0765 add_library(Geant4::${G4GLOBLIB_NAME} ALIAS ${G4GLOBLIB_NAME})
0766 target_compile_features(${G4GLOBLIB_NAME} PUBLIC ${GEANT4_TARGET_COMPILE_FEATURES})
0767 target_compile_definitions(${G4GLOBLIB_NAME} PUBLIC G4LIB_BUILD_DLL)
0768 target_include_directories(${G4GLOBLIB_NAME}
0769 PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
0770 )
0771 set_target_properties(${G4GLOBLIB_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
0772
0773 install(TARGETS ${G4GLOBLIB_NAME}
0774 EXPORT Geant4LibraryDepends
0775 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime
0776 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Runtime
0777 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development
0778 INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
0779 endif()
0780
0781 if(BUILD_STATIC_LIBS)
0782 add_library(${G4GLOBLIB_NAME}-static STATIC ${G4GLOBLIB_SOURCES})
0783 add_library(Geant4::${G4GLOBLIB_NAME}-static ALIAS ${G4GLOBLIB_NAME}-static)
0784 target_compile_features(${G4GLOBLIB_NAME}-static PUBLIC ${GEANT4_TARGET_COMPILE_FEATURES})
0785 target_include_directories(${G4GLOBLIB_NAME}-static
0786 PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
0787 )
0788
0789 if(NOT WIN32)
0790 set_target_properties(${G4GLOBLIB_NAME}-static PROPERTIES OUTPUT_NAME ${G4GLOBLIB_NAME})
0791 endif()
0792
0793 install(TARGETS ${G4GLOBLIB_NAME}-static
0794 EXPORT Geant4LibraryDepends
0795 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime
0796 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Runtime
0797 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development
0798 INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
0799 endif()
0800
0801 # As with a standard library, always add the local include/ directory to exported list
0802 # for scripts
0803 set_property(GLOBAL APPEND PROPERTY GEANT4_BUILDTREE_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/include")
0804
0805 # Needs to be in defined category list for static/shared to be linked correctly.
0806 geant4_add_external_category(${G4GLOBLIB_NAME})
0807 endfunction()
0808
0809 #-----------------------------------------------------------------------
0810 #.rst:
0811 # .. cmake:command:: geant4_add_external_category
0812 #
0813 # .. code-block:: cmake
0814 #
0815 # geant4_add_external_category(<name>)
0816 #
0817 # Mark ``<name>`` as a target that supports the Geant4 target naming
0818 # convention of ``<name>`` as the shared library and ``<name>-static``
0819 # as the static. It allows Geant4 modules to link to targets built
0820 # outside the module/category system and retain consistent shared-shared
0821 # or static-static linking chains.
0822 #
0823 # If ``BUILD_SHARED_LIBS``(``BUILD_STATIC_LIBS``) is ``ON``, then ``<name>``(``<name>-static``)
0824 # must correspond to a shared(static) library target that exists at
0825 # the time this function is called.
0826 #
0827 function(geant4_add_external_category _name)
0828 # Targets must have been defined!
0829 if(BUILD_SHARED_LIBS AND (NOT TARGET ${_name}))
0830 message(FATAL_ERROR "geant4_add_external_category: no target '${_name}' has been declared")
0831 endif()
0832
0833 if(BUILD_STATIC_LIBS AND (NOT TARGET ${_name}-static))
0834 message(FATAL_ERROR "geant4_add_external_category: no target '${_name}-static' has been declared")
0835 endif()
0836
0837 set_property(GLOBAL APPEND PROPERTY GEANT4_EXTERNAL_CATEGORIES ${_name})
0838 endfunction()
0839
0840 #-----------------------------------------------------------------------
0841 #.rst:
0842 # .. cmake:command:: geant4_get_external_categories
0843 #
0844 # .. code-block:: cmake
0845 #
0846 # geant4_get_external_categories(<result>)
0847 #
0848 # Store the list of currently defined external_categories in the variable ``<result>``.
0849 #
0850 function(geant4_get_external_categories _result)
0851 get_property(__tmp GLOBAL PROPERTY GEANT4_EXTERNAL_CATEGORIES)
0852 set(${_result} ${__tmp} PARENT_SCOPE)
0853 endfunction()
0854
0855 #-----------------------------------------------------------------------
0856 #-----------------------------------------------------------------------
0857 #.rst:
0858 # Test Program Commands
0859 # ^^^^^^^^^^^^^^^^^^^^^
0860 # .. cmake:command:: geant4_test_link_libraries
0861 #
0862 # .. code-block:: cmake
0863 #
0864 # geant4_test_link_libraries(<target>
0865 # [PUBLIC pub1 [pub2 ...]
0866 # [PRIVATE pri1 [pri2 ...]
0867 # [INTERFACE int1 [int2 ...])
0868 function(geant4_test_link_libraries _target)
0869 cmake_parse_arguments(G4TESTLINKLIB
0870 ""
0871 ""
0872 "PUBLIC;PRIVATE;INTERFACE"
0873 ${ARGN}
0874 )
0875 __geant4_assert_no_unparsed_arguments(G4TESTLINKLIB geant4_test_link_libraries)
0876
0877 # Need defined libraries and externals to be able to resolve between static/shared
0878 get_property(__g4definedlibraries GLOBAL PROPERTY GEANT4_DEFINED_CATEGORIES)
0879 geant4_get_external_categories(__g4externalcategories)
0880 list(APPEND __g4definedlibraries ${__g4externalcategories})
0881
0882 foreach(__prop PUBLIC PRIVATE INTERFACE)
0883 __geant4_resolve_link_libraries(G4TESTLINKLIB_${__prop})
0884 if(G4TESTLINKLIB_${__prop})
0885 # Filter list for internal static targets
0886 # NB: This only works assuming that the input target is an executable
0887 # If we introduce test libraries, would need same treatment as for main libraries
0888 if(BUILD_STATIC_LIBS AND NOT BUILD_SHARED_LIBS)
0889 set(_g4linklibs )
0890 foreach(_linklib ${G4TESTLINKLIB_${__prop}})
0891 # If the linklib is a G4Library, change name to "name-static"
0892 list(FIND __g4definedlibraries ${_linklib} _isg4lib)
0893 if(_isg4lib GREATER -1)
0894 list(APPEND _g4linklibs "${_linklib}-static")
0895 else()
0896 list(APPEND _g4linklibs "${_linklib}")
0897 endif()
0898 endforeach()
0899 set(_linklibs ${_g4linklibs})
0900 else()
0901 set(_linklibs ${G4TESTLINKLIB_${__prop}})
0902 endif()
0903
0904 target_link_libraries(${_target} ${__prop} ${_linklibs})
0905 endif()
0906 endforeach()
0907 endfunction()
0908
0909 #-----------------------------------------------------------------------
0910 #-----------------------------------------------------------------------
0911 # Composition Functions
0912 #.rst:
0913 # .. cmake:command:: geant4_compose_targets
0914 #
0915 # .. code-block:: cmake
0916 #
0917 # geant4_compose_targets()
0918 #
0919 # Create physical SHARED/STATIC library targets from the defined Geant4
0920 # categories and modules.
0921 #
0922 # Can only be called once, and must be done so after all Geant4 libraries
0923 # and modules are defined.
0924 #
0925 function(geant4_compose_targets)
0926 get_property(__alreadyCalled GLOBAL PROPERTY GEANT4_COMPOSE_TARGETS_CALLED)
0927 if(__alreadyCalled)
0928 get_property(__callsite GLOBAL PROPERTY GEANT4_COMPOSE_TARGETS_LIST_FILE)
0929 message(FATAL_ERROR "geant4_compose_targets already called from ${__callsite}")
0930 endif()
0931
0932 # Check that every defined module is composed
0933 geant4_get_modules(__g4definedmodules)
0934 foreach(__module ${__g4definedmodules})
0935 geant4_get_module_property(__iscomposed ${__module} PARENT_TARGET)
0936 if(NOT __iscomposed)
0937 message(FATAL_ERROR "Geant4 module '${__module}' is not composed into any category")
0938 endif()
0939 endforeach()
0940
0941 # - For each module
0942 # 1. Write out files for
0943 # 1.1. module -> used modules adjacency list for detecting module-module cycles
0944 file(WRITE "${PROJECT_BINARY_DIR}/G4ModuleAdjacencyList.txt" "# Geant4 Module - Module Adjacencies\n")
0945
0946 # 1.2. module,location,public headers for developer query operations
0947 # Basically need a dict of module : [headers, ...]
0948 # - Two main queries to run
0949 # - Given a module, what public headers does it provide?
0950 # - Given a header, what module provides this?
0951 # Also want something to check a module
0952 # - Only really possible by parsing module headers (what it exposes publically)
0953 # and sources (what it uses internally)
0954 # Probaly just needs module : location
0955 # - Checking of files is runtime operation, so will refind/check each time
0956 # - Store set of build settings relevant to filtering headers in dependency checks
0957 # - "Dumb" as simply reproduced as CMake list in last column of every row (de-dupped in script)
0958 # - Settings are designed to overcome limitation of ifdef in parsing, so map
0959 # to symbols in code
0960 set(__gmc_build_settings )
0961 if(GEANT4_BUILD_MULTITHREADED)
0962 list(APPEND __gmc_build_settings "G4MULTITHREADED")
0963 endif()
0964 file(WRITE "${PROJECT_BINARY_DIR}/G4ModuleInterfaceMap.csv" "")
0965 configure_file("${PROJECT_SOURCE_DIR}/cmake/Modules/geant4_module_check.py" "${PROJECT_BINARY_DIR}/geant4_module_check.py" COPYONLY)
0966
0967 # 2. Check it does not link to a composed library composed of N>1 modules
0968 get_property(__g4definedlibraries GLOBAL PROPERTY GEANT4_DEFINED_CATEGORIES)
0969 set(__g4disallowedlinks ${__g4definedlibraries})
0970 list(REMOVE_ITEM __g4disallowedlinks ${__g4definedmodules})
0971
0972 foreach(__module ${__g4definedmodules})
0973 geant4_get_module_property(__publicdeps ${__module} PUBLIC_LINK_LIBRARIES)
0974 geant4_get_module_property(__privatedeps ${__module} PRIVATE_LINK_LIBRARIES)
0975 geant4_get_module_property(__interfacedeps ${__module} INTERFACE_LINK_LIBRARIES)
0976
0977 # 1.1 Adjacency list - take all dependencies
0978 set(__alldeps_l ${__publicdeps} ${__privatedeps} ${__interfacedeps})
0979 list(JOIN __alldeps_l " " __alldeps)
0980 file(APPEND "${PROJECT_BINARY_DIR}/G4ModuleAdjacencyList.txt" "${__module} ${__alldeps}\n")
0981
0982 # 1.2 Module interfaces, needs CMAKE, PUBLIC_HEADER
0983 geant4_get_module_property(__listfile ${__module} CMAKE_LIST_FILE)
0984 geant4_get_module_property(__publichdrs ${__module} PUBLIC_HEADERS)
0985 geant4_get_module_property(__privatehdrs ${__module} PRIVATE_HEADERS)
0986 geant4_get_module_property(__srcs ${__module} SOURCES)
0987 geant4_get_module_property(__parent_target ${__module} PARENT_TARGET)
0988 get_filename_component(__listdir "${__listfile}" DIRECTORY)
0989 # Remove generated headers
0990 list(TRANSFORM __publichdrs REPLACE "^${PROJECT_BINARY_DIR}/.*$" "")
0991 list(TRANSFORM __publichdrs REPLACE "^/.*/" "")
0992 list(TRANSFORM __privatehdrs REPLACE "^/.*/" "")
0993 list(TRANSFORM __srcs REPLACE "^/.*/" "")
0994 file(APPEND "${PROJECT_BINARY_DIR}/G4ModuleInterfaceMap.csv" "${__module},${__listdir},${__publichdrs},${__privatehdrs},${__srcs},${__publicdeps},${__privatedeps},${__interfacedeps},${__parent_target},${__gmc_build_settings}\n")
0995
0996 # 2. Check for disallowed links in each link type
0997 foreach(__linktype IN ITEMS public private interface)
0998 foreach(__link ${__${__linktype}deps})
0999 if(__link IN_LIST __g4disallowedlinks)
1000 geant4_get_category_property(__linktothese ${__link} MODULES)
1001 string(REPLACE "${PROJECT_SOURCE_DIR}/" "" __badlistfile ${__listfile})
1002 message(FATAL_ERROR "Geant4 module '${__module}' has a ${__linktype} link to composed category '${__link}'."
1003 "It must link to one or more of its component modules instead:\n"
1004 "${__linktothese}\n"
1005 "in ${__badlistfile}\n")
1006 endif()
1007 endforeach()
1008 endforeach()
1009 endforeach()
1010
1011 # Process all defined libraries
1012 set(__g4builtlibraries)
1013 set(__g4public_headers)
1014
1015 foreach(__g4lib ${__g4definedlibraries})
1016 if(BUILD_SHARED_LIBS)
1017 __geant4_add_library(${__g4lib} SHARED)
1018 list(APPEND __g4builtlibraries ${__g4lib})
1019 endif()
1020
1021 if(BUILD_STATIC_LIBS)
1022 __geant4_add_library(${__g4lib} STATIC)
1023 list(APPEND __g4builtlibraries ${__g4lib}-static)
1024 endif()
1025
1026 geant4_get_category_property(__headers ${__g4lib} PUBLIC_HEADERS)
1027 list(APPEND __g4public_headers ${__headers})
1028 endforeach()
1029
1030 #-----------------------------------------------------------------------
1031 # TEMP INSTALL - do here purely to review exported links. Should be
1032 # factored out into separate function later.
1033 install(TARGETS ${__g4builtlibraries}
1034 EXPORT Geant4LibraryDepends
1035 ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT Development
1036 LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT Runtime
1037 RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT Runtime
1038 INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}")
1039 install(FILES ${__g4public_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}" COMPONENT Development)
1040
1041 set_property(GLOBAL PROPERTY GEANT4_COMPOSE_TARGETS_CALLED ON)
1042 set_property(GLOBAL PROPERTY GEANT4_COMPOSE_TARGETS_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}")
1043 endfunction()
1044
1045 #-----------------------------------------------------------------------
1046 #-----------------------------------------------------------------------
1047 #.rst:
1048 # Internal Helper Commands
1049 # ^^^^^^^^^^^^^^^^^^^^^^^^
1050 #
1051 # These macros and functions are for use in the implementation of the
1052 # module and library functions. They should never be used directly
1053 # in developer-level scripts.
1054
1055 #-----------------------------------------------------------------------
1056 #.rst:
1057 # .. cmake:command:: __geant4_assert_no_unparsed_arguments
1058 #
1059 # .. code-block:: cmake
1060 #
1061 # __geant4_assert_no_unparsed_arguments(<prefix> <function>)
1062 #
1063 # Emit a ``FATAL_ERROR`` if ``<prefix>_UNPARSED_ARGUMENTS`` is non-empty
1064 # in ``<function>``
1065 #
1066 # This is a macro intended for use in G4DeveloperAPI functions that cannot
1067 # have unparsed arguments to validate their input.
1068 #
1069 # From CMake 3.17, the ``<function>`` argument is no longer required and
1070 # ``CMAKE_CURRENT_FUNCTION`` can be used
1071 #
1072 macro(__geant4_assert_no_unparsed_arguments _prefix _function)
1073 if(${_prefix}_UNPARSED_ARGUMENTS)
1074 message(FATAL_ERROR "${_function} called with unparsed arguments: '${${_prefix}_UNPARSED_ARGUMENTS}'")
1075 endif()
1076 endmacro()
1077
1078 #-----------------------------------------------------------------------
1079 #.rst:
1080 # .. cmake:command:: __geant4_module_assert_exists
1081 #
1082 # .. code-block:: cmake
1083 #
1084 # __geant4_module_assert_exists(<name>)
1085 #
1086 # Emit a ``FATAL_ERROR`` if the module ``<name>`` is not defined.
1087 #
1088 # This is a macro intended for use in G4DeveloperAPI functions when
1089 # the existence of a module is required for further processing
1090 #
1091 macro(__geant4_module_assert_exists _module)
1092 geant4_has_module(__geant4_module_assert_exists_tmp ${_module})
1093 if(NOT __geant4_module_assert_exists_tmp)
1094 message(FATAL_ERROR "Geant4 module '${_module}' has not been created")
1095 endif()
1096 endmacro()
1097
1098 #-----------------------------------------------------------------------
1099 #.rst:
1100 # .. cmake:command:: __geant4_module_assert_not_exists
1101 #
1102 # .. code-block:: cmake
1103 #
1104 # __geant4_module_assert_not_exists(<name>)
1105 #
1106 # Emit a ``FATAL_ERROR`` if the module ``<name>`` is defined
1107 #
1108 # This is a macro intended for use in G4DeveloperAPI functions when
1109 # the non-existence of a module is required for further processing
1110 #
1111 macro(__geant4_module_assert_not_exists _module)
1112 geant4_has_module(__geant4_module_assert_not_exists_tmp ${_module})
1113 if(__geant4_module_assert_not_exists_tmp)
1114 geant4_get_module_property(__previous_cmake_list ${_module} CMAKE_LIST_FILE)
1115 message(FATAL_ERROR "Geant4 module '${_module}' has already been created by call in '${__previous_cmake_list}'")
1116 endif()
1117 endmacro()
1118
1119 #-----------------------------------------------------------------------
1120 #.rst:
1121 # .. cmake:command:: __geant4_module_validate_property
1122 #
1123 # .. code-block:: cmake
1124 #
1125 # __geant4_module_validate_property(<property>)
1126 #
1127 # Emit a ``FATAL_ERROR`` if the ``<property>`` is not one of the valid
1128 # properties for a module:
1129 #
1130 # This is used internally by the property get/set functions.
1131 #
1132 function(__geant4_module_validate_property _property)
1133 if(NOT (${_property} MATCHES "PUBLIC_HEADERS|PRIVATE_HEADERS|SOURCES|PRIVATE_COMPILE_DEFINITIONS|PUBLIC_COMPILE_DEFINITIONS|INTERFACE_COMPILE_DEFINITIONS|PRIVATE_INCLUDE_DIRECTORIES|PUBLIC_INCLUDE_DIRECTORIES|INTERFACE_INCLUDE_DIRECTORIES|PRIVATE_LINK_LIBRARIES|PUBLIC_LINK_LIBRARIES|INTERFACE_LINK_LIBRARIES|PARENT_TARGET|CMAKE_LIST_FILE|GLOBAL_DEPENDENCIES|IS_INTERFACE|AUTOMOC"))
1134 message(FATAL_ERROR "Undefined property '${_property}'")
1135 endif()
1136 endfunction()
1137
1138 #-----------------------------------------------------------------------
1139 #.rst:
1140 # .. cmake:command:: __geant4_category_assert_exists
1141 #
1142 # .. code-block:: cmake
1143 #
1144 # __geant4_category_assert_exists(<name>)
1145 #
1146 # Emit a ``FATAL_ERROR`` if the category ``<name>`` is not defined.
1147 #
1148 # This is a macro intended for use in G4DeveloperAPI functions when
1149 # the existence of a category is required for further processing
1150 #
1151 macro(__geant4_category_assert_exists _category)
1152 geant4_has_category(__geant4_category_assert_exists_tmp ${_category})
1153 if(NOT __geant4_category_assert_exists_tmp)
1154 message(FATAL_ERROR "Geant4 category '${_category}' has not been created")
1155 endif()
1156 endmacro()
1157
1158 #-----------------------------------------------------------------------
1159 #.rst:
1160 # .. cmake:command:: __geant4_category_assert_not_exists
1161 #
1162 # .. code-block:: cmake
1163 #
1164 # __geant4_module_category_not_exists(<name>)
1165 #
1166 # Emit a ``FATAL_ERROR`` if the category ``<name>`` is defined
1167 #
1168 # This is a macro intended for use in G4DeveloperAPI functions when
1169 # the non-existence of a category is required for further processing
1170 #
1171 macro(__geant4_category_assert_not_exists _category)
1172 geant4_has_category(__geant4_category_assert_not_exists_tmp ${_category})
1173 if(__geant4_category_assert_not_exists_tmp)
1174 geant4_get_category_property(__previous_cmake_list ${_category} CMAKE_LIST_FILE)
1175 message(FATAL_ERROR "Geant4 category '${_category}' has already been created by call in '${__previous_cmake_list}'")
1176 endif()
1177 endmacro()
1178
1179 #-----------------------------------------------------------------------
1180 #.rst:
1181 # .. cmake:command:: __geant4_category_validate_property
1182 #
1183 # .. code-block:: cmake
1184 #
1185 # __geant4_category_validate_property(<property>)
1186 #
1187 # Emit a ``FATAL_ERROR`` if the ``<property>`` is not one of the valid
1188 # properties for a category.
1189 #
1190 # This is used internally by the property get/set functions.
1191 #
1192 function(__geant4_category_validate_property _property)
1193 if(NOT (${_property} MATCHES "CMAKE_LIST_FILE|IS_INTERFACE|MODULES|PUBLIC_HEADERS"))
1194 message(FATAL_ERROR "Undefined property '${_property}'")
1195 endif()
1196 endfunction()
1197
1198
1199 #-----------------------------------------------------------------------
1200 #.rst:
1201 # .. cmake:command:: __geant4_category_reset
1202 #
1203 # .. code-block:: cmake
1204 #
1205 # __geant4_category_reset()
1206 #
1207 # Reset all existing categories to allow redefinition.
1208 #
1209 function(__geant4_category_reset)
1210 # Reset parent targets of modules to allow recomposition
1211 geant4_get_modules(__all_modules)
1212 foreach(__mod ${__all_modules})
1213 geant4_set_module_property(${__mod} PROPERTY PARENT_TARGET)
1214 endforeach()
1215
1216 # Reset category properties, then categories
1217 geant4_get_categories(__all_categories)
1218 foreach(__cat ${__all_categories})
1219 foreach(_prop CMAKE_LIST_FILE IS_INTERFACE MODULES PUBLIC_HEADERS)
1220 geant4_set_category_property(${__cat} PROPERTY ${_prop})
1221 endforeach()
1222 endforeach()
1223 set_property(GLOBAL PROPERTY GEANT4_DEFINED_CATEGORIES)
1224 endfunction()
1225
1226 #-----------------------------------------------------------------------
1227 #-----------------------------------------------------------------------
1228 # Library Build functions
1229 #
1230 # Resolve a list of links
1231 # These may include Geant4 modules as well as standard targets or other expressions
1232 # Resolve Modules to PARENT_TARGET, removing duplicates
1233 # Leave other links unchanged
1234 function(__geant4_resolve_link_libraries _list)
1235 set(_resolved_list )
1236 foreach(__lib ${${_list}})
1237 # If "library" is a module, resolve it to PARENT_TARGET
1238 geant4_has_module(__is_module ${__lib})
1239 if(__is_module)
1240 geant4_get_module_property(__parent_lib ${__lib} PARENT_TARGET)
1241 if(NOT __parent_lib)
1242 message(FATAL_ERROR "Module '${__lib}' has no PARENT_TARGET set")
1243 endif()
1244 list(APPEND _resolved_list ${__parent_lib})
1245 else()
1246 list(APPEND _resolved_list ${__lib})
1247 endif()
1248 endforeach()
1249 if(_resolved_list)
1250 list(REMOVE_DUPLICATES _resolved_list)
1251 endif()
1252 set(${_list} ${_resolved_list} PARENT_SCOPE)
1253 endfunction()
1254
1255 #-----------------------------------------------------------------------
1256 #.rst:
1257 # .. cmake:command:: __geant4_add_library
1258 #
1259 # .. code-block:: cmake
1260 #
1261 # __geant4_add_library(<libraryname> <mode>)
1262 #
1263 # Declare an actual CMake library target of type ``<mode>`` from a category
1264 # ``<libraryname>``. The category must have been declared previously, and
1265 # ``<mode>`` must be ``SHARED`` or ``STATIC``.
1266
1267 # In the special case that the category is header-only, ``<mode>`` is only
1268 # used to determine the name of the created target: ``<libraryname>`` for
1269 # ``SHARED``, and ``<libraryname>-static`` otherwise. This ensures consistent
1270 # link chains of only shared or only static Geant4 libraries.
1271 #
1272 # This function is used internally by the ``geant4_compose_targets`` command
1273 # and should not be called directly in developer build scripts.
1274 #
1275 function(__geant4_add_library _name _type)
1276 if(NOT (${_type} MATCHES "SHARED|STATIC"))
1277 message(FATAL_ERROR "Invalid library type '${_type}'")
1278 endif()
1279
1280 # Check if the overall library is binary or header-only
1281 set(_lib_cmake_type ${_type})
1282 geant4_get_category_property(_lib_is_interface ${_name} IS_INTERFACE)
1283 if(_lib_is_interface)
1284 set(_lib_cmake_type "INTERFACE")
1285 endif()
1286
1287 set(_target_name ${_name})
1288 if(_type STREQUAL "STATIC")
1289 set(_target_name ${_name}-static)
1290 endif()
1291
1292 # - General target creation/properties
1293 add_library(${_target_name} ${_lib_cmake_type} "")
1294 # Alias for transparent use with imported targets
1295 add_library(Geant4::${_target_name} ALIAS ${_target_name})
1296
1297 if(_lib_cmake_type STREQUAL "INTERFACE")
1298 target_compile_features(${_target_name} INTERFACE ${GEANT4_TARGET_COMPILE_FEATURES})
1299 set(_props_to_process "INTERFACE")
1300 else()
1301 target_compile_features(${_target_name} PUBLIC ${GEANT4_TARGET_COMPILE_FEATURES})
1302 set(_props_to_process "PUBLIC" "PRIVATE" "INTERFACE")
1303 set(_promote_interface_to_public TRUE)
1304 endif()
1305
1306 if(_lib_cmake_type STREQUAL "SHARED")
1307 # G4LIB_BUILD_DLL is public as despite the name it indicates the shared/archive mode
1308 # and clients must apply it when linking to the shared libs. The global
1309 # category handles the exact import/export statements
1310 target_compile_definitions(${_target_name} PUBLIC G4LIB_BUILD_DLL)
1311 set_target_properties(${_target_name} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
1312
1313 # MacOS
1314 # Use '@rpath' in install names of libraries on macOS to provide relocatibility
1315 # Add '@loader_path' to INSTALL_RPATH on macOS so that Geant4
1316 # libraries self-locate each other whilst remaining relocatable
1317 set_target_properties(${_target_name} PROPERTIES MACOSX_RPATH 1)
1318 if(APPLE)
1319 set_property(TARGET ${_target_name} APPEND PROPERTY INSTALL_RPATH "@loader_path")
1320 endif()
1321 endif()
1322
1323 if((_lib_cmake_type STREQUAL "STATIC") AND NOT WIN32)
1324 set_target_properties(${_target_name} PROPERTIES OUTPUT_NAME ${_name})
1325 endif()
1326
1327 # Get Modules to build into library, and list of defined interna/external libraries to resolve/link against
1328 geant4_get_categories(__g4definedlibraries)
1329 geant4_get_external_categories(__g4externallibraries)
1330 list(APPEND __g4definedlibraries ${__g4externallibraries})
1331 geant4_get_category_property(__g4modules ${_name} MODULES)
1332 foreach(__g4mod ${__g4modules})
1333 # - Process sources...
1334 geant4_get_module_property(_headers ${__g4mod} PUBLIC_HEADERS)
1335 geant4_get_module_property(_headers_private ${__g4mod} PRIVATE_HEADERS)
1336 geant4_get_module_property(_srcs ${__g4mod} SOURCES)
1337 geant4_get_module_property(_cmakescript ${__g4mod} CMAKE_LIST_FILE)
1338 get_filename_component(_moddir "${_cmakescript}" DIRECTORY)
1339
1340 # - Group sources and scripts for IDEs
1341 # NB: Seemingly has to be done at same level we define target.
1342 # TODO: If lib name is same as mod name, don't group avoid extra
1343 # folder layer.
1344 source_group(${__g4mod}\\Headers FILES ${_headers} ${_headers_private})
1345 source_group(${__g4mod}\\Sources FILES ${_srcs})
1346 source_group(${__g4mod} FILES ${_cmakescript})
1347
1348 # - Add sources to target - PRIVATE, because consuming targets don't need them
1349 target_sources(${_target_name} PRIVATE ${_headers} ${_headers_private} ${_srcs} ${_cmakescript})
1350
1351 # - Process usage properties
1352 # Include dirs, compile definitions and libraries can be handled together
1353 # Important to note that these promote PUBLIC/PRIVATE/INTERFACE
1354 # from module level to library level. I.e. other modules in the
1355 # library can see each other's PRIVATE include paths/compile defs.
1356 # The only known way to fully wall things off is OBJECT libs,
1357 # but then run into issues mentioned at start - linking and
1358 # use in IDEs (though newer CMake versions should resolve these)
1359 # This "promotion" is probably correct though - interfaces are
1360 # at physical library level rather than module, and in Geant4
1361 # all files must have globally unique names (no nested headers
1362 # nor namespaces). Also, DLL export symbols may need this
1363 # behaviour (esp. ALLOC_EXPORT).
1364 # Only really an issue if header names/definitions aren't
1365 # globally (in Geant4) unique. Or if a module is moved and hasn't
1366 # declared its deps correctly (but then an error will occur
1367 # anyway, and point is that libs are linked, not modules!)
1368 # "Module" level really means "Source file" level, so same
1369 # sets of rules should apply.
1370 # Can use set_source_files_properties for module-level PRIVATE_HEADERS,
1371 # but that's it
1372 set_property(SOURCE ${_srcs} APPEND PROPERTY INCLUDE_DIRECTORIES "${_moddir}/include/private")
1373
1374 foreach(_prop ${_props_to_process})
1375 # Further gotcha with INTERFACE modules here
1376 # - If an interface module is composed into a non-interface module
1377 # its headers are exposed correctly to *clients* of the library, but
1378 # *not* the internals of the library! This being the case, we promote
1379 # these properties to PUBLIC
1380 set(_target_prop ${_prop})
1381 if(_promote_interface_to_public AND (_prop STREQUAL "INTERFACE"))
1382 set(_target_prop "PUBLIC")
1383 endif()
1384
1385 geant4_get_module_property(_incdirs ${__g4mod} ${_prop}_INCLUDE_DIRECTORIES)
1386 target_include_directories(${_target_name} ${_target_prop} ${_incdirs})
1387
1388 geant4_get_module_property(_defs ${__g4mod} ${_prop}_COMPILE_DEFINITIONS)
1389 target_compile_definitions(${_target_name} ${_target_prop} ${_defs})
1390
1391 # Target linking requires additional processing to resolve
1392 geant4_get_module_property(_linklibs ${__g4mod} ${_prop}_LINK_LIBRARIES)
1393 __geant4_resolve_link_libraries(_linklibs)
1394 if(_linklibs)
1395 # Remove self-linking
1396 list(REMOVE_ITEM _linklibs ${_name})
1397
1398 # Filter list for internal static targets
1399 if(_lib_cmake_type STREQUAL "STATIC")
1400 set(_g4linklibs )
1401 foreach(_linklib ${_linklibs})
1402 # If the linklib is a G4Library, change name to "name-static"
1403 list(FIND __g4definedlibraries ${_linklib} _isg4lib)
1404 if(_isg4lib GREATER -1)
1405 list(APPEND _g4linklibs "${_linklib}-static")
1406 else()
1407 list(APPEND _g4linklibs "${_linklib}")
1408 endif()
1409 endforeach()
1410 set(_linklibs ${_g4linklibs})
1411 endif()
1412
1413 target_link_libraries(${_target_name} ${_target_prop} ${_linklibs})
1414 endif()
1415 endforeach()
1416
1417 # Apply any additional properties supported in modules to target
1418 if(GEANT4_USE_QT)
1419 geant4_get_module_property(_needs_moc ${__g4mod} AUTOMOC)
1420 if(_needs_moc)
1421 set_target_properties(${_target_name} PROPERTIES AUTOMOC ON)
1422 endif()
1423 endif()
1424 endforeach()
1425
1426 # - Postprocess target properties to remove duplicates
1427 # NB: This makes the assumption that there is no order dependence here (and any is considered a bug!)
1428 # CMake will handle static link ordering internally
1429 foreach(_link_prop IN ITEMS LINK_LIBRARIES INTERFACE_LINK_LIBRARIES INCLUDE_DIRECTORIES INTERFACE_INCLUDE_DIRECTORIES COMPILE_DEFINITIONS INTERFACE_COMPILE_DEFINITIONS)
1430 get_target_property(__g4lib_link_libs ${_target_name} ${_link_prop})
1431 if(__g4lib_link_libs)
1432 list(SORT __g4lib_link_libs)
1433 list(REMOVE_DUPLICATES __g4lib_link_libs)
1434 set_property(TARGET ${_target_name} PROPERTY ${_link_prop} ${__g4lib_link_libs})
1435 endif()
1436 endforeach()
1437 endfunction()