Merge topic 'cleanup-custom-command-code'

f9028379f7 cmAddCustomCommandCommand: Move SOURCE signature error messages

Acked-by: Kitware Robot <kwrobot@kitware.com>
Tested-by: buildbot <buildbot@kitware.com>
Merge-request: !9523
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst
index c184a96..77357c0 100644
--- a/Help/command/add_custom_command.rst
+++ b/Help/command/add_custom_command.rst
@@ -269,6 +269,8 @@
   source tree is mentioned as an absolute source file path elsewhere
   in the current directory.
 
+  The output file path may not contain ``<`` or ``>`` characters.
+
   .. versionadded:: 3.20
     Arguments to ``OUTPUT`` may use a restricted set of
     :manual:`generator expressions <cmake-generator-expressions(7)>`.
@@ -280,6 +282,10 @@
     considered private unless they are listed in a non-private file set.
     See policy :policy:`CMP0154`.
 
+  .. versionchanged:: 3.30
+    The output file path may now use ``#`` characters, except
+    when using the :generator:`Borland Makefiles` generator.
+
 ``USES_TERMINAL``
   .. versionadded:: 3.2
 
diff --git a/Help/dev/experimental.rst b/Help/dev/experimental.rst
index 93298c5..35ea34f 100644
--- a/Help/dev/experimental.rst
+++ b/Help/dev/experimental.rst
@@ -50,7 +50,8 @@
 
 This UUID may change in future versions of CMake.  Be sure to use the value
 documented here by the source tree of the version of CMake with which you are
-experimenting.
+experimenting.  It must be set before the ``CXX`` toolchain is discovered by
+CMake, usually as part of a :command:`project` call.
 
 When activated, this experimental feature provides the following:
 
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 8f98f8b..b71e3d9 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -467,6 +467,7 @@
    /variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE
    /variable/CMAKE_LANG_LINK_GROUP_USING_FEATURE
    /variable/CMAKE_LANG_LINK_GROUP_USING_FEATURE_SUPPORTED
+   /variable/CMAKE_LANG_LINK_LIBRARY_FEATURE_PROPERTIES
    /variable/CMAKE_LANG_LINK_LIBRARY_FILE_FLAG
    /variable/CMAKE_LANG_LINK_LIBRARY_FLAG
    /variable/CMAKE_LANG_LINK_LIBRARY_USING_FEATURE
@@ -485,6 +486,7 @@
    /variable/CMAKE_LINK_GROUP_USING_FEATURE
    /variable/CMAKE_LINK_GROUP_USING_FEATURE_SUPPORTED
    /variable/CMAKE_LINK_INTERFACE_LIBRARIES
+   /variable/CMAKE_LINK_LIBRARY_FEATURE_PROPERTIES
    /variable/CMAKE_LINK_LIBRARY_FILE_FLAG
    /variable/CMAKE_LINK_LIBRARY_FLAG
    /variable/CMAKE_LINK_LIBRARY_USING_FEATURE
diff --git a/Help/release/dev/GenEx-LINK_LIBRARY-feature-properties.rst b/Help/release/dev/GenEx-LINK_LIBRARY-feature-properties.rst
new file mode 100644
index 0000000..a96eab9
--- /dev/null
+++ b/Help/release/dev/GenEx-LINK_LIBRARY-feature-properties.rst
@@ -0,0 +1,7 @@
+GenEx-LINK_LIBRARY-feature-properties
+-------------------------------------
+
+* Link features, as used with the :genex:`LINK_LIBRARY` generator expression,
+  gained the ability to have properties that describe their behavior by
+  specifying the :variable:`CMAKE_LINK_LIBRARY_<FEATURE>_PROPERTIES` or
+  :variable:`CMAKE_<LANG>_LINK_LIBRARY_<FEATURE>_PROPERTIES` variables.
diff --git a/Help/variable/CMAKE_LANG_LINK_LIBRARY_FEATURE_PROPERTIES.rst b/Help/variable/CMAKE_LANG_LINK_LIBRARY_FEATURE_PROPERTIES.rst
new file mode 100644
index 0000000..d8efd0f
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_LINK_LIBRARY_FEATURE_PROPERTIES.rst
@@ -0,0 +1,12 @@
+CMAKE_<LANG>_LINK_LIBRARY_<FEATURE>_PROPERTIES
+----------------------------------------------
+
+.. versionadded:: 3.30
+
+This variable defines the semantics of the specified ``<FEATURE>`` for the
+language ``<LANG>`` (as described by the
+:variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>` or
+:variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>` variables) used for the link
+command generation.
+
+.. include:: CMAKE_LINK_LIBRARY_FEATURE_PROPERTIES.txt
diff --git a/Help/variable/CMAKE_LINK_LIBRARY_FEATURE_PROPERTIES.rst b/Help/variable/CMAKE_LINK_LIBRARY_FEATURE_PROPERTIES.rst
new file mode 100644
index 0000000..86b4e77
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_LIBRARY_FEATURE_PROPERTIES.rst
@@ -0,0 +1,14 @@
+CMAKE_LINK_LIBRARY_<FEATURE>_PROPERTIES
+---------------------------------------
+
+.. versionadded:: 3.30
+
+This variable defines the semantics of the specified ``<FEATURE>`` (as
+described by the :variable:`CMAKE_<LANG>_LINK_LIBRARY_USING_<FEATURE>` or
+:variable:`CMAKE_LINK_LIBRARY_USING_<FEATURE>` variables) used for the link
+command generation.
+
+This variable will be considered only if the
+ :variable:`CMAKE_<LANG>_LINK_LIBRARY_<FEATURE>_PROPERTIES` is not defined.
+
+.. include:: CMAKE_LINK_LIBRARY_FEATURE_PROPERTIES.txt
diff --git a/Help/variable/CMAKE_LINK_LIBRARY_FEATURE_PROPERTIES.txt b/Help/variable/CMAKE_LINK_LIBRARY_FEATURE_PROPERTIES.txt
new file mode 100644
index 0000000..202a7ec
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_LIBRARY_FEATURE_PROPERTIES.txt
@@ -0,0 +1,87 @@
+Feature Properties Definition
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A feature properties definition is a
+:ref:`semicolon-separated list <CMake Language Lists>` of ``property=value(s)``
+items. In the case of multiple values can be specified, they are separated by
+a comma.
+
+The following properties are supported:
+
+``LIBRARY_TYPE=<library_type-list>``
+  Specify which library types are supported by this feature. The possible
+  values are: ``STATIC``, ``SHARED``, ``MODULE`` or ``EXECUTABLE``.
+
+  If this property is not specified, the default is
+  ``LIBRARY_TYPE=STATIC,SHARED,MODULE,EXECUTABLE``.
+
+  If the feature is used with an unsupported library type, CMake will emit a
+  developer warning and the feature will be ignored.
+
+``OVERRIDE=<feature-list>``
+  Specify which features will be replaced by this one in the event of a
+  conflict. This override mechanism is superseded by any
+  :prop_tgt:`LINK_LIBRARY_OVERRIDE` or
+  :prop_tgt:`LINK_LIBRARY_OVERRIDE_<LIBRARY>` target properties definitions.
+
+  If this property is not specified, the default is an empty list.
+
+``UNICITY=YES|NO|DEFAULT``
+  Manage the strategy of de-duplication for the libraries using this feature.
+
+  ``YES``
+    Libraries are de-duplicated regardless the default strategy applied by
+    CMake.
+
+  ``NO``
+    Libraries are not de-duplicated regardless the default strategy applied
+    by CMake.
+
+  ``DEFAULT``
+    Apply the default CMake strategy.
+
+  If this property is not specified, ``DEFAULT`` will be used.
+
+Example
+^^^^^^^
+
+A common need is the loading of a full archive as part of the creation of a
+shared library or an executable. For that purpose, the ``WHOLE_ARCHIVE``
+feature can be used.
+
+Currently, the associated properties with this feature are defined as follows:
+
+.. code-block:: cmake
+
+  set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC
+                                                  OVERRIDE=DEFAULT
+                                                  UNICITY=YES)
+
+``LIBRARY_TYPE=STATIC``
+  Obviously, this feature is only meaningful for static libraries.
+``OVERRIDE=DEFAULT``
+  The ``DEFAULT`` feature will be overridden by the ``WHOLE_ARCHIVE`` feature
+  because they are compatible and enhance the user's experience: standard
+  library specification and ``$<LINK_LIBRARY:WHOLE_ARCHIVE>`` can be used
+  freely.
+``UNICITY=YES``
+  When this feature is used, all symbols from the static library are loaded
+  by the linker, so there is no need to duplicate the library on the link
+  command.
+
+A typical usage of the ``WHOLE_ARCHIVE`` can be:
+
+.. code-block:: cmake
+
+  add_library(A STATIC ...)
+  add_library(B STATIC ...)
+
+  target_link_libraries(B PUBLIC A)
+  target_link_libraries(A PUBLIC B)
+
+  add_library(global SHARED ...)
+  target_link_libraries(global PRIVATE $<LINK_LIBRARY:WHOLE_ARCHIVE,A>)
+
+The resulting link command will only have one iteration of the ``A`` library
+specified with the needed linker flags to ensure the load of all the symbols
+of the library.
diff --git a/Help/variable/CMAKE_LINK_LIBRARY_USING_FEATURE.txt b/Help/variable/CMAKE_LINK_LIBRARY_USING_FEATURE.txt
index 4b13b7c..0359f58 100644
--- a/Help/variable/CMAKE_LINK_LIBRARY_USING_FEATURE.txt
+++ b/Help/variable/CMAKE_LINK_LIBRARY_USING_FEATURE.txt
@@ -2,6 +2,9 @@
 and underscores.  Feature names defined in all uppercase are reserved for
 CMake's own built-in features (see `Predefined Features`_ further below).
 
+The feature behavior can be described using the
+:variable:`CMAKE_<LANG>_LINK_LIBRARY_<FEATURE>_PROPERTIES` or
+:variable:`CMAKE_LINK_LIBRARY_<FEATURE>_PROPERTIES` variables.
 
 Feature Definitions
 ^^^^^^^^^^^^^^^^^^^
diff --git a/Modules/CMakeCInformation.cmake b/Modules/CMakeCInformation.cmake
index 998e476..72fb801 100644
--- a/Modules/CMakeCInformation.cmake
+++ b/Modules/CMakeCInformation.cmake
@@ -91,23 +91,6 @@
   set(CMAKE_USER_MAKE_RULES_OVERRIDE_C "${_override}")
 endif()
 
-if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
-  if(NOT DEFINED CMAKE_C_LINK_WHAT_YOU_USE_FLAG)
-    set(CMAKE_C_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
-  endif()
-  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
-    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
-  endif()
-endif()
-
-# for most systems a module is the same as a shared library
-# so unless the variable CMAKE_MODULE_EXISTS is set just
-# copy the values from the LIBRARY variables
-if(NOT CMAKE_MODULE_EXISTS)
-  set(CMAKE_SHARED_MODULE_C_FLAGS ${CMAKE_SHARED_LIBRARY_C_FLAGS})
-  set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS})
-endif()
-
 set(CMAKE_C_FLAGS_INIT "$ENV{CFLAGS} ${CMAKE_C_FLAGS_INIT}")
 
 cmake_initialize_per_config_variable(CMAKE_C_FLAGS "Flags used by the C compiler")
@@ -129,6 +112,7 @@
 endif()
 
 include(CMakeCommonLanguageInclude)
+_cmake_common_language_platform_flags(C)
 
 # now define the following rule variables
 
@@ -191,16 +175,4 @@
     "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 endif()
 
-if(NOT CMAKE_EXECUTABLE_RUNTIME_C_FLAG)
-  set(CMAKE_EXECUTABLE_RUNTIME_C_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG})
-endif()
-
-if(NOT CMAKE_EXECUTABLE_RUNTIME_C_FLAG_SEP)
-  set(CMAKE_EXECUTABLE_RUNTIME_C_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
-endif()
-
-if(NOT CMAKE_EXECUTABLE_RPATH_LINK_C_FLAG)
-  set(CMAKE_EXECUTABLE_RPATH_LINK_C_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG})
-endif()
-
 set(CMAKE_C_INFORMATION_LOADED 1)
diff --git a/Modules/CMakeCUDAInformation.cmake b/Modules/CMakeCUDAInformation.cmake
index e774088..66a5faa 100644
--- a/Modules/CMakeCUDAInformation.cmake
+++ b/Modules/CMakeCUDAInformation.cmake
@@ -55,59 +55,6 @@
 endif()
 
 
