summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml12
-rwxr-xr-x.gitlab/ci/borland-env.ps13
-rw-r--r--.gitlab/ci/download_python3.cmake41
-rwxr-xr-x.gitlab/ci/env_windows_borland5.5.ps11
-rwxr-xr-x.gitlab/ci/env_windows_borland5.8.ps11
-rwxr-xr-x.gitlab/ci/env_windows_msvc_v71_nmake.ps12
-rwxr-xr-x.gitlab/ci/env_windows_openwatcom1.9.ps11
-rwxr-xr-x.gitlab/ci/env_windows_vs2022_x64_jom.ps14
-rwxr-xr-x.gitlab/ci/env_windows_vs2022_x64_nmake.ps11
-rwxr-xr-x.gitlab/ci/openwatcom-env.ps17
-rwxr-xr-x.gitlab/ci/python-env.ps12
-rwxr-xr-x.gitlab/ci/python.ps130
-rw-r--r--.gitlab/os-windows.yml68
-rw-r--r--Auxiliary/cmake-mode.el4
-rw-r--r--Help/command/add_compile_options.rst15
-rw-r--r--Help/command/add_link_options.rst4
-rw-r--r--Help/command/target_compile_options.rst9
-rw-r--r--Help/command/target_link_options.rst4
-rw-r--r--Help/manual/cmake-policies.7.rst1
-rw-r--r--Help/manual/cmake-toolchains.7.rst9
-rw-r--r--Help/policy/CMP0149.rst47
-rw-r--r--Help/prop_tgt/COMPILE_OPTIONS.rst2
-rw-r--r--Help/release/3.26.rst4
-rw-r--r--Help/release/dev/vs-sdk-selection.rst7
-rw-r--r--Help/variable/CMAKE_GENERATOR_PLATFORM.rst42
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS.rst18
-rw-r--r--Help/variable/CMAKE_LANG_FLAGS_CONFIG.rst17
-rw-r--r--Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION.rst29
-rw-r--r--Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM.rst4
-rw-r--r--Modules/CMakeDetermineCompilerABI.cmake1
-rw-r--r--Modules/CMakeDetermineSwiftCompiler.cmake12
-rw-r--r--Modules/Compiler/NVHPC-Fortran.cmake1
-rw-r--r--Modules/FindBLAS.cmake8
-rw-r--r--Modules/FindCUDAToolkit.cmake17
-rw-r--r--Modules/FindLAPACK.cmake10
-rw-r--r--Modules/FindOpenSSL.cmake4
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/cmAlgorithms.h2
-rw-r--r--Source/cmGeneratorExpressionNode.cxx45
-rw-r--r--Source/cmGlobalVisualStudio10Generator.cxx24
-rw-r--r--Source/cmGlobalVisualStudio10Generator.h5
-rw-r--r--Source/cmGlobalVisualStudio14Generator.cxx125
-rw-r--r--Source/cmGlobalVisualStudio14Generator.h15
-rw-r--r--Source/cmGlobalVisualStudio8Generator.cxx92
-rw-r--r--Source/cmGlobalVisualStudio8Generator.h8
-rw-r--r--Source/cmGlobalVisualStudioVersionedGenerator.cxx10
-rw-r--r--Source/cmGlobalVisualStudioVersionedGenerator.h3
-rw-r--r--Source/cmList.cxx998
-rw-r--r--Source/cmList.h1198
-rw-r--r--Source/cmListCommand.cxx1152
-rw-r--r--Source/cmNinjaTargetGenerator.cxx25
-rw-r--r--Source/cmPolicies.h3
-rw-r--r--Tests/CMakeLib/CMakeLists.txt1
-rw-r--r--Tests/CMakeLib/testList.cxx995
-rw-r--r--Tests/RunCMake/Autogen/MocPredefs.cmake1
-rw-r--r--Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt2
-rw-r--r--Tests/RunCMake/CMakeLists.txt9
-rw-r--r--Tests/RunCMake/CMakePresets/validate_schema.py6
-rw-r--r--Tests/RunCMake/CPack/CMakeLists.txt4
-rw-r--r--Tests/RunCMake/CheckCompilerFlag/CMakeLists.txt6
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadFieldNoComma-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadFieldNoComma-stderr.txt11
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadFieldNoComma.cmake1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadFieldUnknown-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadFieldUnknown-stderr.txt11
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadFieldUnknown.cmake1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadVersionEmpty-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadVersionEmpty-stderr.txt11
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadVersionEmpty.cmake1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadVersionMissing-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadVersionMissing-stderr.txt11
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadVersionMissing.cmake1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadVersionPlatform-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadVersionPlatform-stderr.txt19
-rw-r--r--Tests/RunCMake/GeneratorPlatform/BadVersionPlatform.cmake1
-rw-r--r--Tests/RunCMake/GeneratorPlatform/RunCMakeTest.cmake83
-rw-r--r--Tests/RunCMake/GeneratorPlatform/VersionExists-check.cmake9
-rw-r--r--Tests/RunCMake/GeneratorPlatform/VersionExists.cmake5
-rw-r--r--Tests/RunCMake/RunCMake.cmake11
-rw-r--r--Utilities/Sphinx/cmake.py5
-rwxr-xr-xUtilities/Sphinx/create_identifiers.py8
-rwxr-xr-xbootstrap1
83 files changed, 4285 insertions, 1085 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2c81b37b46..b26172d360 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1051,7 +1051,7 @@ t:windows-vs2019-x64:
t:windows-vs2022-x64-nmake:
extends:
- .windows_vs2022_x64_nmake
- - .cmake_test_windows_nmake
+ - .cmake_test_windows_external
- .windows_x86_64_tags_concurrent_vs2022
- .cmake_junit_artifacts
- .run_dependent
@@ -1065,7 +1065,7 @@ t:windows-vs2022-x64-nmake:
t:windows-vs2022-x64-jom:
extends:
- .windows_vs2022_x64_jom
- - .cmake_test_windows_jom
+ - .cmake_test_windows_external
- .windows_x86_64_tags_concurrent_vs2022
- .cmake_junit_artifacts
- .run_dependent
@@ -1079,7 +1079,7 @@ t:windows-vs2022-x64-jom:
t:windows-borland5.5:
extends:
- .windows_borland5.5
- - .cmake_test_windows_borland
+ - .cmake_test_windows_external
- .windows_x86_64_tags_concurrent
- .cmake_junit_artifacts
- .run_dependent
@@ -1093,7 +1093,7 @@ t:windows-borland5.5:
t:windows-borland5.8:
extends:
- .windows_borland5.8
- - .cmake_test_windows_borland
+ - .cmake_test_windows_external
- .windows_x86_64_tags_concurrent
- .cmake_junit_artifacts
- .run_dependent
@@ -1195,7 +1195,7 @@ t:mingw_osdn_io-msys_makefiles:
t:windows-msvc-v71-nmake:
extends:
- .windows_msvc_v71_nmake
- - .cmake_test_windows_msvc
+ - .cmake_test_windows_external
- .windows_x86_64_tags_concurrent
- .cmake_junit_artifacts
- .run_dependent
@@ -1209,7 +1209,7 @@ t:windows-msvc-v71-nmake:
t:windows-openwatcom1.9:
extends:
- .windows_openwatcom1.9
- - .cmake_test_windows_openwatcom
+ - .cmake_test_windows_external
- .windows_x86_64_tags_concurrent
- .cmake_junit_artifacts
- .run_dependent
diff --git a/.gitlab/ci/borland-env.ps1 b/.gitlab/ci/borland-env.ps1
new file mode 100755
index 0000000000..b3b532e37c
--- /dev/null
+++ b/.gitlab/ci/borland-env.ps1
@@ -0,0 +1,3 @@
+Invoke-Expression -Command .gitlab/ci/borland.ps1
+$pwdpath = $pwd.Path
+Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\bcc\bin;$env:PATH"
diff --git a/.gitlab/ci/download_python3.cmake b/.gitlab/ci/download_python3.cmake
deleted file mode 100644
index 0f5b18b4ff..0000000000
--- a/.gitlab/ci/download_python3.cmake
+++ /dev/null
@@ -1,41 +0,0 @@
-cmake_minimum_required(VERSION 3.17)
-
-set(version "3.8.6")
-set(sha256sum "376e18eef7e3ea467f0e3af041b01fc7e2f12855506c2ab2653ceb5e0951212e")
-set(dirname "python-${version}-embed-win-x86_64")
-set(tarball "${dirname}.tar.xz")
-
-# Download the file.
-file(DOWNLOAD
- "https://cmake.org/files/dependencies/${tarball}"
- ".gitlab/${tarball}"
- STATUS download_status
- EXPECTED_HASH "SHA256=${sha256sum}")
-
-# Check the download status.
-list(GET download_status 0 res)
-if (res)
- list(GET download_status 1 err)
- message(FATAL_ERROR
- "Failed to download ${tarball}: ${err}")
-endif ()
-
-# Extract the file.
-execute_process(
- COMMAND
- "${CMAKE_COMMAND}"
- -E tar
- xzf "${tarball}"
- WORKING_DIRECTORY ".gitlab"
- RESULT_VARIABLE res
- ERROR_VARIABLE err
- ERROR_STRIP_TRAILING_WHITESPACE)
-if (res)
- message(FATAL_ERROR
- "Failed to extract ${tarball}: ${err}")
-endif ()
-
-# Move to a predictable directory.
-file(RENAME
- ".gitlab/${dirname}"
- ".gitlab/python3")
diff --git a/.gitlab/ci/env_windows_borland5.5.ps1 b/.gitlab/ci/env_windows_borland5.5.ps1
new file mode 100755
index 0000000000..0d2e46b67f
--- /dev/null
+++ b/.gitlab/ci/env_windows_borland5.5.ps1
@@ -0,0 +1 @@
+. .gitlab/ci/borland-env.ps1
diff --git a/.gitlab/ci/env_windows_borland5.8.ps1 b/.gitlab/ci/env_windows_borland5.8.ps1
new file mode 100755
index 0000000000..0d2e46b67f
--- /dev/null
+++ b/.gitlab/ci/env_windows_borland5.8.ps1
@@ -0,0 +1 @@
+. .gitlab/ci/borland-env.ps1
diff --git a/.gitlab/ci/env_windows_msvc_v71_nmake.ps1 b/.gitlab/ci/env_windows_msvc_v71_nmake.ps1
new file mode 100755
index 0000000000..cb3806d1ca
--- /dev/null
+++ b/.gitlab/ci/env_windows_msvc_v71_nmake.ps1
@@ -0,0 +1,2 @@
+Invoke-Expression -Command .gitlab/ci/msvc.ps1
+Invoke-Expression -Command .gitlab/ci/vcvarsall.ps1
diff --git a/.gitlab/ci/env_windows_openwatcom1.9.ps1 b/.gitlab/ci/env_windows_openwatcom1.9.ps1
new file mode 100755
index 0000000000..49c28f7a20
--- /dev/null
+++ b/.gitlab/ci/env_windows_openwatcom1.9.ps1
@@ -0,0 +1 @@
+. .gitlab/ci/openwatcom-env.ps1
diff --git a/.gitlab/ci/env_windows_vs2022_x64_jom.ps1 b/.gitlab/ci/env_windows_vs2022_x64_jom.ps1
new file mode 100755
index 0000000000..c933421d3a
--- /dev/null
+++ b/.gitlab/ci/env_windows_vs2022_x64_jom.ps1
@@ -0,0 +1,4 @@
+Invoke-Expression -Command .gitlab/ci/jom.ps1
+$pwdpath = $pwd.Path
+Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\jom;$env:PATH"
+Invoke-Expression -Command .gitlab/ci/vcvarsall.ps1
diff --git a/.gitlab/ci/env_windows_vs2022_x64_nmake.ps1 b/.gitlab/ci/env_windows_vs2022_x64_nmake.ps1
new file mode 100755
index 0000000000..62463cd98c
--- /dev/null
+++ b/.gitlab/ci/env_windows_vs2022_x64_nmake.ps1
@@ -0,0 +1 @@
+Invoke-Expression -Command .gitlab/ci/vcvarsall.ps1
diff --git a/.gitlab/ci/openwatcom-env.ps1 b/.gitlab/ci/openwatcom-env.ps1
new file mode 100755
index 0000000000..14ea523028
--- /dev/null
+++ b/.gitlab/ci/openwatcom-env.ps1
@@ -0,0 +1,7 @@
+Invoke-Expression -Command .gitlab/ci/openwatcom.ps1
+$pwdpath = $pwd.Path
+Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\watcom\binnt;$pwdpath\.gitlab\watcom\binw;$env:PATH"
+Set-Item -Force -Path "env:INCLUDE" -Value "$pwdpath\.gitlab\watcom\h;$pwdpath\.gitlab\watcom\h\nt"
+Set-Item -Force -Path "env:EDPATH" -Value "$pwdpath\.gitlab\watcom\eddat"
+Set-Item -Force -Path "env:WATCOM" -Value "$pwdpath\.gitlab\watcom"
+Set-Item -Force -Path "env:WLINKTMP" -Value "."
diff --git a/.gitlab/ci/python-env.ps1 b/.gitlab/ci/python-env.ps1
index 4e897d8dc6..ce16493e61 100755
--- a/.gitlab/ci/python-env.ps1
+++ b/.gitlab/ci/python-env.ps1
@@ -1,4 +1,4 @@
$pwdpath = $pwd.Path
-cmake -P .gitlab/ci/download_python3.cmake
+& "$pwsh" -File ".gitlab/ci/python.ps1"
Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\python3;$env:PATH"
python --version
diff --git a/.gitlab/ci/python.ps1 b/.gitlab/ci/python.ps1
new file mode 100755
index 0000000000..27f18071a6
--- /dev/null
+++ b/.gitlab/ci/python.ps1
@@ -0,0 +1,30 @@
+$erroractionpreference = "stop"
+
+$version = "3.11.3"
+
+if ("$env:PROCESSOR_ARCHITECTURE" -eq "AMD64") {
+ $sha256sum = "7419B2E98516FBD0B66A1237B80187FFB21D32E47B4A4235C2D9D6379597070F"
+ $arch = "amd64"
+} elseif ("$env:PROCESSOR_ARCHITECTURE" -eq "ARM64") {
+ $sha256sum = "03BAD6A7C898FC8F693982437AAB6DB698107B82EA93F76424195AE2C161246C"
+ $arch = "arm64"
+} else {
+ throw ('unknown PROCESSOR_ARCHITECTURE: ' + "$env:PROCESSOR_ARCHITECTURE")
+}
+
+$filename = "python-$version-embed-$arch"
+$tarball = "$filename.zip"
+
+$outdir = $pwd.Path
+$outdir = "$outdir\.gitlab"
+$ProgressPreference = 'SilentlyContinue'
+Invoke-WebRequest -Uri "https://cmake.org/files/dependencies/internal/$tarball" -OutFile "$outdir\$tarball"
+$hash = Get-FileHash "$outdir\$tarball" -Algorithm SHA256
+if ($hash.Hash -ne $sha256sum) {
+ exit 1
+}
+
+Add-Type -AssemblyName System.IO.Compression.FileSystem
+[System.IO.Compression.ZipFile]::ExtractToDirectory("$outdir\$tarball", "$outdir\python3")
+Remove-Item "$outdir\python3\*._pth" # Avoid sys.path specific to embedded python.
+Remove-Item "$outdir\$tarball"
diff --git a/.gitlab/os-windows.yml b/.gitlab/os-windows.yml
index ded3e659ff..f1e86ad3e5 100644
--- a/.gitlab/os-windows.yml
+++ b/.gitlab/os-windows.yml
@@ -349,6 +349,10 @@
- . .gitlab/ci/qt-env.ps1
- . .gitlab/ci/python-env.ps1
+.before_script_windows_external: &before_script_windows_external
+ - . .gitlab/ci/env.ps1
+ - . .gitlab/ci/python-env.ps1
+
.cmake_build_windows:
stage: build
@@ -381,69 +385,7 @@
stage: test-ext
script:
- - . .gitlab/ci/env.ps1
- - build/install/bin/ctest --output-on-failure -V -S .gitlab/ci/ctest_standalone.cmake
-
- interruptible: true
-
-.cmake_test_windows_nmake:
- stage: test-ext
-
- script:
- - . .gitlab/ci/env.ps1
- - Invoke-Expression -Command .gitlab/ci/vcvarsall.ps1
- - build/install/bin/ctest --output-on-failure -V -S .gitlab/ci/ctest_standalone.cmake
-
- interruptible: true
-
-.cmake_test_windows_jom:
- stage: test-ext
-
- script:
- - . .gitlab/ci/env.ps1
- - Invoke-Expression -Command .gitlab/ci/jom.ps1
- - $pwdpath = $pwd.Path
- - Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\jom;$env:PATH"
- - Invoke-Expression -Command .gitlab/ci/vcvarsall.ps1
- - build/install/bin/ctest --output-on-failure -V -S .gitlab/ci/ctest_standalone.cmake
-
- interruptible: true
-
-.cmake_test_windows_borland:
- stage: test-ext
-
- script:
- - . .gitlab/ci/env.ps1
- - Invoke-Expression -Command .gitlab/ci/borland.ps1
- - $pwdpath = $pwd.Path
- - Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\bcc\bin;$env:PATH"
- - build/install/bin/ctest --output-on-failure -V -S .gitlab/ci/ctest_standalone.cmake
-
- interruptible: true
-
-.cmake_test_windows_msvc:
- stage: test-ext
-
- script:
- - . .gitlab/ci/env.ps1
- - Invoke-Expression -Command .gitlab/ci/msvc.ps1
- - Invoke-Expression -Command .gitlab/ci/vcvarsall.ps1
- - build/install/bin/ctest --output-on-failure -V -S .gitlab/ci/ctest_standalone.cmake
-
- interruptible: true
-
-.cmake_test_windows_openwatcom:
- stage: test-ext
-
- script:
- - . .gitlab/ci/env.ps1
- - Invoke-Expression -Command .gitlab/ci/openwatcom.ps1
- - $pwdpath = $pwd.Path
- - Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\watcom\binnt;$pwdpath\.gitlab\watcom\binw;$env:PATH"
- - Set-Item -Force -Path "env:INCLUDE" -Value "$pwdpath\.gitlab\watcom\h;$pwdpath\.gitlab\watcom\h\nt"
- - Set-Item -Force -Path "env:EDPATH" -Value "$pwdpath\.gitlab\watcom\eddat"
- - Set-Item -Force -Path "env:WATCOM" -Value "$pwdpath\.gitlab\watcom"
- - Set-Item -Force -Path "env:WLINKTMP" -Value "."
+ - *before_script_windows_external
- build/install/bin/ctest --output-on-failure -V -S .gitlab/ci/ctest_standalone.cmake
interruptible: true
diff --git a/Auxiliary/cmake-mode.el b/Auxiliary/cmake-mode.el
index a11becbe20..7590ee3c1b 100644
--- a/Auxiliary/cmake-mode.el
+++ b/Auxiliary/cmake-mode.el
@@ -372,7 +372,7 @@ optional argument topic will be appended to the argument list."
(interactive "s")
(let* ((bufname (if buffer buffer (concat "*CMake" type (if topic "-") topic "*")))
(buffer (if (get-buffer bufname) (get-buffer bufname) (generate-new-buffer bufname)))
- (command (concat cmake-mode-cmake-executable " " type " " topic))
+ (command (concat cmake-mode-cmake-executable " " type " " (shell-quote-argument topic)))
;; Turn of resizing of mini-windows for shell-command.
(resize-mini-windows nil)
)
@@ -391,7 +391,7 @@ optional argument topic will be appended to the argument list."
(interactive "s")
(let* ((bufname (if buffer buffer (concat "*CMake" type (if topic "-") topic "*")))
(buffer (if (get-buffer bufname) (get-buffer bufname) (generate-new-buffer bufname)))
- (command (concat cmake-mode-cmake-executable " " type " " topic))
+ (command (concat cmake-mode-cmake-executable " " type " " (shell-quote-argument topic)))
;; Turn of resizing of mini-windows for shell-command.
(resize-mini-windows nil)
)
diff --git a/Help/command/add_compile_options.rst b/Help/command/add_compile_options.rst
index 0ccebc679b..869d0c2ced 100644
--- a/Help/command/add_compile_options.rst
+++ b/Help/command/add_compile_options.rst
@@ -11,6 +11,11 @@ Adds options to the :prop_dir:`COMPILE_OPTIONS` directory property.
These options are used when compiling targets from the current
directory and below.
+.. note::
+
+ These options are not used when linking.
+ See the :command:`add_link_options` command for that.
+
Arguments
^^^^^^^^^
@@ -48,5 +53,15 @@ See Also
* The command :command:`target_compile_options` adds target-specific options.
+* This command adds compile options for all languages.
+ Use the :genex:`COMPILE_LANGUAGE` generator expression to specify
+ per-language compile options.
+
* The source file property :prop_sf:`COMPILE_OPTIONS` adds options to one
source file.
+
+* :command:`add_link_options` adds options for linking.
+
+* :variable:`CMAKE_<LANG>_FLAGS` and :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>`
+ add language-wide flags passed to all invocations of the compiler.
+ This includes invocations that drive compiling and those that drive linking.
diff --git a/Help/command/add_link_options.rst b/Help/command/add_link_options.rst
index c09e106908..df72715431 100644
--- a/Help/command/add_link_options.rst
+++ b/Help/command/add_link_options.rst
@@ -38,3 +38,7 @@ See Also
* :command:`link_libraries`
* :command:`target_link_libraries`
* :command:`target_link_options`
+
+* :variable:`CMAKE_<LANG>_FLAGS` and :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>`
+ add language-wide flags passed to all invocations of the compiler.
+ This includes invocations that drive compiling and those that drive linking.
diff --git a/Help/command/target_compile_options.rst b/Help/command/target_compile_options.rst
index f3ac97bd09..7cfb24b18f 100644
--- a/Help/command/target_compile_options.rst
+++ b/Help/command/target_compile_options.rst
@@ -15,6 +15,11 @@ are used when compiling the given ``<target>``, which must have been
created by a command such as :command:`add_executable` or
:command:`add_library` and must not be an :ref:`ALIAS target <Alias Targets>`.
+.. note::
+
+ These options are not used when linking the target.
+ See the :command:`target_link_options` command for that.
+
Arguments
^^^^^^^^^
@@ -60,3 +65,7 @@ See Also
* :command:`target_link_options`
* :command:`target_precompile_headers`
* :command:`target_sources`
+
+* :variable:`CMAKE_<LANG>_FLAGS` and :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>`
+ add language-wide flags passed to all invocations of the compiler.
+ This includes invocations that drive compiling and those that drive linking.
diff --git a/Help/command/target_link_options.rst b/Help/command/target_link_options.rst
index 0d026f2456..dca9598611 100644
--- a/Help/command/target_link_options.rst
+++ b/Help/command/target_link_options.rst
@@ -62,3 +62,7 @@ See Also
* :command:`target_link_directories`
* :command:`target_precompile_headers`
* :command:`target_sources`
+
+* :variable:`CMAKE_<LANG>_FLAGS` and :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>`
+ add language-wide flags passed to all invocations of the compiler.
+ This includes invocations that drive compiling and those that drive linking.
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 158bf62155..8c7189a72b 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.27
.. toctree::
:maxdepth: 1
+ CMP0149: Visual Studio generators select latest Windows SDK by default. </policy/CMP0149>
CMP0148: The FindPythonInterp and FindPythonLibs modules are removed. </policy/CMP0148>
CMP0147: Visual Studio generators build custom commands in parallel. </policy/CMP0147>
CMP0146: The FindCUDA module is removed. </policy/CMP0146>
diff --git a/Help/manual/cmake-toolchains.7.rst b/Help/manual/cmake-toolchains.7.rst
index 9feb4d203a..a831fa6ef1 100644
--- a/Help/manual/cmake-toolchains.7.rst
+++ b/Help/manual/cmake-toolchains.7.rst
@@ -273,7 +273,7 @@ supported out of the box. Other versions may require one to set
Cross Compiling for Windows 10 Universal Applications
-----------------------------------------------------
-A toolchain file to configure a Visual Studio generator for a
+A toolchain file to configure :ref:`Visual Studio Generators` for a
Windows 10 Universal Application may look like this:
.. code-block:: cmake
@@ -283,9 +283,10 @@ Windows 10 Universal Application may look like this:
A Windows 10 Universal Application targets both Windows Store and
Windows Phone. Specify the :variable:`CMAKE_SYSTEM_VERSION` variable
-to be ``10.0`` to build with the latest available Windows 10 SDK.
-Specify a more specific version (e.g. ``10.0.10240.0`` for RTM)
-to build with the corresponding SDK.
+to be ``10.0`` or higher.
+
+CMake selects a Windows SDK as described by documentation of the
+:variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION` variable.
Cross Compiling for Windows Phone
---------------------------------
diff --git a/Help/policy/CMP0149.rst b/Help/policy/CMP0149.rst
new file mode 100644
index 0000000000..714eeaff2b
--- /dev/null
+++ b/Help/policy/CMP0149.rst
@@ -0,0 +1,47 @@
+CMP0149
+-------
+
+.. versionadded:: 3.27
+
+:ref:`Visual Studio Generators` select latest Windows SDK by default.
+
+Visual Studio Generators select a Windows SDK version to put in the
+``WindowsTargetPlatformVersion`` setting in ``.vcxproj`` files.
+CMake sets the :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION`
+variable to the selected SDK version.
+
+Prior to CMake 3.27, the SDK version was always selected by the value of
+the :variable:`CMAKE_SYSTEM_VERSION` variable. Users or toolchain files
+could set that variable to one of the exact Windows SDK versions available
+on the host system. Since :variable:`CMAKE_SYSTEM_VERSION` defaults to
+:variable:`CMAKE_HOST_SYSTEM_VERSION`, and it is not guaranteed that a
+matching Windows SDK version is available, CMake had to fall back to
+using the latest Windows SDK version if no exact match was available.
+This approach was problematic:
+
+* The latest Windows SDK might or might not be selected based on whether
+ the host version of Windows happens to match an available SDK version.
+
+* An old Windows SDK version might be selected that has not been updated
+ for newer language standards such as C11.
+
+CMake 3.27 and higher prefer to ignore the exact value of
+:variable:`CMAKE_SYSTEM_VERSION` and by default select the latest SDK
+version available. An exact SDK version may be specified explicitly
+using a ``version=`` field in the :variable:`CMAKE_GENERATOR_PLATFORM`
+variable. See :ref:`Visual Studio Platform Selection`.
+
+This policy provides compatibility for projects, toolchain files, and
+build scripts that have not been ported away from using
+:variable:`CMAKE_SYSTEM_VERSION` to specify an exact SDK version.
+
+The ``OLD`` behavior for this policy is to use the exact value of
+:variable:`CMAKE_SYSTEM_VERSION` if possible. The ``NEW`` behavior
+for this policy is to ignore it.
+
+This policy was introduced in CMake version 3.27. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/prop_tgt/COMPILE_OPTIONS.rst b/Help/prop_tgt/COMPILE_OPTIONS.rst
index 0dec25015d..8b032adeee 100644
--- a/Help/prop_tgt/COMPILE_OPTIONS.rst
+++ b/Help/prop_tgt/COMPILE_OPTIONS.rst
@@ -6,7 +6,7 @@ List of options to pass to the compiler.
This property holds a :ref:`semicolon-separated list <CMake Language Lists>`
of options specified so far for its target. Use the
:command:`target_compile_options` command to append more options.
-The options will be added after after flags in the
+The options will be added after flags in the
:variable:`CMAKE_<LANG>_FLAGS` and :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>`
variables, but before those propagated from dependencies by the
:prop_tgt:`INTERFACE_COMPILE_OPTIONS` property.
diff --git a/Help/release/3.26.rst b/Help/release/3.26.rst
index 67ace4a459..9e9327ea57 100644
--- a/Help/release/3.26.rst
+++ b/Help/release/3.26.rst
@@ -175,8 +175,8 @@ Updates
Changes made since CMake 3.26.0 include the following.
-3.26.1, 3.26.2
---------------
+3.26.1, 3.26.2, 3.26.3
+----------------------
* These versions made no changes to documented features or interfaces.
Some implementation updates were made to support ecosystem changes
diff --git a/Help/release/dev/vs-sdk-selection.rst b/Help/release/dev/vs-sdk-selection.rst
new file mode 100644
index 0000000000..856a2033c5
--- /dev/null
+++ b/Help/release/dev/vs-sdk-selection.rst
@@ -0,0 +1,7 @@
+vs-sdk-selection
+----------------
+
+* The :ref:`Visual Studio Generators` for VS 2015 and above learned to
+ select the Windows SDK version explicitly using a ``version=`` field
+ in the :variable:`CMAKE_GENERATOR_PLATFORM` variable.
+ See :ref:`Visual Studio Platform Selection`.
diff --git a/Help/variable/CMAKE_GENERATOR_PLATFORM.rst b/Help/variable/CMAKE_GENERATOR_PLATFORM.rst
index acb7b2e1a2..416ff60f34 100644
--- a/Help/variable/CMAKE_GENERATOR_PLATFORM.rst
+++ b/Help/variable/CMAKE_GENERATOR_PLATFORM.rst
@@ -26,8 +26,46 @@ Platform specification is supported only on specific generators:
See native build system documentation for allowed platform names.
+.. _`Visual Studio Platform Selection`:
+
Visual Studio Platform Selection
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-On :ref:`Visual Studio Generators` the selected platform name
-is provided in the :variable:`CMAKE_VS_PLATFORM_NAME` variable.
+The :ref:`Visual Studio Generators` support platform specification
+using one of these forms:
+
+* ``platform``
+* ``platform[,key=value]*``
+* ``key=value[,key=value]*``
+
+The ``platform`` specifies the target platform (VS target architecture),
+such as ``x64``, ``ARM64``, or ``Win32``. The selected platform
+name is provided in the :variable:`CMAKE_VS_PLATFORM_NAME` variable.
+
+The ``key=value`` pairs form a comma-separated list of options to
+specify generator-specific details of the platform selection.
+Supported pairs are:
+
+``version=<version>``
+ .. versionadded:: 3.27
+
+ Specify the Windows SDK version to use. This is supported by VS 2015 and
+ above when targeting Windows 10.0+ or Windows Store. CMake will set the
+ :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION` variable to the
+ selected SDK version.
+
+ The ``<version>`` may be one of:
+
+ ``10.0``
+ Specify that any 10.0 SDK version may be used, and let Visual Studio
+ pick one. This is supported by VS 2019 and above.
+
+ ``10.0.<build>.<increment>``
+ Specify the exact 4-component SDK version, e.g., ``10.0.19041.0``.
+ The specified version of the SDK must be installed. It may not exceed
+ the value of :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM`,
+ if that variable is set.
+
+ If the ``version`` field is not specified, CMake selects a version as
+ described in the :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION`
+ variable documentation.
diff --git a/Help/variable/CMAKE_LANG_FLAGS.rst b/Help/variable/CMAKE_LANG_FLAGS.rst
index 4b39b1deff..909a001a9c 100644
--- a/Help/variable/CMAKE_LANG_FLAGS.rst
+++ b/Help/variable/CMAKE_LANG_FLAGS.rst
@@ -1,9 +1,10 @@
CMAKE_<LANG>_FLAGS
------------------
-Flags for all build types.
-
-``<LANG>`` flags used regardless of the value of :variable:`CMAKE_BUILD_TYPE`.
+Language-wide flags for language ``<LANG>`` used when building for
+all configurations. These flags will be passed to all invocations
+of the compiler. This includes invocations that drive compiling
+and those that drive linking.
For each language, if this variable is not defined, it is initialized
and stored in the cache using values from environment variables in
@@ -27,7 +28,10 @@ combination with CMake's builtin defaults for the toolchain:
This value is a command-line string fragment. Therefore, multiple options
should be separated by spaces, and options with spaces should be quoted.
-The flags in this variable will be passed to the compiler before those
-in the per-configuration :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` variant,
-and before flags added by the :command:`add_compile_options` or
-:command:`target_compile_options` commands.
+The flags in this variable will be passed before those in the
+per-configuration :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>` variable.
+On invocations driving compiling, flags from both variables will be passed
+before flags added by commands such as :command:`add_compile_options` and
+:command:`target_compile_options`. On invocations driving linking,
+they will be passed before flags added by commands such as
+:command:`add_link_options` and :command:`target_link_options`.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_CONFIG.rst b/Help/variable/CMAKE_LANG_FLAGS_CONFIG.rst
index f0900fdc8d..5daa4c06a1 100644
--- a/Help/variable/CMAKE_LANG_FLAGS_CONFIG.rst
+++ b/Help/variable/CMAKE_LANG_FLAGS_CONFIG.rst
@@ -1,9 +1,16 @@
CMAKE_<LANG>_FLAGS_<CONFIG>
---------------------------
-Flags for language ``<LANG>`` when building for the ``<CONFIG>`` configuration.
+Language-wide flags for language ``<LANG>`` used when building for
+the ``<CONFIG>`` configuration. These flags will be passed to all
+invocations of the compiler in the corresponding configuration.
+This includes invocations that drive compiling and those that drive
+linking.
-The flags in this variable will be passed to the compiler after those
-in the :variable:`CMAKE_<LANG>_FLAGS` variable, but before flags added
-by the :command:`add_compile_options` or :command:`target_compile_options`
-commands.
+The flags in this variable will be passed after those in the
+:variable:`CMAKE_<LANG>_FLAGS` variable. On invocations driving compiling,
+flags from both variables will be passed before flags added by commands
+such as :command:`add_compile_options` and :command:`target_compile_options`.
+On invocations driving linking, they will be passed before flags added by
+commands such as :command:`add_link_options` and
+:command:`target_link_options`.
diff --git a/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION.rst b/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION.rst
index eb7104998a..2c14d3900d 100644
--- a/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION.rst
+++ b/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION.rst
@@ -5,11 +5,30 @@ CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION
Visual Studio Windows Target Platform Version.
-When targeting Windows 10 and above Visual Studio 2015 and above support
-specification of a target Windows version to select a corresponding SDK.
-The :variable:`CMAKE_SYSTEM_VERSION` variable may be set to specify a
-version. Otherwise CMake computes a default version based on the Windows
-SDK versions available. The chosen Windows target version number is provided
+When targeting Windows 10 and above, :ref:`Visual Studio Generators` for
+VS 2015 and above support specification of a Windows SDK version:
+
+* If :variable:`CMAKE_GENERATOR_PLATFORM` specifies a ``version=`` field,
+ as documented by :ref:`Visual Studio Platform Selection`, that SDK
+ version is selected.
+
+* Otherwise, if the ``WindowsSDKVersion`` environment variable
+ is set to an available SDK version, that version is selected.
+ This is intended for use in environments established by ``vcvarsall.bat``
+ or similar scripts.
+
+ .. versionadded:: 3.27
+ This is enabled by policy :policy:`CMP0149`.
+
+* Otherwise, if :variable:`CMAKE_SYSTEM_VERSION` is set to an available
+ SDK version, that version is selected.
+
+ .. versionchanged:: 3.27
+ This is disabled by policy :policy:`CMP0149`.
+
+* Otherwise, CMake uses the latest Windows SDK version available.
+
+The chosen Windows target version number is provided
in ``CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION``. If no Windows 10 SDK
is available this value will be empty.
diff --git a/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM.rst b/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM.rst
index f1a1977448..727ccc95be 100644
--- a/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM.rst
+++ b/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM.rst
@@ -10,5 +10,5 @@ be set to a false value (e.g. ``OFF``, ``FALSE``, or ``0``) or the SDK version
to use as the maximum (e.g. ``10.0.14393.0``). If unset, the default depends
on which version of Visual Studio is targeted by the current generator.
-This can be used in conjunction with :variable:`CMAKE_SYSTEM_VERSION`, which
-CMake uses to select :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION`.
+This can be used to exclude Windows SDK versions from consideration for
+:variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION`.
diff --git a/Modules/CMakeDetermineCompilerABI.cmake b/Modules/CMakeDetermineCompilerABI.cmake
index 4169734af0..3fd54cc7ef 100644
--- a/Modules/CMakeDetermineCompilerABI.cmake
+++ b/Modules/CMakeDetermineCompilerABI.cmake
@@ -163,7 +163,6 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
PROJECT IntelFortranImplicit
SOURCE_DIR ${CMAKE_ROOT}/Modules/IntelVSImplicitPath
BINARY_DIR ${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath
- IntelFortranImplicit
CMAKE_FLAGS
"-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}"
OUTPUT_VARIABLE _output)
diff --git a/Modules/CMakeDetermineSwiftCompiler.cmake b/Modules/CMakeDetermineSwiftCompiler.cmake
index f0a63a8cff..7239424652 100644
--- a/Modules/CMakeDetermineSwiftCompiler.cmake
+++ b/Modules/CMakeDetermineSwiftCompiler.cmake
@@ -15,7 +15,14 @@ if("${CMAKE_GENERATOR}" STREQUAL "Xcode")
message(FATAL_ERROR "Swift language not supported by Xcode ${XCODE_VERSION}")
endif()
set(CMAKE_Swift_COMPILER_XCODE_TYPE sourcecode.swift)
- _cmake_find_compiler_path(Swift)
+ execute_process(COMMAND xcrun --find swiftc
+ OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE _xcrun_err RESULT_VARIABLE _xcrun_result)
+ if(_xcrun_result EQUAL 0 AND EXISTS "${_xcrun_out}")
+ set(CMAKE_Swift_COMPILER "${_xcrun_out}")
+ else()
+ _cmake_find_compiler_path(Swift)
+ endif()
elseif("${CMAKE_GENERATOR}" MATCHES "^Ninja")
if(CMAKE_Swift_COMPILER)
_cmake_find_compiler_path(Swift)
@@ -52,9 +59,6 @@ if(NOT CMAKE_Swift_COMPILER_ID_RUN)
if("${CMAKE_GENERATOR}" STREQUAL "Xcode")
list(APPEND CMAKE_Swift_COMPILER_ID_MATCH_VENDORS Apple)
set(CMAKE_Swift_COMPILER_ID_MATCH_VENDOR_REGEX_Apple "com.apple.xcode.tools.swift.compiler")
-
- set(CMAKE_Swift_COMPILER_ID_TOOL_MATCH_REGEX "\nCompileSwift[^\n]*(\n[ \t]+[^\n]*)*\n[ \t]+([^ \t\r\n]+)[^\r\n]* -c[^\r\n]*CompilerIdSwift/CompilerId/main.swift")
- set(CMAKE_Swift_COMPILER_ID_TOOL_MATCH_INDEX 2)
endif()
# Try to identify the compiler.
diff --git a/Modules/Compiler/NVHPC-Fortran.cmake b/Modules/Compiler/NVHPC-Fortran.cmake
index 59755b3a71..5c0645737d 100644
--- a/Modules/Compiler/NVHPC-Fortran.cmake
+++ b/Modules/Compiler/NVHPC-Fortran.cmake
@@ -1,3 +1,4 @@
include(Compiler/PGI-Fortran)
include(Compiler/NVHPC)
__compiler_nvhpc(Fortran)
+set(CMAKE_Fortran_PREPROCESS_SOURCE_EXCLUDE_FLAGS_REGEX "(^| )-Werror +[a-z][a-z-]+( |$)")
diff --git a/Modules/FindBLAS.cmake b/Modules/FindBLAS.cmake
index 7af1017006..19bef9471c 100644
--- a/Modules/FindBLAS.cmake
+++ b/Modules/FindBLAS.cmake
@@ -386,10 +386,10 @@ set(BLAS_LINKER_FLAGS)
set(BLAS_LIBRARIES)
set(BLAS95_LIBRARIES)
set(_blas_fphsa_req_var BLAS_LIBRARIES)
-if(NOT $ENV{BLA_VENDOR} STREQUAL "")
- set(BLA_VENDOR $ENV{BLA_VENDOR})
-else()
- if(NOT BLA_VENDOR)
+if(NOT BLA_VENDOR)
+ if(NOT "$ENV{BLA_VENDOR}" STREQUAL "")
+ set(BLA_VENDOR "$ENV{BLA_VENDOR}")
+ else()
set(BLA_VENDOR "All")
endif()
endif()
diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake
index 67bf4246d2..4423ebb628 100644
--- a/Modules/FindCUDAToolkit.cmake
+++ b/Modules/FindCUDAToolkit.cmake
@@ -1036,12 +1036,20 @@ if(CUDAToolkit_FOUND)
endif()
endif()
+ if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 12.0.0)
+ _CUDAToolkit_find_and_add_import_lib(nvJitLink)
+ _CUDAToolkit_find_and_add_import_lib(nvJitLink_static DEPS cudart_static_deps)
+ endif()
+
_CUDAToolkit_find_and_add_import_lib(culibos) # it's a static library
- foreach (cuda_lib cublasLt cufft curand cusparse nppc nvjpeg)
+ foreach (cuda_lib cublasLt cufft curand nppc nvjpeg)
_CUDAToolkit_find_and_add_import_lib(${cuda_lib})
_CUDAToolkit_find_and_add_import_lib(${cuda_lib}_static DEPS culibos)
endforeach()
+ _CUDAToolkit_find_and_add_import_lib(cusparse DEPS nvJitLink)
+ _CUDAToolkit_find_and_add_import_lib(cusparse_static DEPS nvJitLink_static culibos)
+
if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 11.0.0)
# cublas depends on cublasLt
# https://docs.nvidia.com/cuda/archive/11.0/cublas/index.html#static-library
@@ -1129,16 +1137,11 @@ if(CUDAToolkit_FOUND)
if(NOT TARGET CUDA::nvptxcompiler_static)
_CUDAToolkit_find_and_add_import_lib(nvptxcompiler_static DEPS cuda_driver)
if(TARGET CUDA::nvptxcompiler_static)
- target_link_libraries(CUDA::nvptxcompiler_static INTERFACE Threads::Threads)
+ target_link_libraries(CUDA::nvptxcompiler_static INTERFACE CUDA::cudart_static_deps)
endif()
endif()
endif()
- if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 12.0.0)
- _CUDAToolkit_find_and_add_import_lib(nvJitLink DEPS cuda_driver)
- _CUDAToolkit_find_and_add_import_lib(nvJitLink_static DEPS cuda_driver)
- endif()
-
_CUDAToolkit_find_and_add_import_lib(nvrtc_builtins DEPS cuda_driver)
_CUDAToolkit_find_and_add_import_lib(nvrtc DEPS nvrtc_builtins nvJitLink)
if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 11.5.0)
diff --git a/Modules/FindLAPACK.cmake b/Modules/FindLAPACK.cmake
index 1eecb1cbd2..17117bd871 100644
--- a/Modules/FindLAPACK.cmake
+++ b/Modules/FindLAPACK.cmake
@@ -304,10 +304,12 @@ endif()
# Search for different LAPACK distributions if BLAS is found
if(NOT LAPACK_NOT_FOUND_MESSAGE)
set(LAPACK_LINKER_FLAGS ${BLAS_LINKER_FLAGS})
- if(NOT $ENV{BLA_VENDOR} STREQUAL "")
- set(BLA_VENDOR $ENV{BLA_VENDOR})
- elseif(NOT BLA_VENDOR)
- set(BLA_VENDOR "All")
+ if(NOT BLA_VENDOR)
+ if(NOT "$ENV{BLA_VENDOR}" STREQUAL "")
+ set(BLA_VENDOR "$ENV{BLA_VENDOR}")
+ else()
+ set(BLA_VENDOR "All")
+ endif()
endif()
# LAPACK in the Intel MKL 10+ library?
diff --git a/Modules/FindOpenSSL.cmake b/Modules/FindOpenSSL.cmake
index 4e8374c68e..45dc9ac809 100644
--- a/Modules/FindOpenSSL.cmake
+++ b/Modules/FindOpenSSL.cmake
@@ -210,7 +210,7 @@ endif ()
# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
if(OPENSSL_USE_STATIC_LIBS)
set(_openssl_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
- if(WIN32)
+ if(MSVC)
set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
else()
set(CMAKE_FIND_LIBRARY_SUFFIXES .a )
@@ -230,7 +230,7 @@ else()
set(_OPENSSL_FIND_PATH_SUFFIX "include")
endif()
-if (WIN32)
+if (MSVC)
# http://www.slproweb.com/products/Win32OpenSSL.html
set(_OPENSSL_ROOT_HINTS
${OPENSSL_ROOT_DIR}
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index dcc717426c..4a7d9bc591 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -335,6 +335,8 @@ add_library(
cmLinkLineComputer.h
cmLinkLineDeviceComputer.cxx
cmLinkLineDeviceComputer.h
+ cmList.h
+ cmList.cxx
cmListFileCache.cxx
cmListFileCache.h
cmLocalCommonGenerator.cxx
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 73f213e32a..605dc3cb50 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 26)
-set(CMake_VERSION_PATCH 20230403)
+set(CMake_VERSION_PATCH 20230410)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
diff --git a/Source/cmAlgorithms.h b/Source/cmAlgorithms.h
index a1830f9f8e..2c3ee9b5ef 100644
--- a/Source/cmAlgorithms.h
+++ b/Source/cmAlgorithms.h
@@ -95,7 +95,7 @@ typename Range::const_iterator cmRemoveIndices(Range& r, InputRange const& rem)
}
template <typename Range, typename MatchRange>
-typename Range::const_iterator cmRemoveMatching(Range& r, MatchRange const& m)
+auto cmRemoveMatching(Range& r, MatchRange const& m) -> decltype(r.begin())
{
return std::remove_if(r.begin(), r.end(),
ContainerAlgorithms::BinarySearcher<MatchRange>(m));
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 6e78f55776..a47366b4a1 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -12,6 +12,7 @@
#include <memory>
#include <set>
#include <sstream>
+#include <stdexcept>
#include <unordered_map>
#include <utility>
@@ -25,7 +26,6 @@
#include "cmsys/RegularExpression.hxx"
#include "cmsys/String.h"
-#include "cmAlgorithms.h"
#include "cmCMakePath.h"
#include "cmComputeLinkInformation.h"
#include "cmGeneratorExpression.h"
@@ -35,6 +35,7 @@
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmLinkItem.h"
+#include "cmList.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
@@ -291,18 +292,18 @@ static const struct InListNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* /*content*/,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- std::vector<std::string> values;
- std::vector<std::string> checkValues;
+ cmList values;
+ cmList checkValues;
bool check = false;
switch (context->LG->GetPolicyStatus(cmPolicies::CMP0085)) {
case cmPolicies::WARN:
if (parameters.front().empty()) {
check = true;
- cmExpandList(parameters[1], checkValues, true);
+ checkValues.assign(parameters[1], cmList::EmptyElements::Yes);
}
CM_FALLTHROUGH;
case cmPolicies::OLD:
- cmExpandList(parameters[1], values);
+ values.assign(parameters[1]);
if (check && values != checkValues) {
std::ostringstream e;
e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0085)
@@ -319,11 +320,11 @@ static const struct InListNode : public cmGeneratorExpressionNode
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::NEW:
- cmExpandList(parameters[1], values, true);
+ values.assign(parameters[1], cmList::EmptyElements::Yes);
break;
}
- return cm::contains(values, parameters.front()) ? "1" : "0";
+ return values.find(parameters.front()) != cmList::npos ? "1" : "0";
}
} inListNode;
@@ -352,24 +353,17 @@ static const struct FilterNode : public cmGeneratorExpressionNode
return {};
}
- const bool exclude = parameters[1] == "EXCLUDE";
-
- cmsys::RegularExpression re;
- if (!re.compile(parameters[2])) {
+ try {
+ return cmList{ parameters.front(), cmList::EmptyElements::Yes }
+ .filter(parameters[2],
+ parameters[1] == "EXCLUDE" ? cmList::FilterMode::EXCLUDE
+ : cmList::FilterMode::INCLUDE)
+ .to_string();
+ } catch (std::invalid_argument&) {
reportError(context, content->GetOriginalExpression(),
"$<FILTER:...> failed to compile regex");
return {};
}
-
- std::vector<std::string> values;
- std::vector<std::string> result;
- cmExpandList(parameters.front(), values, true);
-
- std::copy_if(values.cbegin(), values.cend(), std::back_inserter(result),
- [&re, exclude](std::string const& input) {
- return exclude ^ re.find(input);
- });
- return cmJoin(cmMakeRange(result.cbegin(), result.cend()), ";");
}
} filterNode;
@@ -391,11 +385,7 @@ static const struct RemoveDuplicatesNode : public cmGeneratorExpressionNode
"$<REMOVE_DUPLICATES:...> expression requires one parameter");
}
- std::vector<std::string> values = cmExpandedList(parameters.front(), true);
-
- auto valuesEnd = cmRemoveDuplicates(values);
- auto valuesBegin = values.cbegin();
- return cmJoin(cmMakeRange(valuesBegin, valuesEnd), ";");
+ return cmList{ parameters.front() }.remove_duplicates().to_string();
}
} removeDuplicatesNode;
@@ -1500,8 +1490,7 @@ static const struct JoinNode : public cmGeneratorExpressionNode
const GeneratorExpressionContent* /*content*/,
cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
{
- std::vector<std::string> list = cmExpandedList(parameters.front());
- return cmJoin(list, parameters[1]);
+ return cmList{ parameters.front() }.join(parameters[1]);
}
} joinNode;
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index 1e01dd6a2b..321f3779d0 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -525,6 +525,30 @@ bool cmGlobalVisualStudio10Generator::InitializeAndroid(cmMakefile* mf)
return false;
}
+bool cmGlobalVisualStudio10Generator::InitializePlatform(cmMakefile* mf)
+{
+ if (this->SystemName == "Windows" || this->SystemName == "WindowsStore") {
+ if (!this->InitializePlatformWindows(mf)) {
+ return false;
+ }
+ } else if (!this->SystemName.empty() &&
+ !this->VerifyNoGeneratorPlatformVersion(mf)) {
+ return false;
+ }
+ return this->cmGlobalVisualStudio8Generator::InitializePlatform(mf);
+}
+
+bool cmGlobalVisualStudio10Generator::InitializePlatformWindows(cmMakefile*)
+{
+ return true;
+}
+
+bool cmGlobalVisualStudio10Generator::VerifyNoGeneratorPlatformVersion(
+ cmMakefile*, cm::optional<std::string>) const
+{
+ return true;
+}
+
bool cmGlobalVisualStudio10Generator::SelectWindowsPhoneToolset(
std::string& toolset) const
{
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index deed206c13..6917ffcc06 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -183,6 +183,11 @@ protected:
virtual bool InitializeTegraAndroid(cmMakefile* mf);
virtual bool InitializeAndroid(cmMakefile* mf);
+ bool InitializePlatform(cmMakefile* mf) override;
+ virtual bool InitializePlatformWindows(cmMakefile* mf);
+ virtual bool VerifyNoGeneratorPlatformVersion(
+ cmMakefile* mf, cm::optional<std::string> reason = cm::nullopt) const;
+
virtual bool ProcessGeneratorToolsetField(std::string const& key,
std::string const& value);
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
index 7424ca3980..4300d5c9f3 100644
--- a/Source/cmGlobalVisualStudio14Generator.cxx
+++ b/Source/cmGlobalVisualStudio14Generator.cxx
@@ -12,6 +12,7 @@
#include "cmGlobalVisualStudioGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmPolicies.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmValue.h"
@@ -137,12 +138,36 @@ bool cmGlobalVisualStudio14Generator::MatchesGeneratorName(
return false;
}
-bool cmGlobalVisualStudio14Generator::InitializeWindows(cmMakefile* mf)
+bool cmGlobalVisualStudio14Generator::InitializePlatformWindows(cmMakefile* mf)
{
if (cmHasLiteralPrefix(this->SystemVersion, "10.0")) {
- return this->SelectWindows10SDK(mf, false);
+ return this->SelectWindows10SDK(mf);
}
- return true;
+ return this->VerifyNoGeneratorPlatformVersion(mf);
+}
+
+bool cmGlobalVisualStudio14Generator::VerifyNoGeneratorPlatformVersion(
+ cmMakefile* mf, cm::optional<std::string> reason) const
+{
+ if (!this->GeneratorPlatformVersion) {
+ return true;
+ }
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "given platform specification containing a\n"
+ " version=" << *this->GeneratorPlatformVersion << "\n"
+ "field. The version field is not supported when targeting\n"
+ " " << this->SystemName << " " << this->SystemVersion << "\n"
+ ;
+ /* clang-format on */
+ if (reason) {
+ e << *reason << ".";
+ }
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
}
bool cmGlobalVisualStudio14Generator::InitializeWindowsStore(cmMakefile* mf)
@@ -162,9 +187,6 @@ bool cmGlobalVisualStudio14Generator::InitializeWindowsStore(cmMakefile* mf)
mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
return false;
}
- if (cmHasLiteralPrefix(this->SystemVersion, "10.0")) {
- return this->SelectWindows10SDK(mf, true);
- }
return true;
}
@@ -173,19 +195,51 @@ bool cmGlobalVisualStudio14Generator::InitializeAndroid(cmMakefile*)
return true;
}
-bool cmGlobalVisualStudio14Generator::SelectWindows10SDK(cmMakefile* mf,
- bool required)
+bool cmGlobalVisualStudio14Generator::ProcessGeneratorPlatformField(
+ std::string const& key, std::string const& value)
+{
+ if (key == "version") {
+ this->GeneratorPlatformVersion = value;
+ return true;
+ }
+ return false;
+}
+
+bool cmGlobalVisualStudio14Generator::SelectWindows10SDK(cmMakefile* mf)
{
+ if (this->GeneratorPlatformVersion &&
+ this->GeneratorPlatformVersion->empty()) {
+ mf->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Generator\n ", this->GetName(),
+ "\ngiven platform specification with empty\n version=\n"
+ "field."));
+ return false;
+ }
+
// Find the default version of the Windows 10 SDK.
std::string const version = this->GetWindows10SDKVersion(mf);
- if (required && version.empty()) {
- std::ostringstream e;
- e << "Could not find an appropriate version of the Windows 10 SDK"
- << " installed on this machine";
- mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
- return false;
+ if (version.empty()) {
+ if (this->GeneratorPlatformVersion) {
+ mf->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmStrCat("Generator\n ", this->GetName(),
+ "\ngiven platform specification with\n version=",
+ *this->GeneratorPlatformVersion,
+ "\nfield, but no Windows SDK with that version was found."));
+ return false;
+ }
+
+ if (this->SystemName == "WindowsStore") {
+ mf->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "Could not find an appropriate version of the Windows 10 SDK"
+ " installed on this machine");
+ return false;
+ }
}
+
this->SetWindowsTargetPlatformVersion(version, mf);
return true;
}
@@ -302,6 +356,16 @@ std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion(
cmMakefile* mf)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
+ // Accept specific version requests as-is.
+ if (this->GeneratorPlatformVersion) {
+ std::string const& ver = *this->GeneratorPlatformVersion;
+
+ // VS 2019 and above support specifying plain "10.0".
+ if (this->Version >= VSVersion::VS16 && ver == "10.0") {
+ return ver;
+ }
+ }
+
std::vector<std::string> win10Roots;
{
@@ -360,10 +424,35 @@ std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion(
// Sort the results to make sure we select the most recent one.
std::sort(sdks.begin(), sdks.end(), cmSystemTools::VersionCompareGreater);
- // Look for a SDK exactly matching the requested target version.
- for (std::string const& i : sdks) {
- if (cmSystemTools::VersionCompareEqual(i, this->SystemVersion)) {
- return i;
+ // Look for a SDK exactly matching the requested version, if any.
+ if (this->GeneratorPlatformVersion) {
+ for (std::string const& i : sdks) {
+ if (cmSystemTools::VersionCompareEqual(
+ i, *this->GeneratorPlatformVersion)) {
+ return i;
+ }
+ }
+ // An exact version was requested but not found.
+ // Our caller will issue the error message.
+ return std::string();
+ }
+
+ if (mf->GetPolicyStatus(cmPolicies::CMP0149) == cmPolicies::NEW) {
+ if (cm::optional<std::string> const envVer =
+ cmSystemTools::GetEnvVar("WindowsSDKVersion")) {
+ // Look for a SDK exactly matching the environment variable.
+ for (std::string const& i : sdks) {
+ if (cmSystemTools::VersionCompareEqual(i, *envVer)) {
+ return i;
+ }
+ }
+ }
+ } else {
+ // Look for a SDK exactly matching the target Windows version.
+ for (std::string const& i : sdks) {
+ if (cmSystemTools::VersionCompareEqual(i, this->SystemVersion)) {
+ return i;
+ }
}
}
diff --git a/Source/cmGlobalVisualStudio14Generator.h b/Source/cmGlobalVisualStudio14Generator.h
index 7fb9b4bbb8..f59a323308 100644
--- a/Source/cmGlobalVisualStudio14Generator.h
+++ b/Source/cmGlobalVisualStudio14Generator.h
@@ -7,6 +7,8 @@
#include <memory>
#include <string>
+#include <cm/optional>
+
#include "cmGlobalVisualStudio12Generator.h"
class cmGlobalGeneratorFactory;
@@ -30,7 +32,6 @@ protected:
cmGlobalVisualStudio14Generator(cmake* cm, const std::string& name,
std::string const& platformInGeneratorName);
- bool InitializeWindows(cmMakefile* mf) override;
bool InitializeWindowsStore(cmMakefile* mf) override;
bool InitializeAndroid(cmMakefile* mf) override;
bool SelectWindowsStoreToolset(std::string& toolset) const override;
@@ -39,6 +40,14 @@ protected:
// of the toolset is installed
bool IsWindowsStoreToolsetInstalled() const;
+ bool InitializePlatformWindows(cmMakefile* mf) override;
+ bool VerifyNoGeneratorPlatformVersion(
+ cmMakefile* mf,
+ cm::optional<std::string> reason = cm::nullopt) const override;
+
+ bool ProcessGeneratorPlatformField(std::string const& key,
+ std::string const& value) override;
+
// Used to adjust the max-SDK-version calculation to accommodate user
// configuration.
std::string GetWindows10SDKMaxVersion(cmMakefile* mf) const;
@@ -47,7 +56,7 @@ protected:
// version of the toolset.
virtual std::string GetWindows10SDKMaxVersionDefault(cmMakefile* mf) const;
- virtual bool SelectWindows10SDK(cmMakefile* mf, bool required);
+ virtual bool SelectWindows10SDK(cmMakefile* mf);
void SetWindowsTargetPlatformVersion(std::string const& version,
cmMakefile* mf);
@@ -61,4 +70,6 @@ protected:
private:
class Factory;
friend class Factory;
+
+ cm::optional<std::string> GeneratorPlatformVersion;
};
diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx
index 2e2c8b686d..2aba46fe2c 100644
--- a/Source/cmGlobalVisualStudio8Generator.cxx
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -94,7 +94,9 @@ bool cmGlobalVisualStudio8Generator::SetGeneratorPlatform(std::string const& p,
return this->cmGlobalVisualStudio7Generator::SetGeneratorPlatform(p, mf);
}
- this->GeneratorPlatform = p;
+ if (!this->ParseGeneratorPlatform(p, mf)) {
+ return false;
+ }
// FIXME: Add CMAKE_GENERATOR_PLATFORM field to set the framework.
// For now, just report the generator's default, if any.
@@ -114,12 +116,100 @@ bool cmGlobalVisualStudio8Generator::SetGeneratorPlatform(std::string const& p,
*targetFrameworkTargetsVersion);
}
+ if (!this->InitializePlatform(mf)) {
+ return false;
+ }
+
// The generator name does not contain the platform name, and so supports
// explicit platform specification. We handled that above, so pass an
// empty platform name to our base class implementation so it does not error.
return this->cmGlobalVisualStudio7Generator::SetGeneratorPlatform("", mf);
}
+bool cmGlobalVisualStudio8Generator::ParseGeneratorPlatform(
+ std::string const& p, cmMakefile* mf)
+{
+ this->GeneratorPlatform.clear();
+
+ std::vector<std::string> const fields = cmTokenize(p, ",");
+ auto fi = fields.begin();
+ if (fi == fields.end()) {
+ return true;
+ }
+
+ // The first field may be the VS platform.
+ if (fi->find('=') == fi->npos) {
+ this->GeneratorPlatform = *fi;
+ ++fi;
+ }
+
+ std::set<std::string> handled;
+
+ // The rest of the fields must be key=value pairs.
+ for (; fi != fields.end(); ++fi) {
+ std::string::size_type pos = fi->find('=');
+ if (pos == fi->npos) {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "given platform specification\n"
+ " " << p << "\n"
+ "that contains a field after the first ',' with no '='."
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ std::string const key = fi->substr(0, pos);
+ std::string const value = fi->substr(pos + 1);
+ if (!handled.insert(key).second) {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "given platform specification\n"
+ " " << p << "\n"
+ "that contains duplicate field key '" << key << "'."
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ if (!this->ProcessGeneratorPlatformField(key, value)) {
+ std::ostringstream e;
+ /* clang-format off */
+ e <<
+ "Generator\n"
+ " " << this->GetName() << "\n"
+ "given platform specification\n"
+ " " << p << "\n"
+ "that contains invalid field '" << *fi << "'."
+ ;
+ /* clang-format on */
+ mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool cmGlobalVisualStudio8Generator::ProcessGeneratorPlatformField(
+ std::string const& key, std::string const& value)
+{
+ static_cast<void>(key);
+ static_cast<void>(value);
+ return false;
+}
+
+bool cmGlobalVisualStudio8Generator::InitializePlatform(cmMakefile*)
+{
+ return true;
+}
+
cm::optional<std::string> const&
cmGlobalVisualStudio8Generator::GetTargetFrameworkVersion() const
{
diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h
index fe57c545fd..5555e9b2de 100644
--- a/Source/cmGlobalVisualStudio8Generator.h
+++ b/Source/cmGlobalVisualStudio8Generator.h
@@ -60,6 +60,11 @@ protected:
cmGlobalVisualStudio8Generator(cmake* cm, const std::string& name,
std::string const& platformInGeneratorName);
+ virtual bool InitializePlatform(cmMakefile* mf);
+
+ virtual bool ProcessGeneratorPlatformField(std::string const& key,
+ std::string const& value);
+
void AddExtraIDETargets() override;
std::string FindDevEnvCommand() override;
@@ -96,4 +101,7 @@ protected:
cm::optional<std::string> DefaultTargetFrameworkVersion;
cm::optional<std::string> DefaultTargetFrameworkIdentifier;
cm::optional<std::string> DefaultTargetFrameworkTargetsVersion;
+
+private:
+ bool ParseGeneratorPlatform(std::string const& is, cmMakefile* mf);
};
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
index 415eb7cf55..f28419a80c 100644
--- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
@@ -885,7 +885,8 @@ cmGlobalVisualStudioVersionedGenerator::FindAuxToolset(
return AuxToolset::PropsMissing;
}
-bool cmGlobalVisualStudioVersionedGenerator::InitializeWindows(cmMakefile* mf)
+bool cmGlobalVisualStudioVersionedGenerator::InitializePlatformWindows(
+ cmMakefile* mf)
{
// If the Win 8.1 SDK is installed then we can select a SDK matching
// the target Windows version.
@@ -894,13 +895,14 @@ bool cmGlobalVisualStudioVersionedGenerator::InitializeWindows(cmMakefile* mf)
if (this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS16 &&
!cmSystemTools::VersionCompareGreater(this->SystemVersion, "8.1")) {
this->SetWindowsTargetPlatformVersion("8.1", mf);
- return true;
+ return this->VerifyNoGeneratorPlatformVersion(
+ mf, "with the Windows 8.1 SDK installed");
}
- return cmGlobalVisualStudio14Generator::InitializeWindows(mf);
+ return cmGlobalVisualStudio14Generator::InitializePlatformWindows(mf);
}
// Otherwise we must choose a Win 10 SDK even if we are not targeting
// Windows 10.
- return this->SelectWindows10SDK(mf, false);
+ return this->SelectWindows10SDK(mf);
}
bool cmGlobalVisualStudioVersionedGenerator::SelectWindowsStoreToolset(
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h
index 45aca74a80..fb4b1d7934 100644
--- a/Source/cmGlobalVisualStudioVersionedGenerator.h
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.h
@@ -61,7 +61,6 @@ protected:
VSVersion version, cmake* cm, const std::string& name,
std::string const& platformInGeneratorName);
- bool InitializeWindows(cmMakefile* mf) override;
bool SelectWindowsStoreToolset(std::string& toolset) const override;
// Used to verify that the Desktop toolset for the current generator is
@@ -72,6 +71,8 @@ protected:
// of the toolset is installed
bool IsWindowsStoreToolsetInstalled() const;
+ bool InitializePlatformWindows(cmMakefile* mf) override;
+
// Check for a Win 8 SDK known to the registry or VS installer tool.
bool IsWin81SDKInstalled() const;
diff --git a/Source/cmList.cxx b/Source/cmList.cxx
new file mode 100644
index 0000000000..bf5a65459a
--- /dev/null
+++ b/Source/cmList.cxx
@@ -0,0 +1,998 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmList.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <functional>
+#include <iterator>
+#include <set>
+#include <stdexcept>
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmAlgorithms.h"
+#include "cmGeneratorExpression.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+#include "cmStringReplaceHelper.h"
+#include "cmSystemTools.h"
+
+cm::string_view cmList::element_separator{ ";" };
+
+cmList cmList::sublist(size_type pos, size_type length) const
+{
+ if (pos >= this->Values.size()) {
+ throw std::out_of_range(cmStrCat(
+ "begin index: ", pos, " is out of range 0 - ", this->Values.size() - 1));
+ }
+
+ size_type count = (length == npos || pos + length > this->size())
+ ? this->size()
+ : pos + length;
+ return this->sublist(this->begin() + pos, this->begin() + count);
+}
+
+cmList::size_type cmList::find(cm::string_view value) const
+{
+ auto res = std::find(this->Values.begin(), this->Values.end(), value);
+ if (res == this->Values.end()) {
+ return npos;
+ }
+
+ return std::distance(this->Values.begin(), res);
+}
+
+cmList& cmList::remove_duplicates()
+{
+ auto newEnd = cmRemoveDuplicates(this->Values);
+ this->Values.erase(newEnd, this->Values.end());
+
+ return *this;
+}
+
+namespace {
+class MatchesRegex
+{
+public:
+ MatchesRegex(cmsys::RegularExpression& regex, cmList::FilterMode mode)
+ : Regex(regex)
+ , IncludeMatches(mode == cmList::FilterMode::INCLUDE)
+ {
+ }
+
+ bool operator()(const std::string& target)
+ {
+ return this->Regex.find(target) ^ this->IncludeMatches;
+ }
+
+private:
+ cmsys::RegularExpression& Regex;
+ const bool IncludeMatches;
+};
+}
+
+cmList& cmList::filter(cm::string_view pattern, FilterMode mode)
+{
+ cmsys::RegularExpression regex(std::string{ pattern });
+ if (!regex.is_valid()) {
+ throw std::invalid_argument(
+ cmStrCat("sub-command FILTER, mode REGEX failed to compile regex \"",
+ pattern, "\"."));
+ }
+
+ auto it = std::remove_if(this->Values.begin(), this->Values.end(),
+ MatchesRegex{ regex, mode });
+ this->Values.erase(it, this->Values.end());
+
+ return *this;
+}
+
+namespace {
+class StringSorter
+{
+protected:
+ using StringFilter = std::function<std::string(const std::string&)>;
+
+ using OrderMode = cmList::SortConfiguration::OrderMode;
+ using CompareMethod = cmList::SortConfiguration::CompareMethod;
+ using CaseSensitivity = cmList::SortConfiguration::CaseSensitivity;
+
+ StringFilter GetCompareFilter(CompareMethod compare)
+ {
+ return (compare == CompareMethod::FILE_BASENAME)
+ ? cmSystemTools::GetFilenameName
+ : nullptr;
+ }
+
+ StringFilter GetCaseFilter(CaseSensitivity sensitivity)
+ {
+ return (sensitivity == CaseSensitivity::INSENSITIVE)
+ ? cmSystemTools::LowerCase
+ : nullptr;
+ }
+
+ using ComparisonFunction =
+ std::function<bool(const std::string&, const std::string&)>;
+ ComparisonFunction GetComparisonFunction(CompareMethod compare)
+ {
+ if (compare == CompareMethod::NATURAL) {
+ return std::function<bool(const std::string&, const std::string&)>(
+ [](const std::string& x, const std::string& y) {
+ return cmSystemTools::strverscmp(x, y) < 0;
+ });
+ }
+ return std::function<bool(const std::string&, const std::string&)>(
+ [](const std::string& x, const std::string& y) { return x < y; });
+ }
+
+public:
+ StringSorter(cmList::SortConfiguration const& config)
+ : Filters{ this->GetCompareFilter(config.Compare),
+ this->GetCaseFilter(config.Case) }
+ , SortMethod(this->GetComparisonFunction(config.Compare))
+ , Descending(config.Order == OrderMode::DESCENDING)
+ {
+ }
+
+ std::string ApplyFilter(const std::string& argument)
+ {
+ std::string result = argument;
+ for (auto const& filter : this->Filters) {
+ if (filter != nullptr) {
+ result = filter(result);
+ }
+ }
+ return result;
+ }
+
+ bool operator()(const std::string& a, const std::string& b)
+ {
+ std::string af = this->ApplyFilter(a);
+ std::string bf = this->ApplyFilter(b);
+ bool result;
+ if (this->Descending) {
+ result = this->SortMethod(bf, af);
+ } else {
+ result = this->SortMethod(af, bf);
+ }
+ return result;
+ }
+
+private:
+ StringFilter Filters[2] = { nullptr, nullptr };
+ ComparisonFunction SortMethod;
+ bool Descending;
+};
+}
+
+cmList::SortConfiguration::SortConfiguration() = default;
+
+cmList& cmList::sort(const SortConfiguration& cfg)
+{
+ SortConfiguration config{ cfg };
+
+ if (config.Order == SortConfiguration::OrderMode::DEFAULT) {
+ config.Order = SortConfiguration::OrderMode::ASCENDING;
+ }
+ if (config.Compare == SortConfiguration::CompareMethod::DEFAULT) {
+ config.Compare = SortConfiguration::CompareMethod::STRING;
+ }
+ if (config.Case == SortConfiguration::CaseSensitivity::DEFAULT) {
+ config.Case = SortConfiguration::CaseSensitivity::SENSITIVE;
+ }
+
+ if ((config.Compare == SortConfiguration::CompareMethod::STRING) &&
+ (config.Case == SortConfiguration::CaseSensitivity::SENSITIVE) &&
+ (config.Order == SortConfiguration::OrderMode::ASCENDING)) {
+ std::sort(this->Values.begin(), this->Values.end());
+ } else {
+ StringSorter sorter(config);
+ std::sort(this->Values.begin(), this->Values.end(), sorter);
+ }
+
+ return *this;
+}
+
+namespace {
+using transform_type = std::function<std::string(const std::string&)>;
+using transform_error = cmList::transform_error;
+
+class TransformSelector : public cmList::TransformSelector
+{
+public:
+ ~TransformSelector() override = default;
+
+ std::string Tag;
+
+ const std::string& GetTag() override { return this->Tag; }
+
+ virtual bool Validate(std::size_t count = 0) = 0;
+
+ virtual bool InSelection(const std::string&) = 0;
+
+ virtual void Transform(cmList::container_type& list,
+ const transform_type& transform)
+ {
+ std::transform(list.begin(), list.end(), list.begin(), transform);
+ }
+
+protected:
+ TransformSelector(std::string&& tag)
+ : Tag(std::move(tag))
+ {
+ }
+};
+
+class TransformNoSelector : public TransformSelector
+{
+public:
+ TransformNoSelector()
+ : TransformSelector("NO SELECTOR")
+ {
+ }
+
+ bool Validate(std::size_t) override { return true; }
+
+ bool InSelection(const std::string&) override { return true; }
+};
+class TransformSelectorRegex : public TransformSelector
+{
+public:
+ TransformSelectorRegex(const std::string& regex)
+ : TransformSelector("REGEX")
+ , Regex(regex)
+ {
+ }
+ TransformSelectorRegex(std::string&& regex)
+ : TransformSelector("REGEX")
+ , Regex(regex)
+ {
+ }
+
+ bool Validate(std::size_t) override { return this->Regex.is_valid(); }
+
+ bool InSelection(const std::string& value) override
+ {
+ return this->Regex.find(value);
+ }
+
+ cmsys::RegularExpression Regex;
+};
+class TransformSelectorIndexes : public TransformSelector
+{
+public:
+ std::vector<index_type> Indexes;
+
+ bool InSelection(const std::string&) override { return true; }
+
+ void Transform(std::vector<std::string>& list,
+ const transform_type& transform) override
+ {
+ this->Validate(list.size());
+
+ for (auto index : this->Indexes) {
+ list[index] = transform(list[index]);
+ }
+ }
+
+protected:
+ TransformSelectorIndexes(std::string&& tag)
+ : TransformSelector(std::move(tag))
+ {
+ }
+ TransformSelectorIndexes(std::string&& tag, std::vector<int> const& indexes)
+ : TransformSelector(std::move(tag))
+ , Indexes(indexes)
+ {
+ }
+ TransformSelectorIndexes(std::string&& tag, std::vector<int>&& indexes)
+ : TransformSelector(std::move(tag))
+ , Indexes(indexes)
+ {
+ }
+
+ int NormalizeIndex(index_type index, std::size_t count)
+ {
+ if (index < 0) {
+ index = static_cast<index_type>(count) + index;
+ }
+ if (index < 0 || count <= static_cast<std::size_t>(index)) {
+ throw transform_error(cmStrCat(
+ "sub-command TRANSFORM, selector ", this->Tag, ", index: ", index,
+ " out of range (-", count, ", ", count - 1, ")."));
+ }
+ return index;
+ }
+};
+class TransformSelectorAt : public TransformSelectorIndexes
+{
+public:
+ TransformSelectorAt(std::vector<index_type> const& indexes)
+ : TransformSelectorIndexes("AT", indexes)
+ {
+ }
+ TransformSelectorAt(std::vector<index_type>&& indexes)
+ : TransformSelectorIndexes("AT", std::move(indexes))
+ {
+ }
+
+ bool Validate(std::size_t count) override
+ {
+ decltype(this->Indexes) indexes;
+
+ for (auto index : this->Indexes) {
+ indexes.push_back(this->NormalizeIndex(index, count));
+ }
+ this->Indexes = std::move(indexes);
+
+ return true;
+ }
+};
+class TransformSelectorFor : public TransformSelectorIndexes
+{
+public:
+ TransformSelectorFor(int start, int stop, int step)
+ : TransformSelectorIndexes("FOR")
+ , Start(start)
+ , Stop(stop)
+ , Step(step)
+ {
+ }
+
+ bool Validate(std::size_t count) override
+ {
+ this->Start = this->NormalizeIndex(this->Start, count);
+ this->Stop = this->NormalizeIndex(this->Stop, count);
+
+ // Does stepping move us further from the end?
+ if (this->Start > this->Stop) {
+ throw transform_error(
+ cmStrCat("sub-command TRANSFORM, selector FOR "
+ "expects <start> to be no greater than <stop> (",
+ this->Start, " > ", this->Stop, ")"));
+ }
+
+ // compute indexes
+ auto size = (this->Stop - this->Start + 1) / this->Step;
+ if ((this->Stop - this->Start + 1) % this->Step != 0) {
+ size += 1;
+ }
+
+ this->Indexes.resize(size);
+ auto start = this->Start;
+ auto step = this->Step;
+ std::generate(this->Indexes.begin(), this->Indexes.end(),
+ [&start, step]() -> int {
+ auto r = start;
+ start += step;
+ return r;
+ });
+
+ return true;
+ }
+
+private:
+ index_type Start, Stop, Step;
+};
+
+class TransformAction
+{
+public:
+ virtual ~TransformAction() = default;
+
+ void Initialize(TransformSelector* selector) { this->Selector = selector; }
+ virtual void Initialize(TransformSelector*, const std::string&) {}
+ virtual void Initialize(TransformSelector*, const std::string&,
+ const std::string&)
+ {
+ }
+ virtual void Initialize(TransformSelector* selector,
+ const std::vector<std::string>&)
+ {
+ this->Initialize(selector);
+ }
+
+ virtual std::string operator()(const std::string& s) = 0;
+
+protected:
+ TransformSelector* Selector;
+};
+class TransformActionAppend : public TransformAction
+{
+public:
+ using TransformAction::Initialize;
+
+ void Initialize(TransformSelector* selector,
+ const std::string& append) override
+ {
+ TransformAction::Initialize(selector);
+ this->Append = append;
+ }
+ void Initialize(TransformSelector* selector,
+ const std::vector<std::string>& append) override
+ {
+ this->Initialize(selector, append.front());
+ }
+
+ std::string operator()(const std::string& s) override
+ {
+ if (this->Selector->InSelection(s)) {
+ return cmStrCat(s, this->Append);
+ }
+
+ return s;
+ }
+
+private:
+ std::string Append;
+};
+class TransformActionPrepend : public TransformAction
+{
+public:
+ using TransformAction::Initialize;
+
+ void Initialize(TransformSelector* selector,
+ const std::string& prepend) override
+ {
+ TransformAction::Initialize(selector);
+ this->Prepend = prepend;
+ }
+ void Initialize(TransformSelector* selector,
+ const std::vector<std::string>& prepend) override
+ {
+ this->Initialize(selector, prepend.front());
+ }
+
+ std::string operator()(const std::string& s) override
+ {
+ if (this->Selector->InSelection(s)) {
+ return cmStrCat(this->Prepend, s);
+ }
+
+ return s;
+ }
+
+private:
+ std::string Prepend;
+};
+class TransformActionToUpper : public TransformAction
+{
+public:
+ std::string operator()(const std::string& s) override
+ {
+ if (this->Selector->InSelection(s)) {
+ return cmSystemTools::UpperCase(s);
+ }
+
+ return s;
+ }
+};
+class TransformActionToLower : public TransformAction
+{
+public:
+ std::string operator()(const std::string& s) override
+ {
+ if (this->Selector->InSelection(s)) {
+ return cmSystemTools::LowerCase(s);
+ }
+
+ return s;
+ }
+};
+class TransformActionStrip : public TransformAction
+{
+public:
+ std::string operator()(const std::string& s) override
+ {
+ if (this->Selector->InSelection(s)) {
+ return cmTrimWhitespace(s);
+ }
+
+ return s;
+ }
+};
+class TransformActionGenexStrip : public TransformAction
+{
+public:
+ std::string operator()(const std::string& s) override
+ {
+ if (this->Selector->InSelection(s)) {
+ return cmGeneratorExpression::Preprocess(
+ s, cmGeneratorExpression::StripAllGeneratorExpressions);
+ }
+
+ return s;
+ }
+};
+class TransformActionReplace : public TransformAction
+{
+public:
+ using TransformAction::Initialize;
+
+ void Initialize(TransformSelector* selector, const std::string& regex,
+ const std::string& replace) override
+ {
+ TransformAction::Initialize(selector);
+ this->ReplaceHelper =
+ cm::make_unique<cmStringReplaceHelper>(regex, replace);
+
+ if (!this->ReplaceHelper->IsRegularExpressionValid()) {
+ throw transform_error(
+ cmStrCat("sub-command TRANSFORM, action REPLACE: Failed to compile "
+ "regex \"",
+ regex, "\"."));
+ }
+ if (!this->ReplaceHelper->IsReplaceExpressionValid()) {
+ throw transform_error(cmStrCat("sub-command TRANSFORM, action REPLACE: ",
+ this->ReplaceHelper->GetError(), "."));
+ }
+ }
+ void Initialize(TransformSelector* selector,
+ const std::vector<std::string>& args) override
+ {
+ this->Initialize(selector, args[0], args[1]);
+ }
+
+ std::string operator()(const std::string& s) override
+ {
+ if (this->Selector->InSelection(s)) {
+ // Scan through the input for all matches.
+ std::string output;
+
+ if (!this->ReplaceHelper->Replace(s, output)) {
+ throw transform_error(
+ cmStrCat("sub-command TRANSFORM, action REPLACE: ",
+ this->ReplaceHelper->GetError(), "."));
+ }
+
+ return output;
+ }
+
+ return s;
+ }
+
+private:
+ std::unique_ptr<cmStringReplaceHelper> ReplaceHelper;
+};
+
+// Descriptor of action
+// Arity: number of arguments required for the action
+// Transform: Object implementing the action
+struct ActionDescriptor
+{
+ ActionDescriptor(cmList::TransformAction action)
+ : Action(action)
+ {
+ }
+ ActionDescriptor(cmList::TransformAction action, std::string name,
+ std::size_t arity,
+ std::unique_ptr<TransformAction> transform)
+ : Action(action)
+ , Name(std::move(name))
+ , Arity(arity)
+ , Transform(std::move(transform))
+ {
+ }
+
+ operator cmList::TransformAction() const { return this->Action; }
+
+ cmList::TransformAction Action;
+ std::string Name;
+ std::size_t Arity = 0;
+ std::unique_ptr<TransformAction> Transform;
+};
+
+// Build a set of supported actions.
+using ActionDescriptorSet = std::set<
+ ActionDescriptor,
+ std::function<bool(cmList::TransformAction, cmList::TransformAction)>>;
+
+ActionDescriptorSet Descriptors([](cmList::TransformAction x,
+ cmList::TransformAction y) {
+ return x < y;
+});
+
+ActionDescriptorSet::iterator TransformConfigure(
+ cmList::TransformAction action,
+ std::unique_ptr<cmList::TransformSelector>& selector, std::size_t arity)
+{
+ if (Descriptors.empty()) {
+ Descriptors.emplace(cmList::TransformAction::APPEND, "APPEND", 1,
+ cm::make_unique<TransformActionAppend>());
+ Descriptors.emplace(cmList::TransformAction::PREPEND, "PREPEND", 1,
+ cm::make_unique<TransformActionPrepend>());
+ Descriptors.emplace(cmList::TransformAction::TOUPPER, "TOUPPER", 0,
+ cm::make_unique<TransformActionToUpper>());
+ Descriptors.emplace(cmList::TransformAction::TOLOWER, "TOLOWER", 0,
+ cm::make_unique<TransformActionToLower>());
+ Descriptors.emplace(cmList::TransformAction::STRIP, "STRIP", 0,
+ cm::make_unique<TransformActionStrip>());
+ Descriptors.emplace(cmList::TransformAction::GENEX_STRIP, "GENEX_STRIP", 0,
+ cm::make_unique<TransformActionGenexStrip>());
+ Descriptors.emplace(cmList::TransformAction::REPLACE, "REPLACE", 2,
+ cm::make_unique<TransformActionReplace>());
+ }
+
+ auto descriptor = Descriptors.find(action);
+ if (descriptor == Descriptors.end()) {
+ throw transform_error(cmStrCat(" sub-command TRANSFORM, ",
+ std::to_string(static_cast<int>(action)),
+ " invalid action."));
+ }
+
+ if (descriptor->Arity != arity) {
+ throw transform_error(cmStrCat("sub-command TRANSFORM, action ",
+ descriptor->Name, " expects ",
+ descriptor->Arity, " argument(s)."));
+ }
+ if (!selector) {
+ selector = cm::make_unique<TransformNoSelector>();
+ }
+
+ return descriptor;
+}
+}
+
+std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewAT(
+ std::initializer_list<index_type> indexes)
+{
+ return cm::make_unique<TransformSelectorAt>(
+ std::vector<index_type>{ indexes.begin(), indexes.end() });
+ ;
+}
+std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewAT(
+ std::vector<index_type> const& indexes)
+{
+ return cm::make_unique<TransformSelectorAt>(indexes);
+}
+std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewAT(
+ std::vector<index_type>&& indexes)
+{
+ return cm::make_unique<TransformSelectorAt>(std::move(indexes));
+}
+
+std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewFOR(
+ std::initializer_list<index_type> indexes)
+{
+ if (indexes.size() < 2 || indexes.size() > 3) {
+ throw transform_error("sub-command TRANSFORM, selector FOR "
+ "expects 2 or 3 arguments");
+ }
+ if (indexes.size() == 3 && *(indexes.begin() + 2) < 0) {
+ throw transform_error("sub-command TRANSFORM, selector FOR expects "
+ "positive numeric value for <step>.");
+ }
+
+ return cm::make_unique<TransformSelectorFor>(
+ *indexes.begin(), *(indexes.begin() + 1),
+ indexes.size() == 3 ? *(indexes.begin() + 2) : 1);
+}
+std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewFOR(
+ std::vector<index_type> const& indexes)
+{
+ if (indexes.size() < 2 || indexes.size() > 3) {
+ throw transform_error("sub-command TRANSFORM, selector FOR "
+ "expects 2 or 3 arguments");
+ }
+ if (indexes.size() == 3 && indexes[2] < 0) {
+ throw transform_error("sub-command TRANSFORM, selector FOR expects "
+ "positive numeric value for <step>.");
+ }
+
+ return cm::make_unique<TransformSelectorFor>(
+ indexes[0], indexes[1], indexes.size() == 3 ? indexes[2] : 1);
+}
+std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewFOR(
+ std::vector<index_type>&& indexes)
+{
+ if (indexes.size() < 2 || indexes.size() > 3) {
+ throw transform_error("sub-command TRANSFORM, selector FOR "
+ "expects 2 or 3 arguments");
+ }
+ if (indexes.size() == 3 && indexes[2] < 0) {
+ throw transform_error("sub-command TRANSFORM, selector FOR expects "
+ "positive numeric value for <step>.");
+ }
+
+ return cm::make_unique<TransformSelectorFor>(
+ indexes[0], indexes[1], indexes.size() == 3 ? indexes[2] : 1);
+}
+
+std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewREGEX(
+ std::string const& regex)
+{
+ std::unique_ptr<::TransformSelector> selector =
+ cm::make_unique<TransformSelectorRegex>(regex);
+ if (!selector->Validate()) {
+ throw transform_error(
+ cmStrCat("sub-command TRANSFORM, selector REGEX failed to compile "
+ "regex \"",
+ regex, "\"."));
+ }
+ // weird construct to please all compilers
+ return std::unique_ptr<cmList::TransformSelector>(selector.release());
+}
+std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewREGEX(
+ std::string&& regex)
+{
+ std::unique_ptr<::TransformSelector> selector =
+ cm::make_unique<TransformSelectorRegex>(std::move(regex));
+ if (!selector->Validate()) {
+ throw transform_error(
+ cmStrCat("sub-command TRANSFORM, selector REGEX failed to compile "
+ "regex \"",
+ regex, "\"."));
+ }
+ // weird construct to please all compilers
+ return std::unique_ptr<cmList::TransformSelector>(selector.release());
+}
+
+cmList& cmList::transform(TransformAction action,
+ std::unique_ptr<TransformSelector> selector)
+{
+ auto descriptor = TransformConfigure(action, selector, 0);
+
+ descriptor->Transform->Initialize(
+ static_cast<::TransformSelector*>(selector.get()));
+
+ static_cast<::TransformSelector&>(*selector).Transform(
+ this->Values, [&descriptor](const std::string& s) -> std::string {
+ return (*descriptor->Transform)(s);
+ });
+
+ return *this;
+}
+
+cmList& cmList::transform(TransformAction action, std::string const& arg,
+ std::unique_ptr<TransformSelector> selector)
+{
+ auto descriptor = TransformConfigure(action, selector, 1);
+
+ descriptor->Transform->Initialize(
+ static_cast<::TransformSelector*>(selector.get()), arg);
+
+ static_cast<::TransformSelector&>(*selector).Transform(
+ this->Values, [&descriptor](const std::string& s) -> std::string {
+ return (*descriptor->Transform)(s);
+ });
+
+ return *this;
+}
+
+cmList& cmList::transform(TransformAction action, std::string const& arg1,
+ std::string const& arg2,
+ std::unique_ptr<TransformSelector> selector)
+{
+ auto descriptor = TransformConfigure(action, selector, 2);
+
+ descriptor->Transform->Initialize(
+ static_cast<::TransformSelector*>(selector.get()), arg1, arg2);
+
+ static_cast<::TransformSelector&>(*selector).Transform(
+ this->Values, [&descriptor](const std::string& s) -> std::string {
+ return (*descriptor->Transform)(s);
+ });
+
+ return *this;
+}
+
+cmList& cmList::transform(TransformAction action,
+ std::vector<std::string> const& args,
+ std::unique_ptr<TransformSelector> selector)
+{
+ auto descriptor = TransformConfigure(action, selector, args.size());
+
+ descriptor->Transform->Initialize(
+ static_cast<::TransformSelector*>(selector.get()), args);
+
+ static_cast<::TransformSelector&>(*selector).Transform(
+ this->Values, [&descriptor](const std::string& s) -> std::string {
+ return (*descriptor->Transform)(s);
+ });
+
+ return *this;
+}
+
+std::string cmList::join(cm::string_view glue) const
+{
+ return cmJoin(this->Values, glue);
+}
+
+std::string& cmList::append(cm::string_view value, std::string& list)
+{
+ if (list.empty()) {
+ list = std::string(value);
+ } else {
+ list += cmStrCat(cmList::element_separator, value);
+ }
+
+ return list;
+}
+
+std::string& cmList::prepend(cm::string_view value, std::string& list)
+{
+ if (list.empty()) {
+ list = std::string(value);
+ } else {
+ list.insert(0, cmStrCat(value, cmList::element_separator));
+ }
+
+ return list;
+}
+
+cmList::size_type cmList::ComputeIndex(index_type pos, bool boundCheck) const
+{
+ if (boundCheck) {
+ if (this->Values.empty()) {
+ throw std::out_of_range(
+ cmStrCat("index: ", pos, " out of range (0, 0)"));
+ }
+
+ if (!this->Values.empty()) {
+ auto length = this->Values.size();
+ if (pos < 0) {
+ pos = static_cast<index_type>(length) + pos;
+ }
+ if (pos < 0 || length <= static_cast<size_type>(pos)) {
+ throw std::out_of_range(cmStrCat("index: ", pos, " out of range (-",
+ this->Values.size(), ", ",
+ this->Values.size() - 1, ")"));
+ }
+ }
+ return pos;
+ }
+
+ return pos < 0 ? this->Values.size() + pos : pos;
+}
+cmList::size_type cmList::ComputeInsertIndex(index_type pos,
+ bool boundCheck) const
+{
+ if (boundCheck) {
+ if (this->Values.empty() && pos != 0) {
+ throw std::out_of_range(
+ cmStrCat("index: ", pos, " out of range (0, 0)"));
+ }
+
+ if (!this->Values.empty()) {
+ auto length = this->Values.size();
+ if (pos < 0) {
+ pos = static_cast<index_type>(length) + pos;
+ }
+ if (pos < 0 || length < static_cast<size_type>(pos)) {
+ throw std::out_of_range(cmStrCat("index: ", pos, " out of range (-",
+ this->Values.size(), ", ",
+ this->Values.size(), ")"));
+ }
+ }
+ return pos;
+ }
+
+ return pos < 0 ? this->Values.size() + pos : pos;
+}
+
+cmList cmList::GetItems(std::vector<index_type>&& indexes) const
+{
+ cmList listItems;
+
+ for (auto index : indexes) {
+ listItems.emplace_back(this->at(index));
+ }
+
+ return listItems;
+}
+
+cmList& cmList::RemoveItems(std::vector<index_type>&& indexes)
+{
+ if (indexes.empty()) {
+ return *this;
+ }
+
+ // compute all indexes
+ std::vector<size_type> idx(indexes.size());
+ std::transform(
+ indexes.cbegin(), indexes.cend(), idx.begin(),
+ [this](const index_type& index) { return this->ComputeIndex(index); });
+
+ std::sort(idx.begin(), idx.end(),
+ [](size_type l, size_type r) { return l > r; });
+ auto newEnd = std::unique(idx.begin(), idx.end());
+ idx.erase(newEnd, idx.end());
+
+ for (auto index : idx) {
+ this->erase(this->begin() + index);
+ }
+
+ return *this;
+}
+
+cmList& cmList::RemoveItems(std::vector<std::string>&& items)
+{
+ std::sort(items.begin(), items.end());
+ auto last = std::unique(items.begin(), items.end());
+ auto first = items.begin();
+
+ auto newEnd = cmRemoveMatching(this->Values, cmMakeRange(first, last));
+ this->Values.erase(newEnd, this->Values.end());
+
+ return *this;
+}
+
+cmList::container_type::iterator cmList::Insert(
+ container_type::const_iterator pos, std::string&& value,
+ container_type& container, ExpandElements expandElements,
+ EmptyElements emptyElements)
+{
+ auto delta = std::distance(container.cbegin(), pos);
+ auto insertPos = container.begin() + delta;
+
+ if (expandElements == ExpandElements::Yes) {
+ // If argument is empty, it is an empty list.
+ if (emptyElements == EmptyElements::No && value.empty()) {
+ return insertPos;
+ }
+
+ // if there are no ; in the name then just copy the current string
+ if (value.find(';') == std::string::npos) {
+ return container.insert(insertPos, std::move(value));
+ }
+
+ std::string newValue;
+ // Break the string at non-escaped semicolons not nested in [].
+ int squareNesting = 0;
+ auto last = value.begin();
+ auto const cend = value.end();
+ for (auto c = last; c != cend; ++c) {
+ switch (*c) {
+ case '\\': {
+ // We only want to allow escaping of semicolons. Other
+ // escapes should not be processed here.
+ auto cnext = c + 1;
+ if ((cnext != cend) && *cnext == ';') {
+ newValue.append(last, c);
+ // Skip over the escape character
+ last = cnext;
+ c = cnext;
+ }
+ } break;
+ case '[': {
+ ++squareNesting;
+ } break;
+ case ']': {
+ --squareNesting;
+ } break;
+ case ';': {
+ // brackets.
+ if (squareNesting == 0) {
+ newValue.append(last, c);
+ // Skip over the semicolon
+ last = c + 1;
+ if (!newValue.empty() || emptyElements == EmptyElements::Yes) {
+ // Add the last argument.
+ insertPos = container.insert(insertPos, newValue);
+ insertPos++;
+ newValue.clear();
+ }
+ }
+ } break;
+ default: {
+ // Just append this character.
+ } break;
+ }
+ }
+ newValue.append(last, cend);
+ if (!newValue.empty() || emptyElements == EmptyElements::Yes) {
+ // Add the last argument.
+ container.insert(insertPos, std::move(newValue));
+ }
+ } else if (!value.empty() || emptyElements == EmptyElements::Yes) {
+ return container.insert(insertPos, std::move(value));
+ }
+ return container.begin() + delta;
+}
diff --git a/Source/cmList.h b/Source/cmList.h
new file mode 100644
index 0000000000..d994ad3890
--- /dev/null
+++ b/Source/cmList.h
@@ -0,0 +1,1198 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <algorithm>
+#include <initializer_list>
+#include <iterator>
+#include <memory>
+#include <numeric>
+#include <stdexcept>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/string_view>
+
+#include "cmValue.h"
+
+/**
+ * CMake lists management
+ *
+ * For all operations, input arguments (single value like cm::string_view or
+ * multiple values specified through pair of iterators) are, by default,
+ * expanded. The expansion can be controlled by the cmList::ExpandElements
+ * option.
+ *
+ * There is an exception to this rule. The following methods do not expand
+ * their argument: cmList::push_back, cmList::emplace and cmList::emplace_back.
+ */
+
+class cmList
+{
+public:
+ using container_type = std::vector<std::string>;
+
+ using value_type = container_type::value_type;
+ using allocator_type = container_type::allocator_type;
+ using index_type = int;
+ using size_type = container_type::size_type;
+ using difference_type = container_type::difference_type;
+ using reference = container_type::reference;
+ using const_reference = container_type::const_reference;
+ using iterator = container_type::iterator;
+ using const_iterator = container_type::const_iterator;
+ using reverse_iterator = container_type::reverse_iterator;
+ using const_reverse_iterator = container_type::const_reverse_iterator;
+
+ static const size_type npos = static_cast<size_type>(-1);
+
+ static cm::string_view element_separator;
+
+ enum class EmptyElements
+ {
+ No,
+ Yes,
+ };
+ enum class ExpandElements
+ {
+ No,
+ Yes,
+ };
+
+ cmList() = default;
+ cmList(const cmList&) = default;
+ cmList(cmList&&) = default;
+
+ cmList(cm::string_view value,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ this->assign(value, expandElements, emptyElements);
+ }
+ cmList(cm::string_view value, EmptyElements emptyElements)
+ {
+ this->assign(value, ExpandElements::Yes, emptyElements);
+ }
+ cmList(cmValue list, ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ if (list) {
+ this->assign(*list, expandElements, emptyElements);
+ }
+ }
+ cmList(cmValue list, EmptyElements emptyElements)
+ : cmList(list, ExpandElements::Yes, emptyElements)
+ {
+ }
+ template <typename InputIterator>
+ cmList(InputIterator first, InputIterator last,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ this->assign(first, last, expandElements, emptyElements);
+ }
+ template <typename InputIterator>
+ cmList(InputIterator first, InputIterator last, EmptyElements emptyElements)
+ : cmList(first, last, ExpandElements::Yes, emptyElements)
+ {
+ }
+ cmList(const container_type& init,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ : cmList(init.begin(), init.end(), expandElements, emptyElements)
+ {
+ }
+ cmList(const container_type& init, EmptyElements emptyElements)
+ : cmList(init, ExpandElements::Yes, emptyElements)
+ {
+ }
+ cmList(container_type&& init,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ : cmList(std::make_move_iterator(init.begin()),
+ std::make_move_iterator(init.end()), expandElements,
+ emptyElements)
+ {
+ init.clear();
+ }
+ cmList(container_type&& init, EmptyElements emptyElements)
+ : cmList(std::move(init), ExpandElements::Yes, emptyElements)
+ {
+ }
+ cmList(std::initializer_list<std::string> init) { this->assign(init); }
+
+ ~cmList() = default;
+
+ cmList& operator=(const cmList&) = default;
+ cmList& operator=(cmList&&) = default;
+
+ cmList& operator=(cm::string_view value)
+ {
+ this->assign(value);
+ return *this;
+ }
+ cmList& operator=(cmValue value)
+ {
+ if (value) {
+ this->operator=(*value);
+ } else {
+ this->clear();
+ }
+
+ return *this;
+ }
+
+ cmList& operator=(const container_type& init)
+ {
+ this->assign(init);
+ return *this;
+ }
+ cmList& operator=(container_type&& init)
+ {
+ this->assign(std::move(init));
+
+ return *this;
+ }
+
+ cmList& operator=(std::initializer_list<std::string> init)
+ {
+ this->assign(init);
+ return *this;
+ }
+
+ void assign(cm::string_view value,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ this->clear();
+ this->append(value, expandElements, emptyElements);
+ }
+ void assign(cm::string_view value, EmptyElements emptyElements)
+ {
+ this->assign(value, ExpandElements::Yes, emptyElements);
+ }
+ void assign(cmValue value,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ if (value) {
+ this->assign(*value, expandElements, emptyElements);
+ } else {
+ this->clear();
+ }
+ }
+ void assign(cmValue value, EmptyElements emptyElements)
+ {
+ this->assign(value, ExpandElements::Yes, emptyElements);
+ }
+ template <typename InputIterator>
+ void assign(InputIterator first, InputIterator last,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ this->clear();
+ this->append(first, last, expandElements, emptyElements);
+ }
+ template <typename InputIterator>
+ void assign(InputIterator first, InputIterator last,
+ EmptyElements emptyElements)
+ {
+ this->assign(first, last, ExpandElements::Yes, emptyElements);
+ }
+ void assign(const cmList& init,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ this->assign(init.begin(), init.end(), expandElements, emptyElements);
+ }
+ void assign(const cmList& init, EmptyElements emptyElements)
+ {
+ this->assign(init, ExpandElements::Yes, emptyElements);
+ }
+ void assign(cmList&& init,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ this->assign(std::make_move_iterator(init.begin()),
+ std::make_move_iterator(init.end()), expandElements,
+ emptyElements);
+ init.clear();
+ }
+ void assign(cmList&& init, EmptyElements emptyElements)
+ {
+ this->assign(std::move(init), ExpandElements::Yes, emptyElements);
+ }
+ void assign(const container_type& init,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ this->assign(init.begin(), init.end(), expandElements, emptyElements);
+ }
+ void assign(const container_type& init, EmptyElements emptyElements)
+ {
+ this->assign(init, ExpandElements::Yes, emptyElements);
+ }
+ void assign(container_type&& init,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ this->assign(std::make_move_iterator(init.begin()),
+ std::make_move_iterator(init.end()), expandElements,
+ emptyElements);
+ init.clear();
+ }
+ void assign(container_type&& init, EmptyElements emptyElements)
+ {
+ this->assign(std::move(init), ExpandElements::Yes, emptyElements);
+ }
+ void assign(std::initializer_list<std::string> init)
+ {
+ this->assign(init.begin(), init.end());
+ }
+
+ // Conversions
+ std::string to_string() const
+ {
+ return this->join(cmList::element_separator);
+ }
+
+ operator container_type&() & noexcept { return this->Values; }
+ operator const container_type&() const& noexcept { return this->Values; }
+ operator container_type&&() && noexcept { return std::move(this->Values); }
+
+ // Element access
+ reference at(index_type pos)
+ {
+ return this->Values.at(this->ComputeIndex(pos));
+ }
+ const_reference at(index_type pos) const
+ {
+ return this->Values.at(this->ComputeIndex(pos));
+ }
+
+ reference operator[](index_type pos)
+ {
+ return this->Values[this->ComputeIndex(pos, false)];
+ }
+ const_reference operator[](index_type pos) const
+ {
+ return this->Values[this->ComputeIndex(pos, false)];
+ }
+
+ reference front() { return this->Values.front(); }
+ const_reference front() const { return this->Values.front(); }
+
+ reference back() { return this->Values.back(); }
+ const_reference back() const { return this->Values.back(); }
+
+ // extract sublist in range [first, last)
+ cmList sublist(const_iterator first, const_iterator last) const
+ {
+ return cmList{ first, last };
+ }
+ // Extract sublist in range [first, last)
+ // Throw std::out_of_range if pos is invalid
+ cmList sublist(size_type pos = 0, size_type length = npos) const;
+
+ // Returns the list of elements
+ // Throw std::out_of_range if any index is invalid
+ cmList get_items(std::initializer_list<index_type> indexes) const
+ {
+ return this->GetItems(
+ std::vector<index_type>{ indexes.begin(), indexes.end() });
+ }
+ template <typename InputIterator>
+ cmList get_items(InputIterator first, InputIterator last) const
+ {
+ return this->GetItems(std::vector<index_type>{ first, last });
+ }
+
+ size_type find(cm::string_view value) const;
+ size_type find(cmValue value) const
+ {
+ if (value) {
+ return this->find(*value);
+ }
+
+ return npos;
+ }
+
+ container_type& data() noexcept { return this->Values; }
+ const container_type& data() const noexcept { return this->Values; }
+
+ // Iterators
+ iterator begin() noexcept { return this->Values.begin(); }
+ const_iterator begin() const noexcept { return this->Values.begin(); }
+ const_iterator cbegin() const noexcept { return this->Values.cbegin(); }
+
+ iterator end() noexcept { return this->Values.end(); }
+ const_iterator end() const noexcept { return this->Values.end(); }
+ const_iterator cend() const noexcept { return this->Values.cend(); }
+
+ reverse_iterator rbegin() noexcept { return this->Values.rbegin(); }
+ const_reverse_iterator rbegin() const noexcept
+ {
+ return this->Values.rbegin();
+ }
+ const_reverse_iterator crbegin() const noexcept
+ {
+ return this->Values.crbegin();
+ }
+
+ reverse_iterator rend() noexcept { return this->Values.rend(); }
+ const_reverse_iterator rend() const noexcept { return this->Values.rend(); }
+ const_reverse_iterator crend() const noexcept
+ {
+ return this->Values.crend();
+ }
+
+ // Capacity
+ bool empty() const noexcept { return this->Values.empty(); }
+ size_type size() const noexcept { return this->Values.size(); }
+
+ // Modifiers
+ void clear() noexcept { this->Values.clear(); }
+
+ iterator insert(const_iterator pos, cm::string_view value,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return cmList::Insert(pos, std::string(value), this->Values,
+ expandElements, emptyElements);
+ }
+ iterator insert(const_iterator pos, cm::string_view value,
+ EmptyElements emptyElements)
+ {
+ return this->insert(pos, value, ExpandElements::Yes, emptyElements);
+ }
+ iterator insert(const_iterator pos, cmValue value,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ if (value) {
+ return this->insert(pos, *value, expandElements, emptyElements);
+ }
+
+ auto delta = std::distance(this->cbegin(), pos);
+ return this->begin() + delta;
+ }
+ iterator insert(const_iterator pos, cmValue value,
+ EmptyElements emptyElements)
+ {
+ return this->insert(pos, value, ExpandElements::Yes, emptyElements);
+ }
+ template <typename InputIterator>
+ iterator insert(const_iterator pos, InputIterator first, InputIterator last,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return cmList::Insert(pos, first, last, this->Values, expandElements,
+ emptyElements);
+ }
+ template <typename InputIterator>
+ iterator insert(const_iterator pos, InputIterator first, InputIterator last,
+ EmptyElements emptyElements)
+ {
+ return this->insert(pos, first, last, ExpandElements::Yes, emptyElements);
+ }
+ iterator insert(const_iterator pos, const cmList& values,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return this->insert(pos, values.begin(), values.end(), expandElements,
+ emptyElements);
+ }
+ iterator insert(const_iterator pos, const cmList& values,
+ EmptyElements emptyElements)
+ {
+ return this->insert(pos, values, ExpandElements::Yes, emptyElements);
+ }
+ iterator insert(const_iterator pos, cmList&& values,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ auto result = this->insert(pos, std::make_move_iterator(values.begin()),
+ std::make_move_iterator(values.end()),
+ expandElements, emptyElements);
+ values.clear();
+
+ return result;
+ }
+ iterator insert(const_iterator pos, cmList&& values,
+ EmptyElements emptyElements)
+ {
+ return this->insert(pos, std::move(values), ExpandElements::Yes,
+ emptyElements);
+ }
+ iterator insert(const_iterator pos, const container_type& values,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return this->insert(pos, values.begin(), values.end(), expandElements,
+ emptyElements);
+ }
+ iterator insert(const_iterator pos, const container_type& values,
+ EmptyElements emptyElements)
+ {
+ return this->insert(pos, values, ExpandElements::Yes, emptyElements);
+ }
+ iterator insert(const_iterator pos, container_type&& values,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ auto result = this->insert(pos, std::make_move_iterator(values.begin()),
+ std::make_move_iterator(values.end()),
+ expandElements, emptyElements);
+ values.clear();
+
+ return result;
+ }
+ iterator insert(const_iterator pos, container_type&& values,
+ EmptyElements emptyElements)
+ {
+ return this->insert(pos, std::move(values), ExpandElements::Yes,
+ emptyElements);
+ }
+ iterator insert(const_iterator pos, std::initializer_list<std::string> ilist)
+ {
+ return this->insert(pos, ilist.begin(), ilist.end());
+ }
+
+ iterator append(cm::string_view value,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return this->insert(this->cend(), value, expandElements, emptyElements);
+ }
+ iterator append(cm::string_view value, EmptyElements emptyElements)
+ {
+ return this->append(value, ExpandElements::Yes, emptyElements);
+ }
+ iterator append(cmValue value,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ if (value) {
+ return this->append(*value, expandElements, emptyElements);
+ }
+
+ return this->end();
+ }
+ iterator append(cmValue value, EmptyElements emptyElements)
+ {
+ return this->append(value, ExpandElements::Yes, emptyElements);
+ }
+ template <typename InputIterator>
+ iterator append(InputIterator first, InputIterator last,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return this->insert(this->cend(), first, last, expandElements,
+ emptyElements);
+ }
+ template <typename InputIterator>
+ iterator append(InputIterator first, InputIterator last,
+ EmptyElements emptyElements)
+ {
+ return this->append(first, last, ExpandElements::Yes, emptyElements);
+ }
+ iterator append(const cmList& values,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return this->append(values.begin(), values.end(), expandElements,
+ emptyElements);
+ }
+ iterator append(const cmList& values, EmptyElements emptyElements)
+ {
+ return this->append(values, ExpandElements::Yes, emptyElements);
+ }
+ iterator append(cmList&& values,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ auto result = this->append(std::make_move_iterator(values.begin()),
+ std::make_move_iterator(values.end()),
+ expandElements, emptyElements);
+ values.clear();
+
+ return result;
+ }
+ iterator append(cmList&& values, EmptyElements emptyElements)
+ {
+ return this->append(std::move(values), ExpandElements::Yes, emptyElements);
+ }
+ iterator append(const container_type& values,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return this->append(values.begin(), values.end(), expandElements,
+ emptyElements);
+ }
+ iterator append(const container_type& values, EmptyElements emptyElements)
+ {
+ return this->append(values, ExpandElements::Yes, emptyElements);
+ }
+ iterator append(container_type&& values,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ auto result = this->append(std::make_move_iterator(values.begin()),
+ std::make_move_iterator(values.end()),
+ expandElements, emptyElements);
+ values.clear();
+
+ return result;
+ }
+ iterator append(container_type&& values, EmptyElements emptyElements)
+ {
+ return this->append(std::move(values), ExpandElements::Yes, emptyElements);
+ }
+ iterator append(std::initializer_list<std::string> ilist)
+ {
+ return this->insert(this->cend(), ilist);
+ }
+
+ iterator prepend(cm::string_view value,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return this->insert(this->cbegin(), value, expandElements, emptyElements);
+ }
+ iterator prepend(cm::string_view value, EmptyElements emptyElements)
+ {
+ return this->prepend(value, ExpandElements::Yes, emptyElements);
+ }
+ iterator prepend(cmValue value,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ if (value) {
+ return this->prepend(*value, expandElements, emptyElements);
+ }
+
+ return this->begin();
+ }
+ iterator prepend(cmValue value, EmptyElements emptyElements)
+ {
+ return this->prepend(value, ExpandElements::Yes, emptyElements);
+ }
+ template <typename InputIterator>
+ iterator prepend(InputIterator first, InputIterator last,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return this->insert(this->cbegin(), first, last, expandElements,
+ emptyElements);
+ }
+ template <typename InputIterator>
+ iterator prepend(InputIterator first, InputIterator last,
+ EmptyElements emptyElements)
+ {
+ return this->prepend(first, last, ExpandElements::Yes, emptyElements);
+ }
+ iterator prepend(const cmList& values,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return this->prepend(values.begin(), values.end(), expandElements,
+ emptyElements);
+ }
+ iterator prepend(const cmList& values, EmptyElements emptyElements)
+ {
+ return this->prepend(values, ExpandElements::Yes, emptyElements);
+ }
+ iterator prepend(cmList&& values,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ auto result = this->prepend(std::make_move_iterator(values.begin()),
+ std::make_move_iterator(values.end()),
+ expandElements, emptyElements);
+ values.clear();
+
+ return result;
+ }
+ iterator prepend(cmList&& values, EmptyElements emptyElements)
+ {
+ return this->prepend(std::move(values), ExpandElements::Yes,
+ emptyElements);
+ }
+ iterator prepend(const container_type& values,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return this->prepend(values.begin(), values.end(), expandElements,
+ emptyElements);
+ }
+ iterator prepend(const container_type& values, EmptyElements emptyElements)
+ {
+ return this->prepend(values, ExpandElements::Yes, emptyElements);
+ }
+ iterator prepend(container_type&& values,
+ ExpandElements expandElements = ExpandElements::Yes,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ auto result = this->prepend(std::make_move_iterator(values.begin()),
+ std::make_move_iterator(values.end()),
+ expandElements, emptyElements);
+ values.clear();
+
+ return result;
+ }
+ iterator prepend(container_type&& values, EmptyElements emptyElements)
+ {
+ return this->prepend(std::move(values), ExpandElements::Yes,
+ emptyElements);
+ }
+ iterator prepend(std::initializer_list<std::string> ilist)
+ {
+ return this->insert(this->cbegin(), ilist);
+ }
+
+ void push_back(cm::string_view value)
+ {
+ this->Values.push_back(std::string{ value });
+ }
+ void push_back(std::string&& value)
+ {
+ this->Values.push_back(std::move(value));
+ }
+
+ template <typename... Args>
+ iterator emplace(const_iterator pos, Args&&... args)
+ {
+ return this->Values.emplace(pos, std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ void emplace_back(Args&&... args)
+ {
+ this->Values.emplace_back(std::forward<Args>(args)...);
+ }
+
+ // Inserts elements in the list
+ // Throw std::out_of_range if index is invalid
+ template <typename InputIterator>
+ cmList& insert_items(index_type index, InputIterator first,
+ InputIterator last)
+ {
+ this->insert(this->begin() + this->ComputeInsertIndex(index), first, last);
+ return *this;
+ }
+ cmList& insert_items(index_type index,
+ std::initializer_list<std::string> values)
+ {
+ return this->insert_items(index, values.begin(), values.end());
+ }
+
+ iterator erase(const_iterator pos)
+ {
+ // convert const_iterator in iterator to please non standard c++11
+ // compilers (gcc 4.8 for example)
+ auto pos2 =
+ this->Values.begin() + std::distance(this->Values.cbegin(), pos);
+ return this->Values.erase(pos2);
+ }
+ iterator erase(const_iterator first, const_iterator last)
+ {
+ // convert const_iterator in iterator to please non standard c++11
+ // compilers (gcc 4.8 for example)
+ auto first2 =
+ this->Values.begin() + std::distance(this->Values.cbegin(), first);
+ auto last2 =
+ this->Values.begin() + std::distance(this->Values.cbegin(), last);
+ return this->Values.erase(first2, last2);
+ }
+
+ void pop_back() { this->Values.pop_back(); }
+ void pop_front() { this->Values.erase(this->begin()); }
+
+ // Removes elements from the list
+ // Throw std::out_of_range if any index is invalid
+ cmList& remove_items(std::initializer_list<index_type> indexes)
+ {
+ return this->RemoveItems(
+ std::vector<index_type>{ indexes.begin(), indexes.end() });
+ }
+ cmList& remove_items(std::initializer_list<std::string> values)
+ {
+ return this->RemoveItems(
+ std::vector<std::string>{ values.begin(), values.end() });
+ }
+ template <typename InputIterator>
+ cmList& remove_items(InputIterator first, InputIterator last)
+ {
+ return this->RemoveItems(
+ std::vector<typename InputIterator::value_type>{ first, last });
+ }
+
+ cmList& remove_duplicates();
+
+ enum class FilterMode
+ {
+ INCLUDE,
+ EXCLUDE
+ };
+ // Includes or removes items from the list
+ // Throw std::invalid_argument if regular expression is invalid
+ cmList& filter(cm::string_view regex, FilterMode mode);
+
+ cmList& reverse()
+ {
+ std::reverse(this->Values.begin(), this->Values.end());
+ return *this;
+ }
+
+ struct SortConfiguration
+ {
+ enum class OrderMode
+ {
+ DEFAULT,
+ ASCENDING,
+ DESCENDING,
+ } Order = OrderMode::DEFAULT;
+
+ enum class CompareMethod
+ {
+ DEFAULT,
+ STRING,
+ FILE_BASENAME,
+ NATURAL,
+ } Compare = CompareMethod::DEFAULT;
+
+ enum class CaseSensitivity
+ {
+ DEFAULT,
+ SENSITIVE,
+ INSENSITIVE,
+ } Case = CaseSensitivity::DEFAULT;
+
+ // declare the default constructor to work-around clang bug
+ SortConfiguration();
+
+ SortConfiguration(OrderMode order, CompareMethod compare,
+ CaseSensitivity caseSensitivity)
+ : Order(order)
+ , Compare(compare)
+ , Case(caseSensitivity)
+ {
+ }
+ };
+ cmList& sort(const SortConfiguration& config = SortConfiguration{});
+
+ // exception raised on error during transform operations
+ class transform_error : public std::runtime_error
+ {
+ public:
+ transform_error(const std::string& error)
+ : std::runtime_error(error)
+ {
+ }
+ };
+
+ class TransformSelector
+ {
+ public:
+ using index_type = cmList::index_type;
+
+ // define some structs used as template selector
+ struct AT;
+ struct FOR;
+ struct REGEX;
+
+ virtual ~TransformSelector() = default;
+
+ virtual const std::string& GetTag() = 0;
+
+ // method NEW is used to allocate a selector of the needed type.
+ // For example:
+ // cmList::TransformSelector::New<AT>({1, 2, 5, 6});
+ // or
+ // cmList::TransformSelector::New<REGEX>("^XX.*");
+ template <typename Type>
+ static std::unique_ptr<TransformSelector> New(
+ std::initializer_list<index_type>);
+ template <typename Type>
+ static std::unique_ptr<TransformSelector> New(
+ std::vector<index_type> const&);
+ template <typename Type>
+ static std::unique_ptr<TransformSelector> New(std::vector<index_type>&&);
+
+ template <typename Type>
+ static std::unique_ptr<TransformSelector> New(std::string const&);
+ template <typename Type>
+ static std::unique_ptr<TransformSelector> New(std::string&&);
+
+ private:
+ static std::unique_ptr<TransformSelector> NewAT(
+ std::initializer_list<index_type> init);
+ static std::unique_ptr<TransformSelector> NewAT(
+ std::vector<index_type> const& init);
+ static std::unique_ptr<TransformSelector> NewAT(
+ std::vector<index_type>&& init);
+
+ static std::unique_ptr<TransformSelector> NewFOR(
+ std::initializer_list<index_type> init);
+ static std::unique_ptr<TransformSelector> NewFOR(
+ std::vector<index_type> const& init);
+ static std::unique_ptr<TransformSelector> NewFOR(
+ std::vector<index_type>&& init);
+
+ static std::unique_ptr<TransformSelector> NewREGEX(
+ std::string const& init);
+ static std::unique_ptr<TransformSelector> NewREGEX(std::string&& init);
+ };
+
+ enum class TransformAction
+ {
+ APPEND,
+ PREPEND,
+ TOLOWER,
+ TOUPPER,
+ STRIP,
+ GENEX_STRIP,
+ REPLACE
+ };
+
+ // Transforms the list by applying an action
+ // Throw std::transform_error is any of arguments specified are invalid
+ cmList& transform(TransformAction action,
+ std::unique_ptr<TransformSelector> = {});
+ cmList& transform(TransformAction action, std::string const& arg,
+ std::unique_ptr<TransformSelector> = {});
+ cmList& transform(TransformAction action, std::string const& arg1,
+ std::string const& arg2,
+ std::unique_ptr<TransformSelector> = {});
+ cmList& transform(TransformAction action,
+ std::vector<std::string> const& args,
+ std::unique_ptr<TransformSelector> = {});
+
+ std::string join(cm::string_view glue) const;
+
+ void swap(cmList& other) noexcept { this->Values.swap(other.Values); }
+
+ // static members
+ // ==============
+ // these methods can be used to store CMake list expansion directly in a
+ // std::vector.
+ static void assign(cm::string_view value,
+ std::vector<std::string>& container,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ container.clear();
+ cmList::append(value, container, emptyElements);
+ }
+ static void assign(cmValue value, std::vector<std::string>& container,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ if (value) {
+ cmList::assign(*value, container, emptyElements);
+ } else {
+ container.clear();
+ }
+ }
+ template <typename InputIterator>
+ static void assign(InputIterator first, InputIterator last,
+ std::vector<std::string>& container,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ container.clear();
+ cmList::append(first, last, container, emptyElements);
+ }
+
+ static std::vector<std::string>::iterator insert(
+ std::vector<std::string>::const_iterator pos, cm::string_view value,
+ std::vector<std::string>& container,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return cmList::Insert(pos, std::string(value), container,
+ ExpandElements::Yes, emptyElements);
+ }
+ static std::vector<std::string>::iterator insert(
+ std::vector<std::string>::const_iterator pos, cmValue value,
+ std::vector<std::string>& container,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ if (value) {
+ return cmList::insert(pos, *value, container, emptyElements);
+ }
+
+ auto delta = std::distance(container.cbegin(), pos);
+ return container.begin() + delta;
+ }
+ template <typename InputIterator>
+ static std::vector<std::string>::iterator insert(
+ std::vector<std::string>::const_iterator pos, InputIterator first,
+ InputIterator last, std::vector<std::string>& container,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return cmList::Insert(pos, first, last, container, ExpandElements::Yes,
+ emptyElements);
+ }
+
+ static std::vector<std::string>::iterator append(
+ cm::string_view value, std::vector<std::string>& container,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return cmList::insert(container.cend(), value, container, emptyElements);
+ }
+ static std::vector<std::string>::iterator append(
+ cmValue value, std::vector<std::string>& container,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ if (value) {
+ return cmList::append(*value, container, emptyElements);
+ }
+
+ return container.end();
+ }
+ template <typename InputIterator>
+ static std::vector<std::string>::iterator append(
+ InputIterator first, InputIterator last,
+ std::vector<std::string>& container,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return cmList::insert(container.cend(), first, last, container,
+ emptyElements);
+ }
+
+ static std::vector<std::string>::iterator prepend(
+ cm::string_view value, std::vector<std::string>& container,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return cmList::insert(container.cbegin(), value, container, emptyElements);
+ }
+ static std::vector<std::string>::iterator prepend(
+ cmValue value, std::vector<std::string>& container,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ if (value) {
+ return cmList::prepend(*value, container, emptyElements);
+ }
+
+ return container.begin();
+ }
+ template <typename InputIterator>
+ static std::vector<std::string>::iterator prepend(
+ InputIterator first, InputIterator last,
+ std::vector<std::string>& container,
+ EmptyElements emptyElements = EmptyElements::No)
+ {
+ return cmList::insert(container.cbegin(), first, last, container,
+ emptyElements);
+ }
+
+ // The following methods offer the possibility to extend a CMake list
+ // but without any intermediate expansion. So the operation is simply a
+ // string concatenation with special handling for the CMake list item
+ // separator
+ static std::string& append(cm::string_view value, std::string& list);
+ template <typename InputIterator>
+ static std::string& append(InputIterator first, InputIterator last,
+ std::string& list)
+ {
+ if (first == last) {
+ return list;
+ }
+
+ return cmList::append(cm::string_view{ std::accumulate(
+ std::next(first), last, *first,
+ [](std::string a, const std::string& b) {
+ return std::move(a) +
+ std::string(cmList::element_separator) + b;
+ }) },
+ list);
+ }
+
+ static std::string& prepend(cm::string_view value, std::string& list);
+ template <typename InputIterator>
+ static std::string& prepend(InputIterator first, InputIterator last,
+ std::string& list)
+ {
+ if (first == last) {
+ return list;
+ }
+
+ return cmList::prepend(cm::string_view{ std::accumulate(
+ std::next(first), last, *first,
+ [](std::string a, const std::string& b) {
+ return std::move(a) +
+ std::string(cmList::element_separator) + b;
+ }) },
+ list);
+ }
+
+ // Non-members
+ // ===========
+ friend inline bool operator==(const cmList& lhs, const cmList& rhs) noexcept
+ {
+ return lhs.Values == rhs.Values;
+ }
+ friend inline bool operator!=(const cmList& lhs, const cmList& rhs) noexcept
+ {
+ return lhs.Values != rhs.Values;
+ }
+
+private:
+ size_type ComputeIndex(index_type pos, bool boundCheck = true) const;
+ size_type ComputeInsertIndex(index_type pos, bool boundCheck = true) const;
+
+ cmList GetItems(std::vector<index_type>&& indexes) const;
+
+ cmList& RemoveItems(std::vector<index_type>&& indexes);
+ cmList& RemoveItems(std::vector<std::string>&& items);
+
+ static container_type::iterator Insert(container_type::const_iterator pos,
+ std::string&& value,
+ container_type& container,
+ ExpandElements expandElements,
+ EmptyElements emptyElements);
+ static container_type::iterator Insert(container_type::const_iterator pos,
+ const std::string& value,
+ container_type& container,
+ ExpandElements expandElements,
+ EmptyElements emptyElements)
+ {
+ auto tmp = value;
+ return cmList::Insert(pos, std::move(tmp), container, expandElements,
+ emptyElements);
+ }
+ template <typename InputIterator>
+ static container_type::iterator Insert(container_type::const_iterator pos,
+ InputIterator first,
+ InputIterator last,
+ container_type& container,
+ ExpandElements expandElements,
+ EmptyElements emptyElements)
+ {
+ auto delta = std::distance(container.cbegin(), pos);
+
+ if (first == last) {
+ return container.begin() + delta;
+ }
+
+ auto insertPos = container.begin() + delta;
+ if (expandElements == ExpandElements::Yes) {
+ for (; first != last; ++first) {
+ auto size = container.size();
+ insertPos = cmList::Insert(insertPos, *first, container,
+ expandElements, emptyElements);
+ insertPos += container.size() - size;
+ }
+ } else {
+ for (; first != last; ++first) {
+ if (!first->empty() || emptyElements == EmptyElements::Yes) {
+ insertPos = container.insert(insertPos, *first);
+ insertPos++;
+ }
+ }
+ }
+
+ return container.begin() + delta;
+ }
+
+ container_type Values;
+};
+
+// specializations for cmList::TransformSelector allocators
+// ========================================================
+template <>
+inline std::unique_ptr<cmList::TransformSelector>
+cmList::TransformSelector::New<cmList::TransformSelector::AT>(
+ std::initializer_list<index_type> init)
+{
+ return cmList::TransformSelector::NewAT(init);
+}
+template <>
+inline std::unique_ptr<cmList::TransformSelector>
+cmList::TransformSelector::New<cmList::TransformSelector::AT>(
+ std::vector<index_type> const& init)
+{
+ return cmList::TransformSelector::NewAT(init);
+}
+template <>
+inline std::unique_ptr<cmList::TransformSelector>
+cmList::TransformSelector::New<cmList::TransformSelector::AT>(
+ std::vector<index_type>&& init)
+{
+ return cmList::TransformSelector::NewAT(std::move(init));
+}
+
+template <>
+inline std::unique_ptr<cmList::TransformSelector>
+cmList::TransformSelector::New<cmList::TransformSelector::FOR>(
+ std::initializer_list<index_type> init)
+{
+ return cmList::TransformSelector::NewFOR(init);
+}
+template <>
+inline std::unique_ptr<cmList::TransformSelector>
+cmList::TransformSelector::New<cmList::TransformSelector::FOR>(
+ std::vector<index_type> const& init)
+{
+ return cmList::TransformSelector::NewFOR(init);
+}
+template <>
+inline std::unique_ptr<cmList::TransformSelector>
+cmList::TransformSelector::New<cmList::TransformSelector::FOR>(
+ std::vector<index_type>&& init)
+{
+ return cmList::TransformSelector::NewFOR(std::move(init));
+}
+
+template <>
+inline std::unique_ptr<cmList::TransformSelector>
+cmList::TransformSelector::New<cmList::TransformSelector::REGEX>(
+ std::string const& init)
+{
+ return cmList::TransformSelector::NewREGEX(init);
+}
+template <>
+inline std::unique_ptr<cmList::TransformSelector>
+cmList::TransformSelector::New<cmList::TransformSelector::REGEX>(
+ std::string&& init)
+{
+ return cmList::TransformSelector::NewREGEX(std::move(init));
+}
+
+// Non-member functions
+// ====================
+inline std::vector<std::string>& operator+=(std::vector<std::string>& l,
+ const cmList& r)
+{
+ l.insert(l.end(), r.begin(), r.end());
+ return l;
+}
+inline std::vector<std::string>& operator+=(std::vector<std::string>& l,
+ cmList&& r)
+{
+ std::move(r.begin(), r.end(), std::back_inserter(l));
+ r.clear();
+
+ return l;
+}
+
+namespace cm {
+inline void erase(cmList& list, const std::string& value)
+{
+ list.erase(std::remove(list.begin(), list.end(), value), list.end());
+}
+
+template <typename Predicate>
+inline void erase_if(cmList& list, Predicate pred)
+{
+ list.erase(std::remove_if(list.begin(), list.end(), pred), list.end());
+}
+}
+
+namespace srd {
+inline void swap(cmList& lhs, cmList& rhs) noexcept
+{
+ lhs.swap(rhs);
+}
+}
diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx
index d412534c0e..40be0ceeb5 100644
--- a/Source/cmListCommand.cxx
+++ b/Source/cmListCommand.cxx
@@ -2,11 +2,9 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmListCommand.h"
-#include <algorithm>
#include <cassert>
#include <cstdio>
#include <functional>
-#include <iterator>
#include <set>
#include <sstream>
#include <stdexcept>
@@ -14,22 +12,18 @@
#include <vector>
#include <cm/memory>
+#include <cm/optional>
#include <cmext/algorithm>
#include <cmext/string_view>
-#include "cmsys/RegularExpression.hxx"
-
-#include "cmAlgorithms.h"
#include "cmExecutionStatus.h"
-#include "cmGeneratorExpression.h"
+#include "cmList.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
#include "cmRange.h"
#include "cmStringAlgorithms.h"
-#include "cmStringReplaceHelper.h"
#include "cmSubcommandTable.h"
-#include "cmSystemTools.h"
#include "cmValue.h"
namespace {
@@ -70,11 +64,6 @@ bool GetIndexArg(const std::string& arg, int* idx, cmMakefile& mf)
return true;
}
-bool FilterRegex(std::vector<std::string> const& args, bool includeMatches,
- std::string const& listName,
- std::vector<std::string>& varArgsExpanded,
- cmExecutionStatus& status);
-
bool GetListString(std::string& listString, const std::string& var,
const cmMakefile& makefile)
{
@@ -87,22 +76,25 @@ bool GetListString(std::string& listString, const std::string& var,
return true;
}
-bool GetList(std::vector<std::string>& list, const std::string& var,
- const cmMakefile& makefile)
+cm::optional<cmList> GetList(const std::string& var,
+ const cmMakefile& makefile)
{
+ cm::optional<cmList> list;
+
std::string listString;
if (!GetListString(listString, var, makefile)) {
- return false;
+ return list;
}
// if the size of the list
if (listString.empty()) {
- return true;
+ list.emplace();
+ return list;
}
// expand the variable into a list
- cmExpandList(listString, list, true);
+ list.emplace(listString, cmList::EmptyElements::Yes);
// if no empty elements then just return
- if (!cm::contains(list, std::string())) {
- return true;
+ if (!cm::contains(*list, std::string())) {
+ return list;
}
// if we have empty elements we need to check policy CMP0007
switch (makefile.GetPolicyStatus(cmPolicies::CMP0007)) {
@@ -111,31 +103,29 @@ bool GetList(std::vector<std::string>& list, const std::string& var,
// OLD behavior is to allow compatibility, so recall
// ExpandListArgument without the true which will remove
// empty values
- list.clear();
- cmExpandList(listString, list);
+ list->assign(listString);
std::string warn =
cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0007),
" List has value = [", listString, "].");
makefile.IssueMessage(MessageType::AUTHOR_WARNING, warn);
- return true;
+ return list;
}
case cmPolicies::OLD:
// OLD behavior is to allow compatibility, so recall
// ExpandListArgument without the true which will remove
// empty values
- list.clear();
- cmExpandList(listString, list);
- return true;
+ list->assign(listString);
+ return list;
case cmPolicies::NEW:
- return true;
+ return list;
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::REQUIRED_ALWAYS:
makefile.IssueMessage(
MessageType::FATAL_ERROR,
cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0007));
- return false;
+ return {};
}
- return true;
+ return list;
}
bool HandleLengthCommand(std::vector<std::string> const& args,
@@ -148,16 +138,11 @@ bool HandleLengthCommand(std::vector<std::string> const& args,
const std::string& listName = args[1];
const std::string& variableName = args.back();
- std::vector<std::string> varArgsExpanded;
- // do not check the return value here
- // if the list var is not found varArgsExpanded will have size 0
- // and we will return 0
- GetList(varArgsExpanded, listName, status.GetMakefile());
- size_t length = varArgsExpanded.size();
- char buffer[1024];
- snprintf(buffer, sizeof(buffer), "%d", static_cast<int>(length));
-
- status.GetMakefile().AddDefinition(variableName, buffer);
+
+ auto list = GetList(listName, status.GetMakefile());
+ status.GetMakefile().AddDefinition(variableName,
+ std::to_string(list ? list->size() : 0));
+
return true;
}
@@ -172,42 +157,35 @@ bool HandleGetCommand(std::vector<std::string> const& args,
const std::string& listName = args[1];
const std::string& variableName = args.back();
// expand the variable
- std::vector<std::string> varArgsExpanded;
- if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
+ auto list = GetList(listName, status.GetMakefile());
+ if (!list) {
status.GetMakefile().AddDefinition(variableName, "NOTFOUND");
return true;
}
// FIXME: Add policy to make non-existing lists an error like empty lists.
- if (varArgsExpanded.empty()) {
+ if (list->empty()) {
status.SetError("GET given empty list");
return false;
}
- std::string value;
- size_t cc;
- const char* sep = "";
- size_t nitem = varArgsExpanded.size();
- for (cc = 2; cc < args.size() - 1; cc++) {
- int item;
- if (!GetIndexArg(args[cc], &item, status.GetMakefile())) {
+ std::vector<int> indexes;
+ for (std::size_t cc = 2; cc < args.size() - 1; cc++) {
+ int index;
+ if (!GetIndexArg(args[cc], &index, status.GetMakefile())) {
status.SetError(cmStrCat("index: ", args[cc], " is not a valid index"));
return false;
}
- value += sep;
- sep = ";";
- if (item < 0) {
- item = static_cast<int>(nitem) + item;
- }
- if (item < 0 || nitem <= static_cast<size_t>(item)) {
- status.SetError(cmStrCat("index: ", item, " out of range (-", nitem,
- ", ", nitem - 1, ")"));
- return false;
- }
- value += varArgsExpanded[item];
+ indexes.push_back(index);
}
- status.GetMakefile().AddDefinition(variableName, value);
- return true;
+ try {
+ auto values = list->get_items(indexes.begin(), indexes.end());
+ status.GetMakefile().AddDefinition(variableName, values.to_string());
+ return true;
+ } catch (std::out_of_range& e) {
+ status.SetError(e.what());
+ return false;
+ }
}
bool HandleAppendCommand(std::vector<std::string> const& args,
@@ -226,13 +204,8 @@ bool HandleAppendCommand(std::vector<std::string> const& args,
std::string listString;
GetListString(listString, listName, makefile);
- // If `listString` or `args` is empty, no need to append `;`,
- // then index is going to be `1` and points to the end-of-string ";"
- auto const offset =
- static_cast<std::string::size_type>(listString.empty() || args.empty());
- listString += &";"[offset] + cmJoin(cmMakeRange(args).advance(2), ";");
-
- makefile.AddDefinition(listName, listString);
+ makefile.AddDefinition(
+ listName, cmList::append(args.begin() + 2, args.end(), listString));
return true;
}
@@ -252,14 +225,8 @@ bool HandlePrependCommand(std::vector<std::string> const& args,
std::string listString;
GetListString(listString, listName, makefile);
- // If `listString` or `args` is empty, no need to append `;`,
- // then `offset` is going to be `1` and points to the end-of-string ";"
- auto const offset =
- static_cast<std::string::size_type>(listString.empty() || args.empty());
- listString.insert(0,
- cmJoin(cmMakeRange(args).advance(2), ";") + &";"[offset]);
-
- makefile.AddDefinition(listName, listString);
+ makefile.AddDefinition(
+ listName, cmList::prepend(args.begin() + 2, args.end(), listString));
return true;
}
@@ -272,8 +239,9 @@ bool HandlePopBackCommand(std::vector<std::string> const& args,
auto ai = args.cbegin();
++ai; // Skip subcommand name
std::string const& listName = *ai++;
- std::vector<std::string> varArgsExpanded;
- if (!GetList(varArgsExpanded, listName, makefile)) {
+ auto list = GetList(listName, makefile);
+
+ if (!list) {
// Can't get the list definition... undefine any vars given after.
for (; ai != args.cend(); ++ai) {
makefile.RemoveDefinition(*ai);
@@ -281,16 +249,16 @@ bool HandlePopBackCommand(std::vector<std::string> const& args,
return true;
}
- if (!varArgsExpanded.empty()) {
+ if (!list->empty()) {
if (ai == args.cend()) {
// No variables are given... Just remove one element.
- varArgsExpanded.pop_back();
+ list->pop_back();
} else {
// Ok, assign elements to be removed to the given variables
- for (; !varArgsExpanded.empty() && ai != args.cend(); ++ai) {
+ for (; !list->empty() && ai != args.cend(); ++ai) {
assert(!ai->empty());
- makefile.AddDefinition(*ai, varArgsExpanded.back());
- varArgsExpanded.pop_back();
+ makefile.AddDefinition(*ai, list->back());
+ list->pop_back();
}
// Undefine the rest variables if the list gets empty earlier...
for (; ai != args.cend(); ++ai) {
@@ -298,7 +266,7 @@ bool HandlePopBackCommand(std::vector<std::string> const& args,
}
}
- makefile.AddDefinition(listName, cmJoin(varArgsExpanded, ";"));
+ makefile.AddDefinition(listName, list->to_string());
} else if (ai !=
args.cend()) { // The list is empty, but some args were given
@@ -320,8 +288,9 @@ bool HandlePopFrontCommand(std::vector<std::string> const& args,
auto ai = args.cbegin();
++ai; // Skip subcommand name
std::string const& listName = *ai++;
- std::vector<std::string> varArgsExpanded;
- if (!GetList(varArgsExpanded, listName, makefile)) {
+ auto list = GetList(listName, makefile);
+
+ if (!list) {
// Can't get the list definition... undefine any vars given after.
for (; ai != args.cend(); ++ai) {
makefile.RemoveDefinition(*ai);
@@ -329,25 +298,25 @@ bool HandlePopFrontCommand(std::vector<std::string> const& args,
return true;
}
- if (!varArgsExpanded.empty()) {
+ if (!list->empty()) {
if (ai == args.cend()) {
// No variables are given... Just remove one element.
- varArgsExpanded.erase(varArgsExpanded.begin());
+ list->pop_front();
} else {
// Ok, assign elements to be removed to the given variables
- auto vi = varArgsExpanded.begin();
- for (; vi != varArgsExpanded.end() && ai != args.cend(); ++ai, ++vi) {
+ auto vi = list->begin();
+ for (; vi != list->end() && ai != args.cend(); ++ai, ++vi) {
assert(!ai->empty());
makefile.AddDefinition(*ai, *vi);
}
- varArgsExpanded.erase(varArgsExpanded.begin(), vi);
+ list->erase(list->begin(), vi);
// Undefine the rest variables if the list gets empty earlier...
for (; ai != args.cend(); ++ai) {
makefile.RemoveDefinition(*ai);
}
}
- makefile.AddDefinition(listName, cmJoin(varArgsExpanded, ";"));
+ makefile.AddDefinition(listName, list->to_string());
} else if (ai !=
args.cend()) { // The list is empty, but some args were given
@@ -371,21 +340,16 @@ bool HandleFindCommand(std::vector<std::string> const& args,
const std::string& listName = args[1];
const std::string& variableName = args.back();
// expand the variable
- std::vector<std::string> varArgsExpanded;
- if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
- status.GetMakefile().AddDefinition(variableName, "-1");
- return true;
- }
+ auto list = GetList(listName, status.GetMakefile());
- auto it = std::find(varArgsExpanded.begin(), varArgsExpanded.end(), args[2]);
- if (it != varArgsExpanded.end()) {
- status.GetMakefile().AddDefinition(
- variableName,
- std::to_string(std::distance(varArgsExpanded.begin(), it)));
+ if (!list) {
+ status.GetMakefile().AddDefinition(variableName, "-1");
return true;
}
- status.GetMakefile().AddDefinition(variableName, "-1");
+ auto index = list->find(args[2]);
+ status.GetMakefile().AddDefinition(
+ variableName, index == cmList::npos ? "-1" : std::to_string(index));
return true;
}
@@ -400,38 +364,24 @@ bool HandleInsertCommand(std::vector<std::string> const& args,
const std::string& listName = args[1];
// expand the variable
- int item;
- if (!GetIndexArg(args[2], &item, status.GetMakefile())) {
+ int index;
+ if (!GetIndexArg(args[2], &index, status.GetMakefile())) {
status.SetError(cmStrCat("index: ", args[2], " is not a valid index"));
return false;
}
- std::vector<std::string> varArgsExpanded;
- if ((!GetList(varArgsExpanded, listName, status.GetMakefile()) ||
- varArgsExpanded.empty()) &&
- item != 0) {
- status.SetError(cmStrCat("index: ", item, " out of range (0, 0)"));
- return false;
+ auto list = GetList(listName, status.GetMakefile());
+ if (!list) {
+ list = cmList{};
}
- if (!varArgsExpanded.empty()) {
- size_t nitem = varArgsExpanded.size();
- if (item < 0) {
- item = static_cast<int>(nitem) + item;
- }
- if (item < 0 || nitem < static_cast<size_t>(item)) {
- status.SetError(cmStrCat("index: ", item, " out of range (-",
- varArgsExpanded.size(), ", ",
- varArgsExpanded.size(), ")"));
- return false;
- }
+ try {
+ list->insert_items(index, args.begin() + 3, args.end());
+ status.GetMakefile().AddDefinition(listName, list->to_string());
+ return true;
+ } catch (std::out_of_range& e) {
+ status.SetError(e.what());
+ return false;
}
-
- varArgsExpanded.insert(varArgsExpanded.begin() + item, args.begin() + 3,
- args.end());
-
- std::string value = cmJoin(varArgsExpanded, ";");
- status.GetMakefile().AddDefinition(listName, value);
- return true;
}
bool HandleJoinCommand(std::vector<std::string> const& args,
@@ -448,16 +398,14 @@ bool HandleJoinCommand(std::vector<std::string> const& args,
const std::string& variableName = args[3];
// expand the variable
- std::vector<std::string> varArgsExpanded;
- if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
+ auto list = GetList(listName, status.GetMakefile());
+
+ if (!list) {
status.GetMakefile().AddDefinition(variableName, "");
return true;
}
- std::string value =
- cmJoin(cmMakeRange(varArgsExpanded.begin(), varArgsExpanded.end()), glue);
-
- status.GetMakefile().AddDefinition(variableName, value);
+ status.GetMakefile().AddDefinition(variableName, list->join(glue));
return true;
}
@@ -472,21 +420,14 @@ bool HandleRemoveItemCommand(std::vector<std::string> const& args,
const std::string& listName = args[1];
// expand the variable
- std::vector<std::string> varArgsExpanded;
- if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
+ auto list = GetList(listName, status.GetMakefile());
+
+ if (!list) {
return true;
}
- std::vector<std::string> remove(args.begin() + 2, args.end());
- std::sort(remove.begin(), remove.end());
- auto remEnd = std::unique(remove.begin(), remove.end());
- auto remBegin = remove.begin();
-
- auto argsEnd =
- cmRemoveMatching(varArgsExpanded, cmMakeRange(remBegin, remEnd));
- auto argsBegin = varArgsExpanded.cbegin();
- std::string value = cmJoin(cmMakeRange(argsBegin, argsEnd), ";");
- status.GetMakefile().AddDefinition(listName, value);
+ status.GetMakefile().AddDefinition(
+ listName, list->remove_items(args.begin() + 2, args.end()).to_string());
return true;
}
@@ -501,14 +442,13 @@ bool HandleReverseCommand(std::vector<std::string> const& args,
const std::string& listName = args[1];
// expand the variable
- std::vector<std::string> varArgsExpanded;
- if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
+ auto list = GetList(listName, status.GetMakefile());
+
+ if (!list) {
return true;
}
- std::string value = cmJoin(cmReverseRange(varArgsExpanded), ";");
-
- status.GetMakefile().AddDefinition(listName, value);
+ status.GetMakefile().AddDefinition(listName, list->reverse().to_string());
return true;
}
@@ -523,237 +463,17 @@ bool HandleRemoveDuplicatesCommand(std::vector<std::string> const& args,
const std::string& listName = args[1];
// expand the variable
- std::vector<std::string> varArgsExpanded;
- if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
+ auto list = GetList(listName, status.GetMakefile());
+
+ if (!list) {
return true;
}
- auto argsEnd = cmRemoveDuplicates(varArgsExpanded);
- auto argsBegin = varArgsExpanded.cbegin();
- std::string value = cmJoin(cmMakeRange(argsBegin, argsEnd), ";");
-
- status.GetMakefile().AddDefinition(listName, value);
+ status.GetMakefile().AddDefinition(listName,
+ list->remove_duplicates().to_string());
return true;
}
-// Helpers for list(TRANSFORM <list> ...)
-using transform_type = std::function<std::string(const std::string&)>;
-
-class transform_error : public std::runtime_error
-{
-public:
- transform_error(const std::string& error)
- : std::runtime_error(error)
- {
- }
-};
-
-class TransformSelector
-{
-public:
- virtual ~TransformSelector() = default;
-
- std::string Tag;
-
- virtual bool Validate(std::size_t count = 0) = 0;
-
- virtual bool InSelection(const std::string&) = 0;
-
- virtual void Transform(std::vector<std::string>& list,
- const transform_type& transform)
- {
- std::transform(list.begin(), list.end(), list.begin(), transform);
- }
-
-protected:
- TransformSelector(std::string&& tag)
- : Tag(std::move(tag))
- {
- }
-};
-class TransformNoSelector : public TransformSelector
-{
-public:
- TransformNoSelector()
- : TransformSelector("NO SELECTOR")
- {
- }
-
- bool Validate(std::size_t) override { return true; }
-
- bool InSelection(const std::string&) override { return true; }
-};
-class TransformSelectorRegex : public TransformSelector
-{
-public:
- TransformSelectorRegex(const std::string& regex)
- : TransformSelector("REGEX")
- , Regex(regex)
- {
- }
-
- bool Validate(std::size_t) override { return this->Regex.is_valid(); }
-
- bool InSelection(const std::string& value) override
- {
- return this->Regex.find(value);
- }
-
- cmsys::RegularExpression Regex;
-};
-class TransformSelectorIndexes : public TransformSelector
-{
-public:
- std::vector<int> Indexes;
-
- bool InSelection(const std::string&) override { return true; }
-
- void Transform(std::vector<std::string>& list,
- const transform_type& transform) override
- {
- this->Validate(list.size());
-
- for (auto index : this->Indexes) {
- list[index] = transform(list[index]);
- }
- }
-
-protected:
- TransformSelectorIndexes(std::string&& tag)
- : TransformSelector(std::move(tag))
- {
- }
- TransformSelectorIndexes(std::string&& tag, std::vector<int>&& indexes)
- : TransformSelector(std::move(tag))
- , Indexes(indexes)
- {
- }
-
- int NormalizeIndex(int index, std::size_t count)
- {
- if (index < 0) {
- index = static_cast<int>(count) + index;
- }
- if (index < 0 || count <= static_cast<std::size_t>(index)) {
- throw transform_error(cmStrCat(
- "sub-command TRANSFORM, selector ", this->Tag, ", index: ", index,
- " out of range (-", count, ", ", count - 1, ")."));
- }
- return index;
- }
-};
-class TransformSelectorAt : public TransformSelectorIndexes
-{
-public:
- TransformSelectorAt(std::vector<int>&& indexes)
- : TransformSelectorIndexes("AT", std::move(indexes))
- {
- }
-
- bool Validate(std::size_t count) override
- {
- decltype(this->Indexes) indexes;
-
- for (auto index : this->Indexes) {
- indexes.push_back(this->NormalizeIndex(index, count));
- }
- this->Indexes = std::move(indexes);
-
- return true;
- }
-};
-class TransformSelectorFor : public TransformSelectorIndexes
-{
-public:
- TransformSelectorFor(int start, int stop, int step)
- : TransformSelectorIndexes("FOR")
- , Start(start)
- , Stop(stop)
- , Step(step)
- {
- }
-
- bool Validate(std::size_t count) override
- {
- this->Start = this->NormalizeIndex(this->Start, count);
- this->Stop = this->NormalizeIndex(this->Stop, count);
-
- // Does stepping move us further from the end?
- if (this->Start > this->Stop) {
- throw transform_error(
- cmStrCat("sub-command TRANSFORM, selector FOR "
- "expects <start> to be no greater than <stop> (",
- this->Start, " > ", this->Stop, ")"));
- }
-
- // compute indexes
- auto size = (this->Stop - this->Start + 1) / this->Step;
- if ((this->Stop - this->Start + 1) % this->Step != 0) {
- size += 1;
- }
-
- this->Indexes.resize(size);
- auto start = this->Start;
- auto step = this->Step;
- std::generate(this->Indexes.begin(), this->Indexes.end(),
- [&start, step]() -> int {
- auto r = start;
- start += step;
- return r;
- });
-
- return true;
- }
-
-private:
- int Start, Stop, Step;
-};
-
-class TransformAction
-{
-public:
- virtual ~TransformAction() = default;
-
- virtual std::string Transform(const std::string& input) = 0;
-};
-class TransformReplace : public TransformAction
-{
-public:
- TransformReplace(const std::vector<std::string>& arguments,
- cmMakefile* makefile)
- : ReplaceHelper(arguments[0], arguments[1], makefile)
- {
- makefile->ClearMatches();
-
- if (!this->ReplaceHelper.IsRegularExpressionValid()) {
- throw transform_error(
- cmStrCat("sub-command TRANSFORM, action REPLACE: Failed to compile "
- "regex \"",
- arguments[0], "\"."));
- }
- if (!this->ReplaceHelper.IsReplaceExpressionValid()) {
- throw transform_error(cmStrCat("sub-command TRANSFORM, action REPLACE: ",
- this->ReplaceHelper.GetError(), "."));
- }
- }
-
- std::string Transform(const std::string& input) override
- {
- // Scan through the input for all matches.
- std::string output;
-
- if (!this->ReplaceHelper.Replace(input, output)) {
- throw transform_error(cmStrCat("sub-command TRANSFORM, action REPLACE: ",
- this->ReplaceHelper.GetError(), "."));
- }
-
- return output;
- }
-
-private:
- cmStringReplaceHelper ReplaceHelper;
-};
-
bool HandleTransformCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
@@ -763,119 +483,50 @@ bool HandleTransformCommand(std::vector<std::string> const& args,
return false;
}
- // Structure collecting all elements of the command
- struct Command
- {
- Command(const std::string& listName)
- : ListName(listName)
- , OutputName(listName)
- {
- }
-
- std::string Name;
- std::string ListName;
- std::vector<std::string> Arguments;
- std::unique_ptr<TransformAction> Action;
- std::unique_ptr<TransformSelector> Selector;
- std::string OutputName;
- } command(args[1]);
-
// Descriptor of action
+ // Action: enum value identifying action
// Arity: number of arguments required for the action
- // Transform: lambda function implementing the action
struct ActionDescriptor
{
ActionDescriptor(std::string name)
: Name(std::move(name))
{
}
- ActionDescriptor(std::string name, int arity, transform_type transform)
+ ActionDescriptor(std::string name, cmList::TransformAction action,
+ int arity)
: Name(std::move(name))
+ , Action(action)
, Arity(arity)
-#if defined(__GNUC__) && __GNUC__ == 6 && defined(__aarch64__)
- // std::function move constructor miscompiles on this architecture
- , Transform(transform)
-#else
- , Transform(std::move(transform))
-#endif
{
}
operator const std::string&() const { return this->Name; }
std::string Name;
+ cmList::TransformAction Action;
int Arity = 0;
- transform_type Transform;
};
// Build a set of supported actions.
std::set<ActionDescriptor,
std::function<bool(const std::string&, const std::string&)>>
- descriptors(
- [](const std::string& x, const std::string& y) { return x < y; });
- descriptors = { { "APPEND", 1,
- [&command](const std::string& s) -> std::string {
- if (command.Selector->InSelection(s)) {
- return s + command.Arguments[0];
- }
-
- return s;
- } },
- { "PREPEND", 1,
- [&command](const std::string& s) -> std::string {
- if (command.Selector->InSelection(s)) {
- return command.Arguments[0] + s;
- }
-
- return s;
- } },
- { "TOUPPER", 0,
- [&command](const std::string& s) -> std::string {
- if (command.Selector->InSelection(s)) {
- return cmSystemTools::UpperCase(s);
- }
-
- return s;
- } },
- { "TOLOWER", 0,
- [&command](const std::string& s) -> std::string {
- if (command.Selector->InSelection(s)) {
- return cmSystemTools::LowerCase(s);
- }
-
- return s;
- } },
- { "STRIP", 0,
- [&command](const std::string& s) -> std::string {
- if (command.Selector->InSelection(s)) {
- return cmTrimWhitespace(s);
- }
-
- return s;
- } },
- { "GENEX_STRIP", 0,
- [&command](const std::string& s) -> std::string {
- if (command.Selector->InSelection(s)) {
- return cmGeneratorExpression::Preprocess(
- s,
- cmGeneratorExpression::StripAllGeneratorExpressions);
- }
-
- return s;
- } },
- { "REPLACE", 2,
- [&command](const std::string& s) -> std::string {
- if (command.Selector->InSelection(s)) {
- return command.Action->Transform(s);
- }
-
- return s;
- } } };
+ descriptors{ { { "APPEND", cmList::TransformAction::APPEND, 1 },
+ { "PREPEND", cmList::TransformAction::PREPEND, 1 },
+ { "TOUPPER", cmList::TransformAction::TOUPPER, 0 },
+ { "TOLOWER", cmList::TransformAction::TOLOWER, 0 },
+ { "STRIP", cmList::TransformAction::STRIP, 0 },
+ { "GENEX_STRIP", cmList::TransformAction::GENEX_STRIP, 0 },
+ { "REPLACE", cmList::TransformAction::REPLACE, 2 } },
+ [](const std::string& x, const std::string& y) {
+ return x < y;
+ } };
+ const std::string& listName = args[1];
+
+ // Parse all possible function parameters
using size_type = std::vector<std::string>::size_type;
size_type index = 2;
- // Parse all possible function parameters
auto descriptor = descriptors.find(args[index]);
if (descriptor == descriptors.end()) {
@@ -893,295 +544,184 @@ bool HandleTransformCommand(std::vector<std::string> const& args,
return false;
}
- command.Name = descriptor->Name;
+ std::vector<std::string> arguments;
index += descriptor->Arity;
if (descriptor->Arity > 0) {
- command.Arguments =
+ arguments =
std::vector<std::string>(args.begin() + 3, args.begin() + index);
}
- if (command.Name == "REPLACE") {
- try {
- command.Action = cm::make_unique<TransformReplace>(
- command.Arguments, &status.GetMakefile());
- } catch (const transform_error& e) {
- status.SetError(e.what());
- return false;
- }
- }
-
const std::string REGEX{ "REGEX" };
const std::string AT{ "AT" };
const std::string FOR{ "FOR" };
const std::string OUTPUT_VARIABLE{ "OUTPUT_VARIABLE" };
+ std::unique_ptr<cmList::TransformSelector> selector;
+ std::string outputName = listName;
- // handle optional arguments
- while (args.size() > index) {
- if ((args[index] == REGEX || args[index] == AT || args[index] == FOR) &&
- command.Selector) {
- status.SetError(
- cmStrCat("sub-command TRANSFORM, selector already specified (",
- command.Selector->Tag, ")."));
-
- return false;
- }
+ try {
+ // handle optional arguments
+ while (args.size() > index) {
+ if ((args[index] == REGEX || args[index] == AT || args[index] == FOR) &&
+ selector) {
+ status.SetError(
+ cmStrCat("sub-command TRANSFORM, selector already specified (",
+ selector->GetTag(), ")."));
- // REGEX selector
- if (args[index] == REGEX) {
- if (args.size() == ++index) {
- status.SetError("sub-command TRANSFORM, selector REGEX expects "
- "'regular expression' argument.");
return false;
}
- command.Selector = cm::make_unique<TransformSelectorRegex>(args[index]);
- if (!command.Selector->Validate()) {
- status.SetError(
- cmStrCat("sub-command TRANSFORM, selector REGEX failed to compile "
- "regex \"",
- args[index], "\"."));
- return false;
- }
+ // REGEX selector
+ if (args[index] == REGEX) {
+ if (args.size() == ++index) {
+ status.SetError("sub-command TRANSFORM, selector REGEX expects "
+ "'regular expression' argument.");
+ return false;
+ }
- index += 1;
- continue;
- }
+ selector =
+ cmList::TransformSelector::New<cmList::TransformSelector::REGEX>(
+ args[index]);
- // AT selector
- if (args[index] == AT) {
- // get all specified indexes
- std::vector<int> indexes;
- while (args.size() > ++index) {
- std::size_t pos;
- int value;
+ index += 1;
+ continue;
+ }
- try {
- value = std::stoi(args[index], &pos);
- if (pos != args[index].length()) {
+ // AT selector
+ if (args[index] == AT) {
+ // get all specified indexes
+ std::vector<cmList::index_type> indexes;
+ while (args.size() > ++index) {
+ std::size_t pos;
+ int value;
+
+ try {
+ value = std::stoi(args[index], &pos);
+ if (pos != args[index].length()) {
+ // this is not a number, stop processing
+ break;
+ }
+ indexes.push_back(value);
+ } catch (const std::invalid_argument&) {
// this is not a number, stop processing
break;
}
- indexes.push_back(value);
- } catch (const std::invalid_argument&) {
- // this is not a number, stop processing
- break;
}
- }
- if (indexes.empty()) {
- status.SetError(
- "sub-command TRANSFORM, selector AT expects at least one "
- "numeric value.");
- return false;
- }
+ if (indexes.empty()) {
+ status.SetError(
+ "sub-command TRANSFORM, selector AT expects at least one "
+ "numeric value.");
+ return false;
+ }
- command.Selector =
- cm::make_unique<TransformSelectorAt>(std::move(indexes));
+ selector =
+ cmList::TransformSelector::New<cmList::TransformSelector::AT>(
+ std::move(indexes));
- continue;
- }
-
- // FOR selector
- if (args[index] == FOR) {
- if (args.size() <= ++index + 1) {
- status.SetError(
- "sub-command TRANSFORM, selector FOR expects, at least,"
- " two arguments.");
- return false;
+ continue;
}
- int start = 0;
- int stop = 0;
- int step = 1;
- bool valid = true;
- try {
- std::size_t pos;
-
- start = std::stoi(args[index], &pos);
- if (pos != args[index].length()) {
- // this is not a number
- valid = false;
- } else {
- stop = std::stoi(args[++index], &pos);
- if (pos != args[index].length()) {
- // this is not a number
- valid = false;
- }
+ // FOR selector
+ if (args[index] == FOR) {
+ if (args.size() <= ++index + 1) {
+ status.SetError(
+ "sub-command TRANSFORM, selector FOR expects, at least,"
+ " two arguments.");
+ return false;
}
- } catch (const std::invalid_argument&) {
- // this is not numbers
- valid = false;
- }
- if (!valid) {
- status.SetError("sub-command TRANSFORM, selector FOR expects, "
- "at least, two numeric values.");
- return false;
- }
- // try to read a third numeric value for step
- if (args.size() > ++index) {
+
+ cmList::index_type start = 0;
+ cmList::index_type stop = 0;
+ cmList::index_type step = 1;
+ bool valid = true;
try {
std::size_t pos;
- step = std::stoi(args[index], &pos);
+ start = std::stoi(args[index], &pos);
if (pos != args[index].length()) {
// this is not a number
- step = 1;
+ valid = false;
} else {
- index += 1;
+ stop = std::stoi(args[++index], &pos);
+ if (pos != args[index].length()) {
+ // this is not a number
+ valid = false;
+ }
}
} catch (const std::invalid_argument&) {
- // this is not number, ignore exception
+ // this is not numbers
+ valid = false;
+ }
+ if (!valid) {
+ status.SetError("sub-command TRANSFORM, selector FOR expects, "
+ "at least, two numeric values.");
+ return false;
+ }
+ // try to read a third numeric value for step
+ if (args.size() > ++index) {
+ try {
+ std::size_t pos;
+
+ step = std::stoi(args[index], &pos);
+ if (pos != args[index].length()) {
+ // this is not a number
+ step = 1;
+ } else {
+ index += 1;
+ }
+ } catch (const std::invalid_argument&) {
+ // this is not number, ignore exception
+ }
}
- }
- if (step <= 0) {
- status.SetError("sub-command TRANSFORM, selector FOR expects "
- "positive numeric value for <step>.");
- return false;
- }
+ if (step <= 0) {
+ status.SetError("sub-command TRANSFORM, selector FOR expects "
+ "positive numeric value for <step>.");
+ return false;
+ }
- command.Selector =
- cm::make_unique<TransformSelectorFor>(start, stop, step);
+ selector =
+ cmList::TransformSelector::New<cmList::TransformSelector::FOR>(
+ { start, stop, step });
- continue;
- }
+ continue;
+ }
- // output variable
- if (args[index] == OUTPUT_VARIABLE) {
- if (args.size() == ++index) {
- status.SetError("sub-command TRANSFORM, OUTPUT_VARIABLE "
- "expects variable name argument.");
- return false;
+ // output variable
+ if (args[index] == OUTPUT_VARIABLE) {
+ if (args.size() == ++index) {
+ status.SetError("sub-command TRANSFORM, OUTPUT_VARIABLE "
+ "expects variable name argument.");
+ return false;
+ }
+
+ outputName = args[index++];
+ continue;
}
- command.OutputName = args[index++];
- continue;
+ status.SetError(cmStrCat("sub-command TRANSFORM, '",
+ cmJoin(cmMakeRange(args).advance(index), " "),
+ "': unexpected argument(s)."));
+ return false;
}
- status.SetError(cmStrCat("sub-command TRANSFORM, '",
- cmJoin(cmMakeRange(args).advance(index), " "),
- "': unexpected argument(s)."));
- return false;
- }
-
- // expand the list variable
- std::vector<std::string> varArgsExpanded;
- if (!GetList(varArgsExpanded, command.ListName, status.GetMakefile())) {
- status.GetMakefile().AddDefinition(command.OutputName, "");
- return true;
- }
+ // expand the list variable
+ auto list = GetList(listName, status.GetMakefile());
- if (!command.Selector) {
- // no selector specified, apply transformation to all elements
- command.Selector = cm::make_unique<TransformNoSelector>();
- }
+ if (!list) {
+ status.GetMakefile().AddDefinition(outputName, "");
+ return true;
+ }
- try {
- command.Selector->Transform(varArgsExpanded, descriptor->Transform);
- } catch (const transform_error& e) {
+ list->transform(descriptor->Action, arguments, std::move(selector));
+ status.GetMakefile().AddDefinition(outputName, list->to_string());
+ return true;
+ } catch (cmList::transform_error& e) {
status.SetError(e.what());
return false;
}
-
- status.GetMakefile().AddDefinition(command.OutputName,
- cmJoin(varArgsExpanded, ";"));
-
- return true;
}
-class cmStringSorter
-{
-public:
- enum class Order
- {
- UNINITIALIZED,
- ASCENDING,
- DESCENDING,
- };
-
- enum class Compare
- {
- UNINITIALIZED,
- STRING,
- FILE_BASENAME,
- NATURAL,
- };
- enum class CaseSensitivity
- {
- UNINITIALIZED,
- SENSITIVE,
- INSENSITIVE,
- };
-
-protected:
- using StringFilter = std::string (*)(const std::string&);
- StringFilter GetCompareFilter(Compare compare)
- {
- return (compare == Compare::FILE_BASENAME) ? cmSystemTools::GetFilenameName
- : nullptr;
- }
-
- StringFilter GetCaseFilter(CaseSensitivity sensitivity)
- {
- return (sensitivity == CaseSensitivity::INSENSITIVE)
- ? cmSystemTools::LowerCase
- : nullptr;
- }
-
- using ComparisonFunction =
- std::function<bool(const std::string&, const std::string&)>;
- ComparisonFunction GetComparisonFunction(Compare compare)
- {
- if (compare == Compare::NATURAL) {
- return std::function<bool(const std::string&, const std::string&)>(
- [](const std::string& x, const std::string& y) {
- return cmSystemTools::strverscmp(x, y) < 0;
- });
- }
- return std::function<bool(const std::string&, const std::string&)>(
- [](const std::string& x, const std::string& y) { return x < y; });
- }
-
-public:
- cmStringSorter(Compare compare, CaseSensitivity caseSensitivity,
- Order desc = Order::ASCENDING)
- : filters{ this->GetCompareFilter(compare),
- this->GetCaseFilter(caseSensitivity) }
- , sortMethod(this->GetComparisonFunction(compare))
- , descending(desc == Order::DESCENDING)
- {
- }
-
- std::string ApplyFilter(const std::string& argument)
- {
- std::string result = argument;
- for (auto filter : this->filters) {
- if (filter != nullptr) {
- result = filter(result);
- }
- }
- return result;
- }
-
- bool operator()(const std::string& a, const std::string& b)
- {
- std::string af = this->ApplyFilter(a);
- std::string bf = this->ApplyFilter(b);
- bool result;
- if (this->descending) {
- result = this->sortMethod(bf, af);
- } else {
- result = this->sortMethod(af, bf);
- }
- return result;
- }
-
-protected:
- StringFilter filters[2] = { nullptr, nullptr };
- ComparisonFunction sortMethod;
- bool descending;
-};
-
bool HandleSortCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
@@ -1191,9 +731,8 @@ bool HandleSortCommand(std::vector<std::string> const& args,
return false;
}
- auto sortCompare = cmStringSorter::Compare::UNINITIALIZED;
- auto sortCaseSensitivity = cmStringSorter::CaseSensitivity::UNINITIALIZED;
- auto sortOrder = cmStringSorter::Order::UNINITIALIZED;
+ using SortConfig = cmList::SortConfiguration;
+ SortConfig sortConfig;
size_t argumentIndex = 2;
const std::string messageHint = "sub-command SORT ";
@@ -1201,7 +740,7 @@ bool HandleSortCommand(std::vector<std::string> const& args,
while (argumentIndex < args.size()) {
std::string const& option = args[argumentIndex++];
if (option == "COMPARE") {
- if (sortCompare != cmStringSorter::Compare::UNINITIALIZED) {
+ if (sortConfig.Compare != SortConfig::CompareMethod::DEFAULT) {
std::string error = cmStrCat(messageHint, "option \"", option,
"\" has been specified multiple times.");
status.SetError(error);
@@ -1210,11 +749,11 @@ bool HandleSortCommand(std::vector<std::string> const& args,
if (argumentIndex < args.size()) {
std::string const& argument = args[argumentIndex++];
if (argument == "STRING") {
- sortCompare = cmStringSorter::Compare::STRING;
+ sortConfig.Compare = SortConfig::CompareMethod::STRING;
} else if (argument == "FILE_BASENAME") {
- sortCompare = cmStringSorter::Compare::FILE_BASENAME;
+ sortConfig.Compare = SortConfig::CompareMethod::FILE_BASENAME;
} else if (argument == "NATURAL") {
- sortCompare = cmStringSorter::Compare::NATURAL;
+ sortConfig.Compare = SortConfig::CompareMethod::NATURAL;
} else {
std::string error =
cmStrCat(messageHint, "value \"", argument, "\" for option \"",
@@ -1228,8 +767,7 @@ bool HandleSortCommand(std::vector<std::string> const& args,
return false;
}
} else if (option == "CASE") {
- if (sortCaseSensitivity !=
- cmStringSorter::CaseSensitivity::UNINITIALIZED) {
+ if (sortConfig.Case != SortConfig::CaseSensitivity::DEFAULT) {
status.SetError(cmStrCat(messageHint, "option \"", option,
"\" has been specified multiple times."));
return false;
@@ -1237,9 +775,9 @@ bool HandleSortCommand(std::vector<std::string> const& args,
if (argumentIndex < args.size()) {
std::string const& argument = args[argumentIndex++];
if (argument == "SENSITIVE") {
- sortCaseSensitivity = cmStringSorter::CaseSensitivity::SENSITIVE;
+ sortConfig.Case = SortConfig::CaseSensitivity::SENSITIVE;
} else if (argument == "INSENSITIVE") {
- sortCaseSensitivity = cmStringSorter::CaseSensitivity::INSENSITIVE;
+ sortConfig.Case = SortConfig::CaseSensitivity::INSENSITIVE;
} else {
status.SetError(cmStrCat(messageHint, "value \"", argument,
"\" for option \"", option,
@@ -1253,7 +791,7 @@ bool HandleSortCommand(std::vector<std::string> const& args,
}
} else if (option == "ORDER") {
- if (sortOrder != cmStringSorter::Order::UNINITIALIZED) {
+ if (sortConfig.Order != SortConfig::OrderMode::DEFAULT) {
status.SetError(cmStrCat(messageHint, "option \"", option,
"\" has been specified multiple times."));
return false;
@@ -1261,9 +799,9 @@ bool HandleSortCommand(std::vector<std::string> const& args,
if (argumentIndex < args.size()) {
std::string const& argument = args[argumentIndex++];
if (argument == "ASCENDING") {
- sortOrder = cmStringSorter::Order::ASCENDING;
+ sortConfig.Order = SortConfig::OrderMode::ASCENDING;
} else if (argument == "DESCENDING") {
- sortOrder = cmStringSorter::Order::DESCENDING;
+ sortConfig.Order = SortConfig::OrderMode::DESCENDING;
} else {
status.SetError(cmStrCat(messageHint, "value \"", argument,
"\" for option \"", option,
@@ -1281,35 +819,17 @@ bool HandleSortCommand(std::vector<std::string> const& args,
return false;
}
}
- // set Default Values if Option is not given
- if (sortCompare == cmStringSorter::Compare::UNINITIALIZED) {
- sortCompare = cmStringSorter::Compare::STRING;
- }
- if (sortCaseSensitivity == cmStringSorter::CaseSensitivity::UNINITIALIZED) {
- sortCaseSensitivity = cmStringSorter::CaseSensitivity::SENSITIVE;
- }
- if (sortOrder == cmStringSorter::Order::UNINITIALIZED) {
- sortOrder = cmStringSorter::Order::ASCENDING;
- }
const std::string& listName = args[1];
// expand the variable
- std::vector<std::string> varArgsExpanded;
- if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
- return true;
- }
+ auto list = GetList(listName, status.GetMakefile());
- if ((sortCompare == cmStringSorter::Compare::STRING) &&
- (sortCaseSensitivity == cmStringSorter::CaseSensitivity::SENSITIVE) &&
- (sortOrder == cmStringSorter::Order::ASCENDING)) {
- std::sort(varArgsExpanded.begin(), varArgsExpanded.end());
- } else {
- cmStringSorter sorter(sortCompare, sortCaseSensitivity, sortOrder);
- std::sort(varArgsExpanded.begin(), varArgsExpanded.end(), sorter);
+ if (!list) {
+ return true;
}
- std::string value = cmJoin(varArgsExpanded, ";");
- status.GetMakefile().AddDefinition(listName, value);
+ status.GetMakefile().AddDefinition(listName,
+ list->sort(sortConfig).to_string());
return true;
}
@@ -1326,9 +846,9 @@ bool HandleSublistCommand(std::vector<std::string> const& args,
const std::string& variableName = args.back();
// expand the variable
- std::vector<std::string> varArgsExpanded;
- if (!GetList(varArgsExpanded, listName, status.GetMakefile()) ||
- varArgsExpanded.empty()) {
+ auto list = GetList(listName, status.GetMakefile());
+
+ if (!list || list->empty()) {
status.GetMakefile().AddDefinition(variableName, "");
return true;
}
@@ -1344,11 +864,9 @@ bool HandleSublistCommand(std::vector<std::string> const& args,
return false;
}
- using size_type = decltype(varArgsExpanded)::size_type;
-
- if (start < 0 || static_cast<size_type>(start) >= varArgsExpanded.size()) {
+ if (start < 0) {
status.SetError(cmStrCat("begin index: ", start, " is out of range 0 - ",
- varArgsExpanded.size() - 1));
+ list->size() - 1));
return false;
}
if (length < -1) {
@@ -1356,15 +874,17 @@ bool HandleSublistCommand(std::vector<std::string> const& args,
return false;
}
- const size_type end =
- (length == -1 ||
- static_cast<size_type>(start + length) > varArgsExpanded.size())
- ? varArgsExpanded.size()
- : static_cast<size_type>(start + length);
- std::vector<std::string> sublist(varArgsExpanded.begin() + start,
- varArgsExpanded.begin() + end);
- status.GetMakefile().AddDefinition(variableName, cmJoin(sublist, ";"));
- return true;
+ using size_type = cmList::size_type;
+
+ try {
+ auto sublist = list->sublist(static_cast<size_type>(start),
+ static_cast<size_type>(length));
+ status.GetMakefile().AddDefinition(variableName, sublist.to_string());
+ return true;
+ } catch (std::out_of_range& e) {
+ status.SetError(e.what());
+ return false;
+ }
}
bool HandleRemoveAtCommand(std::vector<std::string> const& args,
@@ -1378,9 +898,9 @@ bool HandleRemoveAtCommand(std::vector<std::string> const& args,
const std::string& listName = args[1];
// expand the variable
- std::vector<std::string> varArgsExpanded;
- if (!GetList(varArgsExpanded, listName, status.GetMakefile()) ||
- varArgsExpanded.empty()) {
+ auto list = GetList(listName, status.GetMakefile());
+
+ if (!list || list->empty()) {
std::ostringstream str;
str << "index: ";
for (size_t i = 1; i < args.size(); ++i) {
@@ -1395,36 +915,25 @@ bool HandleRemoveAtCommand(std::vector<std::string> const& args,
}
size_t cc;
- std::vector<size_t> removed;
- size_t nitem = varArgsExpanded.size();
+ std::vector<cmList::index_type> removed;
for (cc = 2; cc < args.size(); ++cc) {
- int item;
- if (!GetIndexArg(args[cc], &item, status.GetMakefile())) {
+ int index;
+ if (!GetIndexArg(args[cc], &index, status.GetMakefile())) {
status.SetError(cmStrCat("index: ", args[cc], " is not a valid index"));
return false;
}
- if (item < 0) {
- item = static_cast<int>(nitem) + item;
- }
- if (item < 0 || nitem <= static_cast<size_t>(item)) {
- status.SetError(cmStrCat("index: ", item, " out of range (-", nitem,
- ", ", nitem - 1, ")"));
- return false;
- }
- removed.push_back(static_cast<size_t>(item));
+ removed.push_back(index);
}
- std::sort(removed.begin(), removed.end());
- auto remEnd = std::unique(removed.begin(), removed.end());
- auto remBegin = removed.begin();
-
- auto argsEnd =
- cmRemoveIndices(varArgsExpanded, cmMakeRange(remBegin, remEnd));
- auto argsBegin = varArgsExpanded.cbegin();
- std::string value = cmJoin(cmMakeRange(argsBegin, argsEnd), ";");
-
- status.GetMakefile().AddDefinition(listName, value);
- return true;
+ try {
+ status.GetMakefile().AddDefinition(
+ listName,
+ list->remove_items(removed.begin(), removed.end()).to_string());
+ return true;
+ } catch (std::out_of_range& e) {
+ status.SetError(e.what());
+ return false;
+ }
}
bool HandleFilterCommand(std::vector<std::string> const& args,
@@ -1447,11 +956,11 @@ bool HandleFilterCommand(std::vector<std::string> const& args,
}
const std::string& op = args[2];
- bool includeMatches;
+ cmList::FilterMode filterMode;
if (op == "INCLUDE") {
- includeMatches = true;
+ filterMode = cmList::FilterMode::INCLUDE;
} else if (op == "EXCLUDE") {
- includeMatches = false;
+ filterMode = cmList::FilterMode::EXCLUDE;
} else {
status.SetError("sub-command FILTER does not recognize operator " + op);
return false;
@@ -1459,70 +968,33 @@ bool HandleFilterCommand(std::vector<std::string> const& args,
const std::string& listName = args[1];
// expand the variable
- std::vector<std::string> varArgsExpanded;
- if (!GetList(varArgsExpanded, listName, status.GetMakefile())) {
+ auto list = GetList(listName, status.GetMakefile());
+
+ if (!list) {
return true;
}
const std::string& mode = args[3];
- if (mode == "REGEX") {
- if (args.size() != 5) {
- status.SetError("sub-command FILTER, mode REGEX "
- "requires five arguments.");
- return false;
- }
- return FilterRegex(args, includeMatches, listName, varArgsExpanded,
- status);
- }
-
- status.SetError("sub-command FILTER does not recognize mode " + mode);
- return false;
-}
-
-class MatchesRegex
-{
-public:
- MatchesRegex(cmsys::RegularExpression& in_regex, bool in_includeMatches)
- : regex(in_regex)
- , includeMatches(in_includeMatches)
- {
+ if (mode != "REGEX") {
+ status.SetError("sub-command FILTER does not recognize mode " + mode);
+ return false;
}
-
- bool operator()(const std::string& target)
- {
- return this->regex.find(target) ^ this->includeMatches;
+ if (args.size() != 5) {
+ status.SetError("sub-command FILTER, mode REGEX "
+ "requires five arguments.");
+ return false;
}
-
-private:
- cmsys::RegularExpression& regex;
- const bool includeMatches;
-};
-
-bool FilterRegex(std::vector<std::string> const& args, bool includeMatches,
- std::string const& listName,
- std::vector<std::string>& varArgsExpanded,
- cmExecutionStatus& status)
-{
const std::string& pattern = args[4];
- cmsys::RegularExpression regex(pattern);
- if (!regex.is_valid()) {
- std::string error =
- cmStrCat("sub-command FILTER, mode REGEX failed to compile regex \"",
- pattern, "\".");
- status.SetError(error);
+
+ try {
+ status.GetMakefile().AddDefinition(
+ listName, list->filter(pattern, filterMode).to_string());
+ return true;
+ } catch (std::invalid_argument& e) {
+ status.SetError(e.what());
return false;
}
-
- auto argsBegin = varArgsExpanded.begin();
- auto argsEnd = varArgsExpanded.end();
- auto newArgsEnd =
- std::remove_if(argsBegin, argsEnd, MatchesRegex(regex, includeMatches));
-
- std::string value = cmJoin(cmMakeRange(argsBegin, newArgsEnd), ";");
- status.GetMakefile().AddDefinition(listName, value);
- return true;
}
-
} // namespace
bool cmListCommand(std::vector<std::string> const& args,
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index e163edbda7..5dbc283fac 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -21,6 +21,8 @@
#include <cm3p/json/value.h>
#include <cm3p/json/writer.h>
+#include "cmsys/RegularExpression.hxx"
+
#include "cmComputeLinkInformation.h"
#include "cmCustomCommandGenerator.h"
#include "cmDyndepCollation.h"
@@ -1259,6 +1261,7 @@ namespace {
cmNinjaBuild GetScanBuildStatement(const std::string& ruleName,
const std::string& ppFileName,
bool compilePP, bool compilePPWithDefines,
+ cmValue ppExcludeFlagsRegex,
cmNinjaBuild& objBuild, cmNinjaVars& vars,
const std::string& objectFileName,
cmLocalGenerator* lg)
@@ -1287,6 +1290,20 @@ cmNinjaBuild GetScanBuildStatement(const std::string& ruleName,
// Scanning and compilation generally use the same flags.
scanBuild.Variables["FLAGS"] = vars["FLAGS"];
+ // Exclude flags not valid during preprocessing.
+ if (compilePP && !ppExcludeFlagsRegex.IsEmpty()) {
+ std::string in = std::move(scanBuild.Variables["FLAGS"]);
+ std::string out;
+ cmsys::RegularExpression regex(*ppExcludeFlagsRegex);
+ std::string::size_type pos = 0;
+ while (regex.find(in.c_str() + pos)) {
+ out = cmStrCat(out, in.substr(pos, regex.start()), ' ');
+ pos += regex.end();
+ }
+ out = cmStrCat(out, in.substr(pos));
+ scanBuild.Variables["FLAGS"] = std::move(out);
+ }
+
if (compilePP && !compilePPWithDefines) {
// Move preprocessor definitions to the scan/preprocessor build statement.
std::swap(scanBuild.Variables["DEFINES"], vars["DEFINES"]);
@@ -1511,18 +1528,22 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
std::string scanRuleName;
std::string ppFileName;
+ cmValue ppExcludeFlagsRegex;
if (compilePP) {
scanRuleName = this->LanguagePreprocessAndScanRule(language, config);
ppFileName = this->ConvertToNinjaPath(
this->GetPreprocessedFilePath(source, config));
+ ppExcludeFlagsRegex = this->Makefile->GetDefinition(cmStrCat(
+ "CMAKE_", language, "_PREPROCESS_SOURCE_EXCLUDE_FLAGS_REGEX"));
} else {
scanRuleName = this->LanguageScanRule(language, config);
ppFileName = cmStrCat(objectFileName, ".ddi.i");
}
cmNinjaBuild ppBuild = GetScanBuildStatement(
- scanRuleName, ppFileName, compilePP, compilePPWithDefines, objBuild,
- vars, objectFileName, this->LocalGenerator);
+ scanRuleName, ppFileName, compilePP, compilePPWithDefines,
+ ppExcludeFlagsRegex, objBuild, vars, objectFileName,
+ this->LocalGenerator);
if (compilePP) {
// In case compilation requires flags that are incompatible with
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 37d697fc87..fe883826aa 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -447,6 +447,9 @@ class cmMakefile;
27, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0148, \
"The FindPythonInterp and FindPythonLibs modules are removed.", 3, \
+ 27, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0149, \
+ "Visual Studio generators select latest Windows SDK by default.", 3, \
27, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt
index 612d4b4d82..0fc3debc9f 100644
--- a/Tests/CMakeLib/CMakeLists.txt
+++ b/Tests/CMakeLib/CMakeLists.txt
@@ -30,6 +30,7 @@ set(CMakeLib_TESTS
testCMExtMemory.cxx
testCMExtAlgorithm.cxx
testCMExtEnumSet.cxx
+ testList.cxx
)
if (CMake_TEST_FILESYSTEM_PATH OR NOT CMake_HAVE_CXX_FILESYSTEM)
list(APPEND CMakeLib_TESTS testCMFilesystemPath.cxx)
diff --git a/Tests/CMakeLib/testList.cxx b/Tests/CMakeLib/testList.cxx
new file mode 100644
index 0000000000..7294be0b31
--- /dev/null
+++ b/Tests/CMakeLib/testList.cxx
@@ -0,0 +1,995 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <iostream>
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include <cm/string_view>
+
+#include "cmList.h"
+
+namespace {
+
+void checkResult(bool success)
+{
+ if (!success) {
+ std::cout << " => failed";
+ }
+ std::cout << std::endl;
+}
+
+bool testConstructors()
+{
+ std::cout << "testConstructors()";
+
+ bool result = true;
+
+ {
+ cmList list;
+ if (!list.empty() || list != cmList{}) {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "aa;bb" };
+ if (list.size() != 2 || list.to_string() != "aa;bb") {
+ result = false;
+ }
+ }
+ {
+ cmList list1{ "aa", "bb" };
+ cmList list2("aa;bb");
+
+ if (list1.size() != 2 || list2.size() != 2 || list1 != list2) {
+ result = false;
+ }
+ if (list1.to_string() != "aa;bb") {
+ result = false;
+ }
+ if (list1.to_string() != list2.to_string()) {
+ result = false;
+ }
+ }
+ {
+ std::vector<std::string> v{ "aa", "bb", "cc" };
+ cmList list(v.begin(), v.end());
+ if (list.size() != 3 || list.to_string() != "aa;bb;cc") {
+ result = false;
+ }
+ }
+ {
+ std::vector<std::string> values{ "aa;bb", "cc", "dd;ee" };
+ cmList list1(values.begin(), values.end());
+ cmList list2(values.begin(), values.end(), cmList::ExpandElements::No);
+
+ if (list1.size() != 5 || list1.to_string() != "aa;bb;cc;dd;ee") {
+ result = false;
+ }
+ if (list2.size() != 3 || list2.to_string() != "aa;bb;cc;dd;ee") {
+ result = false;
+ }
+ }
+ {
+ std::vector<std::string> values{ "aa;bb;;cc", "", "dd;ee" };
+ cmList list1(values.begin(), values.end(), cmList::ExpandElements::No,
+ cmList::EmptyElements::No);
+ cmList list2(values.begin(), values.end(), cmList::ExpandElements::No,
+ cmList::EmptyElements::Yes);
+ cmList list3(values.begin(), values.end(), cmList::ExpandElements::Yes,
+ cmList::EmptyElements::No);
+ cmList list4(values.begin(), values.end(), cmList::ExpandElements::Yes,
+ cmList::EmptyElements::Yes);
+
+ if (list1.size() != 2 || list1.to_string() != "aa;bb;;cc;dd;ee") {
+ result = false;
+ }
+ if (list2.size() != 3 || list2.to_string() != "aa;bb;;cc;;dd;ee") {
+ result = false;
+ }
+ if (list3.size() != 5 || list3.to_string() != "aa;bb;cc;dd;ee") {
+ result = false;
+ }
+ if (list4.size() != 7 || list4.to_string() != "aa;bb;;cc;;dd;ee") {
+ result = false;
+ }
+ }
+ {
+ std::vector<std::string> values{ "aa;bb", "cc", "dd;ee" };
+ cmList list1(values);
+ cmList list2(values, cmList::ExpandElements::No);
+
+ if (list1.size() != 5 || list1.to_string() != "aa;bb;cc;dd;ee") {
+ result = false;
+ }
+ if (list2.size() != 3 || list2.to_string() != "aa;bb;cc;dd;ee") {
+ result = false;
+ }
+ }
+ {
+ std::vector<std::string> values{ "aa", "bb", "cc", "dd", "ee" };
+ cmList list(std::move(values));
+
+ if (list.size() != 5 || list.to_string() != "aa;bb;cc;dd;ee") {
+ result = false;
+ }
+ if (!values.empty()) {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testAssign()
+{
+ std::cout << "testAssign()";
+
+ bool result = true;
+
+ {
+ cmList list1{ "aa", "bb" };
+ cmList list2{ "cc", "dd" };
+
+ list2 = list1;
+ if (list1.size() != 2 || list2.size() != 2 || list1 != list2) {
+ result = false;
+ }
+ if (list1.to_string() != "aa;bb") {
+ result = false;
+ }
+ if (list1.to_string() != list2.to_string()) {
+ result = false;
+ }
+ }
+ {
+ cmList list1{ "aa", "bb" };
+ cmList list2{ "cc", "dd" };
+
+ list2 = std::move(list1);
+ if (!list1.empty() || list2.size() != 2) {
+ result = false;
+ }
+ if (list2.to_string() != "aa;bb") {
+ result = false;
+ }
+ }
+ {
+ std::vector<std::string> v{ "aa", "bb" };
+ cmList list{ "cc", "dd" };
+
+ list = std::move(v);
+ if (!v.empty() || list.size() != 2) {
+ result = false;
+ }
+ if (list.to_string() != "aa;bb") {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "cc", "dd" };
+
+ list = "aa;bb";
+ if (list.size() != 2) {
+ result = false;
+ }
+ if (list.to_string() != "aa;bb") {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testConversions()
+{
+ std::cout << "testConversions()";
+
+ bool result = true;
+
+ {
+ cmList list("a;b;c");
+ std::string s = list.to_string();
+
+ if (s != "a;b;c") {
+ result = false;
+ }
+ }
+ {
+ cmList list("a;b;c");
+ std::vector<std::string> v = list;
+
+ if (list.size() != 3 || v.size() != 3) {
+ result = false;
+ }
+ }
+ {
+ cmList list("a;b;c");
+ std::vector<std::string> v = std::move(list);
+
+ // Microsoft compiler is not able to handle correctly the move semantics
+ // so the initial list is not moved, so do not check its size...
+ if (v.size() != 3) {
+ result = false;
+ }
+ }
+ {
+ cmList list("a;b;c");
+ std::vector<std::string> v;
+
+ // compiler is not able to select the cmList conversion operator
+ // and the std::vector assignment operator using the move semantics
+ // v = std::move(list);
+ v = std::move(list.data());
+
+ if (!list.empty() || v.size() != 3) {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testAccess()
+{
+ std::cout << "testAccess()";
+
+ bool result = true;
+
+ {
+ cmList list{ "a", "b", "c" };
+ if (list.at(1) != "b") {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "a", "b", "c" };
+ if (list.at(-3) != "a") {
+ result = false;
+ }
+ }
+ {
+ try {
+ cmList list{ "a", "b", "c" };
+ if (list.at(4) != "a") {
+ result = false;
+ }
+ } catch (std::out_of_range&) {
+ }
+ }
+ {
+ try {
+ cmList list{ "a", "b", "c" };
+ if (list.at(-4) != "a") {
+ result = false;
+ }
+ } catch (std::out_of_range&) {
+ }
+ }
+ {
+ cmList list{ "a", "b", "c", "d", "e" };
+ auto sublist = list.sublist(list.begin() + 1, list.begin() + 3);
+ if (sublist.size() != 2 || sublist != cmList{ "b", "c" }) {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "a", "b", "c", "d", "e" };
+ auto sublist = list.sublist(1, 2);
+ if (sublist.size() != 2 || sublist != cmList{ "b", "c" }) {
+ result = false;
+ }
+
+ sublist = list.sublist(1, cmList::npos);
+ if (sublist.size() != 4 || sublist != cmList{ "b", "c", "d", "e" }) {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "a", "b", "c", "d", "e", "f" };
+ auto sublist = list.get_items({ 1, 3, 5 });
+ if (sublist.size() != 3 || sublist != cmList{ "b", "d", "f" }) {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "a", "b", "c", "d", "e", "f" };
+ auto sublist = list.get_items({ 1, -3, 5, -3 });
+ if (sublist.size() != 4 || sublist != cmList{ "b", "d", "f", "d" }) {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "a", "b", "c", "d", "e", "f" };
+ try {
+ if (list.get_items({ 1, -3, 5, -3, 10 }).size() != 5) {
+ result = false;
+ }
+ } catch (std::out_of_range&) {
+ }
+ }
+ {
+ cmList list{ "a", "b", "c", "d", "e", "f" };
+
+ if (list.find("b") != 1) {
+ result = false;
+ }
+ if (list.find("x") != cmList::npos) {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testModifiers()
+{
+ std::cout << "testModifiers()";
+
+ bool result = true;
+
+ {
+ cmList list{ "1;2;3;4;5" };
+
+ auto it = list.insert(list.begin() + 2, "6;7;8");
+ if (list.size() != 8 || list.to_string() != "1;2;6;7;8;3;4;5") {
+ result = false;
+ }
+ if (*it != "6") {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "1;2;3;4;5" };
+
+ auto it =
+ list.insert(list.begin() + 2, "6;7;8", cmList::ExpandElements::No);
+ if (list.size() != 6 || list.to_string() != "1;2;6;7;8;3;4;5") {
+ result = false;
+ }
+ if (*it != "6;7;8") {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "1;2;3;4;5" };
+ cmList v{ "6", "7", "8" };
+
+ auto it = list.insert(list.begin() + 2, v);
+ if (list.size() != 8 || list.to_string() != "1;2;6;7;8;3;4;5") {
+ result = false;
+ }
+ if (*it != "6") {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "1;2;3;4;5" };
+ cmList v{ "6", "7", "8" };
+
+ auto it = list.insert(list.begin() + 2, std::move(v));
+ if (list.size() != 8 || list.to_string() != "1;2;6;7;8;3;4;5") {
+ result = false;
+ }
+ if (*it != "6") {
+ result = false;
+ }
+
+ if (!v.empty()) {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "1;2;3;4;5" };
+ std::vector<std::string> v{ "6", "7", "8" };
+
+ auto it = list.insert(list.begin() + 2, v);
+ if (list.size() != 8 || list.to_string() != "1;2;6;7;8;3;4;5") {
+ result = false;
+ }
+ if (*it != "6") {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "1;2;3;4;5" };
+ std::vector<std::string> v{ "6;7", "8" };
+
+ auto it = list.insert(list.begin() + 2, v);
+ if (list.size() != 8 || list.to_string() != "1;2;6;7;8;3;4;5") {
+ result = false;
+ }
+ if (*it != "6") {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "1;2;3;4;5" };
+ std::vector<std::string> v{ "6;7", "8" };
+
+ auto it = list.insert(list.begin() + 2, v, cmList::ExpandElements::No);
+ if (list.size() != 7 || list.to_string() != "1;2;6;7;8;3;4;5") {
+ result = false;
+ }
+ if (*it != "6;7") {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "1;2;3;4;5" };
+ std::vector<std::string> v{ "6;;7", "8" };
+
+ auto it = list.insert(list.begin() + 2, v);
+ if (list.size() != 8 || list.to_string() != "1;2;6;7;8;3;4;5") {
+ result = false;
+ }
+ if (*it != "6") {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "1;2;3;4;5" };
+ std::vector<std::string> v{ "6;;7", "8" };
+
+ auto it = list.insert(list.begin() + 2, v, cmList::EmptyElements::Yes);
+ if (list.size() != 9 || list.to_string() != "1;2;6;;7;8;3;4;5") {
+ result = false;
+ }
+ if (*it != "6") {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "1;2;3;4;5" };
+ std::vector<std::string> v{ "6", "7", "8" };
+
+ auto it = list.insert(list.begin() + 2, std::move(v));
+ if (list.size() != 8 || list.to_string() != "1;2;6;7;8;3;4;5") {
+ result = false;
+ }
+ if (*it != "6") {
+ result = false;
+ }
+
+ if (!v.empty()) {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testRemoveItems()
+{
+ std::cout << "testRemoveItems()";
+
+ bool result = true;
+
+ {
+ cmList list("a;b;c;d;e;f;g;h");
+
+ list.remove_items({ 1, 3, 5 });
+
+ if (list.size() != 5 || list.to_string() != "a;c;e;g;h") {
+ result = false;
+ }
+ }
+ {
+ cmList list("a;b;c;b;a;d;e;f");
+
+ list.remove_items({ "a", "b", "h" });
+
+ if (list.size() != 4 || list.to_string() != "c;d;e;f") {
+ result = false;
+ }
+ }
+ {
+ cmList list("a;b;c;d;e;f;g;h");
+ std::vector<cmList::index_type> remove{ 1, 3, 5 };
+
+ list.remove_items(remove.begin(), remove.end());
+
+ if (list.size() != 5 || list.to_string() != "a;c;e;g;h") {
+ result = false;
+ }
+ }
+ {
+ cmList list("a;b;c;b;a;d;e;f");
+ std::vector<std::string> remove{ "b", "a", "h" };
+
+ list.remove_items(remove.begin(), remove.end());
+
+ if (list.size() != 4 || list.to_string() != "c;d;e;f") {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testRemoveDuplicates()
+{
+ std::cout << "testRemoveDuplicates()";
+
+ bool result = true;
+
+ {
+ cmList list("b;c;b;a;a;c;b;a;c;b");
+
+ list.remove_duplicates();
+
+ if (list.size() != 3 || list.to_string() != "b;c;a") {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testFilter()
+{
+ std::cout << "testFilter()";
+
+ bool result = true;
+
+ {
+ cmList list{ "AA", "Aa", "aA" };
+
+ list.filter("^A", cmList::FilterMode::INCLUDE);
+ if (list.size() != 2 || list.to_string() != "AA;Aa") {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "AA", "Aa", "aA" };
+
+ list.filter("^A", cmList::FilterMode::EXCLUDE);
+ if (list.size() != 1 || list.to_string() != "aA") {
+ result = false;
+ }
+ }
+ {
+ cmList list{ "AA", "Aa", "aA" };
+
+ try {
+ list.filter("^(A", cmList::FilterMode::EXCLUDE);
+ if (list.size() != 1) {
+ result = false;
+ }
+ } catch (const std::invalid_argument&) {
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testReverse()
+{
+ std::cout << "testReverse()";
+
+ bool result = true;
+
+ {
+ cmList list{ "a", "b", "c" };
+ if (list.reverse().to_string() != "c;b;a") {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testSort()
+{
+ std::cout << "testSort()";
+
+ bool result = true;
+
+ using SortConfiguration = cmList::SortConfiguration;
+
+ {
+ cmList list{ "A", "D", "C", "B", "A" };
+
+ list.sort();
+ if (list.to_string() != "A;A;B;C;D") {
+ result = false;
+ }
+
+ list.sort({ SortConfiguration::OrderMode::DESCENDING,
+ SortConfiguration::CompareMethod::DEFAULT,
+ SortConfiguration::CaseSensitivity::DEFAULT });
+ if (list.to_string() != "D;C;B;A;A") {
+ result = false;
+ }
+ }
+ {
+ SortConfiguration sortCfg;
+ cmList list{ "1.0", "1.1", "2.5", "10.2" };
+
+ list.sort(sortCfg);
+ if (list.to_string() != "1.0;1.1;10.2;2.5") {
+ result = false;
+ }
+
+ sortCfg.Compare = SortConfiguration::CompareMethod::NATURAL;
+ list.sort(sortCfg);
+ if (list.to_string() != "1.0;1.1;2.5;10.2") {
+ result = false;
+ }
+
+ sortCfg.Order = SortConfiguration::OrderMode::DESCENDING;
+ list.sort(sortCfg);
+ if (list.to_string() != "10.2;2.5;1.1;1.0") {
+ result = false;
+ }
+ }
+ {
+ SortConfiguration sortCfg;
+ cmList list{ "/zz/bb.cc", "/xx/yy/dd.cc", "/aa/cc.aa" };
+
+ list.sort(sortCfg);
+ if (list.to_string() != "/aa/cc.aa;/xx/yy/dd.cc;/zz/bb.cc") {
+ result = false;
+ }
+
+ sortCfg.Compare = SortConfiguration::CompareMethod::FILE_BASENAME;
+ if (list.sort(sortCfg).to_string() != "/zz/bb.cc;/aa/cc.aa;/xx/yy/dd.cc") {
+ result = false;
+ }
+ }
+ {
+ SortConfiguration sortCfg;
+ cmList list{ "c/B", "a/c", "B/a" };
+
+ if (list.sort().to_string() != "B/a;a/c;c/B") {
+ result = false;
+ }
+
+ sortCfg.Case = SortConfiguration::CaseSensitivity::INSENSITIVE;
+ if (list.sort(sortCfg).to_string() != "a/c;B/a;c/B") {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testTransform()
+{
+ std::cout << "testTransform()";
+
+ bool result = true;
+
+ using AT = cmList::TransformSelector::AT;
+ using FOR = cmList::TransformSelector::FOR;
+ using REGEX = cmList::TransformSelector::REGEX;
+
+ {
+ cmList list({ "AA", "BB", "CC", "DD", "EE" });
+
+ list.transform(cmList::TransformAction::APPEND, "-X");
+ if (list.to_string() != "AA-X;BB-X;CC-X;DD-X;EE-X") {
+ result = false;
+ }
+ }
+ {
+ cmList list({ "AA", "BB", "CC", "DD", "EE" });
+
+ list.transform(cmList::TransformAction::PREPEND, "X-");
+ if (list.to_string() != "X-AA;X-BB;X-CC;X-DD;X-EE") {
+ result = false;
+ }
+ }
+ {
+ cmList list({ "AA", "BB", "CC", "DD", "EE" });
+
+ list.transform(cmList::TransformAction::TOLOWER);
+ if (list.to_string() != "aa;bb;cc;dd;ee") {
+ result = false;
+ }
+ }
+ {
+ cmList list({ "aa", "bb", "cc", "dd", "ee" });
+
+ list.transform(cmList::TransformAction::TOUPPER);
+ if (list.to_string() != "AA;BB;CC;DD;EE") {
+ result = false;
+ }
+ }
+ {
+ cmList list({ " AA", "BB ", " CC ", "DD", "EE" });
+
+ list.transform(cmList::TransformAction::STRIP);
+ if (list.to_string() != "AA;BB;CC;DD;EE") {
+ result = false;
+ }
+ }
+ {
+ cmList list({ "$<CONFIG>AA", "BB$<OR>", "C$<AND>C", "$<OR>DD$<AND>",
+ "$<>E$<>E$<>" });
+
+ list.transform(cmList::TransformAction::GENEX_STRIP);
+ if (list.to_string() != "AA;BB;CC;DD;EE") {
+ result = false;
+ }
+ }
+ {
+ cmList list({ "ABC", "BBCB", "BCCCBC", "BCBCDD", "EBCBCEBC" });
+
+ list.transform(cmList::TransformAction::REPLACE, "^BC|BC$", "X");
+ if (list.to_string() != "AX;BBCB;XCCX;XXDD;EBCBCEX") {
+ result = false;
+ }
+ }
+ {
+ auto atSelector = cmList::TransformSelector::New<AT>({ 1, 2, 4 });
+ cmList list({ "AA", "BB", "CC", "DD", "EE" });
+
+ list.transform(cmList::TransformAction::TOLOWER, std::move(atSelector));
+ if (list.to_string() != "AA;bb;cc;DD;ee") {
+ result = false;
+ }
+ }
+ {
+ auto atSelector = cmList::TransformSelector::New<AT>({ 1, 2, -1 });
+ cmList list({ "AA", "BB", "CC", "DD", "EE" });
+
+ list.transform(cmList::TransformAction::TOLOWER, std::move(atSelector));
+ if (list.to_string() != "AA;bb;cc;DD;ee") {
+ result = false;
+ }
+ }
+ {
+ auto forSelector = cmList::TransformSelector::New<FOR>({ 1, 3 });
+ cmList list({ "AA", "BB", "CC", "DD", "EE" });
+
+ list.transform(cmList::TransformAction::TOLOWER, std::move(forSelector));
+ if (list.to_string() != "AA;bb;cc;dd;EE") {
+ result = false;
+ }
+ }
+ {
+ auto forSelector = cmList::TransformSelector::New<FOR>({ 0, 4, 2 });
+ cmList list({ "AA", "BB", "CC", "DD", "EE" });
+
+ list.transform(cmList::TransformAction::TOLOWER, std::move(forSelector));
+ if (list.to_string() != "aa;BB;cc;DD;ee") {
+ result = false;
+ }
+ }
+ {
+ auto regexSelector = cmList::TransformSelector::New<REGEX>("^(A|D|E)");
+ cmList list({ "AA", "BB", "CC", "DD", "EE" });
+
+ list.transform(cmList::TransformAction::TOLOWER, std::move(regexSelector));
+ if (list.to_string() != "aa;BB;CC;dd;ee") {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+
+bool testStaticModifiers()
+{
+ std::cout << "testStaticModifiers()";
+
+ bool result = true;
+
+ {
+ std::vector<std::string> v{ "a", "b", "c" };
+ cmList::assign("d;e", v);
+
+ if (v.size() != 2 || v[0] != "d" || v[1] != "e") {
+ result = false;
+ }
+ }
+ {
+ std::vector<std::string> v{ "a", "b", "c" };
+ cmList::append("d;;e", v);
+
+ if (v.size() != 5 || v[3] != "d" || v[4] != "e") {
+ result = false;
+ }
+ }
+ {
+ std::vector<std::string> v{ "a", "b", "c" };
+ cmList::append("d;;e", v, cmList::EmptyElements::Yes);
+
+ if (v.size() != 6 || v[3] != "d" || !v[4].empty() || v[5] != "e") {
+ result = false;
+ }
+ }
+ {
+ std::vector<std::string> v{ "a", "b", "c" };
+ cmList::prepend("d;e", v);
+
+ if (v.size() != 5 || v[0] != "d" || v[1] != "e") {
+ result = false;
+ }
+ }
+ {
+ std::vector<std::string> v{ "a", "b", "c" };
+ cmList::prepend("d;;e", v, cmList::EmptyElements::Yes);
+
+ if (v.size() != 6 || v[0] != "d" || !v[1].empty() || v[2] != "e") {
+ result = false;
+ }
+ }
+ {
+ std::string list{ "a;b;c" };
+ cmList::append("d;e", list);
+
+ if (list != "a;b;c;d;e") {
+ result = false;
+ }
+ }
+ {
+ std::string list;
+ cmList::append("d;e", list);
+
+ if (list != "d;e") {
+ result = false;
+ }
+ }
+ {
+ std::string list{ "a;b;c" };
+ cmList::append("", list);
+
+ if (list != "a;b;c;") {
+ result = false;
+ }
+ }
+ {
+ std::string list{ "a;b;c" };
+ std::vector<std::string> v{ "d", "e" };
+ cmList::append(v.begin(), v.end(), list);
+
+ if (list != "a;b;c;d;e") {
+ result = false;
+ }
+ }
+ {
+ std::string list{ "a;b;c" };
+ std::vector<std::string> v;
+ cmList::append(v.begin(), v.end(), list);
+
+ if (list != "a;b;c") {
+ result = false;
+ }
+ }
+ {
+ std::string list;
+ std::vector<std::string> v{ "d", "e" };
+ cmList::append(v.begin(), v.end(), list);
+
+ if (list != "d;e") {
+ result = false;
+ }
+ }
+ {
+ std::string list{ "a;b;c" };
+ cmList::prepend("d;e", list);
+
+ if (list != "d;e;a;b;c") {
+ result = false;
+ }
+ }
+ {
+ std::string list;
+ cmList::prepend("d;e", list);
+
+ if (list != "d;e") {
+ result = false;
+ }
+ }
+ {
+ std::string list{ "a;b;c" };
+ cmList::prepend("", list);
+
+ if (list != ";a;b;c") {
+ result = false;
+ }
+ }
+ {
+ std::string list{ "a;b;c" };
+ std::vector<std::string> v{ "d", "e" };
+ cmList::prepend(v.begin(), v.end(), list);
+
+ if (list != "d;e;a;b;c") {
+ result = false;
+ }
+ }
+ {
+ std::string list{ "a;b;c" };
+ std::vector<std::string> v;
+ cmList::prepend(v.begin(), v.end(), list);
+
+ if (list != "a;b;c") {
+ result = false;
+ }
+ }
+ {
+ std::string list;
+ std::vector<std::string> v{ "d", "e" };
+ cmList::prepend(v.begin(), v.end(), list);
+
+ if (list != "d;e") {
+ result = false;
+ }
+ }
+
+ checkResult(result);
+
+ return result;
+}
+}
+
+int testList(int /*unused*/, char* /*unused*/[])
+{
+ int result = 0;
+
+ if (!testConstructors()) {
+ result = 1;
+ }
+ if (!testAssign()) {
+ result = 1;
+ }
+ if (!testConversions()) {
+ result = 1;
+ }
+ if (!testAccess()) {
+ result = 1;
+ }
+ if (!testModifiers()) {
+ result = 1;
+ }
+ if (!testRemoveItems()) {
+ result = 1;
+ }
+ if (!testRemoveDuplicates()) {
+ result = 1;
+ }
+ if (!testFilter()) {
+ result = 1;
+ }
+ if (!testReverse()) {
+ result = 1;
+ }
+ if (!testSort()) {
+ result = 1;
+ }
+ if (!testTransform()) {
+ result = 1;
+ }
+ if (!testStaticModifiers()) {
+ result = 1;
+ }
+
+ return result;
+}
diff --git a/Tests/RunCMake/Autogen/MocPredefs.cmake b/Tests/RunCMake/Autogen/MocPredefs.cmake
index 7a89bb5471..8307e04cce 100644
--- a/Tests/RunCMake/Autogen/MocPredefs.cmake
+++ b/Tests/RunCMake/Autogen/MocPredefs.cmake
@@ -1,4 +1,3 @@
-cmake_policy(SET CMP0129 NEW)
enable_language(CXX)
find_package(Qt${with_qt_version} REQUIRED COMPONENTS Core)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt
index 1e7b127571..cb4ea46439 100644
--- a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt
@@ -7,7 +7,7 @@ Call Stack \(most recent call first\):
CMP0121-ERANGE-WARN.cmake:2 \(include\)
CMakeLists.txt:3 \(include\)
This warning is for project developers. Use -Wno-dev to suppress it.
-
+.*
CMake Error at CMP0121-ERANGE-Common.cmake:3 \(list\):
list index: (-2147483643|2147483647) out of range \(-5, 4\)
Call Stack \(most recent call first\):
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 080740c7b2..f05f784d7d 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -15,6 +15,9 @@ macro(add_RunCMake_test test)
else()
set(Test_Dir ${test})
endif()
+ if(CMAKE_C_COMPILER_ID STREQUAL "LCC")
+ list(APPEND TEST_ARGS -DRunCMake_TEST_LCC=1)
+ endif()
add_test(NAME RunCMake.${test} COMMAND ${CMAKE_CMAKE_COMMAND}
-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_SOURCE_DIR}
-DRunCMake_GENERATOR_IS_MULTI_CONFIG=${_isMultiConfig}
@@ -41,6 +44,11 @@ function(add_RunCMake_test_group test types)
file(REMOVE_RECURSE "${TEST_CONFIG_DIR}")
file(MAKE_DIRECTORY "${TEST_CONFIG_DIR}")
+ set(TEST_ARGS "")
+ if(CMAKE_C_COMPILER_ID STREQUAL "LCC")
+ list(APPEND TEST_ARGS -DRunCMake_TEST_LCC=1)
+ endif()
+
foreach(type IN LISTS types)
# generate prerequirements config file in cmake as ctest doesn't have as
# much system information so it is easier to set programs and environment
@@ -68,6 +76,7 @@ function(add_RunCMake_test_group test types)
-DRunCMake_MAKE_PROGRAM=${CMake_TEST_EXPLICIT_MAKE_PROGRAM}
-DRunCMake_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/${test}
-DRunCMake_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/${type}/${test}
+ ${TEST_ARGS}
-Dconfig_file=${TEST_CONFIG_DIR}/${type}_config.cmake
-P "${CMAKE_CURRENT_SOURCE_DIR}/${test}/RunCMakeTest.cmake"
)
diff --git a/Tests/RunCMake/CMakePresets/validate_schema.py b/Tests/RunCMake/CMakePresets/validate_schema.py
index b2a67fc4b9..836147aab2 100644
--- a/Tests/RunCMake/CMakePresets/validate_schema.py
+++ b/Tests/RunCMake/CMakePresets/validate_schema.py
@@ -4,13 +4,13 @@ import os.path
import sys
-with open(sys.argv[1], "rb") as f:
- contents = json.loads(f.read().decode("utf-8-sig"))
+with open(sys.argv[1], "r", encoding="utf-8-sig") as f:
+ contents = json.load(f)
schema_file = os.path.join(
os.path.dirname(__file__),
"..", "..", "..", "Help", "manual", "presets", "schema.json")
-with open(schema_file) as f:
+with open(schema_file, "r", encoding="utf-8") as f:
schema = json.load(f)
jsonschema.validate(contents, schema)
diff --git a/Tests/RunCMake/CPack/CMakeLists.txt b/Tests/RunCMake/CPack/CMakeLists.txt
index f210474d82..18a673e7d7 100644
--- a/Tests/RunCMake/CPack/CMakeLists.txt
+++ b/Tests/RunCMake/CPack/CMakeLists.txt
@@ -1,9 +1,5 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
-if(POLICY CMP0129)
- cmake_policy(SET CMP0129 NEW)
-endif()
-
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "")
project(${RunCMake_TEST} CXX)
diff --git a/Tests/RunCMake/CheckCompilerFlag/CMakeLists.txt b/Tests/RunCMake/CheckCompilerFlag/CMakeLists.txt
index 30cb9aebf0..67eae6576c 100644
--- a/Tests/RunCMake/CheckCompilerFlag/CMakeLists.txt
+++ b/Tests/RunCMake/CheckCompilerFlag/CMakeLists.txt
@@ -1,9 +1,3 @@
cmake_minimum_required(VERSION 3.13)
-
-if(POLICY CMP0129)
- cmake_policy(SET CMP0129 NEW)
-endif()
-
project(${RunCMake_TEST} LANGUAGES NONE)
-
include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/GeneratorPlatform/BadFieldNoComma-result.txt b/Tests/RunCMake/GeneratorPlatform/BadFieldNoComma-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/BadFieldNoComma-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorPlatform/BadFieldNoComma-stderr.txt b/Tests/RunCMake/GeneratorPlatform/BadFieldNoComma-stderr.txt
new file mode 100644
index 0000000000..b2098bd425
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/BadFieldNoComma-stderr.txt
@@ -0,0 +1,11 @@
+^CMake Error at CMakeLists.txt:[0-9]+ \(project\):
+ Generator
+
+ Visual Studio [^
+]+
+
+ given platform specification
+
+ Test Platform,nocomma
+
+ that contains a field after the first ',' with no '='\.$
diff --git a/Tests/RunCMake/GeneratorPlatform/BadFieldNoComma.cmake b/Tests/RunCMake/GeneratorPlatform/BadFieldNoComma.cmake
new file mode 100644
index 0000000000..2fc38e5c59
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/BadFieldNoComma.cmake
@@ -0,0 +1 @@
+message(FATAL_ERROR "This should not be reached!")
diff --git a/Tests/RunCMake/GeneratorPlatform/BadFieldUnknown-result.txt b/Tests/RunCMake/GeneratorPlatform/BadFieldUnknown-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/BadFieldUnknown-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorPlatform/BadFieldUnknown-stderr.txt b/Tests/RunCMake/GeneratorPlatform/BadFieldUnknown-stderr.txt
new file mode 100644
index 0000000000..654f9201c8
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/BadFieldUnknown-stderr.txt
@@ -0,0 +1,11 @@
+^CMake Error at CMakeLists.txt:[0-9]+ \(project\):
+ Generator
+
+ Visual Studio [^
+]+
+
+ given platform specification
+
+ Test Platform,unknown=
+
+ that contains invalid field 'unknown='\.$
diff --git a/Tests/RunCMake/GeneratorPlatform/BadFieldUnknown.cmake b/Tests/RunCMake/GeneratorPlatform/BadFieldUnknown.cmake
new file mode 100644
index 0000000000..2fc38e5c59
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/BadFieldUnknown.cmake
@@ -0,0 +1 @@
+message(FATAL_ERROR "This should not be reached!")
diff --git a/Tests/RunCMake/GeneratorPlatform/BadVersionEmpty-result.txt b/Tests/RunCMake/GeneratorPlatform/BadVersionEmpty-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/BadVersionEmpty-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorPlatform/BadVersionEmpty-stderr.txt b/Tests/RunCMake/GeneratorPlatform/BadVersionEmpty-stderr.txt
new file mode 100644
index 0000000000..1b7804da36
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/BadVersionEmpty-stderr.txt
@@ -0,0 +1,11 @@
+^CMake Error at CMakeLists.txt:[0-9]+ \(project\):
+ Generator
+
+ Visual Studio [^
+]+
+
+ given platform specification with empty
+
+ version=
+
+ field\.$
diff --git a/Tests/RunCMake/GeneratorPlatform/BadVersionEmpty.cmake b/Tests/RunCMake/GeneratorPlatform/BadVersionEmpty.cmake
new file mode 100644
index 0000000000..2fc38e5c59
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/BadVersionEmpty.cmake
@@ -0,0 +1 @@
+message(FATAL_ERROR "This should not be reached!")
diff --git a/Tests/RunCMake/GeneratorPlatform/BadVersionMissing-result.txt b/Tests/RunCMake/GeneratorPlatform/BadVersionMissing-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/BadVersionMissing-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorPlatform/BadVersionMissing-stderr.txt b/Tests/RunCMake/GeneratorPlatform/BadVersionMissing-stderr.txt
new file mode 100644
index 0000000000..d82eb0bbac
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/BadVersionMissing-stderr.txt
@@ -0,0 +1,11 @@
+^CMake Error at CMakeLists.txt:[0-9]+ \(project\):
+ Generator
+
+ Visual Studio [^
+]+
+
+ given platform specification with
+
+ version=1\.2\.3\.4
+
+ field, but no Windows SDK with that version was found\.$
diff --git a/Tests/RunCMake/GeneratorPlatform/BadVersionMissing.cmake b/Tests/RunCMake/GeneratorPlatform/BadVersionMissing.cmake
new file mode 100644
index 0000000000..2fc38e5c59
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/BadVersionMissing.cmake
@@ -0,0 +1 @@
+message(FATAL_ERROR "This should not be reached!")
diff --git a/Tests/RunCMake/GeneratorPlatform/BadVersionPlatform-result.txt b/Tests/RunCMake/GeneratorPlatform/BadVersionPlatform-result.txt
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/BadVersionPlatform-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorPlatform/BadVersionPlatform-stderr.txt b/Tests/RunCMake/GeneratorPlatform/BadVersionPlatform-stderr.txt
new file mode 100644
index 0000000000..d3c62e3629
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/BadVersionPlatform-stderr.txt
@@ -0,0 +1,19 @@
+^CMake Error at CMakeLists.txt:[0-9]+ \(project\):
+ Generator
+
+ Visual Studio [^
+]+
+
+ given platform specification (containing a
+
+ version=8\.1
+
+ field\. The version field is not supported when targeting
+
+ Windows 8\.1(
+
+ with the Windows 8\.1 SDK installed\.)?|with
+
+ version=8\.1
+
+ field, but no Windows SDK with that version was found\.)$
diff --git a/Tests/RunCMake/GeneratorPlatform/BadVersionPlatform.cmake b/Tests/RunCMake/GeneratorPlatform/BadVersionPlatform.cmake
new file mode 100644
index 0000000000..2fc38e5c59
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/BadVersionPlatform.cmake
@@ -0,0 +1 @@
+message(FATAL_ERROR "This should not be reached!")
diff --git a/Tests/RunCMake/GeneratorPlatform/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorPlatform/RunCMakeTest.cmake
index a7519c373c..233eb0a2f0 100644
--- a/Tests/RunCMake/GeneratorPlatform/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorPlatform/RunCMakeTest.cmake
@@ -26,3 +26,86 @@ else()
run_cmake(BadPlatformToolchain)
unset(RunCMake_TEST_OPTIONS)
endif()
+
+if("${RunCMake_GENERATOR}" MATCHES "^Visual Studio (1[4567])( 20[0-9][0-9])?$")
+ unset(ENV{WindowsSDKVersion})
+
+ set(RunCMake_GENERATOR_PLATFORM "Test Platform,nocomma")
+ run_cmake(BadFieldNoComma)
+ set(RunCMake_GENERATOR_PLATFORM "Test Platform,unknown=")
+ run_cmake(BadFieldUnknown)
+ set(RunCMake_GENERATOR_PLATFORM "version=")
+ run_cmake(BadVersionEmpty)
+ set(RunCMake_GENERATOR_PLATFORM "version=1.2.3.4")
+ run_cmake(BadVersionMissing)
+ set(RunCMake_GENERATOR_PLATFORM "version=8.1")
+ run_cmake_with_options(BadVersionPlatform -DCMAKE_SYSTEM_VERSION=8.1)
+
+ if(NOT RunCMake_GENERATOR MATCHES "^Visual Studio (1[45]) ")
+ set(expect_version "10.0")
+ set(RunCMake_GENERATOR_PLATFORM "version=${expect_version}")
+ set(RunCMake_TEST_VARIANT_DESCRIPTION "-${expect_version}")
+ run_cmake_with_options(VersionExists -DCMAKE_SYSTEM_VERSION=10.0)
+ unset(RunCMake_GENERATOR_PLATFORM)
+ endif()
+
+ set(kits "")
+ cmake_host_system_information(RESULT kitsRoot10
+ QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Microsoft/Windows Kits/Installed Roots"
+ VALUE "KitsRoot10"
+ VIEW 64_32
+ ERROR_VARIABLE kitsRoot10Error
+ )
+ if(NOT kitsRoot10Error AND IS_DIRECTORY "${kitsRoot10}/include")
+ cmake_path(SET kitsInclude "${kitsRoot10}/include")
+ file(GLOB kits RELATIVE "${kitsInclude}" "${kitsInclude}/*/um/windows.h")
+ list(TRANSFORM kits REPLACE "/.*" "")
+ endif()
+ if(kits)
+ message(STATUS "Available Kits: ${kits}")
+ if(RunCMake_GENERATOR MATCHES "^Visual Studio 14 ")
+ set(kitMax 10.0.14393.0)
+ else()
+ set(kitMax "")
+ endif()
+ if(kitMax)
+ set(kitsIn "${kits}")
+ set(kits "")
+ foreach(kit IN LISTS kitsIn)
+ if(kit VERSION_LESS_EQUAL "${kitMax}")
+ list(APPEND kits "${kit}")
+ else()
+ message(STATUS "Excluding Kit ${kit} > ${kitMax}")
+ endif()
+ endforeach()
+ endif()
+ elseif(NOT RunCMake_GENERATOR MATCHES "^Visual Studio 14 ")
+ message(FATAL_ERROR "Could not find any Windows SDKs to drive test cases.")
+ endif()
+
+ if(kits)
+ foreach(expect_version IN LISTS kits)
+ set(RunCMake_GENERATOR_PLATFORM "version=${expect_version}")
+ set(RunCMake_TEST_VARIANT_DESCRIPTION "-${expect_version}")
+ run_cmake_with_options(VersionExists -DCMAKE_SYSTEM_VERSION=10.0)
+ unset(RunCMake_GENERATOR_PLATFORM)
+ endforeach()
+ foreach(expect_version IN LISTS kits)
+ set(RunCMake_TEST_VARIANT_DESCRIPTION "-CMP0149-OLD-${expect_version}")
+ run_cmake_with_options(VersionExists -DCMAKE_SYSTEM_VERSION=${expect_version} -DCMAKE_POLICY_DEFAULT_CMP0149=OLD)
+ endforeach()
+ if(kits MATCHES "(^|;)([0-9.]+)$")
+ set(expect_version "${CMAKE_MATCH_2}")
+ foreach(test_version IN LISTS kits)
+ set(RunCMake_TEST_VARIANT_DESCRIPTION "-CMP0149-NEW-${test_version}")
+ run_cmake_with_options(VersionExists -DCMAKE_SYSTEM_VERSION=${test_version} -DCMAKE_POLICY_DEFAULT_CMP0149=NEW)
+ endforeach()
+ endif()
+ foreach(expect_version IN LISTS kits)
+ set(RunCMake_TEST_VARIANT_DESCRIPTION "-WindowsSDKVersion-${expect_version}")
+ set(ENV{WindowsSDKVersion} "${expect_version}\\")
+ run_cmake_with_options(VersionExists -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_POLICY_DEFAULT_CMP0149=NEW)
+ unset(ENV{WindowsSDKVersion})
+ endforeach()
+ endif()
+endif()
diff --git a/Tests/RunCMake/GeneratorPlatform/VersionExists-check.cmake b/Tests/RunCMake/GeneratorPlatform/VersionExists-check.cmake
new file mode 100644
index 0000000000..6c3c8e542b
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/VersionExists-check.cmake
@@ -0,0 +1,9 @@
+if(actual_stdout MATCHES "CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION='([^']+)'")
+ set(actual_version "${CMAKE_MATCH_1}")
+ if(NOT "${actual_version}" STREQUAL "${expect_version}")
+ set(RunCMake_TEST_FAILED "Actual SDK version '${actual_version}' did not match expected '${expect_version}'")
+ return()
+ endif()
+else()
+ set(RunCMake_TEST_FAILED "No CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION found in output.")
+endif()
diff --git a/Tests/RunCMake/GeneratorPlatform/VersionExists.cmake b/Tests/RunCMake/GeneratorPlatform/VersionExists.cmake
new file mode 100644
index 0000000000..5c30e2b616
--- /dev/null
+++ b/Tests/RunCMake/GeneratorPlatform/VersionExists.cmake
@@ -0,0 +1,5 @@
+cmake_policy(GET CMP0149 cmp0149)
+message(STATUS "CMP0149='${cmp0149}'")
+message(STATUS "CMAKE_SYSTEM_VERSION='${CMAKE_SYSTEM_VERSION}'")
+message(STATUS "ENV{WindowsSDKVersion}='$ENV{WindowsSDKVersion}'")
+message(STATUS "CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION='${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}'")
diff --git a/Tests/RunCMake/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake
index e1c923d621..8e85f6cf46 100644
--- a/Tests/RunCMake/RunCMake.cmake
+++ b/Tests/RunCMake/RunCMake.cmake
@@ -11,8 +11,12 @@ foreach(
endforeach()
function(run_cmake test)
- if(DEFINED ENV{RunCMake_TEST_FILTER} AND NOT test MATCHES "$ENV{RunCMake_TEST_FILTER}")
- return()
+ if(DEFINED ENV{RunCMake_TEST_FILTER})
+ set(test_and_variant "${test}${RunCMake_TEST_VARIANT_DESCRIPTION}")
+ if(NOT test_and_variant MATCHES "$ENV{RunCMake_TEST_FILTER}")
+ return()
+ endif()
+ unset(test_and_variant)
endif()
set(top_src "${RunCMake_SOURCE_DIR}")
@@ -94,7 +98,7 @@ function(run_cmake test)
if(APPLE)
list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0025=NEW)
endif()
- if(NOT RunCMake_TEST_NO_CMP0129 AND CMAKE_C_COMPILER_ID STREQUAL "LCC")
+ if(RunCMake_TEST_LCC AND NOT RunCMake_TEST_NO_CMP0129)
list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0129=NEW)
endif()
if(RunCMake_MAKE_PROGRAM)
@@ -174,6 +178,7 @@ function(run_cmake test)
"|icp?c: remark #10441: The Intel\\(R\\) C\\+\\+ Compiler Classic \\(ICC\\) is deprecated"
"|[^\n]*install_name_tool: warning: changes being made to the file will invalidate the code signature in:"
+ "|[^\n]*xcodebuild[^\n]*DVTCoreDeviceEnabledState: DVTCoreDeviceEnabledState_Disabled set via user default"
"|[^\n]*xcodebuild[^\n]*DVTPlugInManager"
"|[^\n]*xcodebuild[^\n]*DVTSDK: Warning: SDK path collision for path"
"|[^\n]*xcodebuild[^\n]*Requested but did not find extension point with identifier"
diff --git a/Utilities/Sphinx/cmake.py b/Utilities/Sphinx/cmake.py
index 2ccaf9a7fe..ffef5b36a2 100644
--- a/Utilities/Sphinx/cmake.py
+++ b/Utilities/Sphinx/cmake.py
@@ -242,12 +242,13 @@ class CMakeTransform(Transform):
The cmake --help-*-list commands also depend on this convention.
Return the title or False if the document file does not exist.
"""
- env = self.document.settings.env
+ settings = self.document.settings
+ env = settings.env
title = self.titles.get(docname)
if title is None:
fname = os.path.join(env.srcdir, docname+'.rst')
try:
- f = open(fname, 'r')
+ f = open(fname, 'r', encoding=settings.input_encoding)
except IOError:
title = False
else:
diff --git a/Utilities/Sphinx/create_identifiers.py b/Utilities/Sphinx/create_identifiers.py
index 0ff39a0c2a..61dd819b42 100755
--- a/Utilities/Sphinx/create_identifiers.py
+++ b/Utilities/Sphinx/create_identifiers.py
@@ -6,12 +6,12 @@ if len(sys.argv) != 2:
sys.exit(-1)
name = sys.argv[1] + "/CMake.qhp"
-f = open(name, "rb")
+f = open(name, "r", encoding="utf-8")
if not f:
sys.exit(-1)
-lines = f.read().decode("utf-8").splitlines()
+lines = f.read().splitlines()
if not lines:
sys.exit(-1)
@@ -47,5 +47,5 @@ for line in lines:
line = part1 + prefix + "id=\"" + domain_object_type + "/" + domain_object + "\" " + part2
newlines.append(line + "\n")
-f = open(name, "wb")
-f.writelines(map(lambda line: line.encode("utf-8"), newlines))
+f = open(name, "w", encoding="utf-8")
+f.writelines(newlines)
diff --git a/bootstrap b/bootstrap
index 88438dfd22..a006aeee87 100755
--- a/bootstrap
+++ b/bootstrap
@@ -307,6 +307,7 @@ CMAKE_CXX_SOURCES="\
cmBuildCommand \
cmCMakeLanguageCommand \
cmCMakeMinimumRequired \
+ cmList \
cmCMakePath \
cmCMakePathCommand \
cmCMakePolicyCommand \