Back to home page

EIC code displayed by LXR

 
 

    


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> [INTERFACE] [MODULES <module> [<module> ...]])
0501 #
0502 #   Add a Geant4 category ``<name>`` to the project. It can be composed from modules
0503 #   supplied in the ``MODULES`` list, or the ``INTERFACE`` option can be used
0504 #   to create an alias to one or more other categories.
0505 #
0506 #   Calling this function does not create an actual CMake library target.
0507 #   Because modules declare dependencies on modules rather than libraries, we
0508 #   defer creation of library targets to after creation of categories, which
0509 #   allows resolution of module <-> category use. Additionally, category specific
0510 #   actions such as install may be added.
0511 #
0512 function(geant4_add_category _name)
0513   __geant4_category_assert_not_exists(${_name})
0514   set_property(GLOBAL APPEND PROPERTY GEANT4_DEFINED_CATEGORIES ${_name})
0515   cmake_parse_arguments(G4ADDCAT
0516     ""
0517     ""
0518     "INTERFACE;MODULES"
0519     ${ARGN}
0520     )
0521   # INTERFACE/MODULES are mutually exclusive
0522   if(G4ADDCAT_INTERFACE AND G4ADDCAT_MODULES)
0523     message(FATAL_ERROR "geant4_add_category: INTERFACE and MODULES arguments are mutually exclusive")
0524   endif()
0525   # They must have value(s) supplied
0526   if(G4ADDCAT_KEYWORDS_MISSING_VALUES MATCHES "INTERFACE")
0527     message(FATAL_ERROR "geant4_add_category: Empty 'INTERFACE' argument")
0528   endif()
0529   if(G4ADDCAT_KEYWORDS_MISSING_VALUES MATCHES "MODULES")
0530     message(FATAL_ERROR "geant4_add_category: Empty 'MODULES' argument")
0531   endif()
0532 
0533   # - Have an ALIAS based category
0534   if(G4ADDCAT_INTERFACE)
0535     geant4_set_category_property(${_name} PROPERTY IS_ALIAS TRUE)
0536     geant4_category_interfaces(${_name} ${G4ADDCAT_INTERFACE})
0537     return()
0538   endif()
0539 
0540   # - Otherwise, must be a MODULE based category
0541   # Default to an interface module, geant4_category_modules will update this if needed
0542   geant4_set_category_property(${_name} PROPERTY IS_INTERFACE TRUE)
0543 
0544   # Compose Category from Modules
0545   geant4_category_modules(${_name} ${G4ADDCAT_MODULES})
0546 
0547   # As we do not create a physical target, store the script in which we're called
0548   geant4_set_category_property(${_name} PROPERTY CMAKE_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}")
0549 endfunction()
0550 
0551 #-----------------------------------------------------------------------
0552 #.rst:
0553 # .. cmake:command:: geant4_category_is_alias
0554 #
0555 #   .. code-block:: cmake
0556 #
0557 #     geant4_category_is_alias(<category> <outputvar>)
0558 #
0559 #   Set ``outputvar`` to ``TRUE`` if ``<category>`` is an alias to one or
0560 #   more others.
0561 #
0562 function(geant4_category_is_alias _outvar _name)
0563   __geant4_category_assert_exists(${_name})
0564   geant4_get_category_property(_result ${_name} IS_ALIAS)
0565   set(${_outvar} ${_result} PARENT_SCOPE)
0566 endfunction()
0567 
0568 #-----------------------------------------------------------------------
0569 #.rst:
0570 # .. cmake:command:: geant4_category_modules
0571 #
0572 #   .. code-block:: cmake
0573 #
0574 #     geant4_category_modules(<category> <module> [<module> ...])
0575 #
0576 #   Add modules to  category ``<category>``
0577 #
0578 function(geant4_category_modules _name)
0579   __geant4_category_assert_exists(${_name})
0580   geant4_category_is_alias(check ${_name})
0581   if(check)
0582     message(FATAL_ERROR "geant4_category_modules: Trying to add modules to ALIAS-type category '${_name}'")
0583   endif()
0584 
0585   # ARGN must not be empty
0586   if(NOT ARGN)
0587     message(FATAL_ERROR "no modules given to add to to category '${_name}'")
0588   endif()
0589 
0590   # Need to track if any added module has source files. If so, must set IS_INTERFACE to false
0591   # Compose Category from Modules, accounting for potential interface-only composition
0592   geant4_get_category_property(__cat_is_interface ${_name} IS_INTERFACE)
0593   foreach(__g4module ${ARGN})
0594     # Module must not have been composed already (Might want to mark special case where module added twice into same category)
0595     geant4_get_module_property(_parent ${__g4module} PARENT_TARGET)
0596     if(_parent)
0597       message(FATAL_ERROR "trying to compose category '${_name}' using module '${__g4module}' which is already composed into category '${_parent}'")
0598     endif()
0599 
0600     # Compose it
0601     geant4_set_module_property(${__g4module} PROPERTY PARENT_TARGET ${_name})
0602     geant4_set_category_property(${_name} APPEND PROPERTY MODULES ${__g4module})
0603 
0604     geant4_get_module_property(_headers ${__g4module} PUBLIC_HEADERS)
0605     geant4_set_category_property(${_name} APPEND PROPERTY PUBLIC_HEADERS ${_headers})
0606 
0607     # Is this module interface only?
0608     geant4_get_module_property(_is_interface ${__g4module} IS_INTERFACE)
0609     if(NOT _is_interface)
0610       set(__cat_is_interface FALSE)
0611     endif()
0612   endforeach()
0613   geant4_set_category_property(${_name} PROPERTY IS_INTERFACE ${__cat_is_interface}) 
0614 endfunction()
0615 
0616 #-----------------------------------------------------------------------
0617 #.rst:
0618 # .. cmake:command:: geant4_category_interfaces
0619 #
0620 #   .. code-block:: cmake
0621 #
0622 #     geant4_category_interfaces(<category> <cat> [<mat> ...]))
0623 #
0624 #   Add categories to alias category ``<category>``
0625 #
0626 function(geant4_category_interfaces _name)
0627   __geant4_category_assert_exists(${_name})
0628   geant4_category_is_alias(check ${_name})
0629   if(NOT check)
0630     message(FATAL_ERROR "geant4_category_interfaces: Trying to add categories to non-ALIAS category '${_name}'")
0631   endif()
0632 
0633   # ARGN must not be empty
0634   if(NOT ARGN)
0635     message(FATAL_ERROR "no categories given to add to to category '${_name}'")
0636   endif()
0637 
0638   foreach(iface ${ARGN})
0639     __geant4_category_assert_exists(${iface})
0640     geant4_set_category_property(${_name} APPEND PROPERTY CATEGORIES ${iface})
0641   endforeach()
0642 endfunction()
0643 
0644 #-----------------------------------------------------------------------
0645 #.rst:
0646 # .. cmake:command:: geant4_get_categories
0647 #
0648 #   .. code-block:: cmake
0649 #
0650 #     geant4_get_categories(<result>)
0651 #
0652 #   Store the list of currently defined categories in the variable ``<result>``.
0653 #
0654 function(geant4_get_categories _result)
0655   get_property(__tmp GLOBAL PROPERTY GEANT4_DEFINED_CATEGORIES)
0656   set(${_result} ${__tmp} PARENT_SCOPE)
0657 endfunction()
0658 
0659 #-----------------------------------------------------------------------
0660 #.rst:
0661 # .. cmake:command:: geant4_has_category
0662 #
0663 #   .. code-block:: cmake
0664 #
0665 #     geant4_has_category(<result> <name>)
0666 #
0667 #   Set variable ``<result>`` to a boolean which will be true if the category
0668 #   ``<name>`` is defined.
0669 #
0670 function(geant4_has_category _result _name)
0671   set(__exists FALSE)
0672 
0673   geant4_get_categories(__tmp)
0674   if(__tmp)
0675     list(FIND __tmp ${_name} __index)
0676     if(__index GREATER -1)
0677       set(__exists TRUE)
0678     endif()
0679   endif()
0680 
0681   set(${_result} ${__exists} PARENT_SCOPE)
0682 endfunction()
0683 
0684 #-----------------------------------------------------------------------
0685 #.rst:
0686 # Category Properties
0687 # ===================
0688 #
0689 # A Geant4 category stores its build and usage requirements in a series
0690 # of properties:
0691 #
0692 # * ``CMAKE_LIST_FILE``
0693 # * ``IS_INTERFACE``
0694 # * ``MODULES``
0695 # * ``PUBLIC_HEADERS``
0696 # * ``IS_ALIAS``
0697 # * ``CATEGORIES``
0698 #
0699 # The properties of a category may be queried and set using the following
0700 # commands.
0701 #
0702 
0703 #-----------------------------------------------------------------------
0704 #.rst:
0705 # .. cmake:command:: geant4_get_category_property
0706 #
0707 #   .. code-block:: cmake
0708 #
0709 #     geant4_get_category_property(<result> <category> <property>)
0710 #
0711 #   Store value of property ``<property>`` for ``<module>`` in variable
0712 #   ``<result>``.
0713 #
0714 #   If ``<property>`` is not a valid module property, a FATAL_ERROR is
0715 #   emitted.
0716 #
0717 function(geant4_get_category_property _output _category _propertyname)
0718   __geant4_category_assert_exists(${_category})
0719   __geant4_category_validate_property(${_propertyname})
0720   get_property(__result GLOBAL PROPERTY GEANT4_CATEGORY_${_category}_${_propertyname})
0721   set(${_output} ${__result} PARENT_SCOPE)
0722 endfunction()
0723 
0724 #-----------------------------------------------------------------------
0725 #.rst:
0726 # .. cmake:command:: geant4_set_category_property
0727 #
0728 #   .. code-block:: cmake
0729 #
0730 #     geant4_set_category_property(<module>
0731 #                                  [APPEND | APPEND_STRING]
0732 #                                  PROPERTY <property> <value>)
0733 #
0734 #   Set property ``<property>`` of category ``<category>`` to ``<value>``.
0735 #
0736 #   If ``APPEND`` is supplied, ``<value>`` will be appended to any existing
0737 #   value for the property as a list.
0738 #
0739 #   If ``APPEND_STRING`` is supplied, ``<value>`` will be appended to any existing
0740 #   value for the property as a string. This option is mutually exclusive with
0741 #   ``APPEND``.
0742 #
0743 #   If ``<property>`` is not a valid category property, a FATAL_ERROR is
0744 #   emitted.
0745 #
0746 function(geant4_set_category_property _category)
0747   __geant4_category_assert_exists(${_category})
0748   cmake_parse_arguments(G4CMP
0749     "APPEND;APPEND_STRING"
0750     ""
0751     "PROPERTY"
0752     ${ARGN}
0753     )
0754   __geant4_assert_no_unparsed_arguments(G4CMP geant4_set_category_property)
0755 
0756 
0757   # Append/Append_string are mutually exclusive
0758   if(G4CMP_APPEND AND G4CMP_APPEND_STRING)
0759     message(FATAL_ERROR "geant4_set_category_property: cannot set both APPEND and APPEND_STRING")
0760   elseif(G4CMP_APPEND)
0761     set(G4CMP_APPEND_MODE "APPEND")
0762   elseif(G4CMP_APPEND_MODE)
0763     set(G4CMP_APPEND_MODE "APPEND_STRING")
0764   endif()
0765 
0766   # First element of PROPERTY list is prop name
0767   list(GET G4CMP_PROPERTY 0 G4CMP_PROPERTY_NAME)
0768   if(NOT G4CMP_PROPERTY_NAME)
0769     message(FATAL_ERROR "geant4_set_category_property: Required PROPERTY argument is missing")
0770   endif()
0771 
0772   __geant4_category_validate_property(${G4CMP_PROPERTY_NAME})
0773   # Remainder is arguments, so strip first element
0774   list(REMOVE_AT G4CMP_PROPERTY 0)
0775 
0776   set_property(GLOBAL ${G4CMP_APPEND_MODE} PROPERTY GEANT4_CATEGORY_${_category}_${G4CMP_PROPERTY_NAME} ${G4CMP_PROPERTY})
0777 endfunction()
0778 
0779 
0780 #-----------------------------------------------------------------------
0781 #-----------------------------------------------------------------------
0782 #.rst:
0783 # External Library Commands
0784 # ^^^^^^^^^^^^^^^^^^^^^^^^^
0785 #
0786 # Geant4 provides internal copies of libraries that are required to build
0787 # the toolkit:
0788 #
0789 # - CLHEP
0790 # - PTL
0791 # - Expat
0792 # - ZLIB
0793 # - Tools
0794 #
0795 # Because these may have different build systems and source/header structures than
0796 # Geant4, the following commands help adapt their build and use to:
0797 #
0798 # - Provide shared and/or static library targets using the same settings as the
0799 #   toolkit libraries (for example, C++ Standard)
0800 # - Use of these targets as other Geant4 libraries to allow consistent full static/full
0801 #   shared linking
0802 #
0803 
0804 #-----------------------------------------------------------------------
0805 #.rst:
0806 # .. cmake:command:: geant4_add_external_library
0807 #
0808 #   .. code-block::
0809 #
0810 #     geant4_add_external_library(NAME <name>
0811 #                           SOURCES source1 [source2 ...])
0812 #
0813 # Maintained for building external targets because we try and reuse their 
0814 # upstream code/build layout as far as possible, but want to ensure the
0815 # targets are compiled in same way as toolkit libraries.
0816 #
0817 function(geant4_add_external_library)
0818   cmake_parse_arguments(G4GLOBLIB
0819     ""
0820     "NAME"
0821     "SOURCES"
0822     ${ARGN}
0823     )
0824   __geant4_assert_no_unparsed_arguments(G4GLOBLIB geant4_add_external_library)
0825 
0826   # Only supported for externals G4clhep/G4expat/G4zlib, so an error if used elsewhere
0827   if(NOT (${G4GLOBLIB_NAME} MATCHES "G4clhep|G4expat|G4zlib"))
0828     message(FATAL_ERROR "geant4_add_external_library called for '${G4GLOBLIB_NAME}' in '${CMAKE_CURRENT_LIST_DIR}'")
0829   endif()
0830 
0831   if(BUILD_SHARED_LIBS)
0832     add_library(${G4GLOBLIB_NAME} SHARED ${G4GLOBLIB_SOURCES})
0833     add_library(Geant4::${G4GLOBLIB_NAME} ALIAS ${G4GLOBLIB_NAME})
0834     target_compile_features(${G4GLOBLIB_NAME} PUBLIC ${GEANT4_TARGET_COMPILE_FEATURES})
0835     target_compile_definitions(${G4GLOBLIB_NAME} PUBLIC G4LIB_BUILD_DLL)
0836     target_include_directories(${G4GLOBLIB_NAME}
0837       PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
0838     )
0839     set_target_properties(${G4GLOBLIB_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
0840 
0841     install(TARGETS ${G4GLOBLIB_NAME}
0842       EXPORT Geant4LibraryDepends
0843       RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime
0844       LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Runtime
0845       ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development
0846       INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
0847   endif()
0848 
0849   if(BUILD_STATIC_LIBS)
0850     add_library(${G4GLOBLIB_NAME}-static STATIC ${G4GLOBLIB_SOURCES})
0851     add_library(Geant4::${G4GLOBLIB_NAME}-static ALIAS ${G4GLOBLIB_NAME}-static)
0852     target_compile_features(${G4GLOBLIB_NAME}-static PUBLIC ${GEANT4_TARGET_COMPILE_FEATURES})
0853     target_include_directories(${G4GLOBLIB_NAME}-static
0854       PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
0855     )
0856 
0857     if(NOT WIN32)
0858       set_target_properties(${G4GLOBLIB_NAME}-static PROPERTIES OUTPUT_NAME ${G4GLOBLIB_NAME})
0859     endif()
0860 
0861     install(TARGETS ${G4GLOBLIB_NAME}-static
0862       EXPORT Geant4LibraryDepends
0863       RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime
0864       LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Runtime
0865       ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Development
0866       INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
0867   endif()
0868 
0869   # As with a standard library, always add the local include/ directory to exported list
0870   # for scripts
0871   set_property(GLOBAL APPEND PROPERTY GEANT4_BUILDTREE_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/include")
0872 
0873   # Needs to be in defined category list for static/shared to be linked correctly.
0874   geant4_add_external_category(${G4GLOBLIB_NAME})
0875 endfunction()
0876 
0877 #-----------------------------------------------------------------------
0878 #.rst:
0879 # .. cmake:command:: geant4_add_external_category
0880 #
0881 #   .. code-block:: cmake
0882 #
0883 #     geant4_add_external_category(<name>)
0884 #
0885 #   Mark ``<name>`` as a target that supports the Geant4 target naming
0886 #   convention of ``<name>`` as the shared library and ``<name>-static``
0887 #   as the static. It allows Geant4 modules to link to targets built
0888 #   outside the module/category system and retain consistent shared-shared
0889 #   or static-static linking chains.
0890 #
0891 #   If ``BUILD_SHARED_LIBS``(``BUILD_STATIC_LIBS``) is ``ON``, then ``<name>``(``<name>-static``) 
0892 #   must correspond to  a shared(static) library target that exists at
0893 #   the time this function is called.
0894 #
0895 function(geant4_add_external_category _name)
0896   # Targets must have been defined!
0897   if(BUILD_SHARED_LIBS AND (NOT TARGET ${_name}))
0898     message(FATAL_ERROR "geant4_add_external_category: no target '${_name}' has been declared")
0899   endif()
0900 
0901   if(BUILD_STATIC_LIBS AND (NOT TARGET ${_name}-static))
0902     message(FATAL_ERROR "geant4_add_external_category: no target '${_name}-static' has been declared")
0903   endif()
0904 
0905   set_property(GLOBAL APPEND PROPERTY GEANT4_EXTERNAL_CATEGORIES ${_name})
0906 endfunction()
0907 
0908 #-----------------------------------------------------------------------
0909 #.rst:
0910 # .. cmake:command:: geant4_get_external_categories
0911 #
0912 #   .. code-block:: cmake
0913 #
0914 #     geant4_get_external_categories(<result>)
0915 #
0916 #   Store the list of currently defined external_categories in the variable ``<result>``.
0917 #
0918 function(geant4_get_external_categories _result)
0919   get_property(__tmp GLOBAL PROPERTY GEANT4_EXTERNAL_CATEGORIES)
0920   set(${_result} ${__tmp} PARENT_SCOPE)
0921 endfunction()
0922 
0923 #-----------------------------------------------------------------------
0924 #-----------------------------------------------------------------------
0925 #.rst:
0926 # Test Program Commands
0927 # ^^^^^^^^^^^^^^^^^^^^^
0928 # .. cmake:command:: geant4_test_link_libraries
0929 #
0930 #  .. code-block:: cmake
0931 #
0932 #    geant4_test_link_libraries(<target>
0933 #                               [PUBLIC pub1 [pub2 ...]
0934 #                               [PRIVATE pri1 [pri2 ...]
0935 #                               [INTERFACE int1 [int2 ...])
0936 function(geant4_test_link_libraries _target)
0937   cmake_parse_arguments(G4TESTLINKLIB
0938     ""
0939     ""
0940     "PUBLIC;PRIVATE;INTERFACE"
0941     ${ARGN}
0942     )
0943   __geant4_assert_no_unparsed_arguments(G4TESTLINKLIB geant4_test_link_libraries)
0944 
0945   # Need defined libraries and externals to be able to resolve between static/shared
0946   get_property(__g4definedlibraries GLOBAL PROPERTY GEANT4_DEFINED_CATEGORIES) 
0947   geant4_get_external_categories(__g4externalcategories)
0948   list(APPEND __g4definedlibraries ${__g4externalcategories})
0949 
0950   foreach(__prop PUBLIC PRIVATE INTERFACE)
0951     __geant4_resolve_link_libraries(G4TESTLINKLIB_${__prop})
0952     if(G4TESTLINKLIB_${__prop})
0953       # Filter list for internal static targets
0954       # NB: This only works assuming that the input target is an executable
0955       # If we introduce test libraries, would need same treatment as for main libraries
0956       if(BUILD_STATIC_LIBS AND NOT BUILD_SHARED_LIBS)
0957         set(_g4linklibs )
0958         foreach(_linklib ${G4TESTLINKLIB_${__prop}})
0959           # If the linklib is a G4Library, change name to "name-static"
0960           list(FIND __g4definedlibraries ${_linklib} _isg4lib)
0961           if(_isg4lib GREATER -1)
0962             list(APPEND _g4linklibs "${_linklib}-static")
0963           else()
0964             list(APPEND _g4linklibs "${_linklib}")
0965           endif()
0966         endforeach()
0967         set(_linklibs ${_g4linklibs})
0968       else()
0969         set(_linklibs ${G4TESTLINKLIB_${__prop}})
0970       endif()
0971 
0972       target_link_libraries(${_target} ${__prop} ${_linklibs})
0973     endif()
0974   endforeach()
0975 endfunction()
0976 
0977 #-----------------------------------------------------------------------
0978 #-----------------------------------------------------------------------
0979 # Composition Functions
0980 #.rst:
0981 # .. cmake:command:: geant4_compose_targets
0982 #
0983 #   .. code-block:: cmake
0984 #
0985 #     geant4_compose_targets()
0986 #
0987 #   Create physical SHARED/STATIC library targets from the defined Geant4
0988 #   categories and modules.
0989 #
0990 #   Can only be called once, and must be done so after all Geant4 libraries
0991 #   and modules are defined.
0992 #
0993 function(geant4_compose_targets)
0994   get_property(__alreadyCalled GLOBAL PROPERTY GEANT4_COMPOSE_TARGETS_CALLED)
0995   if(__alreadyCalled)
0996     get_property(__callsite GLOBAL PROPERTY GEANT4_COMPOSE_TARGETS_LIST_FILE)
0997     message(FATAL_ERROR "geant4_compose_targets already called from ${__callsite}")
0998   endif()
0999 
1000   # Check that every defined module is composed
1001   geant4_get_modules(__g4definedmodules)
1002   foreach(__module ${__g4definedmodules})
1003     geant4_get_module_property(__iscomposed ${__module} PARENT_TARGET)
1004     if(NOT __iscomposed)
1005       message(FATAL_ERROR "Geant4 module '${__module}' is not composed into any category")
1006     endif()
1007   endforeach()
1008 
1009   # - For each module
1010   # 1. Write out files for
1011   # 1.1. module -> used modules adjacency list for detecting module-module cycles
1012   file(WRITE "${PROJECT_BINARY_DIR}/G4ModuleAdjacencyList.txt" "# Geant4 Module - Module Adjacencies\n")
1013   
1014   # 1.2. module,location,public headers for developer query operations
1015   # Basically need a dict of module : [headers, ...]
1016   # - Two main queries to run
1017   #   - Given a module, what public headers does it provide?
1018   #   - Given a header, what module provides this? 
1019   # Also want something to check a module
1020   # - Only really possible by parsing module headers (what it exposes publically)
1021   #   and sources (what it uses internally)
1022   # Probaly just needs module : location
1023   # - Checking of files is runtime operation, so will refind/check each time
1024   # - Store set of build settings relevant to filtering headers in dependency checks
1025   # - "Dumb" as simply reproduced as CMake list in last column of every row (de-dupped in script)
1026   # - Settings are designed to overcome limitation of ifdef in parsing, so map
1027   #   to symbols in code
1028   set(__gmc_build_settings )
1029   if(GEANT4_BUILD_MULTITHREADED)
1030     list(APPEND __gmc_build_settings "G4MULTITHREADED")
1031   endif()
1032   file(WRITE "${PROJECT_BINARY_DIR}/G4ModuleInterfaceMap.csv" "")
1033   configure_file("${PROJECT_SOURCE_DIR}/cmake/Modules/geant4_module_check.py" "${PROJECT_BINARY_DIR}/geant4_module_check.py" COPYONLY)
1034 
1035   # 2. Check it does not link to a composed library composed of N>1 modules
1036   get_property(__g4definedlibraries GLOBAL PROPERTY GEANT4_DEFINED_CATEGORIES)
1037   set(__g4disallowedlinks ${__g4definedlibraries})
1038   list(REMOVE_ITEM __g4disallowedlinks ${__g4definedmodules})
1039 
1040   foreach(__module ${__g4definedmodules})
1041     geant4_get_module_property(__publicdeps ${__module} PUBLIC_LINK_LIBRARIES)
1042     geant4_get_module_property(__privatedeps ${__module} PRIVATE_LINK_LIBRARIES)
1043     geant4_get_module_property(__interfacedeps ${__module} INTERFACE_LINK_LIBRARIES)
1044 
1045     # 1.1 Adjacency list - take all dependencies
1046     set(__alldeps_l ${__publicdeps} ${__privatedeps} ${__interfacedeps})
1047     list(JOIN __alldeps_l " " __alldeps)
1048     file(APPEND "${PROJECT_BINARY_DIR}/G4ModuleAdjacencyList.txt" "${__module} ${__alldeps}\n")
1049 
1050     # 1.2 Module interfaces, needs CMAKE, PUBLIC_HEADER
1051     geant4_get_module_property(__listfile ${__module} CMAKE_LIST_FILE)
1052     geant4_get_module_property(__publichdrs ${__module} PUBLIC_HEADERS)
1053     geant4_get_module_property(__privatehdrs ${__module} PRIVATE_HEADERS)
1054     geant4_get_module_property(__srcs ${__module} SOURCES)
1055     geant4_get_module_property(__parent_target ${__module} PARENT_TARGET)
1056     get_filename_component(__listdir "${__listfile}" DIRECTORY)
1057     # Remove generated headers
1058     list(TRANSFORM __publichdrs REPLACE "^${PROJECT_BINARY_DIR}/.*$" "")
1059     list(TRANSFORM __publichdrs REPLACE "^/.*/" "")
1060     list(TRANSFORM __privatehdrs REPLACE "^/.*/" "")
1061     list(TRANSFORM __srcs REPLACE "^/.*/" "")
1062     file(APPEND "${PROJECT_BINARY_DIR}/G4ModuleInterfaceMap.csv" "${__module},${__listdir},${__publichdrs},${__privatehdrs},${__srcs},${__publicdeps},${__privatedeps},${__interfacedeps},${__parent_target},${__gmc_build_settings}\n")
1063 
1064     # 2. Check for disallowed links in each link type
1065     foreach(__linktype IN ITEMS public private interface)
1066       foreach(__link ${__${__linktype}deps})
1067         if(__link IN_LIST __g4disallowedlinks)
1068           geant4_get_category_property(__linktothese ${__link} MODULES)
1069           string(REPLACE "${PROJECT_SOURCE_DIR}/" "" __badlistfile ${__listfile})
1070           message(FATAL_ERROR "Geant4 module '${__module}' has a ${__linktype} link to composed category '${__link}'."
1071           "It must link to one or more of its component modules instead:\n"
1072           "${__linktothese}\n"
1073           "in ${__badlistfile}\n")
1074         endif()
1075       endforeach()
1076     endforeach()
1077   endforeach()
1078 
1079   # Process all defined libraries
1080   set(__g4builtlibraries)
1081   set(__g4public_headers)
1082 
1083   foreach(__g4lib ${__g4definedlibraries})
1084     if(BUILD_SHARED_LIBS)
1085       __geant4_add_library(${__g4lib} SHARED)
1086       list(APPEND __g4builtlibraries ${__g4lib})
1087     endif()
1088 
1089     if(BUILD_STATIC_LIBS)
1090       __geant4_add_library(${__g4lib} STATIC)
1091       list(APPEND __g4builtlibraries ${__g4lib}-static)
1092     endif()
1093 
1094     geant4_get_category_property(__headers ${__g4lib} PUBLIC_HEADERS)
1095     list(APPEND __g4public_headers ${__headers})
1096   endforeach()
1097 
1098   #-----------------------------------------------------------------------
1099   # TEMP INSTALL - do here purely to review exported links. Should be
1100   # factored out into separate function later.
1101   install(TARGETS ${__g4builtlibraries}
1102     EXPORT Geant4LibraryDepends
1103     ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT Development
1104     LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT Runtime
1105     RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT Runtime
1106     INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}")
1107   install(FILES ${__g4public_headers} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}" COMPONENT Development)
1108 
1109   set_property(GLOBAL PROPERTY GEANT4_COMPOSE_TARGETS_CALLED ON)
1110   set_property(GLOBAL PROPERTY GEANT4_COMPOSE_TARGETS_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}")
1111 endfunction()
1112 
1113 #-----------------------------------------------------------------------
1114 #-----------------------------------------------------------------------
1115 #.rst:
1116 # Internal Helper Commands
1117 # ^^^^^^^^^^^^^^^^^^^^^^^^
1118 #
1119 # These macros and functions are for use in the implementation of the
1120 # module and library functions. They should never be used directly
1121 # in developer-level scripts.
1122 
1123 #-----------------------------------------------------------------------
1124 #.rst:
1125 # .. cmake:command:: __geant4_assert_no_unparsed_arguments
1126 #
1127 #  .. code-block:: cmake
1128 #
1129 #    __geant4_assert_no_unparsed_arguments(<prefix> <function>)
1130 #
1131 #  Emit a ``FATAL_ERROR`` if ``<prefix>_UNPARSED_ARGUMENTS`` is non-empty
1132 #  in ``<function>``
1133 #
1134 #  This is a macro intended for use in G4DeveloperAPI functions that cannot
1135 #  have unparsed arguments to validate their input.
1136 #
1137 #  From CMake 3.17, the ``<function>`` argument is no longer required and
1138 #  ``CMAKE_CURRENT_FUNCTION`` can be used
1139 #
1140 macro(__geant4_assert_no_unparsed_arguments _prefix _function)
1141   if(${_prefix}_UNPARSED_ARGUMENTS)
1142     message(FATAL_ERROR "${_function} called with unparsed arguments: '${${_prefix}_UNPARSED_ARGUMENTS}'")
1143   endif()
1144 endmacro()
1145 
1146 #-----------------------------------------------------------------------
1147 #.rst:
1148 # .. cmake:command:: __geant4_module_assert_exists
1149 #
1150 #  .. code-block:: cmake
1151 #
1152 #    __geant4_module_assert_exists(<name>)
1153 #
1154 #  Emit a ``FATAL_ERROR`` if the module ``<name>`` is not defined.
1155 #
1156 #  This is a macro intended for use in G4DeveloperAPI functions when
1157 #  the existence of a module is required for further processing
1158 #
1159 macro(__geant4_module_assert_exists _module)
1160   geant4_has_module(__geant4_module_assert_exists_tmp ${_module})
1161   if(NOT __geant4_module_assert_exists_tmp)
1162     message(FATAL_ERROR "Geant4 module '${_module}' has not been created")
1163   endif()
1164 endmacro()
1165 
1166 #-----------------------------------------------------------------------
1167 #.rst:
1168 # .. cmake:command:: __geant4_module_assert_not_exists
1169 #
1170 #  .. code-block:: cmake
1171 #
1172 #    __geant4_module_assert_not_exists(<name>)
1173 #
1174 #  Emit a ``FATAL_ERROR`` if the module ``<name>`` is defined
1175 #
1176 #  This is a macro intended for use in G4DeveloperAPI functions when
1177 #  the non-existence of a module is required for further processing
1178 #
1179 macro(__geant4_module_assert_not_exists _module)
1180   geant4_has_module(__geant4_module_assert_not_exists_tmp ${_module})
1181   if(__geant4_module_assert_not_exists_tmp)
1182     geant4_get_module_property(__previous_cmake_list ${_module} CMAKE_LIST_FILE)
1183     message(FATAL_ERROR "Geant4 module '${_module}' has already been created by call in '${__previous_cmake_list}'")
1184   endif()
1185 endmacro()
1186 
1187 #-----------------------------------------------------------------------
1188 #.rst:
1189 # .. cmake:command:: __geant4_module_validate_property
1190 #
1191 #  .. code-block:: cmake
1192 #
1193 #    __geant4_module_validate_property(<property>)
1194 #
1195 #  Emit a ``FATAL_ERROR`` if the ``<property>`` is not one of the valid
1196 #  properties for a module:
1197 #
1198 #  This is used internally by the property get/set functions.
1199 #
1200 function(__geant4_module_validate_property _property)
1201   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"))
1202     message(FATAL_ERROR "Undefined property '${_property}'")
1203   endif()
1204 endfunction()
1205 
1206 #-----------------------------------------------------------------------
1207 #.rst:
1208 # .. cmake:command:: __geant4_category_assert_exists
1209 #
1210 #  .. code-block:: cmake
1211 #
1212 #    __geant4_category_assert_exists(<name>)
1213 #
1214 #  Emit a ``FATAL_ERROR`` if the category ``<name>`` is not defined.
1215 #
1216 #  This is a macro intended for use in G4DeveloperAPI functions when
1217 #  the existence of a category is required for further processing
1218 #
1219 macro(__geant4_category_assert_exists _category)
1220   geant4_has_category(__geant4_category_assert_exists_tmp ${_category})
1221   if(NOT __geant4_category_assert_exists_tmp)
1222     message(FATAL_ERROR "Geant4 category '${_category}' has not been created")
1223   endif()
1224 endmacro()
1225 
1226 #-----------------------------------------------------------------------
1227 #.rst:
1228 # .. cmake:command:: __geant4_category_assert_not_exists
1229 #
1230 #  .. code-block:: cmake
1231 #
1232 #    __geant4_module_category_not_exists(<name>)
1233 #
1234 #  Emit a ``FATAL_ERROR`` if the category ``<name>`` is defined
1235 #
1236 #  This is a macro intended for use in G4DeveloperAPI functions when
1237 #  the non-existence of a category is required for further processing
1238 #
1239 macro(__geant4_category_assert_not_exists _category)
1240   geant4_has_category(__geant4_category_assert_not_exists_tmp ${_category})
1241   if(__geant4_category_assert_not_exists_tmp)
1242     geant4_get_category_property(__previous_cmake_list ${_category} CMAKE_LIST_FILE)
1243     message(FATAL_ERROR "Geant4 category '${_category}' has already been created by call in '${__previous_cmake_list}'")
1244   endif()
1245 endmacro()
1246 
1247 #-----------------------------------------------------------------------
1248 #.rst:
1249 # .. cmake:command:: __geant4_category_validate_property
1250 #
1251 #  .. code-block:: cmake
1252 #
1253 #    __geant4_category_validate_property(<property>)
1254 #
1255 #  Emit a ``FATAL_ERROR`` if the ``<property>`` is not one of the valid
1256 #  properties for a category.
1257 #
1258 #  This is used internally by the property get/set functions.
1259 #
1260 function(__geant4_category_validate_property _property)
1261   if(NOT (${_property} MATCHES "CMAKE_LIST_FILE|IS_INTERFACE|MODULES|PUBLIC_HEADERS|DEFINE_SYMBOL|IS_ALIAS|CATEGORIES"))
1262     message(FATAL_ERROR "Undefined property '${_property}'")
1263   endif()
1264 endfunction()
1265 
1266 
1267 #-----------------------------------------------------------------------
1268 #.rst:
1269 # .. cmake:command:: __geant4_category_reset
1270 #
1271 #  .. code-block:: cmake
1272 #
1273 #    __geant4_category_reset()
1274 #
1275 #  Reset all existing categories to allow redefinition.
1276 #
1277 function(__geant4_category_reset)
1278   # Reset parent targets of modules to allow recomposition
1279   geant4_get_modules(__all_modules)
1280   foreach(__mod ${__all_modules})
1281     geant4_set_module_property(${__mod} PROPERTY PARENT_TARGET)
1282   endforeach()
1283 
1284   # Reset category properties, then categories
1285   geant4_get_categories(__all_categories)
1286   foreach(__cat ${__all_categories})
1287     foreach(_prop CMAKE_LIST_FILE IS_INTERFACE MODULES PUBLIC_HEADERS DEFINE_SYMBOL IS_ALIAS CATEGORIES)
1288       geant4_set_category_property(${__cat} PROPERTY ${_prop})
1289     endforeach()
1290   endforeach()
1291   set_property(GLOBAL PROPERTY GEANT4_DEFINED_CATEGORIES)
1292 endfunction()
1293 
1294 #-----------------------------------------------------------------------
1295 #-----------------------------------------------------------------------
1296 # Library Build functions
1297 #
1298 # Resolve a list of links
1299 # These may include Geant4 modules as well as standard targets or other expressions
1300 # Resolve Modules to PARENT_TARGET, removing duplicates
1301 # Leave other links unchanged
1302 function(__geant4_resolve_link_libraries _list)
1303   set(_resolved_list )
1304   foreach(__lib ${${_list}})
1305     # If "library" is a module, resolve it to PARENT_TARGET
1306     geant4_has_module(__is_module ${__lib})
1307     if(__is_module)
1308       geant4_get_module_property(__parent_lib ${__lib} PARENT_TARGET)
1309       if(NOT __parent_lib)
1310         message(FATAL_ERROR "Module '${__lib}' has no PARENT_TARGET set")
1311       endif()
1312       list(APPEND _resolved_list ${__parent_lib})
1313     else()
1314       list(APPEND _resolved_list ${__lib})
1315     endif()
1316   endforeach()
1317   if(_resolved_list)
1318     list(REMOVE_DUPLICATES _resolved_list)
1319   endif()
1320   set(${_list} ${_resolved_list} PARENT_SCOPE)
1321 endfunction()
1322 
1323 #-----------------------------------------------------------------------
1324 #.rst:
1325 # .. cmake:command:: __geant4_add_library
1326 #
1327 #  .. code-block:: cmake
1328 #
1329 #    __geant4_add_library(<libraryname> <mode>)
1330 #
1331 #  Declare an actual CMake library target of type ``<mode>`` from a category 
1332 #  ``<libraryname>``. The category must have been declared previously, and
1333 #  ``<mode>`` must be ``SHARED`` or ``STATIC``. 
1334 
1335 #  In the special case that the category is header-only, ``<mode>`` is only 
1336 #  used to determine the name of the created target: ``<libraryname>`` for 
1337 #  ``SHARED``, and ``<libraryname>-static`` otherwise. This ensures consistent
1338 #  link chains of only shared or only static Geant4 libraries.
1339 #
1340 #  This function is used internally by the ``geant4_compose_targets`` command
1341 #  and should not be called directly in developer build scripts.
1342 #
1343 function(__geant4_add_library _name _type)
1344   if(NOT (${_type} MATCHES "SHARED|STATIC"))
1345     message(FATAL_ERROR "Invalid library type '${_type}'")
1346   endif()
1347 
1348   # Check if the overall library is binary, header-only, or an alias (really an interface in CMake terms)
1349   set(_lib_cmake_type ${_type})
1350   geant4_get_category_property(_lib_is_interface ${_name} IS_INTERFACE)
1351   geant4_get_category_property(_lib_is_alias ${_name} IS_ALIAS)
1352   if(_lib_is_interface OR _lib_is_alias)
1353     set(_lib_cmake_type "INTERFACE")
1354   endif()
1355 
1356   set(_target_name ${_name})
1357   if(_type STREQUAL "STATIC")
1358     set(_target_name ${_name}-static)
1359   endif()
1360 
1361   # - General target creation/properties
1362   # Conditional on INTERFACE as CMake < 3.19 cannot create interface lib with sources
1363   if(_lib_cmake_type STREQUAL "INTERFACE")
1364     add_library(${_target_name} ${_lib_cmake_type})
1365   else()
1366     add_library(${_target_name} ${_lib_cmake_type} "")
1367   endif()
1368   # Alias for transparent use with imported targets
1369   add_library(Geant4::${_target_name} ALIAS ${_target_name})
1370 
1371   # - Determine what properties to process
1372   if(_lib_cmake_type STREQUAL "INTERFACE")
1373     target_compile_features(${_target_name} INTERFACE ${GEANT4_TARGET_COMPILE_FEATURES})
1374     set(_props_to_process "INTERFACE")
1375 
1376     # Shortcut: If this category is also an "alias", we just extract the link interface directly
1377     if(_lib_is_alias)
1378       geant4_get_category_property(iface ${_name} CATEGORIES)
1379       if(_type STREQUAL "STATIC")
1380         list(TRANSFORM iface APPEND "-static")
1381       endif()
1382       target_link_libraries(${_target_name} INTERFACE ${iface})
1383       return()
1384     endif()
1385   else()
1386     target_compile_features(${_target_name} PUBLIC ${GEANT4_TARGET_COMPILE_FEATURES})
1387     set(_props_to_process "PUBLIC" "PRIVATE" "INTERFACE")
1388     set(_promote_interface_to_public TRUE)
1389   endif()
1390 
1391   if(_lib_cmake_type STREQUAL "SHARED")
1392     # G4LIB_BUILD_DLL is public as despite the name it indicates the shared/archive mode
1393     # and clients must apply it when linking to the shared libs. The global
1394     # category handles the exact import/export statements
1395     target_compile_definitions(${_target_name} PUBLIC G4LIB_BUILD_DLL)
1396     set_target_properties(${_target_name} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
1397 
1398     # Check if we have a DEFINE_SYMBOL for this category
1399     geant4_get_category_property(_lib_define_symbol ${_name} DEFINE_SYMBOL)
1400     if(_lib_define_symbol)
1401       set_target_properties(${_target_name} PROPERTIES DEFINE_SYMBOL ${_lib_define_symbol})
1402     endif()
1403 
1404     # MacOS
1405     # Use '@rpath' in install names of libraries on macOS to provide relocatibility
1406     # Add '@loader_path' to INSTALL_RPATH on macOS so that Geant4
1407     # libraries self-locate each other whilst remaining relocatable
1408     set_target_properties(${_target_name} PROPERTIES MACOSX_RPATH 1)
1409     if(APPLE)
1410       set_property(TARGET ${_target_name} APPEND PROPERTY INSTALL_RPATH "@loader_path")
1411     endif()
1412   endif()
1413 
1414   if((_lib_cmake_type STREQUAL "STATIC") AND NOT WIN32)
1415     set_target_properties(${_target_name} PROPERTIES OUTPUT_NAME ${_name})
1416   endif()
1417 
1418   # Get Modules to build into library, and list of defined interna/external libraries to resolve/link against
1419   geant4_get_categories(__g4definedlibraries)
1420   geant4_get_external_categories(__g4externallibraries)
1421   list(APPEND __g4definedlibraries ${__g4externallibraries})
1422   geant4_get_category_property(__g4modules ${_name} MODULES)
1423   foreach(__g4mod ${__g4modules})
1424     # - Process sources...
1425     geant4_get_module_property(_headers ${__g4mod} PUBLIC_HEADERS)
1426     geant4_get_module_property(_headers_private ${__g4mod} PRIVATE_HEADERS)
1427     geant4_get_module_property(_srcs ${__g4mod} SOURCES)
1428     geant4_get_module_property(_cmakescript ${__g4mod} CMAKE_LIST_FILE)
1429     get_filename_component(_moddir "${_cmakescript}" DIRECTORY)
1430 
1431     # - Group sources and scripts for IDEs
1432     # NB: Seemingly has to be done at same level we define target.
1433     # TODO: If lib name is same as mod name, don't group avoid extra
1434     # folder layer.
1435     source_group(${__g4mod}\\Headers FILES ${_headers} ${_headers_private})
1436     source_group(${__g4mod}\\Sources FILES ${_srcs})
1437     source_group(${__g4mod} FILES ${_cmakescript})
1438 
1439     # - Add sources to target - PRIVATE, because consuming targets don't need them
1440     target_sources(${_target_name} PRIVATE ${_headers} ${_headers_private} ${_srcs} ${_cmakescript})
1441 
1442     # - Process usage properties
1443     # Include dirs, compile definitions and libraries can be handled together
1444     # Important to note that these promote PUBLIC/PRIVATE/INTERFACE
1445     # from module level to library level. I.e. other modules in the
1446     # library can see each other's PRIVATE include paths/compile defs.
1447     # The only known way to fully wall things off is OBJECT libs,
1448     # but then run into issues mentioned at start - linking and
1449     # use in IDEs (though newer CMake versions should resolve these)
1450     # This "promotion" is probably correct though - interfaces are
1451     # at physical library level rather than module, and in Geant4
1452     # all files must have globally unique names (no nested headers
1453     # nor namespaces). Also, DLL export symbols may need this
1454     # behaviour (esp. ALLOC_EXPORT).
1455     # Only really an issue if header names/definitions aren't
1456     # globally (in Geant4) unique. Or if a module is moved and hasn't
1457     # declared its deps correctly (but then an error will occur
1458     # anyway, and point is that libs are linked, not modules!)
1459     # "Module" level really means "Source file" level, so same
1460     # sets of rules should apply.
1461     # Can use set_source_files_properties for module-level PRIVATE_HEADERS,
1462     # but that's it
1463     set_property(SOURCE ${_srcs} APPEND PROPERTY INCLUDE_DIRECTORIES "${_moddir}/include/private")
1464 
1465     foreach(_prop ${_props_to_process})
1466       # Further gotcha with INTERFACE modules here
1467       # - If an interface module is composed into a non-interface module
1468       #   its headers are exposed correctly to *clients* of the library, but
1469       #   *not* the internals of the library! This being the case, we promote
1470       #   these properties to PUBLIC
1471       set(_target_prop ${_prop})
1472       if(_promote_interface_to_public AND (_prop STREQUAL "INTERFACE"))
1473         set(_target_prop "PUBLIC")
1474       endif()
1475 
1476       geant4_get_module_property(_incdirs ${__g4mod} ${_prop}_INCLUDE_DIRECTORIES)
1477       target_include_directories(${_target_name} ${_target_prop} ${_incdirs})
1478 
1479       geant4_get_module_property(_defs ${__g4mod} ${_prop}_COMPILE_DEFINITIONS)
1480       target_compile_definitions(${_target_name} ${_target_prop} ${_defs})
1481 
1482       # Target linking requires additional processing to resolve
1483       geant4_get_module_property(_linklibs ${__g4mod} ${_prop}_LINK_LIBRARIES)
1484       __geant4_resolve_link_libraries(_linklibs)
1485       if(_linklibs)
1486         # Remove self-linking
1487         list(REMOVE_ITEM _linklibs ${_name})
1488 
1489         # Filter list for internal static targets
1490         if(_lib_cmake_type STREQUAL "STATIC")
1491           set(_g4linklibs )
1492           foreach(_linklib ${_linklibs})
1493             # If the linklib is a G4Library, change name to "name-static"
1494             list(FIND __g4definedlibraries ${_linklib} _isg4lib)
1495             if(_isg4lib GREATER -1)
1496               list(APPEND _g4linklibs "${_linklib}-static")
1497             else()
1498               list(APPEND _g4linklibs "${_linklib}")
1499             endif()
1500           endforeach()
1501           set(_linklibs ${_g4linklibs})
1502         endif()
1503 
1504         target_link_libraries(${_target_name} ${_target_prop} ${_linklibs})
1505       endif()
1506     endforeach()
1507 
1508     # Apply any additional properties supported in modules to target
1509     if(GEANT4_USE_QT)
1510       geant4_get_module_property(_needs_moc ${__g4mod} AUTOMOC)
1511       if(_needs_moc)
1512         set_target_properties(${_target_name} PROPERTIES AUTOMOC ON)
1513       endif()
1514     endif()
1515   endforeach()
1516 
1517   # - Postprocess target properties to remove duplicates
1518   # NB: This makes the assumption that there is no order dependence here (and any is considered a bug!)
1519   #     CMake will handle static link ordering internally
1520   foreach(_link_prop IN ITEMS LINK_LIBRARIES INTERFACE_LINK_LIBRARIES INCLUDE_DIRECTORIES INTERFACE_INCLUDE_DIRECTORIES COMPILE_DEFINITIONS INTERFACE_COMPILE_DEFINITIONS)
1521     get_target_property(__g4lib_link_libs ${_target_name} ${_link_prop})
1522     if(__g4lib_link_libs)
1523       list(SORT __g4lib_link_libs)
1524       list(REMOVE_DUPLICATES __g4lib_link_libs)
1525       set_property(TARGET ${_target_name} PROPERTY ${_link_prop} ${__g4lib_link_libs})
1526     endif()
1527   endforeach()
1528 endfunction()