-if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_CUDA_FLAG)
-  set(CMAKE_SHARED_LIBRARY_RUNTIME_CUDA_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG})
-endif()
-
-if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_CUDA_FLAG_SEP)
-  set(CMAKE_SHARED_LIBRARY_RUNTIME_CUDA_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
-endif()
-
-if(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_CUDA_FLAG)
-  set(CMAKE_SHARED_LIBRARY_RPATH_LINK_CUDA_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_EXE_EXPORTS_CUDA_FLAG)
-  set(CMAKE_EXE_EXPORTS_CUDA_FLAG ${CMAKE_EXE_EXPORTS_C_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_SONAME_CUDA_FLAG)
-  set(CMAKE_SHARED_LIBRARY_SONAME_CUDA_FLAG ${CMAKE_SHARED_LIBRARY_SONAME_C_FLAG})
-endif()
-
-if(NOT CMAKE_EXECUTABLE_RUNTIME_CUDA_FLAG)
-  set(CMAKE_EXECUTABLE_RUNTIME_CUDA_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_CUDA_FLAG})
-endif()
-
-if(NOT CMAKE_EXECUTABLE_RUNTIME_CUDA_FLAG_SEP)
-  set(CMAKE_EXECUTABLE_RUNTIME_CUDA_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_CUDA_FLAG_SEP})
-endif()
-
-if(NOT CMAKE_EXECUTABLE_RPATH_LINK_CUDA_FLAG)
-  set(CMAKE_EXECUTABLE_RPATH_LINK_CUDA_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_CUDA_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_CUDA_WITH_RUNTIME_PATH)
-  set(CMAKE_SHARED_LIBRARY_LINK_CUDA_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH})
-endif()
-
-
-# for most systems a module is the same as a shared library
-# so unless the variable CMAKE_MODULE_EXISTS is set just
-# copy the values from the LIBRARY variables
-if(NOT CMAKE_MODULE_EXISTS)
-  set(CMAKE_SHARED_MODULE_CUDA_FLAGS ${CMAKE_SHARED_LIBRARY_CUDA_FLAGS})
-  set(CMAKE_SHARED_MODULE_CREATE_CUDA_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS})
-endif()
-
-if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
-  if(NOT DEFINED CMAKE_CUDA_LINK_WHAT_YOU_USE_FLAG)
-    set(CMAKE_CUDA_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
-  endif()
-  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
-    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
-  endif()
-endif()
 
 # add the flags to the cache based
 # on the initial values computed in the platform/*.cmake files
@@ -129,6 +76,7 @@
 endif()
 
 include(CMakeCommonLanguageInclude)
+_cmake_common_language_platform_flags(CUDA)
 
 # now define the following rules:
 # CMAKE_CUDA_CREATE_SHARED_LIBRARY
diff --git a/Modules/CMakeCXXInformation.cmake b/Modules/CMakeCXXInformation.cmake
index 3753d18..e521fb8 100644
--- a/Modules/CMakeCXXInformation.cmake
+++ b/Modules/CMakeCXXInformation.cmake
@@ -91,117 +91,6 @@
 endif()
 
 
-# Create a set of shared library variable specific to C++
-# For 90% of the systems, these are the same flags as the C versions
-# so if these are not set just copy the flags from the c version
-if(NOT CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS)
-  set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS})
-endif()
-
-if(NOT CMAKE_CXX_COMPILE_OPTIONS_PIC)
-  set(CMAKE_CXX_COMPILE_OPTIONS_PIC ${CMAKE_C_COMPILE_OPTIONS_PIC})
-endif()
-
-if(NOT CMAKE_CXX_COMPILE_OPTIONS_PIE)
-  set(CMAKE_CXX_COMPILE_OPTIONS_PIE ${CMAKE_C_COMPILE_OPTIONS_PIE})
-endif()
-if(NOT CMAKE_CXX_LINK_OPTIONS_PIE)
-  set(CMAKE_CXX_LINK_OPTIONS_PIE ${CMAKE_C_LINK_OPTIONS_PIE})
-endif()
-if(NOT CMAKE_CXX_LINK_OPTIONS_NO_PIE)
-  set(CMAKE_CXX_LINK_OPTIONS_NO_PIE ${CMAKE_C_LINK_OPTIONS_NO_PIE})
-endif()
-
-if(NOT CMAKE_CXX_COMPILE_OPTIONS_DLL)
-  set(CMAKE_CXX_COMPILE_OPTIONS_DLL ${CMAKE_C_COMPILE_OPTIONS_DLL})
-endif()
-
-if(NOT CMAKE_SHARED_LIBRARY_CXX_FLAGS)
-  set(CMAKE_SHARED_LIBRARY_CXX_FLAGS ${CMAKE_SHARED_LIBRARY_C_FLAGS})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
-  set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS ${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS})
-endif()
-
-if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG)
-  set(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG})
-endif()
-
-if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP)
-  set(CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
-endif()
-
-if(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG)
-  set(CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_EXE_EXPORTS_CXX_FLAG)
-  set(CMAKE_EXE_EXPORTS_CXX_FLAG ${CMAKE_EXE_EXPORTS_C_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG)
-  set(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG ${CMAKE_SHARED_LIBRARY_SONAME_C_FLAG})
-endif()
-
-if(NOT CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG)
-  set(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG})
-endif()
-
-if(NOT CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG_SEP)
-  set(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP})
-endif()
-
-if(NOT CMAKE_EXECUTABLE_RPATH_LINK_CXX_FLAG)
-  set(CMAKE_EXECUTABLE_RPATH_LINK_CXX_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_CXX_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_CXX_WITH_RUNTIME_PATH)
-  set(CMAKE_SHARED_LIBRARY_LINK_CXX_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH})
-endif()
-
-if(NOT CMAKE_INCLUDE_FLAG_CXX)
-  set(CMAKE_INCLUDE_FLAG_CXX ${CMAKE_INCLUDE_FLAG_C})
-endif()
-
-# for most systems a module is the same as a shared library
-# so unless the variable CMAKE_MODULE_EXISTS is set just
-# copy the values from the LIBRARY variables
-if(NOT CMAKE_MODULE_EXISTS)
-  set(CMAKE_SHARED_MODULE_CXX_FLAGS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS})
-  set(CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS})
-endif()
-
-# repeat for modules
-if(NOT CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS)
-  set(CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS ${CMAKE_SHARED_MODULE_CREATE_C_FLAGS})
-endif()
-
-if(NOT CMAKE_SHARED_MODULE_CXX_FLAGS)
-  set(CMAKE_SHARED_MODULE_CXX_FLAGS ${CMAKE_SHARED_MODULE_C_FLAGS})
-endif()
-
-# Initialize CXX link type selection flags from C versions.
-foreach(type IN ITEMS SHARED_LIBRARY SHARED_MODULE EXE)
-  if(NOT CMAKE_${type}_LINK_STATIC_CXX_FLAGS)
-    set(CMAKE_${type}_LINK_STATIC_CXX_FLAGS
-      ${CMAKE_${type}_LINK_STATIC_C_FLAGS})
-  endif()
-  if(NOT CMAKE_${type}_LINK_DYNAMIC_CXX_FLAGS)
-    set(CMAKE_${type}_LINK_DYNAMIC_CXX_FLAGS
-      ${CMAKE_${type}_LINK_DYNAMIC_C_FLAGS})
-  endif()
-endforeach()
-
-if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
-  if(NOT DEFINED CMAKE_CXX_LINK_WHAT_YOU_USE_FLAG)
-    set(CMAKE_CXX_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
-  endif()
-  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
-    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
-  endif()
-endif()
-
 # add the flags to the cache based
 # on the initial values computed in the platform/*.cmake files
 # use _INIT variables so that this only happens the first time
@@ -227,6 +116,7 @@
 endif()
 
 include(CMakeCommonLanguageInclude)
+_cmake_common_language_platform_flags(CXX)
 
 # now define the following rules:
 # CMAKE_CXX_CREATE_SHARED_LIBRARY
diff --git a/Modules/CMakeCommonLanguageInclude.cmake b/Modules/CMakeCommonLanguageInclude.cmake
index b043e18..5511930 100644
--- a/Modules/CMakeCommonLanguageInclude.cmake
+++ b/Modules/CMakeCommonLanguageInclude.cmake
@@ -21,3 +21,112 @@
 mark_as_advanced(
 CMAKE_VERBOSE_MAKEFILE
 )
+
+# The Platform/* modules set a bunch of platform-specific flags expressed
+# for the C toolchain.  Other languages call this to copy them as defaults.
+macro(_cmake_common_language_platform_flags lang)
+  if(NOT DEFINED CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS)
+    set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS})
+  endif()
+
+  if(NOT DEFINED CMAKE_${lang}_COMPILE_OPTIONS_PIC)
+    set(CMAKE_${lang}_COMPILE_OPTIONS_PIC ${CMAKE_C_COMPILE_OPTIONS_PIC})
+  endif()
+
+  if(NOT DEFINED CMAKE_${lang}_COMPILE_OPTIONS_PIE)
+    set(CMAKE_${lang}_COMPILE_OPTIONS_PIE ${CMAKE_C_COMPILE_OPTIONS_PIE})
+  endif()
+  if(NOT DEFINED CMAKE_${lang}_LINK_OPTIONS_PIE)
+    set(CMAKE_${lang}_LINK_OPTIONS_PIE ${CMAKE_C_LINK_OPTIONS_PIE})
+  endif()
+  if(NOT DEFINED CMAKE_${lang}_LINK_OPTIONS_NO_PIE)
+    set(CMAKE_${lang}_LINK_OPTIONS_NO_PIE ${CMAKE_C_LINK_OPTIONS_NO_PIE})
+  endif()
+
+  if(NOT DEFINED CMAKE_${lang}_COMPILE_OPTIONS_DLL)
+    set(CMAKE_${lang}_COMPILE_OPTIONS_DLL ${CMAKE_C_COMPILE_OPTIONS_DLL})
+  endif()
+
+  if(NOT DEFINED CMAKE_SHARED_LIBRARY_${lang}_FLAGS)
+    set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS ${CMAKE_SHARED_LIBRARY_C_FLAGS})
+  endif()
+
+  if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS)
+    set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS ${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS})
+  endif()
+
+  if(NOT DEFINED CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG)
+    set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG})
+  endif()
+
+  if(NOT DEFINED CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP)
+    set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
+  endif()
+
+  if(NOT DEFINED CMAKE_SHARED_LIBRARY_RPATH_LINK_${lang}_FLAG)
+    set(CMAKE_SHARED_LIBRARY_RPATH_LINK_${lang}_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG})
+  endif()
+
+  if(NOT DEFINED CMAKE_EXE_EXPORTS_${lang}_FLAG)
+    set(CMAKE_EXE_EXPORTS_${lang}_FLAG ${CMAKE_EXE_EXPORTS_C_FLAG})
+  endif()
+
+  if(NOT DEFINED CMAKE_SHARED_LIBRARY_SONAME_${lang}_FLAG)
+    set(CMAKE_SHARED_LIBRARY_SONAME_${lang}_FLAG ${CMAKE_SHARED_LIBRARY_SONAME_C_FLAG})
+  endif()
+
+  if(NOT DEFINED CMAKE_EXECUTABLE_RUNTIME_${lang}_FLAG)
+    set(CMAKE_EXECUTABLE_RUNTIME_${lang}_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG})
+  endif()
+
+  if(NOT DEFINED CMAKE_EXECUTABLE_RUNTIME_${lang}_FLAG_SEP)
+    set(CMAKE_EXECUTABLE_RUNTIME_${lang}_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP})
+  endif()
+
+  if(NOT DEFINED CMAKE_EXECUTABLE_RPATH_LINK_${lang}_FLAG)
+    set(CMAKE_EXECUTABLE_RPATH_LINK_${lang}_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_${lang}_FLAG})
+  endif()
+
+  if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_${lang}_WITH_RUNTIME_PATH)
+    set(CMAKE_SHARED_LIBRARY_LINK_${lang}_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH})
+  endif()
+
+  if(NOT DEFINED CMAKE_INCLUDE_FLAG_${lang})
+    set(CMAKE_INCLUDE_FLAG_${lang} ${CMAKE_INCLUDE_FLAG_C})
+  endif()
+
+  # for most systems a module is the same as a shared library
+  # so unless the variable CMAKE_MODULE_EXISTS is set just
+  # copy the values from the LIBRARY variables
+  if(NOT CMAKE_MODULE_EXISTS)
+    set(CMAKE_SHARED_MODULE_${lang}_FLAGS ${CMAKE_SHARED_LIBRARY_${lang}_FLAGS})
+    set(CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS})
+  endif()
+
+  if(NOT DEFINED CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS)
+    set(CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS})
+  endif()
+  if(NOT DEFINED CMAKE_SHARED_MODULE_${lang}_FLAGS)
+    set(CMAKE_SHARED_MODULE_${lang}_FLAGS ${CMAKE_SHARED_LIBRARY_C_FLAGS})
+  endif()
+
+  foreach(type IN ITEMS SHARED_LIBRARY SHARED_MODULE EXE)
+    if(NOT DEFINED CMAKE_${type}_LINK_STATIC_${lang}_FLAGS)
+      set(CMAKE_${type}_LINK_STATIC_${lang}_FLAGS
+        ${CMAKE_${type}_LINK_STATIC_C_FLAGS})
+    endif()
+    if(NOT DEFINED CMAKE_${type}_LINK_DYNAMIC_${lang}_FLAGS)
+      set(CMAKE_${type}_LINK_DYNAMIC_${lang}_FLAGS
+        ${CMAKE_${type}_LINK_DYNAMIC_C_FLAGS})
+    endif()
+  endforeach()
+
+  if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+    if(NOT DEFINED CMAKE_${lang}_LINK_WHAT_YOU_USE_FLAG)
+      set(CMAKE_${lang}_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
+    endif()
+    if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
+      set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
+    endif()
+  endif()
+endmacro()
diff --git a/Modules/CMakeFortranInformation.cmake b/Modules/CMakeFortranInformation.cmake
index e364755..984a39d 100644
--- a/Modules/CMakeFortranInformation.cmake
+++ b/Modules/CMakeFortranInformation.cmake
@@ -67,105 +67,6 @@
   set(CMAKE_USER_MAKE_RULES_OVERRIDE_Fortran "${_override}")
 endif()
 
-if(NOT CMAKE_Fortran_COMPILE_OPTIONS_PIC)
-  set(CMAKE_Fortran_COMPILE_OPTIONS_PIC ${CMAKE_C_COMPILE_OPTIONS_PIC})
-endif()
-
-if(NOT CMAKE_Fortran_COMPILE_OPTIONS_PIE)
-  set(CMAKE_Fortran_COMPILE_OPTIONS_PIE ${CMAKE_C_COMPILE_OPTIONS_PIE})
-endif()
-if(NOT CMAKE_Fortran_LINK_OPTIONS_PIE)
-  set(CMAKE_Fortran_LINK_OPTIONS_PIE ${CMAKE_C_LINK_OPTIONS_PIE})
-endif()
-if(NOT CMAKE_Fortran_LINK_OPTIONS_NO_PIE)
-  set(CMAKE_Fortran_LINK_OPTIONS_NO_PIE ${CMAKE_C_LINK_OPTIONS_NO_PIE})
-endif()
-
-if(NOT CMAKE_Fortran_COMPILE_OPTIONS_DLL)
-  set(CMAKE_Fortran_COMPILE_OPTIONS_DLL ${CMAKE_C_COMPILE_OPTIONS_DLL})
-endif()
-
-# Create a set of shared library variable specific to Fortran
-# For 90% of the systems, these are the same flags as the C versions
-# so if these are not set just copy the flags from the c version
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS)
-  set(CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_Fortran_FLAGS)
-  set(CMAKE_SHARED_LIBRARY_Fortran_FLAGS ${CMAKE_SHARED_LIBRARY_C_FLAGS})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS)
-  set(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS ${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG)
-  set(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP)
-  set(CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_RPATH_LINK_Fortran_FLAG)
-  set(CMAKE_SHARED_LIBRARY_RPATH_LINK_Fortran_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_EXE_EXPORTS_Fortran_FLAG)
-  set(CMAKE_EXE_EXPORTS_Fortran_FLAG ${CMAKE_EXE_EXPORTS_C_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG)
-  set(CMAKE_SHARED_LIBRARY_SONAME_Fortran_FLAG ${CMAKE_SHARED_LIBRARY_SONAME_C_FLAG})
-endif()
-
-# for most systems a module is the same as a shared library
-# so unless the variable CMAKE_MODULE_EXISTS is set just
-# copy the values from the LIBRARY variables
-if(NOT CMAKE_MODULE_EXISTS)
-  set(CMAKE_SHARED_MODULE_Fortran_FLAGS ${CMAKE_SHARED_LIBRARY_Fortran_FLAGS})
-  set(CMAKE_SHARED_MODULE_CREATE_Fortran_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_Fortran_FLAGS})
-endif()
-
-# repeat for modules
-if(NOT DEFINED CMAKE_SHARED_MODULE_CREATE_Fortran_FLAGS)
-  set(CMAKE_SHARED_MODULE_CREATE_Fortran_FLAGS ${CMAKE_SHARED_MODULE_CREATE_C_FLAGS})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_MODULE_Fortran_FLAGS)
-  set(CMAKE_SHARED_MODULE_Fortran_FLAGS ${CMAKE_SHARED_MODULE_C_FLAGS})
-endif()
-
-if(NOT DEFINED CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG)
-  set(CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG_SEP)
-  set(CMAKE_EXECUTABLE_RUNTIME_Fortran_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_Fortran_FLAG_SEP})
-endif()
-
-if(NOT DEFINED CMAKE_EXECUTABLE_RPATH_LINK_Fortran_FLAG)
-  set(CMAKE_EXECUTABLE_RPATH_LINK_Fortran_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_Fortran_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_Fortran_WITH_RUNTIME_PATH)
-  set(CMAKE_SHARED_LIBRARY_LINK_Fortran_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH})
-endif()
-
-if(NOT CMAKE_INCLUDE_FLAG_Fortran)
-  set(CMAKE_INCLUDE_FLAG_Fortran ${CMAKE_INCLUDE_FLAG_C})
-endif()
-
-if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
-  if(NOT DEFINED CMAKE_Fortran_LINK_WHAT_YOU_USE_FLAG)
-    set(CMAKE_Fortran_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
-  endif()
-  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
-    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
-  endif()
-endif()
-
 set(CMAKE_VERBOSE_MAKEFILE FALSE CACHE BOOL "If this value is on, makefiles will be generated without the .SILENT directive, and all commands will be echoed to the console during the make.  This is useful for debugging only. With Visual Studio IDE projects all commands are done without /nologo.")
 
 set(CMAKE_Fortran_FLAGS_INIT "$ENV{FFLAGS} ${CMAKE_Fortran_FLAGS_INIT}")
@@ -178,6 +79,7 @@
 endif()
 
 include(CMakeCommonLanguageInclude)
+_cmake_common_language_platform_flags(Fortran)
 
 # now define the following rule variables
 # CMAKE_Fortran_CREATE_SHARED_LIBRARY
diff --git a/Modules/CMakeHIPInformation.cmake b/Modules/CMakeHIPInformation.cmake
index 3995c36..dc76c63 100644
--- a/Modules/CMakeHIPInformation.cmake
+++ b/Modules/CMakeHIPInformation.cmake
@@ -36,60 +36,6 @@
 endif()
 
 
-if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_HIP_FLAG)
-  set(CMAKE_SHARED_LIBRARY_RUNTIME_HIP_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG})
-endif()
-
-if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_HIP_FLAG_SEP)
-  set(CMAKE_SHARED_LIBRARY_RUNTIME_HIP_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP})
-endif()
-
-if(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_HIP_FLAG)
-  set(CMAKE_SHARED_LIBRARY_RPATH_LINK_HIP_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_EXE_EXPORTS_HIP_FLAG)
-  set(CMAKE_EXE_EXPORTS_HIP_FLAG ${CMAKE_EXE_EXPORTS_C_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_SONAME_HIP_FLAG)
-  set(CMAKE_SHARED_LIBRARY_SONAME_HIP_FLAG ${CMAKE_SHARED_LIBRARY_SONAME_C_FLAG})
-endif()
-
-if(NOT CMAKE_EXECUTABLE_RUNTIME_HIP_FLAG)
-  set(CMAKE_EXECUTABLE_RUNTIME_HIP_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_HIP_FLAG})
-endif()
-
-if(NOT CMAKE_EXECUTABLE_RUNTIME_HIP_FLAG_SEP)
-  set(CMAKE_EXECUTABLE_RUNTIME_HIP_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_HIP_FLAG_SEP})
-endif()
-
-if(NOT CMAKE_EXECUTABLE_RPATH_LINK_HIP_FLAG)
-  set(CMAKE_EXECUTABLE_RPATH_LINK_HIP_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_HIP_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_HIP_WITH_RUNTIME_PATH)
-  set(CMAKE_SHARED_LIBRARY_LINK_HIP_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH})
-endif()
-
-
-# for most systems a module is the same as a shared library
-# so unless the variable CMAKE_MODULE_EXISTS is set just
-# copy the values from the LIBRARY variables
-if(NOT CMAKE_MODULE_EXISTS)
-  set(CMAKE_SHARED_MODULE_HIP_FLAGS ${CMAKE_SHARED_LIBRARY_HIP_FLAGS})
-  set(CMAKE_SHARED_MODULE_CREATE_HIP_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_HIP_FLAGS})
-endif()
-
-if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
-  if(NOT DEFINED CMAKE_HIP_LINK_WHAT_YOU_USE_FLAG)
-    set(CMAKE_HIP_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
-  endif()
-  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
-    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
-  endif()
-endif()
-
 # add the flags to the cache based
 # on the initial values computed in the platform/*.cmake files
 # use _INIT variables so that this only happens the first time
@@ -110,6 +56,7 @@
 endif()
 
 include(CMakeCommonLanguageInclude)
+_cmake_common_language_platform_flags(HIP)
 
 # now define the following rules:
 # CMAKE_HIP_CREATE_SHARED_LIBRARY
diff --git a/Modules/CMakeOBJCInformation.cmake b/Modules/CMakeOBJCInformation.cmake
index 8b8f10e..bcb8b11 100644
--- a/Modules/CMakeOBJCInformation.cmake
+++ b/Modules/CMakeOBJCInformation.cmake
@@ -91,24 +91,6 @@
   set(CMAKE_USER_MAKE_RULES_OVERRIDE_OBJC "${_override}")
 endif()
 
-if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
-  if(NOT DEFINED CMAKE_OBJC_LINK_WHAT_YOU_USE_FLAG)
-    set(CMAKE_OBJC_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
-  endif()
-  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
-    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
-  endif()
-endif()
-
-
-# for most systems a module is the same as a shared library
-# so unless the variable CMAKE_MODULE_EXISTS is set just
-# copy the values from the LIBRARY variables
-if(NOT CMAKE_MODULE_EXISTS)
-  set(CMAKE_SHARED_MODULE_OBJC_FLAGS ${CMAKE_SHARED_LIBRARY_OBJC_FLAGS})
-  set(CMAKE_SHARED_MODULE_CREATE_OBJC_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_OBJC_FLAGS})
-endif()
-
 set(CMAKE_OBJC_FLAGS_INIT "$ENV{OBJCFLAGS} ${CMAKE_OBJC_FLAGS_INIT}")
 
 cmake_initialize_per_config_variable(CMAKE_OBJC_FLAGS "Flags used by the Objective-C compiler")
@@ -130,6 +112,7 @@
 endif()
 
 include(CMakeCommonLanguageInclude)
+_cmake_common_language_platform_flags(OBJC)
 
 # now define the following rule variables
 
diff --git a/Modules/CMakeOBJCXXInformation.cmake b/Modules/CMakeOBJCXXInformation.cmake
index da1d6c6..4fcd469 100644
--- a/Modules/CMakeOBJCXXInformation.cmake
+++ b/Modules/CMakeOBJCXXInformation.cmake
@@ -87,117 +87,6 @@
 endif()
 
 
-# Create a set of shared library variable specific to Objective-C++
-# For 90% of the systems, these are the same flags as the Objective-C versions
-# so if these are not set just copy the flags from the Objective-C version
-if(NOT CMAKE_SHARED_LIBRARY_CREATE_OBJCXX_FLAGS)
-  set(CMAKE_SHARED_LIBRARY_CREATE_OBJCXX_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_OBJC_FLAGS})
-endif()
-
-if(NOT CMAKE_OBJCXX_COMPILE_OPTIONS_PIC)
-  set(CMAKE_OBJCXX_COMPILE_OPTIONS_PIC ${CMAKE_OBJC_COMPILE_OPTIONS_PIC})
-endif()
-
-if(NOT CMAKE_OBJCXX_COMPILE_OPTIONS_PIE)
-  set(CMAKE_OBJCXX_COMPILE_OPTIONS_PIE ${CMAKE_OBJC_COMPILE_OPTIONS_PIE})
-endif()
-if(NOT CMAKE_OBJCXX_LINK_OPTIONS_PIE)
-  set(CMAKE_OBJCXX_LINK_OPTIONS_PIE ${CMAKE_OBJC_LINK_OPTIONS_PIE})
-endif()
-if(NOT CMAKE_OBJCXX_LINK_OPTIONS_NO_PIE)
-  set(CMAKE_OBJCXX_LINK_OPTIONS_NO_PIE ${CMAKE_OBJC_LINK_OPTIONS_NO_PIE})
-endif()
-
-if(NOT CMAKE_OBJCXX_COMPILE_OPTIONS_DLL)
-  set(CMAKE_OBJCXX_COMPILE_OPTIONS_DLL ${CMAKE_OBJC_COMPILE_OPTIONS_DLL})
-endif()
-
-if(NOT CMAKE_SHARED_LIBRARY_OBJCXX_FLAGS)
-  set(CMAKE_SHARED_LIBRARY_OBJCXX_FLAGS ${CMAKE_SHARED_LIBRARY_OBJC_FLAGS})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_OBJCXX_FLAGS)
-  set(CMAKE_SHARED_LIBRARY_LINK_OBJCXX_FLAGS ${CMAKE_SHARED_LIBRARY_LINK_OBJC_FLAGS})
-endif()
-
-if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG)
-  set(CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJC_FLAG})
-endif()
-
-if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG_SEP)
-  set(CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJC_FLAG_SEP})
-endif()
-
-if(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_OBJCXX_FLAG)
-  set(CMAKE_SHARED_LIBRARY_RPATH_LINK_OBJCXX_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_OBJC_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_EXE_EXPORTS_OBJCXX_FLAG)
-  set(CMAKE_EXE_EXPORTS_OBJCXX_FLAG ${CMAKE_EXE_EXPORTS_OBJC_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_SONAME_OBJCXX_FLAG)
-  set(CMAKE_SHARED_LIBRARY_SONAME_OBJCXX_FLAG ${CMAKE_SHARED_LIBRARY_SONAME_OBJC_FLAG})
-endif()
-
-if(NOT CMAKE_EXECUTABLE_RUNTIME_OBJCXX_FLAG)
-  set(CMAKE_EXECUTABLE_RUNTIME_OBJCXX_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG})
-endif()
-
-if(NOT CMAKE_EXECUTABLE_RUNTIME_OBJCXX_FLAG_SEP)
-  set(CMAKE_EXECUTABLE_RUNTIME_OBJCXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG_SEP})
-endif()
-
-if(NOT CMAKE_EXECUTABLE_RPATH_LINK_OBJCXX_FLAG)
-  set(CMAKE_EXECUTABLE_RPATH_LINK_OBJCXX_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_OBJCXX_FLAG})
-endif()
-
-if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_OBJCXX_WITH_RUNTIME_PATH)
-  set(CMAKE_SHARED_LIBRARY_LINK_OBJCXX_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_OBJC_WITH_RUNTIME_PATH})
-endif()
-
-if(NOT CMAKE_INCLUDE_FLAG_OBJCXX)
-  set(CMAKE_INCLUDE_FLAG_OBJCXX ${CMAKE_INCLUDE_FLAG_C})
-endif()
-
-# for most systems a module is the same as a shared library
-# so unless the variable CMAKE_MODULE_EXISTS is set just
-# copy the values from the LIBRARY variables
-if(NOT CMAKE_MODULE_EXISTS)
-  set(CMAKE_SHARED_MODULE_OBJCXX_FLAGS ${CMAKE_SHARED_LIBRARY_OBJCXX_FLAGS})
-  set(CMAKE_SHARED_MODULE_CREATE_OBJCXX_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_OBJCXX_FLAGS})
-endif()
-
-# repeat for modules
-if(NOT CMAKE_SHARED_MODULE_CREATE_OBJCXX_FLAGS)
-  set(CMAKE_SHARED_MODULE_CREATE_OBJCXX_FLAGS ${CMAKE_SHARED_MODULE_CREATE_OBJC_FLAGS})
-endif()
-
-if(NOT CMAKE_SHARED_MODULE_OBJCXX_FLAGS)
-  set(CMAKE_SHARED_MODULE_OBJCXX_FLAGS ${CMAKE_SHARED_MODULE_OBJC_FLAGS})
-endif()
-
-# Initialize OBJCXX link type selection flags from OBJC versions.
-foreach(type IN ITEMS SHARED_LIBRARY SHARED_MODULE EXE)
-  if(NOT CMAKE_${type}_LINK_STATIC_OBJCXX_FLAGS)
-    set(CMAKE_${type}_LINK_STATIC_OBJCXX_FLAGS
-      ${CMAKE_${type}_LINK_STATIC_OBJC_FLAGS})
-  endif()
-  if(NOT CMAKE_${type}_LINK_DYNAMIC_OBJCXX_FLAGS)
-    set(CMAKE_${type}_LINK_DYNAMIC_OBJCXX_FLAGS
-      ${CMAKE_${type}_LINK_DYNAMIC_OBJC_FLAGS})
-  endif()
-endforeach()
-
-if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
-  if(NOT DEFINED CMAKE_OBJCXX_LINK_WHAT_YOU_USE_FLAG)
-    set(CMAKE_OBJCXX_LINK_WHAT_YOU_USE_FLAG "LINKER:--no-as-needed")
-  endif()
-  if(NOT DEFINED CMAKE_LINK_WHAT_YOU_USE_CHECK)
-    set(CMAKE_LINK_WHAT_YOU_USE_CHECK ldd -u -r)
-  endif()
-endif()
-
 # add the flags to the cache based
 # on the initial values computed in the platform/*.cmake files
 # use _INIT variables so that this only happens the first time
