summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x.gitlab/ci/cmake.ps14
-rwxr-xr-x.gitlab/ci/cmake.sh8
-rw-r--r--Help/command/cmake_host_system_information.rst152
-rw-r--r--Help/prop_tgt/HEADER_SETS.rst13
-rw-r--r--Help/prop_tgt/INTERFACE_HEADER_SETS.rst8
-rw-r--r--Help/release/3.22.rst13
-rw-r--r--Help/release/3.23.rst8
-rw-r--r--Help/release/dev/chsi-query-windows-registry.rst5
-rw-r--r--Modules/CheckPIESupported.cmake11
-rw-r--r--Modules/FindGLUT.cmake5
-rw-r--r--Modules/FindGit.cmake6
-rw-r--r--Modules/FindPostgreSQL.cmake4
-rw-r--r--Modules/FindwxWidgets.cmake2
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/cmCMakeHostSystemInformationCommand.cxx108
-rw-r--r--Source/cmCMakePresetsGraphReadJSON.cxx2
-rw-r--r--Source/cmCMakePresetsGraphReadJSONTestPresets.cxx10
-rw-r--r--Source/cmExportBuildFileGenerator.cxx2
-rw-r--r--Source/cmFileAPICodemodel.cxx2
-rw-r--r--Source/cmFileSet.cxx62
-rw-r--r--Source/cmFileSet.h21
-rw-r--r--Source/cmGeneratorExpressionNode.cxx2
-rw-r--r--Source/cmGlobalGenerator.h11
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx24
-rw-r--r--Source/cmGlobalXCodeGenerator.h3
-rw-r--r--Source/cmInstallCommand.cxx3
-rw-r--r--Source/cmLocalGenerator.cxx10
-rw-r--r--Source/cmTarget.cxx102
-rw-r--r--Source/cmTarget.h7
-rw-r--r--Source/cmTargetSourcesCommand.cxx52
-rw-r--r--Source/cmVSSetupHelper.cxx182
-rw-r--r--Source/cmVSSetupHelper.h3
-rw-r--r--Source/cmWindowsRegistry.cxx442
-rw-r--r--Source/cmWindowsRegistry.h55
-rw-r--r--Source/cmakemain.cxx5
-rw-r--r--Tests/RunCMake/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMakePresets/ListConfigurePresetsWorkingDir-stdout.txt7
-rw-r--r--Tests/RunCMake/CMakePresets/RunCMakeTest.cmake10
-rw-r--r--Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake9
-rw-r--r--Tests/RunCMake/ObjectLibrary/TargetOverrideMultiArch-result.txt (renamed from Tests/RunCMake/target_sources/FileSetNoScope-result.txt)0
-rw-r--r--Tests/RunCMake/ObjectLibrary/TargetOverrideMultiArch-stderr.txt5
-rw-r--r--Tests/RunCMake/ObjectLibrary/TargetOverrideMultiArch.cmake3
-rw-r--r--Tests/RunCMake/ObjectLibrary/TargetOverrideSingleArch.cmake3
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchIncludedOneLanguage.cmake17
-rw-r--r--Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadKey1-result.txt (renamed from Tests/RunCMake/target_sources/FileSetNoExistPrivate-result.txt)0
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadKey1-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadKey1.cmake4
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadKey2-result.txt (renamed from Tests/RunCMake/target_sources/FileSetNoExistInterface-result.txt)0
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadKey2-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadKey2.cmake4
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadQuery1-result.txt1
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadQuery1-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadQuery1.cmake1
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2-result.txt1
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2-stderr.txt5
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2.cmake1
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadView1-result.txt1
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadView1-stderr.txt5
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadView1.cmake1
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadView2-result.txt1
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadView2-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadView2.cmake1
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadView3-result.txt1
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadView3-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_BadView3.cmake1
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_NoArgs-result.txt1
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_NoArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_NoArgs.cmake1
-rw-r--r--Tests/RunCMake/cmake_host_system_information/Registry_Query.cmake232
-rw-r--r--Tests/RunCMake/cmake_host_system_information/RunCMakeTest.cmake24
-rw-r--r--Tests/RunCMake/cmake_host_system_information/registry_data.regbin0 -> 2322 bytes
-rw-r--r--Tests/RunCMake/target_sources/FileSetImport.cmake4
-rw-r--r--Tests/RunCMake/target_sources/FileSetNoExistInterface-stderr.txt4
-rw-r--r--Tests/RunCMake/target_sources/FileSetNoExistPrivate-stderr.txt4
-rw-r--r--Tests/RunCMake/target_sources/FileSetNoExistPrivate.cmake7
-rw-r--r--Tests/RunCMake/target_sources/FileSetNoScope-stderr.txt4
-rw-r--r--Tests/RunCMake/target_sources/FileSetNoScope.cmake6
-rw-r--r--Tests/RunCMake/target_sources/FileSetProperties.cmake4
-rw-r--r--Tests/RunCMake/target_sources/FileSetReadOnlyInterface-result.txt1
-rw-r--r--Tests/RunCMake/target_sources/FileSetReadOnlyInterface-stderr.txt5
-rw-r--r--Tests/RunCMake/target_sources/FileSetReadOnlyInterface.cmake (renamed from Tests/RunCMake/target_sources/FileSetNoExistInterface.cmake)3
-rw-r--r--Tests/RunCMake/target_sources/FileSetReadOnlyPrivate-result.txt1
-rw-r--r--Tests/RunCMake/target_sources/FileSetReadOnlyPrivate-stderr.txt5
-rw-r--r--Tests/RunCMake/target_sources/FileSetReadOnlyPrivate.cmake4
-rw-r--r--Tests/RunCMake/target_sources/RunCMakeTest.cmake5
87 files changed, 1519 insertions, 257 deletions
diff --git a/.gitlab/ci/cmake.ps1 b/.gitlab/ci/cmake.ps1
index 5d01e3f..fd8e29f 100755
--- a/.gitlab/ci/cmake.ps1
+++ b/.gitlab/ci/cmake.ps1
@@ -1,7 +1,7 @@
$erroractionpreference = "stop"
-$version = "3.21.0"
-$sha256sum = "C7B88C907A753F4EC86E43DDC89F91F70BF1B011859142F7F29E6D51EA4ABB3C"
+$version = "3.23.1"
+$sha256sum = "9B509CC4EB7191DC128CFA3F2170036F9CBC7D9D5F93FF7FAFC5B2D77B3B40DC"
$filename = "cmake-$version-windows-x86_64"
$tarball = "$filename.zip"
diff --git a/.gitlab/ci/cmake.sh b/.gitlab/ci/cmake.sh
index c37f6dc..7d964ee 100755
--- a/.gitlab/ci/cmake.sh
+++ b/.gitlab/ci/cmake.sh
@@ -2,22 +2,22 @@
set -e
-readonly version="3.21.0"
+readonly version="3.23.1"
case "$(uname -s)-$(uname -m)" in
Linux-x86_64)
shatool="sha256sum"
- sha256sum="d54ef6909f519740bc85cec07ff54574cd1e061f9f17357d9ace69f61c6291ce"
+ sha256sum="f3c654b2e226b9d43369e0bd8487c51618d4dbe5a1af929dd32af7e6ca432d60"
platform="linux-x86_64"
;;
Linux-aarch64)
shatool="sha256sum"
- sha256sum="b1e46825bf370f45f8f47c3a497b1122759ee41fbd60187e525f517a4b0934eb"
+ sha256sum="74062efddeb935bce3d33694a4db534cef9a650f77a9a153a9f217d9dc385c75"
platform="linux-aarch64"
;;
Darwin-*)
shatool="shasum -a 256"
- sha256sum="c1c6f19dfc9c658a48b5aed22806595b2337bb3aedb71ab826552f74f568719f"
+ sha256sum="f794ed92ccb4e9b6619a77328f313497d7decf8fb7e047ba35a348b838e0e1e2"
platform="macos-universal"
;;
*)
diff --git a/Help/command/cmake_host_system_information.rst b/Help/command/cmake_host_system_information.rst
index 998e146..f47615a 100644
--- a/Help/command/cmake_host_system_information.rst
+++ b/Help/command/cmake_host_system_information.rst
@@ -1,9 +1,23 @@
cmake_host_system_information
-----------------------------
-Query host system specific information.
+Query various host system information.
-.. code-block:: cmake
+Synopsis
+^^^^^^^^
+
+.. parsed-literal::
+
+ `Query host system specific information`_
+ cmake_host_system_information(RESULT <variable> QUERY <key> ...)
+
+ `Query Windows registry`_
+ cmake_host_system_information(RESULT <variable> QUERY WINDOWS_REGISTRY <key> ...)
+
+Query host system specific information
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+::
cmake_host_system_information(RESULT <variable> QUERY <key> ...)
@@ -180,7 +194,7 @@ distribution-specific files`_ to collect OS identification data and map it
into `man 5 os-release`_ variables.
Fallback Interface Variables
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+""""""""""""""""""""""""""""
.. variable:: CMAKE_GET_OS_RELEASE_FALLBACK_SCRIPTS
@@ -246,3 +260,135 @@ Example:
.. _man 5 os-release: https://www.freedesktop.org/software/systemd/man/os-release.html
.. _various distribution-specific files: http://linuxmafia.com/faq/Admin/release-files.html
+
+Query Windows registry
+^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.24
+
+::
+
+ cmake_host_system_information(RESULT <variable>
+ QUERY WINDOWS_REGISTRY <key> [VALUE_NAMES|SUBKEYS|VALUE <name>]
+ [VIEW (64|32|64_32|32_64|HOST|TARGET|BOTH)]
+ [SEPARATOR <separator>]
+ [ERROR_VARIABLE <result>])
+
+Performs query operations on local computer registry subkey. Returns a list of
+subkeys or value names that are located under the specified subkey in the
+registry or the data of the specified value name. The result of the queried
+entity is stored in ``<variable>``.
+
+.. note::
+
+ Querying registry for any other platforms than ``Windows``, including
+ ``CYGWIN``, will always returns an empty string and sets an error message in
+ the variable specified with sub-option ``ERROR_VARIABLE``.
+
+``<key>`` specify the full path of a subkey on the local computer. The
+``<key>`` must include a valid root key. Valid root keys for the local computer
+are:
+
+* ``HKLM`` or ``HKEY_LOCAL_MACHINE``
+* ``HKCU`` or ``HKEY_CURRENT_USER``
+* ``HKCR`` or ``HKEY_CLASSES_ROOT``
+* ``HKU`` or ``HKEY_USERS``
+* ``HKCC`` or ``HKEY_CURRENT_CONFIG``
+
+And, optionally, the path to a subkey under the specified root key. The path
+separator can be the slash or the backslash. ``<key>`` is not case sensitive.
+For example:
+
+.. code-block:: cmake
+
+ cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "HKLM")
+ cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Kitware")
+ cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "HKCU\\SOFTWARE\\Kitware")
+
+``VALUE_NAMES``
+ Request the list of value names defined under ``<key>``. If a default value
+ is defined, it will be identified with the special name ``(default)``.
+
+``SUBKEYS``
+ Request the list of subkeys defined under ``<key>``.
+
+``VALUE <name>``
+ Request the data stored in value named ``<name>``. If ``VALUE`` is not
+ specified or argument is the special name ``(default)``, the content of the
+ default value, if any, will be returned.
+
+ .. code-block:: cmake
+
+ # query default value for HKLM/SOFTWARE/Kitware key
+ cmake_host_system_information(RESULT result
+ QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Kitware")
+
+ # query default value for HKLM/SOFTWARE/Kitware key using special value name
+ cmake_host_system_information(RESULT result
+ QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Kitware"
+ VALUE "(default)")
+
+ Supported types are:
+
+ * ``REG_SZ``.
+ * ``REG_EXPAND_SZ``. The returned data is expanded.
+ * ``REG_MULTI_SZ``. The returned is expressed as a CMake list. See also
+ ``SEPARATOR`` sub-option.
+ * ``REG_DWORD``.
+ * ``REG_QWORD``.
+
+ For all other types, an empty string is returned.
+
+``VIEW``
+ Specify which registry views must be queried. When not specified, ``BOTH``
+ view is used.
+
+ ``64``
+ Query the 64bit registry. On ``32bit Windows``, returns always an empty
+ string.
+
+ ``32``
+ Query the 32bit registry.
+
+ ``64_32``
+ For ``VALUE`` sub-option or default value, query the registry using view
+ ``64``, and if the request failed, query the registry using view ``32``.
+ For ``VALUE_NAMES`` and ``SUBKEYS`` sub-options, query both views (``64``
+ and ``32``) and merge the results (sorted and duplicates removed).
+
+ ``32_64``
+ For ``VALUE`` sub-option or default value, query the registry using view
+ ``32``, and if the request failed, query the registry using view ``64``.
+ For ``VALUE_NAMES`` and ``SUBKEYS`` sub-options, query both views (``32``
+ and ``64``) and merge the results (sorted and duplicates removed).
+
+ ``HOST``
+ Query the registry matching the architecture of the host: ``64`` on ``64bit
+ Windows`` and ``32`` on ``32bit Windows``.
+
+ ``TARGET``
+ Query the registry matching the architecture specified by
+ :variable:`CMAKE_SIZEOF_VOID_P` variable. If not defined, fallback to
+ ``HOST`` view.
+
+ ``BOTH``
+ Query both views (``32`` and ``64``). The order depends of the following
+ rules: If :variable:`CMAKE_SIZEOF_VOID_P` variable is defined. Use the
+ following view depending of the content of this variable:
+
+ * ``8``: ``64_32``
+ * ``4``: ``32_64``
+
+ If :variable:`CMAKE_SIZEOF_VOID_P` variable is not defined, rely on
+ architecture of the host:
+
+ * ``64bit``: ``64_32``
+ * ``32bit``: ``32``
+
+``SEPARATOR``
+ Specify the separator character for ``REG_MULTI_SZ`` type. When not
+ specified, the character ``\0`` is used.
+
+``ERROR_VARIABLE <result>``
+ Returns any error raised during query operation. In case of success, the
+ variable holds an empty string.
diff --git a/Help/prop_tgt/HEADER_SETS.rst b/Help/prop_tgt/HEADER_SETS.rst
index fcf723e..ceb1df5 100644
--- a/Help/prop_tgt/HEADER_SETS.rst
+++ b/Help/prop_tgt/HEADER_SETS.rst
@@ -3,14 +3,13 @@ HEADER_SETS
.. versionadded:: 3.23
-List of the target's ``PRIVATE`` and ``PUBLIC`` header sets (i.e. all
-file sets with the type ``HEADERS``). Files listed in these file sets
-are treated as source files for the purpose of IDE integration.
-The files also have their :prop_sf:`HEADER_FILE_ONLY` property set to
-``TRUE``.
+Read-only list of the target's ``PRIVATE`` and ``PUBLIC`` header sets (i.e.
+all file sets with the type ``HEADERS``). Files listed in these file sets are
+treated as source files for the purpose of IDE integration. The files also
+have their :prop_sf:`HEADER_FILE_ONLY` property set to ``TRUE``.
-This property is normally only set by :command:`target_sources(FILE_SET)`
-rather than being manipulated directly.
+Header sets may be defined using the :command:`target_sources` command
+``FILE_SET`` option with type ``HEADERS``.
See also :prop_tgt:`HEADER_SET_<NAME>`, :prop_tgt:`HEADER_SET` and
:prop_tgt:`INTERFACE_HEADER_SETS`.
diff --git a/Help/prop_tgt/INTERFACE_HEADER_SETS.rst b/Help/prop_tgt/INTERFACE_HEADER_SETS.rst
index 62db5b3..2d3bdac 100644
--- a/Help/prop_tgt/INTERFACE_HEADER_SETS.rst
+++ b/Help/prop_tgt/INTERFACE_HEADER_SETS.rst
@@ -3,12 +3,12 @@ INTERFACE_HEADER_SETS
.. versionadded:: 3.23
-List of the target's ``INTERFACE`` and ``PUBLIC`` header sets (i.e. all
-file sets with the type ``HEADERS``). Files listed in these header sets
+Read-only list of the target's ``INTERFACE`` and ``PUBLIC`` header sets (i.e.
+all file sets with the type ``HEADERS``). Files listed in these header sets
can be installed with :command:`install(TARGETS)` and exported with
:command:`install(EXPORT)` and :command:`export`.
-This property is normally only set by :command:`target_sources(FILE_SET)`
-rather than being manipulated directly.
+Header sets may be defined using the :command:`target_sources` command
+``FILE_SET`` option with type ``HEADERS``.
See also :prop_tgt:`HEADER_SETS`.
diff --git a/Help/release/3.22.rst b/Help/release/3.22.rst
index efac925..00e93f6 100644
--- a/Help/release/3.22.rst
+++ b/Help/release/3.22.rst
@@ -151,9 +151,9 @@ Changes made since CMake 3.22.0 include the following.
3.22.1
------
-This version made no changes to documented features or interfaces.
-Some implementation updates were made to support ecosystem changes
-and/or fix regressions.
+* This version made no changes to documented features or interfaces.
+ Some implementation updates were made to support ecosystem changes
+ and/or fix regressions.
3.22.2
------
@@ -169,3 +169,10 @@ and/or fix regressions.
errors in existing projects. The fix has been reverted to restore
compatibility. The fix may be restored in a future version of CMake
via a policy.
+
+3.22.4
+------
+
+* This version made no changes to documented features or interfaces.
+ Some implementation updates were made to support ecosystem changes
+ and/or fix regressions.
diff --git a/Help/release/3.23.rst b/Help/release/3.23.rst
index 257c3d5..2febbec 100644
--- a/Help/release/3.23.rst
+++ b/Help/release/3.23.rst
@@ -114,8 +114,8 @@ Variables
Properties
----------
-* The :prop_tgt:`HEADER_SETS` and :prop_tgt:`INTERFACE_HEADER_SETS` target
- properties were added to list header sets associated with a target.
+* The :prop_tgt:`HEADER_SETS` and :prop_tgt:`INTERFACE_HEADER_SETS` read-only
+ target properties were added to list header sets associated with a target.
* The :prop_tgt:`HEADER_SET` and :prop_tgt:`HEADER_SET_<NAME>` target
properties were added to list files in the default header set
@@ -278,3 +278,7 @@ Changes made since CMake 3.23.0 include the following.
targets. Pending further work in a future version of CMake, it is now
an error to add a ``FILE_SET`` of type ``HEADERS`` to such targets on
Apple platforms.
+
+* The :prop_tgt:`HEADER_SETS` and :prop_tgt:`INTERFACE_HEADER_SETS` target
+ properties added in CMake 3.23.0 are now read-only records of the header
+ sets created by the :command:`target_sources` command.
diff --git a/Help/release/dev/chsi-query-windows-registry.rst b/Help/release/dev/chsi-query-windows-registry.rst
new file mode 100644
index 0000000..e75bbd8
--- /dev/null
+++ b/Help/release/dev/chsi-query-windows-registry.rst
@@ -0,0 +1,5 @@
+chsi-query-windows-registry
+---------------------------
+
+* :command:`cmake_host_system_information` command gains the capability, on
+ ``Windows`` platform, to query the registry.
diff --git a/Modules/CheckPIESupported.cmake b/Modules/CheckPIESupported.cmake
index 6424472..452348b 100644
--- a/Modules/CheckPIESupported.cmake
+++ b/Modules/CheckPIESupported.cmake
@@ -22,10 +22,13 @@ property for executables will be honored at link time.
Options are:
``OUTPUT_VARIABLE <output>``
- Set ``<output>`` variable with details about any error.
+ Set ``<output>`` variable with details about any error. If the check is
+ bypassed because it uses cached results from a previous call, the output
+ will be empty even if errors were present in the previous call.
``LANGUAGES <lang>...``
Check the linkers used for each of the specified languages.
+ If this option is not provided, the command checks all enabled languages.
``C``, ``CXX``, ``Fortran`` are supported.
@@ -43,9 +46,9 @@ Variables
For each language checked, two boolean cache variables are defined.
``CMAKE_<lang>_LINK_PIE_SUPPORTED``
- Set to ``YES`` if ``PIE`` is supported by the linker and ``NO`` otherwise.
+ Set to true if ``PIE`` is supported by the linker and false otherwise.
``CMAKE_<lang>_LINK_NO_PIE_SUPPORTED``
- Set to ``YES`` if ``NO_PIE`` is supported by the linker and ``NO`` otherwise.
+ Set to true if ``NO_PIE`` is supported by the linker and false otherwise.
Examples
^^^^^^^^
@@ -139,7 +142,7 @@ function (check_pie_supported)
# no support at link time. Set cache variables to NO
set(CMAKE_${lang}_LINK_PIE_SUPPORTED NO CACHE INTERNAL "PIE (${lang})")
set(CMAKE_${lang}_LINK_NO_PIE_SUPPORTED NO CACHE INTERNAL "NO_PIE (${lang})")
- string (APPEND outputs "PIE and NO_PIE are not supported by linker for ${lang}")
+ string (APPEND outputs "PIE and NO_PIE are not supported by linker for ${lang}\n")
endif()
endforeach()
diff --git a/Modules/FindGLUT.cmake b/Modules/FindGLUT.cmake
index 7a16048..43041c5 100644
--- a/Modules/FindGLUT.cmake
+++ b/Modules/FindGLUT.cmake
@@ -97,6 +97,9 @@ endfunction()
find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
pkg_check_modules(GLUT QUIET glut)
+ if(NOT GLUT_FOUND)
+ pkg_check_modules(GLUT QUIET freeglut)
+ endif()
if(GLUT_FOUND)
# GLUT_INCLUDE_DIRS is now the official result variable, but
# older versions of CMake only provided GLUT_INCLUDE_DIR.
@@ -111,7 +114,7 @@ if(WIN32)
find_path( GLUT_INCLUDE_DIR NAMES GL/glut.h
PATHS ${GLUT_ROOT_PATH}/include )
mark_as_advanced(GLUT_INCLUDE_DIR)
- find_library( GLUT_glut_LIBRARY_RELEASE NAMES glut glut32 freeglut
+ find_library( GLUT_glut_LIBRARY_RELEASE NAMES freeglut glut glut32
PATHS
${OPENGL_LIBRARY_DIR}
${GLUT_ROOT_PATH}/Release
diff --git a/Modules/FindGit.cmake b/Modules/FindGit.cmake
index 99850b4..08a386a 100644
--- a/Modules/FindGit.cmake
+++ b/Modules/FindGit.cmake
@@ -31,16 +31,16 @@ Example usage:
endif()
#]=======================================================================]
-# Look for 'git' or 'eg' (easy git)
+# Look for 'git'
#
-set(git_names git eg)
+set(git_names git)
# Prefer .cmd variants on Windows unless running in a Makefile
# in the MSYS shell.
#
if(CMAKE_HOST_WIN32)
if(NOT CMAKE_GENERATOR MATCHES "MSYS")
- set(git_names git.cmd git eg.cmd eg)
+ set(git_names git.cmd git)
# GitHub search path for Windows
file(GLOB github_path
"$ENV{LOCALAPPDATA}/Github/PortableGit*/cmd"
diff --git a/Modules/FindPostgreSQL.cmake b/Modules/FindPostgreSQL.cmake
index 25c5c09..2233aa0 100644
--- a/Modules/FindPostgreSQL.cmake
+++ b/Modules/FindPostgreSQL.cmake
@@ -53,7 +53,7 @@ is set regardless of the presence of the ``Server`` component in find_package ca
# In Windows the default installation of PostgreSQL uses that as part of the path.
# E.g C:\Program Files\PostgreSQL\8.4.
# Currently, the following version numbers are known to this module:
-# "13" "12" "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0"
+# "14" "13" "12" "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0"
#
# To use this variable just do something like this:
# set(PostgreSQL_ADDITIONAL_VERSIONS "9.2" "8.4.4")
@@ -102,7 +102,7 @@ set(PostgreSQL_ROOT_DIR_MESSAGE "Set the PostgreSQL_ROOT system variable to wher
set(PostgreSQL_KNOWN_VERSIONS ${PostgreSQL_ADDITIONAL_VERSIONS}
- "13" "12" "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0")
+ "14" "13" "12" "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0")
# Define additional search paths for root directories.
set( PostgreSQL_ROOT_DIRECTORIES
diff --git a/Modules/FindwxWidgets.cmake b/Modules/FindwxWidgets.cmake
index 63af9b6..f7996ba 100644
--- a/Modules/FindwxWidgets.cmake
+++ b/Modules/FindwxWidgets.cmake
@@ -218,7 +218,7 @@ endif()
#=====================================================================
# Determine whether unix or win32 paths should be used
#=====================================================================
-if(WIN32 AND NOT CYGWIN AND NOT MSYS AND NOT CMAKE_CROSSCOMPILING)
+if(WIN32 AND NOT CYGWIN AND NOT MSYS AND NOT MINGW AND NOT CMAKE_CROSSCOMPILING)
set(wxWidgets_FIND_STYLE "win32")
else()
set(wxWidgets_FIND_STYLE "unix")
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 7661235..c245f68 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -460,6 +460,8 @@ set(SRCS
cmVariableWatch.h
cmVersion.cxx
cmVersion.h
+ cmWindowsRegistry.cxx
+ cmWindowsRegistry.h
cmWorkerPool.cxx
cmWorkerPool.h
cmWorkingDirectory.cxx
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index c85060b..9bcb3bf 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 23)
-set(CMake_VERSION_PATCH 20220411)
+set(CMake_VERSION_PATCH 20220414)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx
index 3922c56..0c41c68 100644
--- a/Source/cmCMakeHostSystemInformationCommand.cxx
+++ b/Source/cmCMakeHostSystemInformationCommand.cxx
@@ -9,6 +9,7 @@
#include <map>
#include <string>
#include <type_traits>
+#include <unordered_map>
#include <utility>
#include <cm/optional>
@@ -19,10 +20,13 @@
#include "cmsys/Glob.hxx"
#include "cmsys/SystemInformation.hxx"
+#include "cmArgumentParser.h"
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
+#include "cmRange.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
+#include "cmWindowsRegistry.h"
#ifdef _WIN32
# include "cmAlgorithms.h"
@@ -459,6 +463,105 @@ cm::optional<std::string> GetValueChained(GetterFn current, Next... chain)
}
return GetValueChained(chain...);
}
+
+template <typename Range>
+bool QueryWindowsRegistry(Range args, cmExecutionStatus& status,
+ std::string const& variable)
+{
+ using View = cmWindowsRegistry::View;
+ static std::unordered_map<cm::string_view, cmWindowsRegistry::View>
+ ViewDefinitions{
+ { "BOTH"_s, View::Both }, { "HOST"_s, View::Host },
+ { "TARGET"_s, View::Target }, { "32"_s, View::Reg32 },
+ { "64"_s, View::Reg64 }, { "32_64"_s, View::Reg32_64 },
+ { "64_32"_s, View::Reg64_32 }
+ };
+
+ if (args.empty()) {
+ status.SetError("missing <key> specification.");
+ return false;
+ }
+ std::string const& key = *args.begin();
+
+ struct Arguments
+ {
+ std::string ValueName;
+ bool ValueNames = false;
+ bool SubKeys = false;
+ std::string View;
+ std::string Separator;
+ std::string ErrorVariable;
+ };
+ cmArgumentParser<Arguments> parser;
+ parser.Bind("VALUE"_s, &Arguments::ValueName)
+ .Bind("VALUE_NAMES"_s, &Arguments::ValueNames)
+ .Bind("SUBKEYS"_s, &Arguments::SubKeys)
+ .Bind("VIEW"_s, &Arguments::View)
+ .Bind("SEPARATOR"_s, &Arguments::Separator)
+ .Bind("ERROR_VARIABLE"_s, &Arguments::ErrorVariable);
+ std::vector<std::string> invalidArgs;
+ std::vector<std::string> keywordsMissingValue;
+
+ Arguments const arguments =
+ parser.Parse(args.advance(1), &invalidArgs, &keywordsMissingValue);
+ if (!invalidArgs.empty()) {
+ status.SetError(cmStrCat("given invalid argument(s) \"",
+ cmJoin(invalidArgs, ", "_s), "\"."));
+ return false;
+ }
+ if (!keywordsMissingValue.empty()) {
+ status.SetError(cmStrCat("missing expected value for argument(s) \"",
+ cmJoin(keywordsMissingValue, ", "_s), "\"."));
+ return false;
+ }
+ if ((!arguments.ValueName.empty() &&
+ (arguments.ValueNames || arguments.SubKeys)) ||
+ (arguments.ValueName.empty() && arguments.ValueNames &&
+ arguments.SubKeys)) {
+ status.SetError("given mutually exclusive sub-options \"VALUE\", "
+ "\"VALUE_NAMES\" or \"SUBKEYS\".");
+ return false;
+ }
+ if (!arguments.View.empty() &&
+ ViewDefinitions.find(arguments.View) == ViewDefinitions.end()) {
+ status.SetError(
+ cmStrCat("given invalid value for \"VIEW\": ", arguments.View, '.'));
+ return false;
+ }
+
+ auto& makefile = status.GetMakefile();
+
+ makefile.AddDefinition(variable, ""_s);
+
+ auto view =
+ arguments.View.empty() ? View::Both : ViewDefinitions[arguments.View];
+ cmWindowsRegistry registry(makefile);
+ if (arguments.ValueNames) {
+ auto result = registry.GetValueNames(key, view);
+ if (result) {
+ makefile.AddDefinition(variable, cmJoin(*result, ";"_s));
+ }
+ } else if (arguments.SubKeys) {
+ auto result = registry.GetSubKeys(key, view);
+ if (result) {
+ makefile.AddDefinition(variable, cmJoin(*result, ";"_s));
+ }
+ } else {
+ auto result =
+ registry.ReadValue(key, arguments.ValueName, view, arguments.Separator);
+ if (result) {
+ makefile.AddDefinition(variable, *result);
+ }
+ }
+
+ // return error message if requested
+ if (!arguments.ErrorVariable.empty()) {
+ makefile.AddDefinition(arguments.ErrorVariable, registry.GetLastError());
+ }
+
+ return true;
+}
+
// END Private functions
} // anonymous namespace
@@ -481,6 +584,11 @@ bool cmCMakeHostSystemInformationCommand(std::vector<std::string> const& args,
return false;
}
+ if (args[current_index + 1] == "WINDOWS_REGISTRY"_s) {
+ return QueryWindowsRegistry(cmMakeRange(args).advance(current_index + 2),
+ status, variable);
+ }
+
static cmsys::SystemInformation info;
static auto initialized = false;
if (!initialized) {
diff --git a/Source/cmCMakePresetsGraphReadJSON.cxx b/Source/cmCMakePresetsGraphReadJSON.cxx
index e68f0fa..0d3a91f 100644
--- a/Source/cmCMakePresetsGraphReadJSON.cxx
+++ b/Source/cmCMakePresetsGraphReadJSON.cxx
@@ -569,7 +569,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile(
}
// Support for TestOutputTruncation added in version 5.
- if (v < 5 && preset.Output) {
+ if (v < 5 && preset.Output && preset.Output->TestOutputTruncation) {
return ReadFileResult::TEST_OUTPUT_TRUNCATION_UNSUPPORTED;
}
diff --git a/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx b/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx
index 43eccfe..b874575 100644
--- a/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx
+++ b/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx
@@ -58,10 +58,10 @@ auto const TestPresetOptionalOutputVerbosityHelper =
TestPresetOutputVerbosityHelper);
ReadFileResult TestPresetOutputTruncationHelper(
- cmCTestTypes::TruncationMode& out, const Json::Value* value)
+ cm::optional<cmCTestTypes::TruncationMode>& out, const Json::Value* value)
{
if (!value) {
- out = cmCTestTypes::TruncationMode::Tail;
+ out = cm::nullopt;
return ReadFileResult::READ_OK;
}
@@ -87,10 +87,6 @@ ReadFileResult TestPresetOutputTruncationHelper(
return ReadFileResult::INVALID_PRESET;
}
-auto const TestPresetOptionalTruncationHelper =
- cmJSONOptionalHelper<cmCTestTypes::TruncationMode, ReadFileResult>(
- ReadFileResult::READ_OK, TestPresetOutputTruncationHelper);
-
auto const TestPresetOptionalOutputHelper =
cmJSONOptionalHelper<TestPreset::OutputOptions, ReadFileResult>(
ReadFileResult::READ_OK,
@@ -121,7 +117,7 @@ auto const TestPresetOptionalOutputHelper =
cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
.Bind("testOutputTruncation"_s,
&TestPreset::OutputOptions::TestOutputTruncation,
- TestPresetOptionalTruncationHelper, false)
+ TestPresetOutputTruncationHelper, false)
.Bind("maxTestNameWidth"_s, &TestPreset::OutputOptions::MaxTestNameWidth,
cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false));
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index f22c716..a306fdd 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -190,7 +190,7 @@ cmStateEnums::TargetType cmExportBuildFileGenerator::GetExportTargetType(
// to support transitive usage requirements on other targets that
// use the object library.
if (targetType == cmStateEnums::OBJECT_LIBRARY &&
- !this->LG->GetGlobalGenerator()->HasKnownObjectFileLocation(nullptr)) {
+ !target->Target->HasKnownObjectFileLocation(nullptr)) {
targetType = cmStateEnums::INTERFACE_LIBRARY;
}
return targetType;
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index 40e1d2e..dd0540c 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -1728,7 +1728,7 @@ Json::Value Target::DumpArtifacts()
// Object libraries have only object files as artifacts.
if (this->GT->GetType() == cmStateEnums::OBJECT_LIBRARY) {
- if (!this->GT->GetGlobalGenerator()->HasKnownObjectFileLocation(nullptr)) {
+ if (!this->GT->Target->HasKnownObjectFileLocation(nullptr)) {
return artifacts;
}
std::vector<cmSourceFile const*> objectSources;
diff --git a/Source/cmFileSet.cxx b/Source/cmFileSet.cxx
index 2c06dc6..1d1d29e 100644
--- a/Source/cmFileSet.cxx
+++ b/Source/cmFileSet.cxx
@@ -7,19 +7,79 @@
#include <utility>
#include <vector>
+#include <cmext/string_view>
+
#include "cmsys/RegularExpression.hxx"
#include "cmGeneratorExpression.h"
#include "cmListFileCache.h"
#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmake.h"
-cmFileSet::cmFileSet(std::string name, std::string type)
+cm::static_string_view cmFileSetVisibilityToName(cmFileSetVisibility vis)
+{
+ switch (vis) {
+ case cmFileSetVisibility::Interface:
+ return "INTERFACE"_s;
+ case cmFileSetVisibility::Public:
+ return "PUBLIC"_s;
+ case cmFileSetVisibility::Private:
+ return "PRIVATE"_s;
+ }
+ return ""_s;
+}
+
+cmFileSetVisibility cmFileSetVisibilityFromName(cm::string_view name,
+ cmMakefile* mf)
+{
+ if (name == "INTERFACE"_s) {
+ return cmFileSetVisibility::Interface;
+ }
+ if (name == "PUBLIC"_s) {
+ return cmFileSetVisibility::Public;
+ }
+ if (name == "PRIVATE"_s) {
+ return cmFileSetVisibility::Private;
+ }
+ mf->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("File set visibility \"", name, "\" is not valid."));
+ return cmFileSetVisibility::Private;
+}
+
+bool cmFileSetVisibilityIsForSelf(cmFileSetVisibility vis)
+{
+ switch (vis) {
+ case cmFileSetVisibility::Interface:
+ return false;
+ case cmFileSetVisibility::Public:
+ case cmFileSetVisibility::Private:
+ return true;
+ }
+ return false;
+}
+
+bool cmFileSetVisibilityIsForInterface(cmFileSetVisibility vis)
+{
+ switch (vis) {
+ case cmFileSetVisibility::Interface:
+ case cmFileSetVisibility::Public:
+ return true;
+ case cmFileSetVisibility::Private:
+ return false;
+ }
+ return false;
+}
+
+cmFileSet::cmFileSet(std::string name, std::string type,
+ cmFileSetVisibility visibility)
: Name(std::move(name))
, Type(std::move(type))
+ , Visibility(visibility)
{
}
diff --git a/Source/cmFileSet.h b/Source/cmFileSet.h
index 3aad75f..5357e77 100644
--- a/Source/cmFileSet.h
+++ b/Source/cmFileSet.h
@@ -7,20 +7,38 @@
#include <string>
#include <vector>
+#include <cm/string_view>
+#include <cmext/string_view>
+
#include "cmListFileCache.h"
class cmCompiledGeneratorExpression;
struct cmGeneratorExpressionDAGChecker;
class cmGeneratorTarget;
class cmLocalGenerator;
+class cmMakefile;
+
+enum class cmFileSetVisibility
+{
+ Private,
+ Public,
+ Interface,
+};
+cm::static_string_view cmFileSetVisibilityToName(cmFileSetVisibility vis);
+cmFileSetVisibility cmFileSetVisibilityFromName(cm::string_view name,
+ cmMakefile* mf);
+bool cmFileSetVisibilityIsForSelf(cmFileSetVisibility vis);
+bool cmFileSetVisibilityIsForInterface(cmFileSetVisibility vis);
class cmFileSet
{
public:
- cmFileSet(std::string name, std::string type);
+ cmFileSet(std::string name, std::string type,
+ cmFileSetVisibility visibility);
const std::string& GetName() const { return this->Name; }
const std::string& GetType() const { return this->Type; }
+ cmFileSetVisibility GetVisibility() const { return this->Visibility; }
void ClearDirectoryEntries();
void AddDirectoryEntry(BT<std::string> directories);
@@ -61,6 +79,7 @@ public:
private:
std::string Name;
std::string Type;
+ cmFileSetVisibility Visibility;
std::vector<BT<std::string>> DirectoryEntries;
std::vector<BT<std::string>> FileEntries;
};
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 3d1cfbf..a9bc435 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -1785,7 +1785,7 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
{
std::string reason;
if (!context->EvaluateForBuildsystem &&
- !gg->HasKnownObjectFileLocation(&reason)) {
+ !gt->Target->HasKnownObjectFileLocation(&reason)) {
std::ostringstream e;
e << "The evaluation of the TARGET_OBJECTS generator expression "
"is only suitable for consumption by CMake (limited"
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 5965a16..dcef070 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -459,10 +459,13 @@ public:
virtual bool IsNinja() const { return false; }
- /** Return true if we know the exact location of object files.
- If false, store the reason in the given string.
- This is meaningful only after EnableLanguage has been called. */
- virtual bool HasKnownObjectFileLocation(std::string*) const { return true; }
+ /** Return true if we know the exact location of object files for the given
+ cmTarget. If false, store the reason in the given string. This is
+ meaningful only after EnableLanguage has been called. */
+ virtual bool HasKnownObjectFileLocation(cmTarget const&, std::string*) const
+ {
+ return true;
+ }
virtual bool UseFolderProperty() const;
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 3ce3d59..d53c3d5 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -1167,6 +1167,20 @@ std::string GetSourcecodeValueFromFileExtension(
return sourcecode;
}
+template <class T>
+std::string GetTargetObjectDirArch(T const& target,
+ const std::string& defaultVal)
+{
+ auto archs = cmExpandedList(target.GetSafeProperty("OSX_ARCHITECTURES"));
+ if (archs.size() > 1) {
+ return "$(CURRENT_ARCH)";
+ } else if (archs.size() == 1) {
+ return archs.front();
+ } else {
+ return defaultVal;
+ }
+}
+
} // anonymous
// Extracts the framework directory, if path matches the framework syntax
@@ -4924,9 +4938,11 @@ bool cmGlobalXCodeGenerator::IsMultiConfig() const
}
bool cmGlobalXCodeGenerator::HasKnownObjectFileLocation(
- std::string* reason) const
+ cmTarget const& target, std::string* reason) const
{
- if (this->ObjectDirArch.find('$') != std::string::npos) {
+ auto objectDirArch = GetTargetObjectDirArch(target, this->ObjectDirArch);
+
+ if (objectDirArch.find('$') != std::string::npos) {
if (reason != nullptr) {
*reason = " under Xcode with multiple architectures";
}
@@ -4957,10 +4973,12 @@ void cmGlobalXCodeGenerator::ComputeTargetObjectDirectory(
cmGeneratorTarget* gt) const
{
std::string configName = this->GetCMakeCFGIntDir();
+ auto objectDirArch = GetTargetObjectDirArch(*gt, this->ObjectDirArch);
+
std::string dir =
cmStrCat(this->GetObjectsDirectory("$(PROJECT_NAME)", configName, gt,
"$(OBJECT_FILE_DIR_normal:base)/"),
- this->ObjectDirArch, '/');
+ objectDirArch, '/');
gt->ObjectDirectory = dir;
}
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index 1159d1f..92e4528 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -107,7 +107,8 @@ public:
bool IsXcode() const override { return true; }
- bool HasKnownObjectFileLocation(std::string* reason) const override;
+ bool HasKnownObjectFileLocation(cmTarget const&,
+ std::string* reason) const override;
bool IsIPOSupported() const override { return true; }
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 1ed698d..7de2cb1 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -919,8 +919,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
if (!objectArgs.GetDestination().empty()) {
// Verify that we know where the objects are to install them.
std::string reason;
- if (!helper.Makefile->GetGlobalGenerator()
- ->HasKnownObjectFileLocation(&reason)) {
+ if (!target.HasKnownObjectFileLocation(&reason)) {
status.SetError(
cmStrCat("TARGETS given OBJECT library \"", target.GetName(),
"\" whose objects may not be installed", reason, "."));
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 4fa7d4f..c54d5bf 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -2493,12 +2493,12 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
static const std::array<std::string, 4> langs = { { "C", "CXX", "OBJC",
"OBJCXX" } };
- bool haveAnyPch = false;
+ std::set<std::string> pchLangSet;
if (this->GetGlobalGenerator()->IsXcode()) {
for (const std::string& lang : langs) {
const std::string pchHeader = target->GetPchHeader(config, lang, "");
if (!pchHeader.empty()) {
- haveAnyPch = true;
+ pchLangSet.emplace(lang);
}
}
}
@@ -2543,9 +2543,11 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
const std::string pchHeader = target->GetPchHeader(config, lang, arch);
if (pchSource.empty() || pchHeader.empty()) {
- if (this->GetGlobalGenerator()->IsXcode() && haveAnyPch) {
+ if (this->GetGlobalGenerator()->IsXcode() && !pchLangSet.empty()) {
for (auto* sf : sources) {
- sf->SetProperty("SKIP_PRECOMPILE_HEADERS", "ON");
+ if (pchLangSet.find(sf->GetLanguage()) == pchLangSet.end()) {
+ sf->SetProperty("SKIP_PRECOMPILE_HEADERS", "ON");
+ }
}
}
continue;
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index e2314e2..a01321d 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -691,6 +691,11 @@ bool cmTarget::IsAndroidGuiExecutable() const
this->impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI"));
}
+bool cmTarget::HasKnownObjectFileLocation(std::string* reason) const
+{
+ return this->GetGlobalGenerator()->HasKnownObjectFileLocation(*this, reason);
+}
+
std::vector<cmCustomCommand> const& cmTarget::GetPreBuildCommands() const
{
return this->impl->PreBuildCommands;
@@ -1484,37 +1489,14 @@ void cmTarget::StoreProperty(const std::string& prop, ValueType value)
BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
}
} else if (prop == propHEADER_SETS) {
- if (value) {
- for (auto const& name : cmExpandedList(value)) {
- if (!this->GetFileSet(name)) {
- this->impl->Makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("Header set \"", name, "\" has not yet been created."));
- return;
- }
- }
- }
- this->impl->HeaderSetsEntries.clear();
- if (!StringIsEmpty(value)) {
- this->impl->HeaderSetsEntries.emplace_back(
- value, this->impl->Makefile->GetBacktrace());
- }
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ "HEADER_SETS property is read-only\n");
+ return;
} else if (prop == propINTERFACE_HEADER_SETS) {
- if (value) {
- for (auto const& name : cmExpandedList(value)) {
- if (!this->GetFileSet(name)) {
- this->impl->Makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("Header set \"", name, "\" has not yet been created."));
- return;
- }
- }
- }
- this->impl->InterfaceHeaderSetsEntries.clear();
- if (!StringIsEmpty(value)) {
- this->impl->InterfaceHeaderSetsEntries.emplace_back(
- value, this->impl->Makefile->GetBacktrace());
- }
+ this->impl->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "INTERFACE_HEADER_SETS property is read-only\n");
+ return;
} else {
this->impl->Properties.SetProperty(prop, value);
}
@@ -1680,27 +1662,14 @@ void cmTarget::AppendProperty(const std::string& prop,
fileSet->AddFileEntry(
BT<std::string>(value, this->impl->Makefile->GetBacktrace()));
} else if (prop == "HEADER_SETS") {
- for (auto const& name : cmExpandedList(value)) {
- if (!this->GetFileSet(name)) {
- this->impl->Makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("Header set \"", name, "\" has not yet been created."));
- return;
- }
- }
- this->impl->HeaderSetsEntries.emplace_back(
- value, this->impl->Makefile->GetBacktrace());
+ this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR,
+ "HEADER_SETS property is read-only\n");
+ return;
} else if (prop == "INTERFACE_HEADER_SETS") {
- for (auto const& name : cmExpandedList(value)) {
- if (!this->GetFileSet(name)) {
- this->impl->Makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("Header set \"", name, "\" has not yet been created."));
- return;
- }
- }
- this->impl->InterfaceHeaderSetsEntries.emplace_back(
- value, this->impl->Makefile->GetBacktrace());
+ this->impl->Makefile->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "INTERFACE_HEADER_SETS property is read-only\n");
+ return;
} else {
this->impl->Properties.AppendProperty(prop, value, asString);
}
@@ -2125,13 +2094,26 @@ cmValue cmTarget::GetProperty(const std::string& prop) const
return cmValue(output);
}
if (prop == propHEADER_SETS) {
+ std::vector<std::string> set_names;
+ for (auto const& file_set : this->impl->FileSets) {
+ if (cmFileSetVisibilityIsForSelf(file_set.second.GetVisibility())) {
+ set_names.push_back(file_set.second.GetName());
+ }
+ }
static std::string output;
- output = cmJoin(this->impl->HeaderSetsEntries, ";"_s);
+ output = cmJoin(set_names, ";"_s);
return cmValue(output);
}
if (prop == propINTERFACE_HEADER_SETS) {
+ std::vector<std::string> set_names;
+ for (auto const& file_set : this->impl->FileSets) {
+ if (cmFileSetVisibilityIsForInterface(
+ file_set.second.GetVisibility())) {
+ set_names.push_back(file_set.second.GetName());
+ }
+ }
static std::string output;
- output = cmJoin(this->impl->InterfaceHeaderSetsEntries, ";"_s);
+ output = cmJoin(set_names, ";"_s);
return cmValue(output);
}
}
@@ -2429,10 +2411,20 @@ cmFileSet* cmTarget::GetFileSet(const std::string& name)
}
std::pair<cmFileSet*, bool> cmTarget::GetOrCreateFileSet(
- const std::string& name, const std::string& type)
+ const std::string& name, const std::string& type, cmFileSetVisibility vis)
{
- auto result =
- this->impl->FileSets.emplace(std::make_pair(name, cmFileSet(name, type)));
+ auto result = this->impl->FileSets.emplace(
+ std::make_pair(name, cmFileSet(name, type, vis)));
+ if (result.second) {
+ if (cmFileSetVisibilityIsForSelf(vis)) {
+ this->impl->HeaderSetsEntries.emplace_back(
+ name, this->impl->Makefile->GetBacktrace());
+ }
+ if (cmFileSetVisibilityIsForInterface(vis)) {
+ this->impl->InterfaceHeaderSetsEntries.emplace_back(
+ name, this->impl->Makefile->GetBacktrace());
+ }
+ }
return std::make_pair(&result.first->second, result.second);
}
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 0cdd2fc..72497b3 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -12,6 +12,7 @@
#include <vector>
#include "cmAlgorithms.h"
+#include "cmFileSet.h"
#include "cmPolicies.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
@@ -19,7 +20,6 @@
#include "cmValue.h"
class cmCustomCommand;
-class cmFileSet;
class cmGlobalGenerator;
class cmInstallTargetGenerator;
class cmListFileBacktrace;
@@ -220,6 +220,8 @@ public:
//! Return whether this target is a GUI executable on Android.
bool IsAndroidGuiExecutable() const;
+ bool HasKnownObjectFileLocation(std::string* reason = nullptr) const;
+
//! Get a backtrace from the creation of the target.
cmListFileBacktrace const& GetBacktrace() const;
@@ -287,7 +289,8 @@ public:
const cmFileSet* GetFileSet(const std::string& name) const;
cmFileSet* GetFileSet(const std::string& name);
std::pair<cmFileSet*, bool> GetOrCreateFileSet(const std::string& name,
- const std::string& type);
+ const std::string& type,
+ cmFileSetVisibility vis);
std::vector<std::string> GetAllInterfaceFileSets() const;
diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx
index 9173a34..b1367e1 100644
--- a/Source/cmTargetSourcesCommand.cxx
+++ b/Source/cmTargetSourcesCommand.cxx
@@ -2,7 +2,6 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmTargetSourcesCommand.h"
-#include <algorithm>
#include <sstream>
#include <utility>
@@ -239,7 +238,11 @@ bool TargetSourcesImpl::HandleOneFileSet(
(args.Type.empty() && args.FileSet[0] >= 'A' && args.FileSet[0] <= 'Z');
std::string type = isDefault ? args.FileSet : args.Type;
- auto fileSet = this->Target->GetOrCreateFileSet(args.FileSet, type);
+ cmFileSetVisibility visibility =
+ cmFileSetVisibilityFromName(scope, this->Makefile);
+
+ auto fileSet =
+ this->Target->GetOrCreateFileSet(args.FileSet, type, visibility);
if (fileSet.second) {
if (!isDefault) {
if (!cmFileSet::IsValidName(args.FileSet)) {
@@ -261,15 +264,6 @@ bool TargetSourcesImpl::HandleOneFileSet(
if (args.BaseDirs.empty()) {
args.BaseDirs.emplace_back(this->Makefile->GetCurrentSourceDirectory());
}
-
- if (scope == "PRIVATE"_s || scope == "PUBLIC"_s) {
- this->Target->AppendProperty(cmTarget::GetFileSetsPropertyName(type),
- args.FileSet);
- }
- if (scope == "INTERFACE"_s || scope == "PUBLIC"_s) {
- this->Target->AppendProperty(
- cmTarget::GetInterfaceFileSetsPropertyName(type), args.FileSet);
- }
} else {
type = fileSet.first->GetType();
if (!args.Type.empty() && args.Type != type) {
@@ -279,37 +273,11 @@ bool TargetSourcesImpl::HandleOneFileSet(
return false;
}
- std::string existingScope = "PRIVATE";
-
- auto const fileSetsProperty = cmTarget::GetFileSetsPropertyName(type);
- auto const interfaceFileSetsProperty =
- cmTarget::GetInterfaceFileSetsPropertyName(type);
- std::vector<std::string> fileSets;
- std::vector<std::string> interfaceFileSets;
- cmExpandList(this->Target->GetSafeProperty(fileSetsProperty), fileSets);
- cmExpandList(this->Target->GetSafeProperty(interfaceFileSetsProperty),
- interfaceFileSets);
-
- if (std::find(interfaceFileSets.begin(), interfaceFileSets.end(),
- args.FileSet) != interfaceFileSets.end()) {
- existingScope = "INTERFACE";
- }
- if (std::find(fileSets.begin(), fileSets.end(), args.FileSet) !=
- fileSets.end()) {
- if (existingScope == "INTERFACE"_s) {
- existingScope = "PUBLIC";
- }
- } else if (existingScope != "INTERFACE"_s) {
- this->SetError(cmStrCat("File set \"", args.FileSet, "\" is not in ",
- fileSetsProperty, " or ",
- interfaceFileSetsProperty));
- return false;
- }
-
- if (scope != existingScope) {
+ if (visibility != fileSet.first->GetVisibility()) {
this->SetError(
cmStrCat("Scope ", scope, " for file set \"", args.FileSet,
- "\" does not match original scope ", existingScope));
+ "\" does not match original scope ",
+ cmFileSetVisibilityToName(fileSet.first->GetVisibility())));
return false;
}
}
@@ -330,11 +298,11 @@ bool TargetSourcesImpl::HandleOneFileSet(
for (auto const& dir : cmExpandedList(baseDirectories)) {
auto interfaceDirectoriesGenex =
cmStrCat("$<BUILD_INTERFACE:", dir, ">");
- if (scope == "PRIVATE"_s || scope == "PUBLIC"_s) {
+ if (cmFileSetVisibilityIsForSelf(visibility)) {
this->Target->AppendProperty("INCLUDE_DIRECTORIES",
interfaceDirectoriesGenex);
}
- if (scope == "INTERFACE"_s || scope == "PUBLIC"_s) {
+ if (cmFileSetVisibilityIsForInterface(visibility)) {
this->Target->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES",
interfaceDirectoriesGenex);
}
diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx
index cbd241b..1a3e72e 100644
--- a/Source/cmVSSetupHelper.cxx
+++ b/Source/cmVSSetupHelper.cxx
@@ -4,6 +4,11 @@
#include <utility>
+#if !defined(CMAKE_BOOTSTRAP)
+# include <cm3p/json/reader.h>
+# include <cm3p/json/value.h>
+#endif
+
#include "cmsys/Encoding.hxx"
#include "cmsys/FStream.hxx"
@@ -295,6 +300,87 @@ bool cmVSSetupAPIHelper::IsEWDKEnabled()
return false;
}
+bool cmVSSetupAPIHelper::EnumerateVSInstancesWithVswhere(
+ std::vector<VSInstanceInfo>& VSInstances)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+ // Construct vswhere command to get installed VS instances in JSON format
+ std::string vswhereExe = getenv("ProgramFiles(x86)") +
+ std::string(R"(\Microsoft Visual Studio\Installer\vswhere.exe)");
+ std::vector<std::string> vswhereCmd = { vswhereExe, "-format", "json" };
+
+ // Execute vswhere command and capture JSON output
+ std::string json_output;
+ int retVal = 1;
+ if (!cmSystemTools::RunSingleCommand(vswhereCmd, &json_output, &json_output,
+ &retVal, nullptr,
+ cmSystemTools::OUTPUT_NONE)) {
+ return false;
+ }
+
+ // Parse JSON output and iterate over elements
+ Json::CharReaderBuilder builder;
+ auto jsonReader = std::unique_ptr<Json::CharReader>(builder.newCharReader());
+ Json::Value json;
+ std::string error;
+
+ if (!jsonReader->parse(json_output.data(),
+ json_output.data() + json_output.size(), &json,
+ &error)) {
+ return false;
+ }
+
+ for (const auto& item : json) {
+ VSInstanceInfo instance;
+ instance.Version = item["installationVersion"].asString();
+ instance.VSInstallLocation = item["installationPath"].asString();
+ instance.IsWin10SDKInstalled = true;
+ instance.IsWin81SDKInstalled = false;
+ cmSystemTools::ConvertToUnixSlashes(instance.VSInstallLocation);
+ if (LoadVSInstanceVCToolsetVersion(instance)) {
+ VSInstances.push_back(instance);
+ }
+ }
+ return true;
+#else
+ static_cast<void>(VSInstances);
+ return false;
+#endif
+}
+
+bool cmVSSetupAPIHelper::EnumerateVSInstancesWithCOM(
+ std::vector<VSInstanceInfo>& VSInstances)
+{
+ if (initializationFailure || setupConfig == NULL || setupConfig2 == NULL ||
+ setupHelper == NULL)
+ return false;
+
+ SmartCOMPtr<IEnumSetupInstances> enumInstances = NULL;
+ if (FAILED(
+ setupConfig2->EnumInstances((IEnumSetupInstances**)&enumInstances)) ||
+ !enumInstances) {
+ return false;
+ }
+
+ SmartCOMPtr<ISetupInstance> instance;
+ while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) {
+ SmartCOMPtr<ISetupInstance2> instance2 = NULL;
+ if (FAILED(
+ instance->QueryInterface(IID_ISetupInstance2, (void**)&instance2)) ||
+ !instance2) {
+ instance = NULL;
+ continue;
+ }
+
+ VSInstanceInfo instanceInfo;
+ bool isInstalled = GetVSInstanceInfo(instance2, instanceInfo);
+ instance = instance2 = NULL;
+ if (isInstalled)
+ VSInstances.push_back(instanceInfo);
+ }
+ return true;
+}
+
bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance()
{
bool isVSInstanceExists = false;
@@ -321,10 +407,6 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance()
return true;
}
- if (initializationFailure || setupConfig == NULL || setupConfig2 == NULL ||
- setupHelper == NULL)
- return false;
-
std::string envVSCommonToolsDir;
std::string envVSCommonToolsDirEnvName =
"VS" + std::to_string(this->Version) + "0COMNTOOLS";
@@ -334,72 +416,60 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance()
cmSystemTools::ConvertToUnixSlashes(envVSCommonToolsDir);
}
- std::vector<VSInstanceInfo> vecVSInstances;
- SmartCOMPtr<IEnumSetupInstances> enumInstances = NULL;
- if (FAILED(
- setupConfig2->EnumInstances((IEnumSetupInstances**)&enumInstances)) ||
- !enumInstances) {
- return false;
- }
-
std::string const wantVersion = std::to_string(this->Version) + '.';
bool specifiedLocationNotSpecifiedVersion = false;
SmartCOMPtr<ISetupInstance> instance;
- while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) {
- SmartCOMPtr<ISetupInstance2> instance2 = NULL;
- if (FAILED(
- instance->QueryInterface(IID_ISetupInstance2, (void**)&instance2)) ||
- !instance2) {
- instance = NULL;
+
+ std::vector<VSInstanceInfo> vecVSInstancesAll;
+
+ // Enumerate VS instances with either COM interface or Vswhere
+ if (!EnumerateVSInstancesWithCOM(vecVSInstancesAll) &&
+ !EnumerateVSInstancesWithVswhere(vecVSInstancesAll)) {
+ return false;
+ }
+
+ std::vector<VSInstanceInfo> vecVSInstances;
+ for (const auto& instanceInfo : vecVSInstancesAll) {
+ // We are looking for a specific major version.
+ if (instanceInfo.Version.size() < wantVersion.size() ||
+ instanceInfo.Version.substr(0, wantVersion.size()) != wantVersion) {
continue;
}
- VSInstanceInfo instanceInfo;
- bool isInstalled = GetVSInstanceInfo(instance2, instanceInfo);
- instance = instance2 = NULL;
-
- if (isInstalled) {
- // We are looking for a specific major version.
- if (instanceInfo.Version.size() < wantVersion.size() ||
- instanceInfo.Version.substr(0, wantVersion.size()) != wantVersion) {
- continue;
+ if (!this->SpecifiedVSInstallLocation.empty()) {
+ // We are looking for a specific instance.
+ std::string currentVSLocation = instanceInfo.GetInstallLocation();
+ if (cmSystemTools::ComparePath(currentVSLocation,
+ this->SpecifiedVSInstallLocation)) {
+ if (this->SpecifiedVSInstallVersion.empty() ||
+ instanceInfo.Version == this->SpecifiedVSInstallVersion) {
+ chosenInstanceInfo = instanceInfo;
+ return true;
+ }
+ specifiedLocationNotSpecifiedVersion = true;
}
-
- if (!this->SpecifiedVSInstallLocation.empty()) {
- // We are looking for a specific instance.
- std::string currentVSLocation = instanceInfo.GetInstallLocation();
+ } else if (!this->SpecifiedVSInstallVersion.empty()) {
+ // We are looking for a specific version.
+ if (instanceInfo.Version == this->SpecifiedVSInstallVersion) {
+ chosenInstanceInfo = instanceInfo;
+ return true;
+ }
+ } else {
+ // We are not looking for a specific instance.
+ // If we've been given a hint then use it.
+ if (!envVSCommonToolsDir.empty()) {
+ std::string currentVSLocation =
+ cmStrCat(instanceInfo.GetInstallLocation(), "/Common7/Tools");
if (cmSystemTools::ComparePath(currentVSLocation,
- this->SpecifiedVSInstallLocation)) {
- if (this->SpecifiedVSInstallVersion.empty() ||
- instanceInfo.Version == this->SpecifiedVSInstallVersion) {
- chosenInstanceInfo = instanceInfo;
- return true;
- }
- specifiedLocationNotSpecifiedVersion = true;
- }
- } else if (!this->SpecifiedVSInstallVersion.empty()) {
- // We are looking for a specific version.
- if (instanceInfo.Version == this->SpecifiedVSInstallVersion) {
+ envVSCommonToolsDir)) {
chosenInstanceInfo = instanceInfo;
return true;
}
- } else {
- // We are not looking for a specific instance.
- // If we've been given a hint then use it.
- if (!envVSCommonToolsDir.empty()) {
- std::string currentVSLocation =
- cmStrCat(instanceInfo.GetInstallLocation(), "/Common7/Tools");
- if (cmSystemTools::ComparePath(currentVSLocation,
- envVSCommonToolsDir)) {
- chosenInstanceInfo = instanceInfo;
- return true;
- }
- }
- // Otherwise, add this to the list of candidates.
- vecVSInstances.push_back(instanceInfo);
}
+ // Otherwise, add this to the list of candidates.
+ vecVSInstances.push_back(instanceInfo);
}
}
diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h
index 44c883b..a16f00b 100644
--- a/Source/cmVSSetupHelper.h
+++ b/Source/cmVSSetupHelper.h
@@ -118,6 +118,9 @@ private:
int ChooseVSInstance(const std::vector<VSInstanceInfo>& vecVSInstances);
bool EnumerateAndChooseVSInstance();
bool LoadSpecifiedVSInstanceFromDisk();
+ bool EnumerateVSInstancesWithVswhere(
+ std::vector<VSInstanceInfo>& VSInstances);
+ bool EnumerateVSInstancesWithCOM(std::vector<VSInstanceInfo>& VSInstances);
unsigned int Version;
diff --git a/Source/cmWindowsRegistry.cxx b/Source/cmWindowsRegistry.cxx
new file mode 100644
index 0000000..c857a3b
--- /dev/null
+++ b/Source/cmWindowsRegistry.cxx
@@ -0,0 +1,442 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmWindowsRegistry.h"
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <algorithm>
+# include <cstdint>
+# include <exception>
+# include <iterator>
+# include <utility>
+# include <vector>
+
+# include <cm/memory>
+# include <cmext/string_view>
+
+# include <windows.h>
+
+# include "cmsys/Encoding.hxx"
+# include "cmsys/SystemTools.hxx"
+
+# include "cmMakefile.h"
+# include "cmStringAlgorithms.h"
+# include "cmValue.h"
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+namespace {
+bool Is64BitWindows()
+{
+# if defined(_WIN64)
+ // 64-bit programs run only on Win64
+ return true;
+# else
+ // 32-bit programs run on both 32-bit and 64-bit Windows, so we must check.
+ BOOL isWow64 = false;
+ return IsWow64Process(GetCurrentProcess(), &isWow64) && isWow64;
+# endif
+}
+
+// class registry_exception
+class registry_error : public std::exception
+{
+public:
+ registry_error(std::string msg)
+ : What(std::move(msg))
+ {
+ }
+ ~registry_error() override = default;
+
+ const char* what() const noexcept override { return What.c_str(); }
+
+private:
+ std::string What;
+};
+
+// Class KeyHandler
+class KeyHandler
+{
+public:
+ using View = cmWindowsRegistry::View;
+
+ KeyHandler(HKEY hkey)
+ : Handler(hkey)
+ {
+ }
+ ~KeyHandler() { RegCloseKey(this->Handler); }
+
+ static KeyHandler OpenKey(cm::string_view key, View view);
+
+ std::string ReadValue(cm::string_view name, cm::string_view separator);
+
+ std::vector<std::string> GetValueNames();
+ std::vector<std::string> GetSubKeys();
+
+private:
+ static std::string FormatSystemError(LSTATUS status);
+
+ HKEY Handler;
+};
+
+KeyHandler KeyHandler::OpenKey(cm::string_view key, View view)
+{
+ if (view == View::Reg64 && !Is64BitWindows()) {
+ throw registry_error("No 64bit registry on Windows32.");
+ }
+
+ auto start = key.find_first_of("\\/"_s);
+ auto rootKey = key.substr(0, start);
+ HKEY hRootKey;
+
+ if (rootKey == "HKCU"_s || rootKey == "HKEY_CURRENT_USER"_s) {
+ hRootKey = HKEY_CURRENT_USER;
+ } else if (rootKey == "HKLM"_s || rootKey == "HKEY_LOCAL_MACHINE"_s) {
+ hRootKey = HKEY_LOCAL_MACHINE;
+ } else if (rootKey == "HKCR"_s || rootKey == "HKEY_CLASSES_ROOT"_s) {
+ hRootKey = HKEY_CLASSES_ROOT;
+ } else if (rootKey == "HKCC"_s || rootKey == "HKEY_CURRENT_CONFIG"_s) {
+ hRootKey = HKEY_CURRENT_CONFIG;
+ } else if (rootKey == "HKU"_s || rootKey == "HKEY_USERS"_s) {
+ hRootKey = HKEY_USERS;
+ } else {
+ throw registry_error(cmStrCat(rootKey, ": invalid root key."));
+ }
+ std::wstring subKey;
+ if (start != cm::string_view::npos) {
+ subKey = cmsys::Encoding::ToWide(key.substr(start + 1).data());
+ }
+ // Update path format
+ std::replace(subKey.begin(), subKey.end(), L'/', L'\\');
+
+ REGSAM options = KEY_READ;
+ if (Is64BitWindows()) {
+ options |= view == View::Reg64 ? KEY_WOW64_64KEY : KEY_WOW64_32KEY;
+ }
+
+ HKEY hKey;
+ if (LSTATUS status = RegOpenKeyExW(hRootKey, subKey.c_str(), 0, options,
+ &hKey) != ERROR_SUCCESS) {
+ throw registry_error(FormatSystemError(status));
+ }
+
+ return KeyHandler(hKey);
+}
+
+std::string KeyHandler::FormatSystemError(LSTATUS status)
+{
+ std::string formattedMessage;
+ LPWSTR message = nullptr;
+ DWORD size = 1024;
+ if (FormatMessageW(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr,
+ status, 0, reinterpret_cast<LPWSTR>(&message), size, nullptr) == 0) {
+ formattedMessage = "Windows Registry: unexpected error.";
+ } else {
+ formattedMessage = cmTrimWhitespace(cmsys::Encoding::ToNarrow(message));
+ }
+ LocalFree(message);
+
+ return formattedMessage;
+}
+
+std::string KeyHandler::ReadValue(cm::string_view name,
+ cm::string_view separator)
+{
+ LSTATUS status;
+ DWORD size;
+ // pick-up maximum size for value
+ if ((status = RegQueryInfoKeyW(this->Handler, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr,
+ &size, nullptr, nullptr)) != ERROR_SUCCESS) {
+ throw registry_error(this->FormatSystemError(status));
+ }
+ auto data = cm::make_unique<BYTE[]>(size);
+ DWORD type;
+ auto valueName = cmsys::Encoding::ToWide(name.data());
+ if ((status = RegQueryValueExW(this->Handler, valueName.c_str(), nullptr,
+ &type, data.get(), &size)) != ERROR_SUCCESS) {
+ throw registry_error(this->FormatSystemError(status));
+ }
+ switch (type) {
+ case REG_SZ:
+ return cmsys::Encoding::ToNarrow(reinterpret_cast<wchar_t*>(data.get()));
+ break;
+ case REG_EXPAND_SZ: {
+ auto expandSize = ExpandEnvironmentStringsW(
+ reinterpret_cast<wchar_t*>(data.get()), nullptr, 0);
+ auto expandData = cm::make_unique<wchar_t[]>(expandSize + 1);
+ if (ExpandEnvironmentStringsW(reinterpret_cast<wchar_t*>(data.get()),
+ expandData.get(), expandSize + 1) == 0) {
+ throw registry_error(this->FormatSystemError(GetLastError()));
+ } else {
+ return cmsys::Encoding::ToNarrow(expandData.get());
+ }
+ } break;
+ case REG_DWORD:
+ return std::to_string(*reinterpret_cast<std::uint32_t*>(data.get()));
+ break;
+ case REG_QWORD:
+ return std::to_string(*reinterpret_cast<std::uint64_t*>(data.get()));
+ break;
+ case REG_MULTI_SZ: {
+ // replace separator with semicolon
+ auto sep = cmsys::Encoding::ToWide(separator.data())[0];
+ std::replace(reinterpret_cast<wchar_t*>(data.get()),
+ reinterpret_cast<wchar_t*>(data.get()) +
+ (size / sizeof(wchar_t)) - 1,
+ sep, L';');
+ return cmsys::Encoding::ToNarrow(reinterpret_cast<wchar_t*>(data.get()));
+ } break;
+ default:
+ throw registry_error(cmStrCat(type, ": unsupported type."));
+ }
+}
+
+std::vector<std::string> KeyHandler::GetValueNames()
+{
+ LSTATUS status;
+ DWORD maxSize;
+ // pick-up maximum size for value names
+ if ((status = RegQueryInfoKeyW(
+ this->Handler, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, &maxSize, nullptr, nullptr, nullptr)) != ERROR_SUCCESS) {
+ throw registry_error(this->FormatSystemError(status));
+ }
+ // increment size for final null
+ auto data = cm::make_unique<wchar_t[]>(++maxSize);
+ DWORD index = 0;
+ DWORD size = maxSize;
+
+ std::vector<std::string> valueNames;
+
+ while ((status = RegEnumValueW(this->Handler, index, data.get(), &size,
+ nullptr, nullptr, nullptr, nullptr)) ==
+ ERROR_SUCCESS) {
+ auto name = cmsys::Encoding::ToNarrow(data.get());
+ valueNames.push_back(name.empty() ? "(default)" : name);
+ size = maxSize;
+ ++index;
+ }
+
+ if (status != ERROR_NO_MORE_ITEMS) {
+ throw registry_error(this->FormatSystemError(status));
+ }
+
+ return valueNames;
+}
+
+std::vector<std::string> KeyHandler::GetSubKeys()
+{
+ LSTATUS status;
+ DWORD size;
+ // pick-up maximum size for subkeys
+ if ((status = RegQueryInfoKeyW(
+ this->Handler, nullptr, nullptr, nullptr, nullptr, &size, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr)) != ERROR_SUCCESS) {
+ throw registry_error(this->FormatSystemError(status));
+ }
+ // increment size for final null
+ auto data = cm::make_unique<wchar_t[]>(++size);
+ DWORD index = 0;
+ std::vector<std::string> subKeys;
+
+ while ((status = RegEnumKeyW(this->Handler, index, data.get(), size)) ==
+ ERROR_SUCCESS) {
+ subKeys.push_back(cmsys::Encoding::ToNarrow(data.get()));
+ ++index;
+ }
+ if (status != ERROR_NO_MORE_ITEMS) {
+ throw registry_error(this->FormatSystemError(status));
+ }
+
+ return subKeys;
+}
+}
+#endif
+
+// class cmWindowsRegistry
+cmWindowsRegistry::cmWindowsRegistry(cmMakefile& makefile)
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ : LastError("No Registry on this platform.")
+#endif
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (cmValue targetSize = makefile.GetDefinition("CMAKE_SIZEOF_VOID_P")) {
+ this->TargetSize = targetSize == "8" ? 64 : 32;
+ }
+#else
+ (void)makefile;
+#endif
+}
+
+cm::string_view cmWindowsRegistry::GetLastError() const
+{
+ return this->LastError;
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+std::vector<cmWindowsRegistry::View> cmWindowsRegistry::ComputeViews(View view)
+{
+ switch (view) {
+ case View::Both:
+ switch (this->TargetSize) {
+ case 64:
+ return std::vector<View>{ View::Reg64, View::Reg32 };
+ break;
+ case 32:
+ return Is64BitWindows()
+ ? std::vector<View>{ View::Reg32, View::Reg64 }
+ : std::vector<View>{ View::Reg32 };
+ break;
+ default:
+ // No language specified, fallback to host architecture
+ return Is64BitWindows()
+ ? std::vector<View>{ View::Reg64, View::Reg32 }
+ : std::vector<View>{ View::Reg32 };
+ break;
+ }
+ break;
+ case View::Target:
+ switch (this->TargetSize) {
+ case 64:
+ return std::vector<View>{ View::Reg64 };
+ break;
+ case 32:
+ return std::vector<View>{ View::Reg32 };
+ break;
+ default:
+ break;
+ }
+ CM_FALLTHROUGH;
+ case View::Host:
+ return std::vector<View>{ Is64BitWindows() ? View::Reg64 : View::Reg32 };
+ break;
+ case View::Reg64_32:
+ return Is64BitWindows() ? std::vector<View>{ View::Reg64, View::Reg32 }
+ : std::vector<View>{ View::Reg32 };
+ break;
+ case View::Reg32_64:
+ return Is64BitWindows() ? std::vector<View>{ View::Reg32, View::Reg64 }
+ : std::vector<View>{ View::Reg32 };
+ break;
+ default:
+ return std::vector<View>{ view };
+ break;
+ }
+}
+#endif
+
+cm::optional<std::string> cmWindowsRegistry::ReadValue(
+ cm::string_view key, cm::string_view name, View view,
+ cm::string_view separator)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ // compute list of registry views
+ auto views = this->ComputeViews(view);
+
+ if (cmsys::SystemTools::Strucmp(name.data(), "(default)") == 0) {
+ // handle magic name for default value
+ name = ""_s;
+ }
+ if (separator.empty()) {
+ separator = "\0"_s;
+ }
+
+ for (auto v : views) {
+ try {
+ this->LastError.clear();
+ auto handler = KeyHandler::OpenKey(key, v);
+ return handler.ReadValue(name, separator);
+ } catch (const registry_error& e) {
+ this->LastError = e.what();
+ continue;
+ }
+ }
+#else
+ (void)key;
+ (void)name;
+ (void)view;
+ (void)separator;
+#endif
+ return cm::nullopt;
+}
+
+cm::optional<std::vector<std::string>> cmWindowsRegistry::GetValueNames(
+ cm::string_view key, View view)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ this->LastError.clear();
+ // compute list of registry views
+ auto views = this->ComputeViews(view);
+ std::vector<std::string> valueNames;
+ bool querySuccessful = false;
+
+ for (auto v : views) {
+ try {
+ auto handler = KeyHandler::OpenKey(key, v);
+ auto list = handler.GetValueNames();
+ std::move(list.begin(), list.end(), std::back_inserter(valueNames));
+ querySuccessful = true;
+ } catch (const registry_error& e) {
+ this->LastError = e.what();
+ continue;
+ }
+ }
+ if (!valueNames.empty()) {
+ // value names must be unique and sorted
+ std::sort(valueNames.begin(), valueNames.end());
+ valueNames.erase(std::unique(valueNames.begin(), valueNames.end()),
+ valueNames.end());
+ }
+
+ if (querySuccessful) {
+ // At least one query was successful, so clean-up any error message
+ this->LastError.clear();
+ return valueNames;
+ }
+#else
+ (void)key;
+ (void)view;
+#endif
+ return cm::nullopt;
+}
+
+cm::optional<std::vector<std::string>> cmWindowsRegistry::GetSubKeys(
+ cm::string_view key, View view)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ this->LastError.clear();
+ // compute list of registry views
+ auto views = this->ComputeViews(view);
+ std::vector<std::string> subKeys;
+ bool querySuccessful = false;
+
+ for (auto v : views) {
+ try {
+ auto handler = KeyHandler::OpenKey(key, v);
+ auto list = handler.GetSubKeys();
+ std::move(list.begin(), list.end(), std::back_inserter(subKeys));
+ querySuccessful = true;
+ } catch (const registry_error& e) {
+ this->LastError = e.what();
+ continue;
+ }
+ }
+ if (!subKeys.empty()) {
+ // keys must be unique and sorted
+ std::sort(subKeys.begin(), subKeys.end());
+ subKeys.erase(std::unique(subKeys.begin(), subKeys.end()), subKeys.end());
+ }
+
+ if (querySuccessful) {
+ // At least one query was successful, so clean-up any error message
+ this->LastError.clear();
+ return subKeys;
+ }
+#else
+ (void)key;
+ (void)view;
+#endif
+ return cm::nullopt;
+}
diff --git a/Source/cmWindowsRegistry.h b/Source/cmWindowsRegistry.h
new file mode 100644
index 0000000..6f10b3a
--- /dev/null
+++ b/Source/cmWindowsRegistry.h
@@ -0,0 +1,55 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+class cmMakefile;
+
+class cmWindowsRegistry
+{
+public:
+ cmWindowsRegistry(cmMakefile&);
+
+ enum class View
+ {
+ Both,
+ Target,
+ Host,
+ Reg64_32,
+ Reg32_64,
+ Reg32,
+ Reg64
+ };
+
+ cm::optional<std::string> ReadValue(cm::string_view key,
+ View view = View::Both,
+ cm::string_view separator = "\0"_s)
+ {
+ return this->ReadValue(key, ""_s, view, separator);
+ }
+ cm::optional<std::string> ReadValue(cm::string_view key,
+ cm::string_view name,
+ View view = View::Both,
+ cm::string_view separator = "\0"_s);
+
+ cm::optional<std::vector<std::string>> GetValueNames(cm::string_view key,
+ View view = View::Both);
+ cm::optional<std::vector<std::string>> GetSubKeys(cm::string_view key,
+ View view = View::Both);
+
+ cm::string_view GetLastError() const;
+
+private:
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ std::vector<View> ComputeViews(View view);
+
+ int TargetSize = 0;
+#endif
+ std::string LastError;
+};
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index 96bf845..28be166 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -308,10 +308,11 @@ int do_cmake(int ac, char const* const* av)
parsedArgs.emplace_back("--find-package");
return true;
} },
- CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
- [&](std::string const&) -> bool {
+ CommandArgument{ "--list-presets", CommandArgument::Values::ZeroOrOne,
+ [&](std::string const& value) -> bool {
workingMode = cmake::HELP_MODE;
parsedArgs.emplace_back("--list-presets");
+ parsedArgs.emplace_back(value);
return true;
} },
};
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index dbff293..024c388 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -352,6 +352,9 @@ if(MSVC)
add_RunCMake_test(MSVCRuntimeTypeInfo)
add_RunCMake_test(MSVCWarningFlags)
endif()
+if(XCODE_VERSION)
+ set(ObjectLibrary_ARGS -DXCODE_VERSION=${XCODE_VERSION})
+endif()
add_RunCMake_test(ObjectLibrary)
add_RunCMake_test(ParseImplicitIncludeInfo)
add_RunCMake_test(ParseImplicitLinkInfo)
diff --git a/Tests/RunCMake/CMakePresets/ListConfigurePresetsWorkingDir-stdout.txt b/Tests/RunCMake/CMakePresets/ListConfigurePresetsWorkingDir-stdout.txt
new file mode 100644
index 0000000..97eedae
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ListConfigurePresetsWorkingDir-stdout.txt
@@ -0,0 +1,7 @@
+^Not searching for unused variables given on the command line\.
+Available configure presets:
+
+ "zzzzzz" - Sleepy
+ "aaaaaaaa" - Screaming
+ "mmmmmm"
+ "no-generator"$
diff --git a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
index 449132a..5867efd 100644
--- a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
@@ -71,13 +71,18 @@ function(run_cmake_presets name)
set(_unused_cli)
endif()
+ set(_preset "--preset=${name}")
+ if(CMakePresets_NO_PRESET)
+ set(_preset)
+ endif()
+
set(RunCMake_TEST_COMMAND ${CMAKE_COMMAND}
${_source_args}
-DRunCMake_TEST=${name}
-DRunCMake_GENERATOR=${RunCMake_GENERATOR}
-DCMAKE_MAKE_PROGRAM=${RunCMake_MAKE_PROGRAM}
${_unused_cli}
- --preset=${name}
+ ${_preset}
${ARGN}
)
run_cmake(${name})
@@ -288,7 +293,10 @@ run_cmake_presets(ListPresets --list-presets)
set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/ListPresetsWorkingDir")
set(RunCMake_TEST_NO_CLEAN 1)
set(CMakePresets_NO_SOURCE_ARGS 1)
+set(CMakePresets_NO_PRESET 1)
run_cmake_presets(ListPresetsWorkingDir --list-presets)
+run_cmake_presets(ListConfigurePresetsWorkingDir --list-presets=configure)
+unset(CMakePresets_NO_PRESET)
unset(CMakePresets_NO_SOURCE_ARGS)
unset(RunCMake_TEST_NO_CLEAN)
unset(RunCMake_TEST_BINARY_DIR)
diff --git a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake
index 8515ba5..0e31b78 100644
--- a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake
@@ -8,12 +8,21 @@ run_cmake(BadObjSource2)
if(RunCMake_GENERATOR STREQUAL "Xcode" AND "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]")
run_cmake(ImportMultiArch)
run_cmake(InstallNotSupported)
+
+ set(osx_archs $ENV{CMAKE_OSX_ARCHITECTURES})
+ list(GET osx_archs 0 osx_arch)
+ run_cmake_with_options(TargetOverrideSingleArch -Dosx_arch=${osx_arch})
else()
run_cmake(Import)
run_cmake(Install)
run_cmake(InstallLinkedObj1)
run_cmake(InstallLinkedObj2)
+
+ if(RunCMake_GENERATOR STREQUAL "Xcode" AND XCODE_VERSION VERSION_GREATER_EQUAL 13)
+ run_cmake(TargetOverrideMultiArch)
+ endif()
endif()
+
run_cmake(Export)
function (run_object_lib_build name)
diff --git a/Tests/RunCMake/target_sources/FileSetNoScope-result.txt b/Tests/RunCMake/ObjectLibrary/TargetOverrideMultiArch-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/target_sources/FileSetNoScope-result.txt
+++ b/Tests/RunCMake/ObjectLibrary/TargetOverrideMultiArch-result.txt
diff --git a/Tests/RunCMake/ObjectLibrary/TargetOverrideMultiArch-stderr.txt b/Tests/RunCMake/ObjectLibrary/TargetOverrideMultiArch-stderr.txt
new file mode 100644
index 0000000..eb0593c
--- /dev/null
+++ b/Tests/RunCMake/ObjectLibrary/TargetOverrideMultiArch-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error at TargetOverrideMultiArch.cmake:[0-9]+ \(install\):
+ install TARGETS given OBJECT library "A" whose objects may not be installed
+ under Xcode with multiple architectures.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/ObjectLibrary/TargetOverrideMultiArch.cmake b/Tests/RunCMake/ObjectLibrary/TargetOverrideMultiArch.cmake
new file mode 100644
index 0000000..ada77f8
--- /dev/null
+++ b/Tests/RunCMake/ObjectLibrary/TargetOverrideMultiArch.cmake
@@ -0,0 +1,3 @@
+add_library(A OBJECT a.c)
+set_target_properties(A PROPERTIES OSX_ARCHITECTURES "x86_64;arm64")
+install(TARGETS A DESTINATION lib)
diff --git a/Tests/RunCMake/ObjectLibrary/TargetOverrideSingleArch.cmake b/Tests/RunCMake/ObjectLibrary/TargetOverrideSingleArch.cmake
new file mode 100644
index 0000000..3f400e8
--- /dev/null
+++ b/Tests/RunCMake/ObjectLibrary/TargetOverrideSingleArch.cmake
@@ -0,0 +1,3 @@
+add_library(A OBJECT a.c)
+set_target_properties(A PROPERTIES OSX_ARCHITECTURES ${osx_arch})
+install(TARGETS A DESTINATION lib)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchIncludedOneLanguage.cmake b/Tests/RunCMake/PrecompileHeaders/PchIncludedOneLanguage.cmake
new file mode 100644
index 0000000..dd582ac
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchIncludedOneLanguage.cmake
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.16)
+project(PchIncludedAllLanguages C CXX)
+
+if(CMAKE_CXX_COMPILE_OPTIONS_USE_PCH)
+ add_definitions(-DHAVE_PCH_SUPPORT)
+endif()
+
+add_executable(main
+ main.cpp
+ empty.c
+ pch-included.cpp
+)
+
+target_precompile_headers(main PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/pch.h>)
+
+enable_testing()
+add_test(NAME main COMMAND main)
diff --git a/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake b/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake
index a7b3126..fd41e2f 100644
--- a/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake
@@ -30,4 +30,5 @@ if(RunCMake_GENERATOR MATCHES "Make|Ninja")
endif()
run_test(PchReuseFromObjLib)
run_test(PchIncludedAllLanguages)
+run_test(PchIncludedOneLanguage)
run_test(PchLibObjLibExe)
diff --git a/Tests/RunCMake/target_sources/FileSetNoExistPrivate-result.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadKey1-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/target_sources/FileSetNoExistPrivate-result.txt
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadKey1-result.txt
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadKey1-stderr.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadKey1-stderr.txt
new file mode 100644
index 0000000..1832ada
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadKey1-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at Registry_BadKey1.cmake:[0-9]+ \(message\):
+ WRONG_ROOT: invalid root key.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadKey1.cmake b/Tests/RunCMake/cmake_host_system_information/Registry_BadKey1.cmake
new file mode 100644
index 0000000..6299f85
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadKey1.cmake
@@ -0,0 +1,4 @@
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY WRONG_ROOT/SUBKEY ERROR_VARIABLE error)
+if (NOT error STREQUAL "")
+ message(FATAL_ERROR "${error}")
+endif()
diff --git a/Tests/RunCMake/target_sources/FileSetNoExistInterface-result.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadKey2-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/target_sources/FileSetNoExistInterface-result.txt
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadKey2-result.txt
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadKey2-stderr.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadKey2-stderr.txt
new file mode 100644
index 0000000..4be55bf
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadKey2-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at Registry_BadKey2.cmake:[0-9]+ \(message\):
+ HKLM-SUBKEY: invalid root key.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadKey2.cmake b/Tests/RunCMake/cmake_host_system_information/Registry_BadKey2.cmake
new file mode 100644
index 0000000..1750078
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadKey2.cmake
@@ -0,0 +1,4 @@
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY HKLM-SUBKEY ERROR_VARIABLE error)
+if (NOT error STREQUAL "")
+ message(FATAL_ERROR "${error}")
+endif()
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery1-result.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery1-stderr.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery1-stderr.txt
new file mode 100644
index 0000000..9510327
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery1-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at Registry_BadQuery1.cmake:[0-9]+ \(cmake_host_system_information\):
+ cmake_host_system_information given invalid argument\(s\) "BAD_OPTION".
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery1.cmake b/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery1.cmake
new file mode 100644
index 0000000..a92f35c
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery1.cmake
@@ -0,0 +1 @@
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY HKLM/SOFTWARE BAD_OPTION)
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2-result.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2-stderr.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2-stderr.txt
new file mode 100644
index 0000000..6a430f1
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error at Registry_BadQuery2.cmake:[0-9]+ \(cmake_host_system_information\):
+ cmake_host_system_information missing expected value for argument\(s\)
+ "VALUE".
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2.cmake b/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2.cmake
new file mode 100644
index 0000000..7c751cc
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadQuery2.cmake
@@ -0,0 +1 @@
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY HKLM/SOFTWARE VALUE)
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadView1-result.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadView1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadView1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadView1-stderr.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadView1-stderr.txt
new file mode 100644
index 0000000..5eda4ff
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadView1-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error at Registry_BadView1.cmake:[0-9]+ \(cmake_host_system_information\):
+ cmake_host_system_information missing expected value for argument\(s\)
+ "VIEW".
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadView1.cmake b/Tests/RunCMake/cmake_host_system_information/Registry_BadView1.cmake
new file mode 100644
index 0000000..6527784
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadView1.cmake
@@ -0,0 +1 @@
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY HKLM/SOFTWARE VIEW)
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadView2-result.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadView2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadView2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadView2-stderr.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadView2-stderr.txt
new file mode 100644
index 0000000..201d93a
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadView2-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at Registry_BadView2.cmake:[0-9]+ \(cmake_host_system_information\):
+ cmake_host_system_information given invalid value for "VIEW": BAD_VIEW.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadView2.cmake b/Tests/RunCMake/cmake_host_system_information/Registry_BadView2.cmake
new file mode 100644
index 0000000..d116c76
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadView2.cmake
@@ -0,0 +1 @@
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY HKLM/SOFTWARE VIEW BAD_VIEW)
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadView3-result.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadView3-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadView3-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadView3-stderr.txt b/Tests/RunCMake/cmake_host_system_information/Registry_BadView3-stderr.txt
new file mode 100644
index 0000000..5b7f7c7
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadView3-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at Registry_BadView3.cmake:[0-9]+ \(cmake_host_system_information\):
+ cmake_host_system_information given invalid argument\(s\) "64".
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_BadView3.cmake b/Tests/RunCMake/cmake_host_system_information/Registry_BadView3.cmake
new file mode 100644
index 0000000..7c5f272
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_BadView3.cmake
@@ -0,0 +1 @@
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY HKLM/SOFTWARE VIEW 32 64)
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_NoArgs-result.txt b/Tests/RunCMake/cmake_host_system_information/Registry_NoArgs-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_NoArgs-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_NoArgs-stderr.txt b/Tests/RunCMake/cmake_host_system_information/Registry_NoArgs-stderr.txt
new file mode 100644
index 0000000..ff55fcb
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_NoArgs-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at Registry_NoArgs.cmake:[0-9]+ \(cmake_host_system_information\):
+ cmake_host_system_information missing <key> specification.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_NoArgs.cmake b/Tests/RunCMake/cmake_host_system_information/Registry_NoArgs.cmake
new file mode 100644
index 0000000..87e253d
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_NoArgs.cmake
@@ -0,0 +1 @@
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY)
diff --git a/Tests/RunCMake/cmake_host_system_information/Registry_Query.cmake b/Tests/RunCMake/cmake_host_system_information/Registry_Query.cmake
new file mode 100644
index 0000000..9f9fb14
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/Registry_Query.cmake
@@ -0,0 +1,232 @@
+
+# check Windows architecture
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "HKCU" SUBKEYS VIEW 64 ERROR_VARIABLE status)
+if (status STREQUAL "")
+ set(HOST_64BIT TRUE)
+else()
+ set(HOST_64BIT FALSE)
+endif()
+
+# helper function for test validation
+function(CHECK key result status expression)
+ if(status STREQUAL "")
+ cmake_language(EVAL CODE
+ "if (NOT (${expression}))
+ message(SEND_ERROR \"wrong value for key '${key}': '${result}'\")
+ endif()")
+ else()
+ message(SEND_ERROR "query failed for key '${key}': '${status}'")
+ endif()
+endfunction()
+
+
+# HKCU/Software/Classes/CLSID/CMake-Tests/chsi-registry: Query default value
+set(KEY "HKCU/Software/Classes/CLSID/CMake-Tests/chsi-registry")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" ERROR_VARIABLE status)
+check("${KEY}" "${result}" "${status}"
+ "(HOST_64BIT AND result STREQUAL \"default 64bit\")
+ OR (NOT HOST_64BIT AND result STREQUAL \"default 32bit\")")
+# query value using special name should be identical to default value
+cmake_host_system_information(RESULT result2 QUERY WINDOWS_REGISTRY "${KEY}" VALUE "(default)" ERROR_VARIABLE status)
+check("${KEY}{(default)}" "${result2}" "${status}" "result2 STREQUAL result")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VIEW HOST ERROR_VARIABLE status)
+check("${KEY}" "${result}" "${status}"
+ "(HOST_64BIT AND result STREQUAL \"default 64bit\")
+ OR (NOT HOST_64BIT AND result STREQUAL \"default 32bit\")")
+# VIEW TARGET should have same value as VIEW HOST
+cmake_host_system_information(RESULT result2 QUERY WINDOWS_REGISTRY "${KEY}" VIEW TARGET ERROR_VARIABLE status)
+check("${KEY}" "${result2}" "${status}" "result2 STREQUAL result")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VIEW 64 ERROR_VARIABLE status)
+check("${KEY}" "${result}" "${status}" "result STREQUAL \"default 64bit\"")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VIEW 32 ERROR_VARIABLE status)
+check("${KEY}" "${result}" "${status}" "result STREQUAL \"default 32bit\"")
+
+# reg 64bit is read first
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VIEW 64_32 ERROR_VARIABLE status)
+check("${KEY}" "${result}" "${status}" "result STREQUAL \"default 64bit\"")
+
+# reg 32bit is read first
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VIEW 32_64 ERROR_VARIABLE status)
+check("${KEY}" "${result}" "${status}" "result STREQUAL \"default 32bit\"")
+
+
+# HKCU/Software/CMake-Tests/chsi-registry: Query named value
+set(KEY "HKCU/Software/Classes/CLSID/CMake-Tests/chsi-registry")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
+ ERROR_VARIABLE status)
+check("${KEY}{BYTE_SIZE}" "${result}" "${status}"
+ "(HOST_64BIT AND result STREQUAL \"64bit\")
+ OR (NOT HOST_64BIT AND result STREQUAL \"32bit\")")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
+ VIEW HOST ERROR_VARIABLE status)
+check("${KEY}{BYTE_SIZE}" "${result}" "${status}"
+ "(HOST_64BIT AND result STREQUAL \"64bit\")
+ OR (NOT HOST_64BIT AND result STREQUAL \"32bit\")")
+# VIEW TARGET should have same value as VIEW HOST
+cmake_host_system_information(RESULT result2 QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
+ VIEW TARGET ERROR_VARIABLE status)
+check("${KEY}{BYTE_SIZE}" "${result2}" "${status}" "result2 STREQUAL result")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
+ VIEW 64 ERROR_VARIABLE status)
+check("${KEY}{BYTE_SIZE}" "${result}" "${status}" "result STREQUAL \"64bit\"")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
+ VIEW 32 ERROR_VARIABLE status)
+check("${KEY}{BYTE_SIZE}" "${result}" "${status}" "result STREQUAL \"32bit\"")
+
+# reg 64bit is read first
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
+ VIEW 64_32 ERROR_VARIABLE status)
+check("${KEY}{BYTE_SIZE}" "${result}" "${status}" "result STREQUAL \"64bit\"")
+
+# reg 32bit is read first
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
+ VIEW 32_64 ERROR_VARIABLE status)
+check("${KEY}{BYTE_SIZE}" "${result}" "${status}" "result STREQUAL \"32bit\"")
+
+
+# HKCU/Software/CMake-Tests/chsi-registry: check retrieval of various types
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE VALUE_SZ ERROR_VARIABLE status)
+check("${KEY}{VALUE_SZ}" "${result}" "${status}" "result STREQUAL \"data with space\"")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE VALUE_EXPAND_SZ ERROR_VARIABLE status)
+check("${KEY}{VALUE_EXPAND_SZ}" "${result}" "${status}"
+ "(NOT result STREQUAL \"PATH=%PATH%\") AND (result MATCHES \"^PATH=\")")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE VALUE_MULTI_SZ ERROR_VARIABLE status)
+check("${KEY}{VALUE_MULTI_SZ}" "${result}" "${status}" "result STREQUAL \"data1;data2\"")
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE VALUE2_MULTI_SZ
+ SEPARATOR "|" ERROR_VARIABLE status)
+check("${KEY}{VALUE2_MULTI_SZ}" "${result}" "${status}" "result STREQUAL \"data1;data2\"")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE VALUE_DWORD ERROR_VARIABLE status)
+check("${KEY}{VALUE_DWORD}" "${result}" "${status}" "result EQUAL \"129\"")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE VALUE_QWORD ERROR_VARIABLE status)
+check("${KEY}{VALUE_QWORD}" "${result}" "${status}" "result EQUAL \"513\"")
+
+
+# HKCU/Software/CMake-Tests/chsi-registry: check retrieval of value names
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
+ ERROR_VARIABLE status)
+check("${KEY}[VALUE_NAMES]" "${result}" "${status}" "result STREQUAL \"(default);BYTE_SIZE;VALUE2_MULTI_SZ;VALUE2_SZ;VALUE_DWORD;VALUE_EXPAND_SZ;VALUE_MULTI_SZ;VALUE_QWORD;VALUE_SZ\"")
+# VIEW BOTH should have same result as default view
+cmake_host_system_information(RESULT result2 QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
+ VIEW BOTH ERROR_VARIABLE status)
+check("${KEY}[VALUE_NAMES]" "${result2}" "${status}" "result STREQUAL \"(default);BYTE_SIZE;VALUE2_MULTI_SZ;VALUE2_SZ;VALUE_DWORD;VALUE_EXPAND_SZ;VALUE_MULTI_SZ;VALUE_QWORD;VALUE_SZ\"")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
+ VIEW HOST ERROR_VARIABLE status)
+check("${KEY}[VALUE_NAMES]" "${result}" "${status}"
+ "(HOST_64BIT AND result STREQUAL \"(default);BYTE_SIZE;VALUE2_MULTI_SZ;VALUE_DWORD;VALUE_EXPAND_SZ;VALUE_MULTI_SZ;VALUE_QWORD;VALUE_SZ\")
+ OR (NOT HOST_64BIT AND result STREQUAL \"(default);BYTE_SIZE;VALUE2_SZ\")")
+# VIEW TARGET should have same result as VIEW HOST
+cmake_host_system_information(RESULT result2 QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
+ VIEW TARGET ERROR_VARIABLE status)
+check("${KEY}[VALUE_NAMES]" "${result2}" "${status}"
+ "(HOST_64BIT AND result STREQUAL \"(default);BYTE_SIZE;VALUE2_MULTI_SZ;VALUE_DWORD;VALUE_EXPAND_SZ;VALUE_MULTI_SZ;VALUE_QWORD;VALUE_SZ\")
+ OR (NOT HOST_64BIT AND result STREQUAL \"(default);BYTE_SIZE;VALUE2_SZ\")")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
+ VIEW 64 ERROR_VARIABLE status)
+check("${KEY}[VALUE_NAMES]" "${result}" "${status}"
+ "result STREQUAL \"(default);BYTE_SIZE;VALUE2_MULTI_SZ;VALUE_DWORD;VALUE_EXPAND_SZ;VALUE_MULTI_SZ;VALUE_QWORD;VALUE_SZ\"")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
+ VIEW 32 ERROR_VARIABLE status)
+check("${KEY}[VALUE_NAMES]" "${result}" "${status}" "result STREQUAL \"(default);BYTE_SIZE;VALUE2_SZ\"")
+
+# reg 64bit is read first
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
+ VIEW 64_32 ERROR_VARIABLE status)
+check("${KEY}[VALUE_NAMES]" "${result}" "${status}"
+ "result STREQUAL \"(default);BYTE_SIZE;VALUE2_MULTI_SZ;VALUE2_SZ;VALUE_DWORD;VALUE_EXPAND_SZ;VALUE_MULTI_SZ;VALUE_QWORD;VALUE_SZ\"")
+
+# reg 32bit is read first. Result is the same as with view 64_32
+cmake_host_system_information(RESULT result2 QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
+ VIEW 32_64 ERROR_VARIABLE status)
+check("${KEY}[VALUE_NAMES]" "${result2}" "${status}" "result2 STREQUAL result")
+
+
+# HKCU/Software/CMake-Tests/chsi-registry: check retrieval of sub keys
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
+ ERROR_VARIABLE status)
+check("${KEY}[SUBKEYS]" "${result}" "${status}" "result STREQUAL \"subkey1;subkey2;subkey3\"")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
+ VIEW HOST ERROR_VARIABLE status)
+check("${KEY}[SUBKEYS]" "${result}" "${status}"
+ "(HOST_64BIT AND result STREQUAL \"subkey1;subkey2\")
+ OR (NOT HOST_64BIT AND result STREQUAL \"subkey1;subkey3\")")
+# VIEW TARGET should have same result as VIEW HOST
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
+ VIEW TARGET ERROR_VARIABLE status)
+check("${KEY}[SUBKEYS]" "${result}" "${status}"
+ "(HOST_64BIT AND result STREQUAL \"subkey1;subkey2\")
+ OR (NOT HOST_64BIT AND result STREQUAL \"subkey1;subkey3\")")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
+ VIEW 64 ERROR_VARIABLE status)
+check("${KEY}[SUBKEYS]" "${result}" "${status}"
+ "result STREQUAL \"subkey1;subkey2\"")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
+ VIEW 32 ERROR_VARIABLE status)
+check("${KEY}[SUBKEYS]" "${result}" "${status}"
+ "result STREQUAL \"subkey1;subkey3\"")
+
+# reg 64bit is read first
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
+ VIEW 64_32 ERROR_VARIABLE status)
+check("${KEY}[SUBLEYS]" "${result}" "${status}" "result STREQUAL \"subkey1;subkey2;subkey3\"")
+
+# reg 32bit is read first. Result is the same as with view 64_32
+cmake_host_system_information(RESULT result2 QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
+ VIEW 32_64 ERROR_VARIABLE status)
+check("${KEY}[SUBKEYS]" "${result2}" "${status}" "result2 STREQUAL result")
+
+
+# Check influence of variable CMAKE_SIZEOF_VOID_P
+set(CMAKE_SIZEOF_VOID_P 8)
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}"
+ VIEW TARGET ERROR_VARIABLE status)
+check("${KEY}" "${result}" "${status}" "result STREQUAL \"default 64bit\"")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
+ VIEW TARGET ERROR_VARIABLE status)
+check("${KEY}" "${result}" "${status}" "result STREQUAL \"64bit\"")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
+ VIEW TARGET ERROR_VARIABLE status)
+check("${KEY}" "${result}" "${status}" "result STREQUAL \"(default);BYTE_SIZE;VALUE2_MULTI_SZ;VALUE_DWORD;VALUE_EXPAND_SZ;VALUE_MULTI_SZ;VALUE_QWORD;VALUE_SZ\"")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
+ VIEW TARGET ERROR_VARIABLE status)
+check("${KEY}" "${result}" "${status}" "result STREQUAL \"subkey1;subkey2\"")
+
+
+set(CMAKE_SIZEOF_VOID_P 4)
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}"
+ VIEW TARGET ERROR_VARIABLE status)
+check("${KEY}" "${result}" "${status}" "result STREQUAL \"default 32bit\"")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE BYTE_SIZE
+ VIEW TARGET ERROR_VARIABLE status)
+check("${KEY}" "${result}" "${status}" "result STREQUAL \"32bit\"")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" VALUE_NAMES
+ VIEW TARGET ERROR_VARIABLE status)
+check("${KEY}" "${result}" "${status}" "result STREQUAL \"(default);BYTE_SIZE;VALUE2_SZ\"")
+
+cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "${KEY}" SUBKEYS
+ VIEW TARGET ERROR_VARIABLE status)
+check("${KEY}" "${result}" "${status}" "result STREQUAL \"subkey1;subkey3\"")
diff --git a/Tests/RunCMake/cmake_host_system_information/RunCMakeTest.cmake b/Tests/RunCMake/cmake_host_system_information/RunCMakeTest.cmake
index 87b6944..d857bee 100644
--- a/Tests/RunCMake/cmake_host_system_information/RunCMakeTest.cmake
+++ b/Tests/RunCMake/cmake_host_system_information/RunCMakeTest.cmake
@@ -21,3 +21,27 @@ if(RunCMake_GENERATOR MATCHES "^Visual Studio " AND NOT RunCMake_GENERATOR STREQ
else()
run_cmake(VsMSBuildMissing)
endif()
+
+# WINDOWS_REGISTRY tests
+run_cmake(Registry_NoArgs)
+run_cmake(Registry_BadQuery1)
+run_cmake(Registry_BadQuery2)
+run_cmake(Registry_BadView1)
+run_cmake(Registry_BadView2)
+run_cmake(Registry_BadView3)
+if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+ run_cmake(Registry_BadKey1)
+ run_cmake(Registry_BadKey2)
+
+ # Tests using the Windows registry
+ find_program(REG NAMES "reg.exe" NO_CACHE)
+ if (REG)
+ # crete some entries in the registry
+ cmake_path(CONVERT "${RunCMake_SOURCE_DIR}/registry_data.reg" TO_NATIVE_PATH_LIST registry_data)
+ execute_process(COMMAND "${REG}" import "${registry_data}" OUTPUT_QUIET ERROR_QUIET)
+ run_cmake(Registry_Query)
+ # clean-up registry
+ execute_process(COMMAND "${REG}" delete "HKCU\\SOFTWARE\\Classes\\CLSID\\CMake-Tests" /f OUTPUT_QUIET ERROR_QUIET)
+ execute_process(COMMAND "${REG}" delete "HKCU\\SOFTWARE\\Classes\\WOW6432Node\\CLSID\\CMake-Tests" /f OUTPUT_QUIET ERROR_QUIET)
+ endif()
+endif()
diff --git a/Tests/RunCMake/cmake_host_system_information/registry_data.reg b/Tests/RunCMake/cmake_host_system_information/registry_data.reg
new file mode 100644
index 0000000..8596648
--- /dev/null
+++ b/Tests/RunCMake/cmake_host_system_information/registry_data.reg
Binary files differ
diff --git a/Tests/RunCMake/target_sources/FileSetImport.cmake b/Tests/RunCMake/target_sources/FileSetImport.cmake
index 9c7358a..7e790c7 100644
--- a/Tests/RunCMake/target_sources/FileSetImport.cmake
+++ b/Tests/RunCMake/target_sources/FileSetImport.cmake
@@ -17,7 +17,7 @@ include("${export_build_dir}/export.cmake")
include("${export_build_dir}/install/lib/cmake/export.cmake")
assert_prop_eq(export::lib1 HEADER_SETS "")
-assert_prop_eq(export::lib1 INTERFACE_HEADER_SETS "HEADERS;b;c;d;e;f;g;dir3")
+assert_prop_eq(export::lib1 INTERFACE_HEADER_SETS "HEADERS;b;c;d;dir3;e;f;g")
assert_prop_eq(export::lib1 HEADER_SET "${CMAKE_CURRENT_SOURCE_DIR}/error.c")
assert_prop_eq(export::lib1 HEADER_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")
assert_prop_eq(export::lib1 HEADER_SET_b "${CMAKE_CURRENT_SOURCE_DIR}/h2.h")
@@ -35,7 +35,7 @@ assert_prop_eq(export::lib1 HEADER_DIRS_g "${CMAKE_CURRENT_SOURCE_DIR}/dir1;${CM
assert_prop_eq(export::lib1 INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR};$<1:${CMAKE_CURRENT_SOURCE_DIR}/dir>;${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/$<IF:$<CONFIG:Debug>,debug,release>;${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/dir1;${CMAKE_CURRENT_SOURCE_DIR}/dir2;${CMAKE_CURRENT_SOURCE_DIR}/dir3;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:$<1:${CMAKE_CURRENT_SOURCE_DIR}/dir>>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/$<IF:$<CONFIG:Debug>,debug,release>>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir1>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir2>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir3>")
assert_prop_eq(install::lib1 HEADER_SETS "")
-assert_prop_eq(install::lib1 INTERFACE_HEADER_SETS "HEADERS;b;c;d;e;f;g;dir3")
+assert_prop_eq(install::lib1 INTERFACE_HEADER_SETS "HEADERS;b;c;d;dir3;e;f;g")
assert_prop_eq(install::lib1 HEADER_SET "${export_build_dir}/install/include/error.c")
assert_prop_eq(install::lib1 HEADER_DIRS "${export_build_dir}/install/include")
assert_prop_eq(install::lib1 HEADER_SET_b "${export_build_dir}/install/include/h2.h")
diff --git a/Tests/RunCMake/target_sources/FileSetNoExistInterface-stderr.txt b/Tests/RunCMake/target_sources/FileSetNoExistInterface-stderr.txt
deleted file mode 100644
index 3972c89..0000000
--- a/Tests/RunCMake/target_sources/FileSetNoExistInterface-stderr.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-^CMake Error at FileSetNoExistInterface\.cmake:[0-9]+ \(set_property\):
- Header set "a" has not yet been created\.
-Call Stack \(most recent call first\):
- CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/target_sources/FileSetNoExistPrivate-stderr.txt b/Tests/RunCMake/target_sources/FileSetNoExistPrivate-stderr.txt
deleted file mode 100644
index 336bafe..0000000
--- a/Tests/RunCMake/target_sources/FileSetNoExistPrivate-stderr.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-^CMake Error at FileSetNoExistPrivate\.cmake:[0-9]+ \(set_property\):
- Header set "a" has not yet been created\.
-Call Stack \(most recent call first\):
- CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/target_sources/FileSetNoExistPrivate.cmake b/Tests/RunCMake/target_sources/FileSetNoExistPrivate.cmake
deleted file mode 100644
index f501912..0000000
--- a/Tests/RunCMake/target_sources/FileSetNoExistPrivate.cmake
+++ /dev/null
@@ -1,7 +0,0 @@
-enable_language(C)
-
-add_library(lib1 STATIC empty.c)
-set_property(TARGET lib1 PROPERTY HEADER_SETS "a")
-
-# Error happens at configure-time, so this doesn't help.
-target_sources(lib1 PRIVATE FILE_SET a TYPE HEADERS)
diff --git a/Tests/RunCMake/target_sources/FileSetNoScope-stderr.txt b/Tests/RunCMake/target_sources/FileSetNoScope-stderr.txt
deleted file mode 100644
index 835ffe7..0000000
--- a/Tests/RunCMake/target_sources/FileSetNoScope-stderr.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-^CMake Error at FileSetNoScope\.cmake:[0-9]+ \(target_sources\):
- target_sources File set "a" is not in HEADER_SETS or INTERFACE_HEADER_SETS
-Call Stack \(most recent call first\):
- CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/target_sources/FileSetNoScope.cmake b/Tests/RunCMake/target_sources/FileSetNoScope.cmake
deleted file mode 100644
index 79ff341..0000000
--- a/Tests/RunCMake/target_sources/FileSetNoScope.cmake
+++ /dev/null
@@ -1,6 +0,0 @@
-enable_language(C)
-
-add_library(lib1 STATIC empty.c)
-target_sources(lib1 PRIVATE FILE_SET a TYPE HEADERS BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} FILES h1.h)
-set_property(TARGET lib1 PROPERTY HEADER_SETS)
-target_sources(lib1 PRIVATE FILE_SET a TYPE HEADERS FILES h2.h)
diff --git a/Tests/RunCMake/target_sources/FileSetProperties.cmake b/Tests/RunCMake/target_sources/FileSetProperties.cmake
index a671ab3..74487fe 100644
--- a/Tests/RunCMake/target_sources/FileSetProperties.cmake
+++ b/Tests/RunCMake/target_sources/FileSetProperties.cmake
@@ -57,14 +57,14 @@ assert_prop_eq(lib1 INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURC
assert_prop_eq(lib1 INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
target_sources(lib1 PUBLIC FILE_SET HEADERS BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}" FILES h1.h)
-assert_prop_eq(lib1 INTERFACE_HEADER_SETS "a;c;d;HEADERS")
+assert_prop_eq(lib1 INTERFACE_HEADER_SETS "HEADERS;a;c;d")
assert_prop_eq(lib1 HEADER_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")
assert_prop_eq(lib1 HEADER_SET "${CMAKE_CURRENT_SOURCE_DIR}/h1.h")
assert_prop_eq(lib1 INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
assert_prop_eq(lib1 INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
target_sources(lib1 PUBLIC FILE_SET HEADERS FILES h2.h)
-assert_prop_eq(lib1 INTERFACE_HEADER_SETS "a;c;d;HEADERS")
+assert_prop_eq(lib1 INTERFACE_HEADER_SETS "HEADERS;a;c;d")
assert_prop_eq(lib1 HEADER_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")
assert_prop_eq(lib1 HEADER_SET "${CMAKE_CURRENT_SOURCE_DIR}/h1.h;${CMAKE_CURRENT_SOURCE_DIR}/h2.h")
assert_prop_eq(lib1 INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/.>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/dir>;$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
diff --git a/Tests/RunCMake/target_sources/FileSetReadOnlyInterface-result.txt b/Tests/RunCMake/target_sources/FileSetReadOnlyInterface-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/target_sources/FileSetReadOnlyInterface-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/target_sources/FileSetReadOnlyInterface-stderr.txt b/Tests/RunCMake/target_sources/FileSetReadOnlyInterface-stderr.txt
new file mode 100644
index 0000000..2307d13
--- /dev/null
+++ b/Tests/RunCMake/target_sources/FileSetReadOnlyInterface-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at FileSetReadOnlyInterface\.cmake:[0-9]+ \(set_property\):
+ INTERFACE_HEADER_SETS property is read-only
+
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/target_sources/FileSetNoExistInterface.cmake b/Tests/RunCMake/target_sources/FileSetReadOnlyInterface.cmake
index 266bc61..468ef91 100644
--- a/Tests/RunCMake/target_sources/FileSetNoExistInterface.cmake
+++ b/Tests/RunCMake/target_sources/FileSetReadOnlyInterface.cmake
@@ -2,6 +2,3 @@ enable_language(C)
add_library(lib1 STATIC empty.c)
set_property(TARGET lib1 PROPERTY INTERFACE_HEADER_SETS "a")
-
-# Error happens at configure-time, so this doesn't help.
-target_sources(lib1 INTERFACE FILE_SET a TYPE HEADERS)
diff --git a/Tests/RunCMake/target_sources/FileSetReadOnlyPrivate-result.txt b/Tests/RunCMake/target_sources/FileSetReadOnlyPrivate-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/target_sources/FileSetReadOnlyPrivate-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/target_sources/FileSetReadOnlyPrivate-stderr.txt b/Tests/RunCMake/target_sources/FileSetReadOnlyPrivate-stderr.txt
new file mode 100644
index 0000000..5f955da
--- /dev/null
+++ b/Tests/RunCMake/target_sources/FileSetReadOnlyPrivate-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at FileSetReadOnlyPrivate\.cmake:[0-9]+ \(set_property\):
+ HEADER_SETS property is read-only
+
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/target_sources/FileSetReadOnlyPrivate.cmake b/Tests/RunCMake/target_sources/FileSetReadOnlyPrivate.cmake
new file mode 100644
index 0000000..eda92c1
--- /dev/null
+++ b/Tests/RunCMake/target_sources/FileSetReadOnlyPrivate.cmake
@@ -0,0 +1,4 @@
+enable_language(C)
+
+add_library(lib1 STATIC empty.c)
+set_property(TARGET lib1 PROPERTY HEADER_SETS "a")
diff --git a/Tests/RunCMake/target_sources/RunCMakeTest.cmake b/Tests/RunCMake/target_sources/RunCMakeTest.cmake
index 743879e..8429c96 100644
--- a/Tests/RunCMake/target_sources/RunCMakeTest.cmake
+++ b/Tests/RunCMake/target_sources/RunCMakeTest.cmake
@@ -33,9 +33,8 @@ run_cmake(FileSetWrongBaseDirsRelative)
run_cmake(FileSetOverlappingBaseDirs)
run_cmake(FileSetInstallMissingSetsPrivate)
run_cmake(FileSetInstallMissingSetsInterface)
-run_cmake(FileSetNoScope)
-run_cmake(FileSetNoExistPrivate)
-run_cmake(FileSetNoExistInterface)
+run_cmake(FileSetReadOnlyPrivate)
+run_cmake(FileSetReadOnlyInterface)
run_cmake(FileSetNoExistInstall)
run_cmake(FileSetDirectories)
run_cmake(FileSetCustomTarget)