@@ -223,6 +112,7 @@
 endif()
 
 include(CMakeCommonLanguageInclude)
+_cmake_common_language_platform_flags(OBJCXX)
 
 # now define the following rules:
 # CMAKE_OBJCXX_CREATE_SHARED_LIBRARY
diff --git a/Modules/CMakeTestSwiftCompiler.cmake b/Modules/CMakeTestSwiftCompiler.cmake
index c7df912..d89e606 100644
--- a/Modules/CMakeTestSwiftCompiler.cmake
+++ b/Modules/CMakeTestSwiftCompiler.cmake
@@ -24,7 +24,10 @@
   # Clear result from normal variable.
   unset(CMAKE_Swift_COMPILER_WORKS)
   # Puts test result in cache variable.
-  set(__CMAKE_Swift_TEST_SOURCE "print(\"CMake\")\n")
+  string(CONCAT __CMAKE_Swift_TEST_SOURCE
+  "public struct CMakeStruct {"
+  "  let x: Int"
+  "}")
   try_compile(CMAKE_Swift_COMPILER_WORKS
     SOURCE_FROM_VAR main.swift __CMAKE_Swift_TEST_SOURCE
     OUTPUT_VARIABLE __CMAKE_Swift_COMPILER_OUTPUT)
diff --git a/Modules/Compiler/CMakeCommonCompilerMacros.cmake b/Modules/Compiler/CMakeCommonCompilerMacros.cmake
index 75a9da2..ffd02ec 100644
--- a/Modules/Compiler/CMakeCommonCompilerMacros.cmake
+++ b/Modules/Compiler/CMakeCommonCompilerMacros.cmake
@@ -250,7 +250,7 @@
     _cmake_supported_import_std_experimental)
   if (NOT _cmake_supported_import_std_experimental)
     set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Experimental `import std` support not enabled when detecting toolchain\")\n"
+      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Experimental `import std` support not enabled when detecting toolchain; it must be set before `CXX` is enabled (usually a `project()` call)\")\n"
       PARENT_SCOPE)
     return ()
   endif ()
diff --git a/Modules/Platform/Apple-Clang.cmake b/Modules/Platform/Apple-Clang.cmake
index bd5ba9a..31f4293 100644
--- a/Modules/Platform/Apple-Clang.cmake
+++ b/Modules/Platform/Apple-Clang.cmake
@@ -19,6 +19,7 @@
 
   set(CMAKE_${lang}_LINK_LIBRARY_USING_FRAMEWORK "-framework <LIBRARY>")
   set(CMAKE_${lang}_LINK_LIBRARY_USING_FRAMEWORK_SUPPORTED TRUE)
+  set(CMAKE_${lang}_LINK_LIBRARY_FRAMEWORK_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
 
   # linker selection
   set(CMAKE_${lang}_USING_LINKER_SYSTEM "-fuse-ld=ld")
diff --git a/Modules/Platform/Apple-GNU.cmake b/Modules/Platform/Apple-GNU.cmake
index 15f6a71..20b18ad 100644
--- a/Modules/Platform/Apple-GNU.cmake
+++ b/Modules/Platform/Apple-GNU.cmake
@@ -17,6 +17,7 @@
 
   set(CMAKE_${lang}_LINK_LIBRARY_USING_FRAMEWORK "-framework <LIBRARY>")
   set(CMAKE_${lang}_LINK_LIBRARY_USING_FRAMEWORK_SUPPORTED TRUE)
+  set(CMAKE_LINK_LIBRARY_FRAMEWORK_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
 
   set(CMAKE_${lang}_USING_LINKER_SYSTEM "")
   set(CMAKE_${lang}_USING_LINKER_APPLE_CLASSIC "LINKER:-ld_classic")
diff --git a/Modules/Platform/CYGWIN-GNU.cmake b/Modules/Platform/CYGWIN-GNU.cmake
index 070b24d..5e2ba41 100644
--- a/Modules/Platform/CYGWIN-GNU.cmake
+++ b/Modules/Platform/CYGWIN-GNU.cmake
@@ -40,6 +40,7 @@
                                              "LINKER:--no-whole-archive")
 endif()
 set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
 
 
 macro(__cygwin_compiler_gnu lang)
diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake
index 533b9ce..1272baf 100644
--- a/Modules/Platform/Darwin.cmake
+++ b/Modules/Platform/Darwin.cmake
@@ -114,29 +114,37 @@
 # Defines LINK_LIBRARY features for frameworks
 set(CMAKE_LINK_LIBRARY_USING_FRAMEWORK "LINKER:-framework,<LIBRARY>")
 set(CMAKE_LINK_LIBRARY_USING_FRAMEWORK_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_FRAMEWORK_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
 
 set(CMAKE_LINK_LIBRARY_USING_NEEDED_FRAMEWORK "LINKER:-needed_framework,<LIBRARY>")
 set(CMAKE_LINK_LIBRARY_USING_NEEDED_FRAMEWORK_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_NEEDED_FRAMEWORK_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
 
 set(CMAKE_LINK_LIBRARY_USING_REEXPORT_FRAMEWORK "LINKER:-reexport_framework,<LIBRARY>")
 set(CMAKE_LINK_LIBRARY_USING_REEXPORT_FRAMEWORK_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_REEXPORT_FRAMEWORK_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
 
 set(CMAKE_LINK_LIBRARY_USING_WEAK_FRAMEWORK "LINKER:-weak_framework,<LIBRARY>")
 set(CMAKE_LINK_LIBRARY_USING_WEAK_FRAMEWORK_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_WEAK_FRAMEWORK_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
 
 # Defines LINK_LIBRARY features for libraries
 set(CMAKE_LINK_LIBRARY_USING_NEEDED_LIBRARY "PATH{LINKER:-needed_library,<LIBRARY>}NAME{LINKER:-needed-l<LIBRARY>}")
 set(CMAKE_LINK_LIBRARY_USING_NEEDED_LIBRARY_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_NEEDED_LIBRARY_PROPERTIES LIBRARY_TYPE=SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
 
 set(CMAKE_LINK_LIBRARY_USING_REEXPORT_LIBRARY "PATH{LINKER:-reexport_library,<LIBRARY>}NAME{LINKER:-reexport-l<LIBRARY>}")
 set(CMAKE_LINK_LIBRARY_USING_REEXPORT_LIBRARY_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_REEXPORT_LIBRARY_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
 
 set(CMAKE_LINK_LIBRARY_USING_WEAK_LIBRARY "PATH{LINKER:-weak_library,<LIBRARY>}NAME{LINKER:-weak-l<LIBRARY>}")
 set(CMAKE_LINK_LIBRARY_USING_WEAK_LIBRARY_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_WEAK_LIBRARY_PROPERTIES LIBRARY_TYPE=STATIC,SHARED UNICITY=DEFAULT OVERRIDE=DEFAULT)
 
 # Defines LINK_LIBRARY feature to Force loading of all members of an archive
 set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE "LINKER:-force_load,<LIB_ITEM>")
 set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
 
 # default to searching for frameworks first
 if(NOT DEFINED CMAKE_FIND_FRAMEWORK)
diff --git a/Modules/Platform/FreeBSD.cmake b/Modules/Platform/FreeBSD.cmake
index bd5a786..7d5f951 100644
--- a/Modules/Platform/FreeBSD.cmake
+++ b/Modules/Platform/FreeBSD.cmake
@@ -51,6 +51,7 @@
                                              "LINKER:--no-whole-archive")
 endif()
 set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
 
 
 # Features for LINK_GROUP generator expression
diff --git a/Modules/Platform/Linux.cmake b/Modules/Platform/Linux.cmake
index 97a116f..fba6ab8 100644
--- a/Modules/Platform/Linux.cmake
+++ b/Modules/Platform/Linux.cmake
@@ -44,6 +44,7 @@
                                              "LINKER:--no-whole-archive")
 endif()
 set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
 
 # Features for LINK_GROUP generator expression
 ## RESCAN: request the linker to rescan static libraries until there is
diff --git a/Modules/Platform/NetBSD.cmake b/Modules/Platform/NetBSD.cmake
index ab85923..af368cd 100644
--- a/Modules/Platform/NetBSD.cmake
+++ b/Modules/Platform/NetBSD.cmake
@@ -37,6 +37,7 @@
                                              "LINKER:--no-whole-archive")
 endif()
 set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
 
 
 # Features for LINK_GROUP generator expression
diff --git a/Modules/Platform/SunOS.cmake b/Modules/Platform/SunOS.cmake
index b8a302c..73205c1 100644
--- a/Modules/Platform/SunOS.cmake
+++ b/Modules/Platform/SunOS.cmake
@@ -20,6 +20,7 @@
                                              "LINKER:-z,defaultextract")
 endif()
 set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
 
 
 # Features for LINK_GROUP generator expression
diff --git a/Modules/Platform/Windows-Clang.cmake b/Modules/Platform/Windows-Clang.cmake
index b9e6394..35055bc 100644
--- a/Modules/Platform/Windows-Clang.cmake
+++ b/Modules/Platform/Windows-Clang.cmake
@@ -140,6 +140,7 @@
     ## WHOLE_ARCHIVE: Force loading all members of an archive
     set(CMAKE_${lang}_LINK_LIBRARY_USING_WHOLE_ARCHIVE "LINKER:/WHOLEARCHIVE:<LIBRARY>")
     set(CMAKE_${lang}_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
+    set(CMAKE_${lang}_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
   endif()
 
   enable_language(RC)
diff --git a/Modules/Platform/Windows-GNU.cmake b/Modules/Platform/Windows-GNU.cmake
index 9f81882..d2b25c6 100644
--- a/Modules/Platform/Windows-GNU.cmake
+++ b/Modules/Platform/Windows-GNU.cmake
@@ -88,6 +88,7 @@
                                              "LINKER:--no-whole-archive")
 endif()
 set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
 
 # Features for LINK_GROUP generator expression
 ## RESCAN: request the linker to rescan static libraries until there is
diff --git a/Modules/Platform/Windows-IntelLLVM.cmake b/Modules/Platform/Windows-IntelLLVM.cmake
index b1a336b..691c7ce 100644
--- a/Modules/Platform/Windows-IntelLLVM.cmake
+++ b/Modules/Platform/Windows-IntelLLVM.cmake
@@ -37,6 +37,7 @@
     ## WHOLE_ARCHIVE: Force loading all members of an archive
     set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE "LINKER:/WHOLEARCHIVE:<LIBRARY>")
     set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
+    set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
   endif()
 
   set(CMAKE_${lang}_LINK_EXECUTABLE
diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake
index ef57031..c737b88 100644
--- a/Modules/Platform/Windows-MSVC.cmake
+++ b/Modules/Platform/Windows-MSVC.cmake
@@ -358,6 +358,7 @@
   ## WHOLE_ARCHIVE: Force loading all members of an archive
   set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE "/WHOLEARCHIVE:<LIBRARY>")
   set(CMAKE_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
+  set(CMAKE_LINK_LIBRARY_WHOLE_ARCHIVE_PROPERTIES LIBRARY_TYPE=STATIC UNICITY=YES OVERRIDE=DEFAULT)
 endif()
 
 
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 0c28ffd..6096cf0 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 29)
-set(CMake_VERSION_PATCH 20240515)
+set(CMake_VERSION_PATCH 20240517)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index 8651436..db0d71a 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -30,6 +30,7 @@
 #include "cmMessageType.h"
 #include "cmPolicies.h"
 #include "cmRange.h"
+#include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmTarget.h"
@@ -201,6 +202,113 @@
   return makefile->GetDefinition(featureSupported).IsOn();
 }
 
+// LINK_LIBRARY feature properties management
+struct LinkLibraryFeaturePropertySet
+{
+  std::set<cmStateEnums::TargetType> LibraryTypes = {
+    cmStateEnums::EXECUTABLE, cmStateEnums::STATIC_LIBRARY,
+    cmStateEnums::SHARED_LIBRARY, cmStateEnums::MODULE_LIBRARY,
+    cmStateEnums::UNKNOWN_LIBRARY
+  };
+  std::set<std::string> Override;
+
+  enum UnicityKind
+  {
+    Default,
+    Yes,
+    No
+  };
+  UnicityKind Unicity = Default;
+};
+std::map<std::string, LinkLibraryFeaturePropertySet>
+  LinkLibraryFeatureProperties;
+const LinkLibraryFeaturePropertySet& GetLinkLibraryFeatureProperties(
+  cmMakefile* makefile, std::string const& linkLanguage,
+  const std::string& feature)
+{
+  auto it = LinkLibraryFeatureProperties.find(feature);
+  if (it != LinkLibraryFeatureProperties.end()) {
+    return it->second;
+  }
+
+  auto featurePropertiesVariable =
+    cmStrCat("CMAKE_", linkLanguage, "_LINK_LIBRARY_", feature, "_PROPERTIES");
+  auto featurePropertiesValues =
+    makefile->GetDefinition(featurePropertiesVariable);
+  if (featurePropertiesValues.IsEmpty()) {
+    // try language agnostic definition
+    featurePropertiesVariable =
+      cmStrCat("CMAKE_LINK_LIBRARY_", feature, "_PROPERTIES");
+    featurePropertiesValues =
+      makefile->GetDefinition(featurePropertiesVariable);
+  }
+  if (!featurePropertiesValues.IsEmpty()) {
+    LinkLibraryFeaturePropertySet featureProperties;
+    cmsys::RegularExpression processingOption{
+      "^(LIBRARY_TYPE|UNICITY|OVERRIDE)=((STATIC|SHARED|MODULE|EXECUTABLE)(,("
+      "STATIC|"
+      "SHARED|MODULE|EXECUTABLE)"
+      ")*|YES|NO|DEFAULT|[A-Za-z0-9_]+(,[A-Za-z0-9_]+)*)$"
+    };
+    std::string errorMessage;
+    for (auto const& option : cmList{ featurePropertiesValues }) {
+      if (processingOption.find(option)) {
+        if (processingOption.match(1) == "LIBRARY_TYPE") {
+          featureProperties.LibraryTypes.clear();
+          for (auto const& value :
+               cmTokenize(processingOption.match(2), ","_s)) {
+            if (value == "STATIC") {
+              featureProperties.LibraryTypes.emplace(
+                cmStateEnums::STATIC_LIBRARY);
+            } else if (value == "SHARED") {
+              featureProperties.LibraryTypes.emplace(
+                cmStateEnums::SHARED_LIBRARY);
+            } else if (value == "MODULE") {
+              featureProperties.LibraryTypes.emplace(
+                cmStateEnums::MODULE_LIBRARY);
+            } else if (value == "EXECUTABLE") {
+              featureProperties.LibraryTypes.emplace(cmStateEnums::EXECUTABLE);
+            } else {
+              errorMessage += cmStrCat("  ", option, '\n');
+              break;
+            }
+          }
+          // Always add UNKNOWN type
+          featureProperties.LibraryTypes.emplace(
+            cmStateEnums::UNKNOWN_LIBRARY);
+        } else if (processingOption.match(1) == "UNICITY") {
+          if (processingOption.match(2) == "YES") {
+            featureProperties.Unicity = LinkLibraryFeaturePropertySet::Yes;
+          } else if (processingOption.match(2) == "NO") {
+            featureProperties.Unicity = LinkLibraryFeaturePropertySet::No;
+          } else if (processingOption.match(2) == "DEFAULT") {
+            featureProperties.Unicity = LinkLibraryFeaturePropertySet::Default;
+          } else {
+            errorMessage += cmStrCat("  ", option, '\n');
+          }
+        } else if (processingOption.match(1) == "OVERRIDE") {
+          featureProperties.Override.clear();
+          auto values = cmTokenize(processingOption.match(2), ","_s);
+          featureProperties.Override.insert(values.begin(), values.end());
+        }
+      } else {
+        errorMessage += cmStrCat("  ", option, '\n');
+      }
+    }
+    if (!errorMessage.empty()) {
+      makefile->GetCMakeInstance()->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat("Erroneous option(s) for '", featurePropertiesVariable,
+                 "':\n", errorMessage));
+    }
+    return LinkLibraryFeatureProperties.emplace(feature, featureProperties)
+      .first->second;
+  }
+  return LinkLibraryFeatureProperties
+    .emplace(feature, LinkLibraryFeaturePropertySet{})
+    .first->second;
+}
+
 // LINK_GROUP helpers
 const auto LG_BEGIN = "<LINK_GROUP:"_s;
 const auto LG_END = "</LINK_GROUP:"_s;
@@ -235,7 +343,9 @@
   EntriesProcessing(const cmGeneratorTarget* target,
                     const std::string& linkLanguage, EntryVector& entries,
                     EntryVector& finalEntries)
-    : Entries(entries)
+    : Target(target)
+    , LinkLanguage(linkLanguage)
+    , Entries(entries)
     , FinalEntries(finalEntries)
   {
     const auto* makefile = target->Makefile;
@@ -398,6 +508,18 @@
 
   bool IncludeEntry(LinkEntry const& entry) const
   {
+    if (entry.Feature != cmComputeLinkDepends::LinkEntry::DEFAULT) {
+      auto const& featureProperties = GetLinkLibraryFeatureProperties(
+        this->Target->Makefile, this->LinkLanguage, entry.Feature);
+      if ((entry.Target == nullptr ||
+           featureProperties.LibraryTypes.find(entry.Target->GetType()) !=
+             featureProperties.LibraryTypes.end()) &&
+          featureProperties.Unicity !=
+            LinkLibraryFeaturePropertySet::Default) {
+        return featureProperties.Unicity == LinkLibraryFeaturePropertySet::No;
+      }
+    }
+
     return this->Unicity == None ||
       (this->Unicity == Shared &&
        (entry.Target == nullptr ||
@@ -418,6 +540,8 @@
 
   OrderKind Order = Reverse;
   UnicityKind Unicity = Shared;
+  const cmGeneratorTarget* Target;
+  const std::string& LinkLanguage;
   EntryVector& Entries;
   EntryVector& FinalEntries;
   std::set<size_t> Emitted;
@@ -973,12 +1097,14 @@
     auto ale = this->AddLinkEntry(item, groupIndex.first);
     dependee_index = ale.first;
     LinkEntry& entry = this->EntryList[dependee_index];
+    bool supportedItem = true;
     auto const& itemFeature =
       this->GetCurrentFeature(entry.Item.Value, item.Feature);
     if (inGroup && ale.second && entry.Target != nullptr &&
         (entry.Target->GetType() == cmStateEnums::TargetType::OBJECT_LIBRARY ||
          entry.Target->GetType() ==
            cmStateEnums::TargetType::INTERFACE_LIBRARY)) {
+      supportedItem = false;
       const auto& groupFeature = this->EntryList[groupIndex.first].Feature;
       this->CMakeInstance->IssueMessage(
         MessageType::AUTHOR_WARNING,
@@ -995,30 +1121,27 @@
     }
     if (ale.second) {
       // current item not yet defined
-      if (itemFeature != LinkEntry::DEFAULT && entry.Target != nullptr &&
-          (entry.Target->GetType() ==
-             cmStateEnums::TargetType::OBJECT_LIBRARY ||
-           entry.Target->GetType() ==
-             cmStateEnums::TargetType::INTERFACE_LIBRARY)) {
-        this->CMakeInstance->IssueMessage(
-          MessageType::AUTHOR_WARNING,
-          cmStrCat("The feature '", itemFeature,
-                   "', specified as part of a generator-expression "
-                   "'$<LINK_LIBRARY:",
-                   itemFeature, ">', will not be applied to the ",
-                   (entry.Target->GetType() ==
-                        cmStateEnums::TargetType::OBJECT_LIBRARY
-                      ? "OBJECT"
-                      : "INTERFACE"),
-                   " library '", entry.Item.Value, "'."),
-          this->Target->GetBacktrace());
-      }
       entry.Feature = itemFeature;
-    }
 
-    bool supportedItem = entry.Target == nullptr ||
-      (entry.Target->GetType() != cmStateEnums::TargetType::OBJECT_LIBRARY &&
-       entry.Target->GetType() != cmStateEnums::TargetType::INTERFACE_LIBRARY);
+      if (itemFeature != LinkEntry::DEFAULT && entry.Target != nullptr) {
+        auto const& featureProperties = GetLinkLibraryFeatureProperties(
+          this->Makefile, this->LinkLanguage, itemFeature);
+        if (featureProperties.LibraryTypes.find(entry.Target->GetType()) ==
+            featureProperties.LibraryTypes.end()) {
+          supportedItem = false;
+          entry.Feature = LinkEntry::DEFAULT;
+          this->CMakeInstance->IssueMessage(
+            MessageType::AUTHOR_WARNING,
+            cmStrCat("The feature '", itemFeature,
+                     "', specified as part of a generator-expression "
+                     "'$<LINK_LIBRARY:",
+                     itemFeature, ">', will not be applied to the ",
+                     cmState::GetTargetTypeName(entry.Target->GetType()), " '",
+                     entry.Item.Value, "'."),
+            this->Target->GetBacktrace());
+        }
+      }
+    }
 
     if (supportedItem) {
       if (inGroup) {
@@ -1043,21 +1166,41 @@
         }
       }
       if (entry.Feature != itemFeature) {
-        // incompatibles features occurred
-        this->CMakeInstance->IssueMessage(
-          MessageType::FATAL_ERROR,
-          cmStrCat("Impossible to link target '", this->Target->GetName(),
-                   "' because the link item '", entry.Item.Value,
-                   "', specified ",
-                   (itemFeature == LinkEntry::DEFAULT
-                      ? "without any feature or 'DEFAULT' feature"
-                      : cmStrCat("with the feature '", itemFeature, '\'')),
-                   ", has already occurred ",
-                   (entry.Feature == LinkEntry::DEFAULT
-                      ? "without any feature or 'DEFAULT' feature"
-                      : cmStrCat("with the feature '", entry.Feature, '\'')),
-                   ", which is not allowed."),
-          this->Target->GetBacktrace());
+        bool incompatibleFeatures = true;
+        // check if an override is possible
+        auto const& entryFeatureProperties = GetLinkLibraryFeatureProperties(
+          this->Makefile, this->LinkLanguage, entry.Feature);
+        auto const& itemFeatureProperties = GetLinkLibraryFeatureProperties(
+          this->Makefile, this->LinkLanguage, itemFeature);
+        if (entryFeatureProperties.Override.empty() &&
+            !itemFeatureProperties.Override.empty() &&
+            itemFeatureProperties.Override.find(entry.Feature) !=
+              itemFeatureProperties.Override.end()) {
+          entry.Feature = itemFeature;
+          incompatibleFeatures = false;
+        } else if (!entryFeatureProperties.Override.empty() &&
+                   itemFeatureProperties.Override.empty() &&
+                   entryFeatureProperties.Override.find(itemFeature) !=
+                     entryFeatureProperties.Override.end()) {
+          incompatibleFeatures = false;
+        }
+        if (incompatibleFeatures) {
+          // incompatibles features occurred
+          this->CMakeInstance->IssueMessage(
+            MessageType::FATAL_ERROR,
+            cmStrCat("Impossible to link target '", this->Target->GetName(),
+                     "' because the link item '", entry.Item.Value,
+                     "', specified ",
+                     (itemFeature == LinkEntry::DEFAULT
+                        ? "without any feature or 'DEFAULT' feature"
+                        : cmStrCat("with the feature '", itemFeature, '\'')),
+                     ", has already occurred ",
+                     (entry.Feature == LinkEntry::DEFAULT
+                        ? "without any feature or 'DEFAULT' feature"
+                        : cmStrCat("with the feature '", entry.Feature, '\'')),
+                     ", which is not allowed."),
+            this->Target->GetBacktrace());
+        }
       }
     }
 
diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx
index 2fd7f8a..6eabe9c 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.cxx
+++ b/Source/cmGlobalBorlandMakefileGenerator.cxx
@@ -24,6 +24,7 @@
   this->ToolSupportsColor = true;
   this->UseLinkScript = false;
   cm->GetState()->SetWindowsShell(true);
+  cm->GetState()->SetBorlandMake(true);
   this->IncludeDirective = "!include";
   this->DefineWindowsNULL = true;
   this->PassMakeflags = true;
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index bf66255..aa948a5 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -264,6 +264,27 @@
 #endif
 }
 
+namespace {
+std::string ConvertToMakefilePath(std::string const& path)
+{
+  std::string result;
+  result.reserve(path.size());
+  for (char c : path) {
+    switch (c) {
+      case '\\':
+      case ' ':
+      case '#':
+        result.push_back('\\');
+        CM_FALLTHROUGH;
+      default:
+        result.push_back(c);
+        break;
+    }
+  }
+  return result;
+}
+}
+
 bool cmGlobalXCodeGenerator::FindMakeProgram(cmMakefile* mf)
 {
   // The Xcode generator knows how to lookup its build tool
@@ -653,7 +674,7 @@
   if (regenerate && isGenerateProject) {
     this->CreateReRunCMakeFile(root, gens);
     std::string file =
-      this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile);
+      cmSystemTools::ConvertToOutputPath(this->CurrentReRunCMakeMakefile);
     cmSystemTools::ReplaceString(file, "\\ ", " ");
     cc = cm::make_unique<cmCustomCommand>();
     cc->SetCommandLines(cmMakeSingleCommandLine({ "make", "-f", file }));
@@ -732,7 +753,7 @@
 
   for (const auto& lfile : lfiles) {
     makefileStream << "TARGETS += $(subst $(space),$(spaceplus),$(wildcard "
-                   << this->ConvertToRelativeForMake(lfile) << "))\n";
+                   << ConvertToMakefilePath(lfile) << "))\n";
   }
   makefileStream << '\n';
 
@@ -743,25 +764,25 @@
     makefileStream << ".NOTPARALLEL:\n\n"
                       ".PHONY: all VERIFY_GLOBS\n\n"
                       "all: VERIFY_GLOBS "
-                   << this->ConvertToRelativeForMake(checkCache)
+                   << ConvertToMakefilePath(checkCache)
                    << "\n\n"
                       "VERIFY_GLOBS:\n"
                       "\t"
-                   << this->ConvertToRelativeForMake(
-                        cmSystemTools::GetCMakeCommand())
+                   << ConvertToMakefilePath(cmSystemTools::GetCMakeCommand())
                    << " -P "
-                   << this->ConvertToRelativeForMake(cm->GetGlobVerifyScript())
+                   << ConvertToMakefilePath(cm->GetGlobVerifyScript())
                    << "\n\n";
   }
 
-  makefileStream << this->ConvertToRelativeForMake(checkCache)
-                 << ": $(TARGETS)\n";
-  makefileStream
-    << '\t' << this->ConvertToRelativeForMake(cmSystemTools::GetCMakeCommand())
-    << " -S" << this->ConvertToRelativeForMake(root->GetSourceDirectory())
-    << " -B" << this->ConvertToRelativeForMake(root->GetBinaryDirectory())
-    << (cm->GetIgnoreWarningAsError() ? " --compile-no-warning-as-error" : "")
-    << '\n';
+  makefileStream << ConvertToMakefilePath(checkCache) << ": $(TARGETS)\n";
+  makefileStream << '\t'
+                 << ConvertToMakefilePath(cmSystemTools::GetCMakeCommand())
+                 << " -S" << ConvertToMakefilePath(root->GetSourceDirectory())
+                 << " -B" << ConvertToMakefilePath(root->GetBinaryDirectory())
+                 << (cm->GetIgnoreWarningAsError()
+                       ? " --compile-no-warning-as-error"
+                       : "")
+                 << '\n';
 }
 
 static bool objectIdLessThan(const std::unique_ptr<cmXCodeObject>& l,
@@ -2199,11 +2220,10 @@
   }
 
   std::string cdir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory();
-  cdir = this->ConvertToRelativeForMake(cdir);
+  cdir = cmSystemTools::ConvertToOutputPath(cdir);
   std::string makecmd = cmStrCat(
-    "make -C ", cdir, " -f ",
-    this->ConvertToRelativeForMake(cmStrCat(makefile, "$CONFIGURATION")),
-    " OBJDIR=$(basename \"$OBJECT_FILE_DIR_normal\") all");
+    "make -C ", cdir, " -f ", cmSystemTools::ConvertToOutputPath(makefile),
+    "$CONFIGURATION", " OBJDIR=$(basename \"$OBJECT_FILE_DIR_normal\") all");
   buildphase->AddAttribute("shellScript", this->CreateString(makecmd));
   buildphase->AddAttribute("showEnvVarsInLog", this->CreateString("0"));
 }
@@ -2237,7 +2257,7 @@
       const std::vector<std::string>& outputs = ccg.GetOutputs();
       if (!outputs.empty()) {
         for (auto const& output : outputs) {
-          makefileStream << "\\\n\t" << this->ConvertToRelativeForMake(output);
+          makefileStream << "\\\n\t" << ConvertToMakefilePath(output);
         }
       } else {
         std::ostringstream str;
@@ -2291,7 +2311,7 @@
         // There is at least one output, start the rule for it
         const char* sep = "";
         for (auto const& output : outputs) {
-          makefileStream << sep << this->ConvertToRelativeForMake(output);
+          makefileStream << sep << ConvertToMakefilePath(output);
           sep = " ";
         }
         makefileStream << ": ";
@@ -2300,7 +2320,7 @@
         makefileStream << tname[&ccg.GetCC()] << ": ";
       }
       for (auto const& dep : realDepends) {
-        makefileStream << "\\\n" << this->ConvertToRelativeForMake(dep);
+        makefileStream << "\\\n" << ConvertToMakefilePath(dep);
       }
       makefileStream << '\n';
 
@@ -2317,12 +2337,12 @@
         // Build the command line in a single string.
         std::string cmd2 = ccg.GetCommand(c);
         cmSystemTools::ReplaceString(cmd2, "/./", "/");
-        cmd2 = this->ConvertToRelativeForMake(cmd2);
+        cmd2 = ConvertToMakefilePath(cmd2);
         std::string cmd;
         std::string wd = ccg.GetWorkingDirectory();
         if (!wd.empty()) {
           cmd += "cd ";
-          cmd += this->ConvertToRelativeForMake(wd);
+          cmd += ConvertToMakefilePath(wd);
           cmd += " && ";
         }
         cmd += cmd2;
@@ -2336,7 +2356,7 @@
               target->GetLocalGenerator()->GetMakefile()->GetSource(
                 dep, cmSourceFileLocationKind::Known)) {
           if (dsf->GetPropertyAsBool("SYMBOLIC")) {
-            makefileStream << this->ConvertToRelativeForMake(dep) << ":\n";
+            makefileStream << ConvertToMakefilePath(dep) << ":\n";
           }
         }
       }
@@ -4865,7 +4885,7 @@
           gt->GetType() == cmStateEnums::SHARED_LIBRARY ||
           gt->GetType() == cmStateEnums::MODULE_LIBRARY) {
         std::string tfull = gt->GetFullPath(configName);
-        std::string trel = this->ConvertToRelativeForMake(tfull);
+        std::string trel = ConvertToMakefilePath(tfull);
 
         // Add this target to the post-build phases of its dependencies.
         auto const y = target->GetDependTargets().find(configName);
@@ -4891,7 +4911,7 @@
         auto const x = target->GetDependLibraries().find(configName);
         if (x != target->GetDependLibraries().end()) {
           for (auto const& deplib : x->second) {
-            std::string file = this->ConvertToRelativeForMake(deplib);
+            std::string file = ConvertToMakefilePath(deplib);
             makefileStream << "\\\n\t" << file;
             dummyRules.insert(file);
           }
@@ -4903,7 +4923,7 @@
           std::string d = cmStrCat(this->GetTargetTempDir(gt, configName),
                                    "/lib", objLibName, ".a");
 
-          std::string dependency = this->ConvertToRelativeForMake(d);
+          std::string dependency = ConvertToMakefilePath(d);
           makefileStream << "\\\n\t" << dependency;
           dummyRules.insert(dependency);
         }
@@ -4911,7 +4931,7 @@
         // Write the action to remove the target if it is out of date.
         makefileStream << "\n"
                           "\t/bin/rm -f "
-                       << this->ConvertToRelativeForMake(tfull) << '\n';
+                       << ConvertToMakefilePath(tfull) << '\n';
         // if building for more than one architecture
         // then remove those executables as well
         if (this->Architectures.size() > 1) {
@@ -4921,8 +4941,7 @@
             std::string universalFile = cmStrCat(universal, architecture, '/',
                                                  gt->GetFullName(configName));
             makefileStream << "\t/bin/rm -f "
-                           << this->ConvertToRelativeForMake(universalFile)
-                           << '\n';
+                           << ConvertToMakefilePath(universalFile) << '\n';
           }
         }
         makefileStream << "\n\n";
@@ -5123,12 +5142,6 @@
            "Generate Xcode project files." };
 }
 
-std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake(
-  std::string const& p)
-{
-  return cmSystemTools::ConvertToOutputPath(p);
-}
-
 std::string cmGlobalXCodeGenerator::RelativeToSource(const std::string& p)
 {
   std::string const& rootSrc =
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index 2375e95..14e9308 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -163,7 +163,6 @@
   std::string RelativeToSource(const std::string& p);
   std::string RelativeToRootBinary(const std::string& p);
   std::string RelativeToBinary(const std::string& p);
-  std::string ConvertToRelativeForMake(std::string const& p);
   void CreateCustomCommands(
     cmXCodeObject* buildPhases, cmXCodeObject* sourceBuildPhase,
     cmXCodeObject* headerBuildPhase, cmXCodeObject* resourceBuildPhase,
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 22daa0e..1440771 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -4403,7 +4403,12 @@
   }
 
   // Make sure the output file name has no invalid characters.
-  std::string::size_type pos = output.find_first_of("#<>");
+  const bool hashNotAllowed = lg.GetState()->UseBorlandMake();
+  std::string::size_type pos = output.find_first_of("<>");
+  if (pos == std::string::npos && hashNotAllowed) {
+    pos = output.find_first_of('#');
+  }
+
   if (pos != std::string::npos) {
     lg.GetCMakeInstance()->IssueMessage(
       MessageType::FATAL_ERROR,
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index 72eeb9d..e05eb10 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -716,6 +716,16 @@
   return this->GhsMultiIDE;
 }
 
+void cmState::SetBorlandMake(bool borlandMake)
+{
+  this->BorlandMake = borlandMake;
+}
+
+bool cmState::UseBorlandMake() const
+{
+  return this->BorlandMake;
+}
+
 void cmState::SetWatcomWMake(bool watcomWMake)
 {
   this->WatcomWMake = watcomWMake;
diff --git a/Source/cmState.h b/Source/cmState.h
index 5aceb6a..4dc982f 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -213,6 +213,8 @@
   bool UseWindowsVSIDE() const;
   void SetGhsMultiIDE(bool ghsMultiIDE);
   bool UseGhsMultiIDE() const;
+  void SetBorlandMake(bool borlandMake);
+  bool UseBorlandMake() const;
   void SetWatcomWMake(bool watcomWMake);
   bool UseWatcomWMake() const;
   void SetMinGWMake(bool minGWMake);
@@ -294,6 +296,7 @@
   bool WindowsShell = false;
   bool WindowsVSIDE = false;
   bool GhsMultiIDE = false;
+  bool BorlandMake = false;
   bool WatcomWMake = false;
   bool MinGWMake = false;
   bool NMake = false;
diff --git a/Tests/CustomCommand/CMakeLists.txt b/Tests/CustomCommand/CMakeLists.txt
index d46ee08..c145907 100644
--- a/Tests/CustomCommand/CMakeLists.txt
+++ b/Tests/CustomCommand/CMakeLists.txt
@@ -588,3 +588,12 @@
 # Test empty COMMANDs are omitted
 add_executable(empty_command empty_command.cxx)
 add_custom_command(TARGET empty_command POST_BUILD COMMAND $<0:date>)
+
+# Test OUTPUT allows filenames containing "#" on generators that support this
+if(NOT CMAKE_GENERATOR MATCHES "Borland Makefiles")
+  add_custom_target(file_with_hash ALL DEPENDS "${PROJECT_BINARY_DIR}/hash#in#name.txt")
+  add_custom_command(
+    OUTPUT "${PROJECT_BINARY_DIR}/hash#in#name.txt"
+    COMMAND ${CMAKE_COMMAND} -E touch "${PROJECT_BINARY_DIR}/hash#in#name.txt"
+  )
+endif()
diff --git a/Tests/RunCMake/CXXModules/NoCXX23TargetRequired-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX23TargetRequired-stderr.txt
index e3d31c5..866fa55 100644
--- a/Tests/RunCMake/CXXModules/NoCXX23TargetRequired-stderr.txt
+++ b/Tests/RunCMake/CXXModules/NoCXX23TargetRequired-stderr.txt
@@ -3,7 +3,7 @@
   the "__CMAKE::CXX23" target exist, but it was not provided by the
   toolchain.  Reason:
 
-    (Toolchain does not support discovering `import std` support|Experimental `import std` support not enabled when detecting toolchain|Unsupported generator: [^\n]*)
+    (Toolchain does not support discovering `import std` support|Experimental `import std` support not enabled when detecting toolchain; it must be set before `CXX` is enabled \(usually a `project\(\)` call\)|Unsupported generator: [^\n]*)
 
 
 CMake Generate step failed.  Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/CXXModules/NoCXX26TargetRequired-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX26TargetRequired-stderr.txt
index 8addcb2..6e14f1e 100644
--- a/Tests/RunCMake/CXXModules/NoCXX26TargetRequired-stderr.txt
+++ b/Tests/RunCMake/CXXModules/NoCXX26TargetRequired-stderr.txt
@@ -3,7 +3,7 @@
   the "__CMAKE::CXX26" target exist, but it was not provided by the
   toolchain.  Reason:
 
-    (Toolchain does not support discovering `import std` support|Experimental `import std` support not enabled when detecting toolchain|Unsupported generator: [^\n]*)
+    (Toolchain does not support discovering `import std` support|Experimental `import std` support not enabled when detecting toolchain; it must be set before `CXX` is enabled \(usually a `project\(\)` call\)|Unsupported generator: [^\n]*)
 
 
 CMake Generate step failed.  Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake
index 2ad45ba..a061127 100644
--- a/Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/RunCMakeTest.cmake
@@ -35,3 +35,10 @@
 run_cmake(override-features3)
 run_cmake(override-features4)
 run_cmake(override-features5)
+
+# testing feature properties specification
+run_cmake(bad-feature-properties1)
+run_cmake(bad-feature-properties2)
+run_cmake(bad-feature-properties3)
+run_cmake(bad-feature-properties4)
+run_cmake(bad-feature-properties5)
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties1-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties1-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties1-stderr.txt
new file mode 100644
index 0000000..ac07251
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties1-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error:
+  Erroneous option\(s\) for 'CMAKE_LINK_LIBRARY_feature_PROPERTIES':
+
+    BAD_PROPERTY=XXX
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties1.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties1.cmake
new file mode 100644
index 0000000..e5790a8
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties1.cmake
@@ -0,0 +1,10 @@
+enable_language(C)
+
+set(CMAKE_LINK_LIBRARY_USING_feature "<LIBRARY>")
+set(CMAKE_LINK_LIBRARY_USING_feature_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_feature_PROPERTIES BAD_PROPERTY=XXX)
+
+add_library(dep SHARED empty.c)
+
+add_library(lib SHARED empty.c)
+target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feature,dep>")
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties2-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties2-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties2-stderr.txt
new file mode 100644
index 0000000..ac07251
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties2-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error:
+  Erroneous option\(s\) for 'CMAKE_LINK_LIBRARY_feature_PROPERTIES':
+
+    BAD_PROPERTY=XXX
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties2.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties2.cmake
new file mode 100644
index 0000000..dea98d2
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties2.cmake
@@ -0,0 +1,10 @@
+enable_language(C)
+
+set(CMAKE_LINK_LIBRARY_USING_feature "<LIBRARY>")
+set(CMAKE_LINK_LIBRARY_USING_feature_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_feature_PROPERTIES LIBRARY_TYPE=STATIC BAD_PROPERTY=XXX UNICITY=YES)
+
+add_library(dep SHARED empty.c)
+
+add_library(lib SHARED empty.c)
+target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feature,dep>")
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties3-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties3-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties3-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties3-stderr.txt
new file mode 100644
index 0000000..29f5f66
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties3-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error:
+  Erroneous option\(s\) for 'CMAKE_LINK_LIBRARY_feature_PROPERTIES':
+
+    LIBRARY_TYPE=STATIC,BAD_TYPE
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties3.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties3.cmake
new file mode 100644
index 0000000..0a535db
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties3.cmake
@@ -0,0 +1,10 @@
+enable_language(C)
+
+set(CMAKE_LINK_LIBRARY_USING_feature "<LIBRARY>")
+set(CMAKE_LINK_LIBRARY_USING_feature_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_feature_PROPERTIES LIBRARY_TYPE=STATIC,BAD_TYPE)
+
+add_library(dep SHARED empty.c)
+
+add_library(lib SHARED empty.c)
+target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feature,dep>")
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties4-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties4-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties4-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties4-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties4-stderr.txt
new file mode 100644
index 0000000..29f5f66
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties4-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error:
+  Erroneous option\(s\) for 'CMAKE_LINK_LIBRARY_feature_PROPERTIES':
+
+    LIBRARY_TYPE=STATIC,BAD_TYPE
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties4.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties4.cmake
new file mode 100644
index 0000000..c106653
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties4.cmake
@@ -0,0 +1,10 @@
+enable_language(C)
+
+set(CMAKE_LINK_LIBRARY_USING_feature "<LIBRARY>")
+set(CMAKE_LINK_LIBRARY_USING_feature_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_feature_PROPERTIES UNICITY=YES LIBRARY_TYPE=STATIC,BAD_TYPE)
+
+add_library(dep SHARED empty.c)
+
+add_library(lib SHARED empty.c)
+target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feature,dep>")
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties5-result.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties5-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties5-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties5-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties5-stderr.txt
new file mode 100644
index 0000000..3e57782
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties5-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error:
+  Erroneous option\(s\) for 'CMAKE_LINK_LIBRARY_feature_PROPERTIES':
+
+    UNICITY=YES,NO
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties5.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties5.cmake
new file mode 100644
index 0000000..06efe7e
--- /dev/null
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/bad-feature-properties5.cmake
@@ -0,0 +1,10 @@
+enable_language(C)
+
+set(CMAKE_LINK_LIBRARY_USING_feature "<LIBRARY>")
+set(CMAKE_LINK_LIBRARY_USING_feature_SUPPORTED TRUE)
+set(CMAKE_LINK_LIBRARY_feature_PROPERTIES UNICITY=YES,NO)
+
+add_library(dep SHARED empty.c)
+
+add_library(lib SHARED empty.c)
+target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:feature,dep>")
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored-stderr.txt b/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored-stderr.txt
index f9a99af..8f43a7f 100644
--- a/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored-stderr.txt
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored-stderr.txt
@@ -1,6 +1,6 @@
 CMake Warning \(dev\) at library-ignored.cmake:[0-9]+ \(add_library\):
   The feature 'feat', specified as part of a generator-expression
-  '\$<LINK_LIBRARY:feat>', will not be applied to the INTERFACE library
+  '\$<LINK_LIBRARY:feat>', will not be applied to the INTERFACE_LIBRARY
   'front'.
 Call Stack \(most recent call first\):
   CMakeLists.txt:[0-9]+ \(include\)
@@ -8,7 +8,14 @@
 
 CMake Warning \(dev\) at library-ignored.cmake:[0-9]+ \(add_library\):
   The feature 'feat', specified as part of a generator-expression
-  '\$<LINK_LIBRARY:feat>', will not be applied to the OBJECT library 'dep'.
+  '\$<LINK_LIBRARY:feat>', will not be applied to the OBJECT_LIBRARY 'dep'.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\) at library-ignored.cmake:[0-9]+ \(add_library\):
+  The feature 'feat', specified as part of a generator-expression
+  '\$<LINK_LIBRARY:feat>', will not be applied to the SHARED_LIBRARY 'lib'.
 Call Stack \(most recent call first\):
   CMakeLists.txt:[0-9]+ \(include\)
 This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored.cmake b/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored.cmake
index a888bb8..675b87d 100644
--- a/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored.cmake
+++ b/Tests/RunCMake/GenEx-LINK_LIBRARY/library-ignored.cmake
@@ -2,13 +2,14 @@
 
 set(CMAKE_C_LINK_LIBRARY_USING_feat_SUPPORTED TRUE)
 set(CMAKE_C_LINK_LIBRARY_USING_feat "<LIBRARY>")
+set(CMAKE_C_LINK_LIBRARY_feat_PROPERTIES "LIBRARY_TYPE=STATIC")
 
 add_library(dep OBJECT empty.c)
 
 add_library(lib SHARED empty.c)
 
 add_library(front INTERFACE)
-target_link_libraries(front INTERFACE lib)
+target_link_libraries(front INTERFACE "$<LINK_LIBRARY:feat,lib>")
 
 
 add_library(lib2 SHARED empty.c)
diff --git a/Tests/RunCMake/Swift/EnableSwift.cmake b/Tests/RunCMake/Swift/EnableSwift.cmake
new file mode 100644
index 0000000..19f297a
--- /dev/null
+++ b/Tests/RunCMake/Swift/EnableSwift.cmake
@@ -0,0 +1 @@
+enable_language(Swift)
diff --git a/Tests/RunCMake/Swift/RunCMakeTest.cmake b/Tests/RunCMake/Swift/RunCMakeTest.cmake
index 3711efb..e8a1dab 100644
--- a/Tests/RunCMake/Swift/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Swift/RunCMakeTest.cmake
@@ -70,6 +70,20 @@
     endblock()
 
     block()
+      # Try enabling Swift with a static-library try-compile
+      set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/StaticLibTryCompile-build)
+      set(RunCMake_TEST_OPTIONS -DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY)
+      run_cmake(EnableSwift)
+    endblock()
+
+    block()
+      # Try enabling Swift with an executable try-compile
+      set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ExecutableTryCompile-build)
+      set(RunCMake_TEST_OPTIONS -DCMAKE_TRY_COMPILE_TARGET_TYPE=EXECUTABLE)
+      run_cmake(EnableSwift)
+    endblock()
+
+    block()
       set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ForceResponseFile-build)
       run_cmake(ForceResponseFile)
       set(RunCMake_TEST_NO_CLEAN 1)
diff --git a/Tests/RunCMake/add_custom_command/BadByproduct-stderr.txt b/Tests/RunCMake/add_custom_command/BadByproduct-stderr.txt
index 547fb1c..5741ae5 100644
--- a/Tests/RunCMake/add_custom_command/BadByproduct-stderr.txt
+++ b/Tests/RunCMake/add_custom_command/BadByproduct-stderr.txt
@@ -1,9 +1,3 @@
-CMake Error at BadByproduct.cmake:2 \(add_custom_command\):
-  BYPRODUCTS containing a "#" is not allowed.
-Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
-
-
 CMake Error at BadByproduct.cmake:3 \(add_custom_command\):
   BYPRODUCTS containing a "<" is not allowed.
 Call Stack \(most recent call first\):
@@ -17,7 +11,7 @@
 
 (
 CMake Error at BadByproduct.cmake:5 \(add_custom_command\):
-  BYPRODUCTS containing a "#" is not allowed.
+  BYPRODUCTS containing a ">" is not allowed.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 
diff --git a/Tests/RunCMake/add_custom_command/BadByproduct.cmake b/Tests/RunCMake/add_custom_command/BadByproduct.cmake
index cf00f5b..4fe0b82 100644
--- a/Tests/RunCMake/add_custom_command/BadByproduct.cmake
+++ b/Tests/RunCMake/add_custom_command/BadByproduct.cmake
@@ -1,8 +1,8 @@
 set(CMAKE_DISABLE_SOURCE_CHANGES ON)
-add_custom_command(OUTPUT a BYPRODUCTS "a#")
+
 add_custom_command(OUTPUT b BYPRODUCTS "a<")
 add_custom_command(OUTPUT c BYPRODUCTS "a>")
-add_custom_command(OUTPUT d BYPRODUCTS "$<CONFIG>/#")
+add_custom_command(OUTPUT d BYPRODUCTS "$<CONFIG>/$<ANGLE-R>")
 add_custom_command(OUTPUT e BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/f)
 add_custom_command(OUTPUT f BYPRODUCTS "$<TARGET_PROPERTY:prop>")
 add_custom_command(OUTPUT h BYPRODUCTS "$<OUTPUT_CONFIG:h>")
diff --git a/Tests/RunCMake/add_custom_command/BadOutput-stderr.txt b/Tests/RunCMake/add_custom_command/BadOutput-stderr.txt
index 2e43568..9d25949 100644
--- a/Tests/RunCMake/add_custom_command/BadOutput-stderr.txt
+++ b/Tests/RunCMake/add_custom_command/BadOutput-stderr.txt
@@ -1,9 +1,3 @@
-CMake Error at BadOutput.cmake:2 \(add_custom_command\):
-  OUTPUT containing a "#" is not allowed.
-Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
-
-
 CMake Error at BadOutput.cmake:3 \(add_custom_command\):
   OUTPUT containing a "<" is not allowed.
 Call Stack \(most recent call first\):
@@ -17,7 +11,7 @@
 
 (
 CMake Error at BadOutput.cmake:5 \(add_custom_command\):
-  OUTPUT containing a "#" is not allowed.
+  OUTPUT containing a ">" is not allowed.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 
diff --git a/Tests/RunCMake/add_custom_command/BadOutput.cmake b/Tests/RunCMake/add_custom_command/BadOutput.cmake
index f04bdd1..0f6bd07 100644
--- a/Tests/RunCMake/add_custom_command/BadOutput.cmake
+++ b/Tests/RunCMake/add_custom_command/BadOutput.cmake
@@ -1,8 +1,8 @@
 set(CMAKE_DISABLE_SOURCE_CHANGES ON)
-add_custom_command(OUTPUT "a#" COMMAND a)
+
 add_custom_command(OUTPUT "a<" COMMAND b)
 add_custom_command(OUTPUT "a>" COMMAND c)
-add_custom_command(OUTPUT "$<CONFIG>/#" COMMAND d)
+add_custom_command(OUTPUT "$<CONFIG>/$<ANGLE-R>" COMMAND d)
 add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/e COMMAND f)
 add_custom_command(OUTPUT "$<TARGET_PROPERTY:prop>" COMMAND g)
 add_custom_command(OUTPUT "$<OUTPUT_CONFIG:h>" COMMAND h)
diff --git a/Tests/RunCMake/add_custom_target/BadByproduct-stderr.txt b/Tests/RunCMake/add_custom_target/BadByproduct-stderr.txt
index da9af49..b734ddd 100644
--- a/Tests/RunCMake/add_custom_target/BadByproduct-stderr.txt
+++ b/Tests/RunCMake/add_custom_target/BadByproduct-stderr.txt
@@ -1,9 +1,3 @@
-CMake Error at BadByproduct.cmake:2 \(add_custom_target\):
-  BYPRODUCTS containing a "#" is not allowed.
-Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
-
-
 CMake Error at BadByproduct.cmake:3 \(add_custom_target\):
   BYPRODUCTS containing a "<" is not allowed.
 Call Stack \(most recent call first\):
@@ -17,7 +11,7 @@
 
 (
 CMake Error at BadByproduct.cmake:5 \(add_custom_target\):
-  BYPRODUCTS containing a "#" is not allowed.
+  BYPRODUCTS containing a ">" is not allowed.
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
 
diff --git a/Tests/RunCMake/add_custom_target/BadByproduct.cmake b/Tests/RunCMake/add_custom_target/BadByproduct.cmake
index c317b83..d29c02f 100644
--- a/Tests/RunCMake/add_custom_target/BadByproduct.cmake
+++ b/Tests/RunCMake/add_custom_target/BadByproduct.cmake
@@ -1,8 +1,8 @@
 set(CMAKE_DISABLE_SOURCE_CHANGES ON)
-add_custom_target(a BYPRODUCTS "a#" COMMAND b)
+
 add_custom_target(c BYPRODUCTS "a<" COMMAND d)
 add_custom_target(e BYPRODUCTS "a>" COMMAND f)
-add_custom_target(g BYPRODUCTS "$<CONFIG>/#" COMMAND h)
+add_custom_target(g BYPRODUCTS "$<CONFIG>/$<ANGLE-R>" COMMAND h)
 add_custom_target(i BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/j COMMAND k)
 add_custom_target(l BYPRODUCTS "$<TARGET_PROPERTY:prop>" COMMAND m)
 add_custom_target(n BYPRODUCTS "$<OUTPUT_CONFIG:n>" COMMAND o)
diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake
index 88a7e63..97a96b4 100644
--- a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake
+++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/RunCMakeTest.cmake
@@ -135,4 +135,5 @@
     OR CMAKE_SYSTEM_NAME MATCHES "Darwin|iOS|tvOS|visionOS|watchOS|Linux|BSD|MSYS|CYGWIN")
   run_cmake(feature-WHOLE_ARCHIVE)
   run_cmake_target(feature-WHOLE_ARCHIVE link-exe main)
+  run_cmake_target(feature-WHOLE_ARCHIVE circular-exe main_circular)
 endif()
diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/circular1.c b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/circular1.c
new file mode 100644
index 0000000..80ee413
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/circular1.c
@@ -0,0 +1,6 @@
+void circular2(void);
+
+void circular1(void)
+{
+  circular2();
+}
diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/circular2.c b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/circular2.c
new file mode 100644
index 0000000..751bab5
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/circular2.c
@@ -0,0 +1,7 @@
+
+void circular1(void);
+
+void circular2(void)
+{
+  circular1();
+}
diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/feature-WHOLE_ARCHIVE-circular-exe-stderr-darwin.txt b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/feature-WHOLE_ARCHIVE-circular-exe-stderr-darwin.txt
new file mode 100644
index 0000000..fb4871c
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/feature-WHOLE_ARCHIVE-circular-exe-stderr-darwin.txt
@@ -0,0 +1 @@
+(ld: warning: ignoring duplicate libraries:)?
diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/feature-WHOLE_ARCHIVE.cmake b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/feature-WHOLE_ARCHIVE.cmake
index e525325..5c599c9 100644
--- a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/feature-WHOLE_ARCHIVE.cmake
+++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/feature-WHOLE_ARCHIVE.cmake
@@ -9,3 +9,13 @@
 
 add_executable(main main.c)
 target_link_libraries(main PRIVATE lib)
+
+
+add_library(circular1 STATIC circular1.c)
+add_library(circular2 STATIC circular2.c)
+
+target_link_libraries(circular1 PRIVATE circular2)
+target_link_libraries(circular2 PRIVATE circular1)
+
+add_executable(main_circular main_circular.c)
+target_link_libraries(main_circular PRIVATE $<LINK_LIBRARY:WHOLE_ARCHIVE,circular1>)
diff --git a/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main_circular.c b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main_circular.c
new file mode 100644
index 0000000..16ebee6
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINK_LIBRARY/main_circular.c
@@ -0,0 +1,9 @@
+
+void circular1(void);
+
+int main(void)
+{
+  circular1();
+
+  return 0;
+}