Merge branch 'release-3.31'
diff --git a/.clang-tidy b/.clang-tidy
index c85fd67..35503d4 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -8,7 +8,6 @@
-bugprone-implicit-widening-of-multiplication-result,\
-bugprone-inc-dec-in-conditions,\
-bugprone-macro-parentheses,\
--bugprone-misplaced-widening-cast,\
-bugprone-multi-level-implicit-pointer-conversion,\
-bugprone-narrowing-conversions,\
-bugprone-return-const-ref-from-parameter,\
@@ -30,6 +29,7 @@
-misc-use-internal-linkage,\
modernize-*,\
-modernize-avoid-c-arrays,\
+-modernize-concat-nested-namespaces,\
-modernize-macro-to-enum,\
-modernize-return-braced-init-list,\
-modernize-type-traits,\
@@ -45,7 +45,6 @@
-performance-unnecessary-value-param,\
readability-*,\
-readability-avoid-nested-conditional-operator,\
--readability-avoid-return-with-void-value,\
-readability-avoid-unconditional-preprocessor-if,\
-readability-convert-member-functions-to-static,\
-readability-enum-initial-value,\
@@ -59,11 +58,6 @@
-readability-make-member-function-const,\
-readability-math-missing-parentheses,\
-readability-named-parameter,\
--readability-redundant-casting,\
--readability-redundant-declaration,\
--readability-redundant-inline-specifier,\
--readability-redundant-member-init,\
--readability-reference-to-constructed-temporary,\
-readability-simplify-boolean-expr,\
-readability-static-accessed-through-instance,\
-readability-suspicious-call-argument,\
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 222ac91..b4a2425 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -736,6 +736,13 @@
CMAKE_CI_BUILD_NAME: oneapi2024.1.0_makefiles
CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2024.1.0-el8
+t:oneapi2024.2.0-makefiles:
+ extends:
+ - .cmake_test_linux_inteloneapi_makefiles
+ variables:
+ CMAKE_CI_BUILD_NAME: oneapi2024.2.0_makefiles
+ CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2024.2.0-rocky9
+
b:linux-x86_64-package:
extends:
- .linux_package
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 79a562c..ae1359e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,7 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
-cmake_minimum_required(VERSION 3.13...3.29 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.13...3.30 FATAL_ERROR)
set(CMAKE_USER_MAKE_RULES_OVERRIDE_C ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideC.cmake)
set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideCXX.cmake)
diff --git a/Help/command/LINK_LIBRARIES_LINKER.txt b/Help/command/LINK_LIBRARIES_LINKER.txt
new file mode 100644
index 0000000..7dc6b84
--- /dev/null
+++ b/Help/command/LINK_LIBRARIES_LINKER.txt
@@ -0,0 +1,24 @@
+Handling Compiler Driver Differences
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.32
+
+To pass options to the linker tool, each compiler driver has its own syntax.
+The ``LINKER:`` prefix and ``,`` separator can be used to specify, in a portable
+way, options to pass to the linker tool. ``LINKER:`` is replaced by the
+appropriate driver option and ``,`` by the appropriate driver separator.
+The driver prefix and driver separator are given by the values of the
+:variable:`CMAKE_<LANG>_LINKER_WRAPPER_FLAG` and
+:variable:`CMAKE_<LANG>_LINKER_WRAPPER_FLAG_SEP` variables.
+
+For example, ``"LINKER:-z,defs"`` becomes ``-Xlinker -z -Xlinker defs`` for
+``Clang`` and ``-Wl,-z,defs`` for ``GNU GCC``.
+
+The ``LINKER:`` prefix supports, as an alternative syntax, specification of
+arguments using the ``SHELL:`` prefix and space as separator. The previous
+example then becomes ``"LINKER:SHELL:-z defs"``.
+
+.. note::
+
+ Specifying the ``SHELL:`` prefix anywhere other than at the beginning of the
+ ``LINKER:`` prefix is not supported.
diff --git a/Help/command/add_test.rst b/Help/command/add_test.rst
index 2a3c759..dbaa4fb 100644
--- a/Help/command/add_test.rst
+++ b/Help/command/add_test.rst
@@ -16,7 +16,7 @@
CMake only generates tests if the :command:`enable_testing` command has been
invoked. The :module:`CTest` module invokes ``enable_testing`` automatically
-unless ``BUILD_TESTING`` is set to ``OFF``.
+unless :variable:`BUILD_TESTING` is set to ``OFF``.
Tests added with the ``add_test(NAME)`` signature support using
:manual:`generator expressions <cmake-generator-expressions(7)>`
diff --git a/Help/command/ctest_run_script.rst b/Help/command/ctest_run_script.rst
index 145bd90..0d94eb0 100644
--- a/Help/command/ctest_run_script.rst
+++ b/Help/command/ctest_run_script.rst
@@ -9,7 +9,6 @@
script_file_name2 ... [RETURN_VALUE var])
Runs a script or scripts much like if it was run from :option:`ctest -S`.
-If no argument is provided then the current script is run using the current
-settings of the variables. If ``NEW_PROCESS`` is specified then each
-script will be run in a separate process.If ``RETURN_VALUE`` is specified
-the return value of the last script run will be put into ``var``.
+If ``NEW_PROCESS`` is specified then each script will be run in a separate
+process. If ``RETURN_VALUE`` is specified the return value of the last script
+run will be put into ``var``.
diff --git a/Help/command/enable_testing.rst b/Help/command/enable_testing.rst
index 3ac1a19..7bae5c0 100644
--- a/Help/command/enable_testing.rst
+++ b/Help/command/enable_testing.rst
@@ -9,12 +9,12 @@
Enables testing for this directory and below.
-This command should be in the source directory root
-because ctest expects to find a test file in the build
-directory root.
+This command should be in the top-level source directory because
+:manual:`ctest(1)` expects to find a test file in the top-level
+build directory.
This command is automatically invoked when the :module:`CTest`
-module is included, except if the ``BUILD_TESTING`` option is
-turned off.
+module is included, except if the :variable:`BUILD_TESTING`
+option is turned off.
See also the :command:`add_test` command.
diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst
index c26076b..d99dbd5 100644
--- a/Help/command/find_package.rst
+++ b/Help/command/find_package.rst
@@ -507,13 +507,12 @@
configuration file found is used, even if a newer version of the package
resides later in the list of search paths.
-For search paths which contain ``<name>*``, the order among matching paths
-is unspecified unless the :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` variable
-is set. This variable, along with the
-:variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` variable, determines the order
-in which CMake considers paths that match a single search path containing
-``<name>*``. For example, if the file system contains the package
-configuration files
+For search paths which contain glob expressions (``*``), the order in which
+directories matching the glob are searched is unspecified unless the
+:variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` variable is set. This variable,
+along with the :variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` variable,
+determines the order in which CMake considers glob matches. For example, if
+the file system contains the package configuration files
::
@@ -543,6 +542,14 @@
Added the ``CMAKE_FIND_USE_<CATEGORY>`` variables to globally disable
various search locations.
+.. versionchanged:: 3.32
+ The variables :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` and
+ :variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` now also control the order
+ in which ``find_package`` searches directories matching the glob expression
+ in the search paths ``<prefix>/<name>.framework/Versions/*/Resources/``
+ and ``<prefix>/<name>.framework/Versions/*/Resources/CMake``. In previous
+ versions of CMake, this order was unspecified.
+
.. include:: FIND_XXX_ROOT.txt
.. include:: FIND_XXX_ORDER.txt
diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst
index 94a2429..caa6441 100644
--- a/Help/command/target_link_libraries.rst
+++ b/Help/command/target_link_libraries.rst
@@ -148,6 +148,8 @@
See the :manual:`cmake-buildsystem(7)` manual for more on defining
buildsystem properties.
+.. include:: ../command/LINK_LIBRARIES_LINKER.txt
+
Libraries for a Target and/or its Dependents
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Help/command/try_compile.rst b/Help/command/try_compile.rst
index 30ab41a..93713da 100644
--- a/Help/command/try_compile.rst
+++ b/Help/command/try_compile.rst
@@ -336,6 +336,10 @@
The current settings of :policy:`CMP0065` and :policy:`CMP0083` are propagated
through to the generated test project.
+.. versionadded:: 3.32
+ The current setting of :policy:`CMP0181` policy is propagated through to the
+ generated test project.
+
Set variable :variable:`CMAKE_TRY_COMPILE_CONFIGURATION` to choose a build
configuration:
diff --git a/Help/dev/maint.rst b/Help/dev/maint.rst
index 10b3f7d..8098bb0 100644
--- a/Help/dev/maint.rst
+++ b/Help/dev/maint.rst
@@ -350,7 +350,7 @@
away from setting policies to OLD.
Update the ``cmake_policy`` version range generated by ``install(EXPORT)``
-in ``cmExportFileGenerator::GeneratePolicyHeaderCode`` and
+in ``cmExportCMakeConfigGenerator::GeneratePolicyHeaderCode`` and
``install_jar_exports`` in ``javaTargets.cmake.in`` to end at the
previous release. We use one release back since we now know all the
policies added for that version. Commit with a message such as::
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index c62fb48..d32c737 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -51,6 +51,14 @@
to determine whether to report an error on use of deprecated macros or
functions.
+Policies Introduced by CMake 3.32
+=================================
+
+.. toctree::
+ :maxdepth: 1
+
+ CMP0181: Link command-line fragment variables are parsed and re-quoted. </policy/CMP0181>
+
Policies Introduced by CMake 3.31
=================================
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 10dbe10..8adc64a 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -415,6 +415,7 @@
/prop_tgt/UNITY_BUILD_CODE_AFTER_INCLUDE
/prop_tgt/UNITY_BUILD_CODE_BEFORE_INCLUDE
/prop_tgt/UNITY_BUILD_MODE
+ /prop_tgt/UNITY_BUILD_RELOCATABLE
/prop_tgt/UNITY_BUILD_UNIQUE_ID
/prop_tgt/VERIFY_INTERFACE_HEADER_SETS
/prop_tgt/VERSION
@@ -583,6 +584,7 @@
/prop_sf/UNITY_GROUP
/prop_sf/VS_COPY_TO_OUT_DIR
/prop_sf/VS_CSHARP_tagname
+ /prop_sf/VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD
/prop_sf/VS_DEPLOYMENT_CONTENT
/prop_sf/VS_DEPLOYMENT_LOCATION
/prop_sf/VS_INCLUDE_IN_VSIX
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 4c27bd5..0c0f1c5 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -175,6 +175,7 @@
:maxdepth: 1
/variable/BUILD_SHARED_LIBS
+ /variable/BUILD_TESTING
/variable/CMAKE_ABSOLUTE_DESTINATION_FILES
/variable/CMAKE_ADD_CUSTOM_COMMAND_DEPENDS_EXPLICIT_ONLY
/variable/CMAKE_APPBUNDLE_PATH
diff --git a/Help/manual/ctest.1.rst b/Help/manual/ctest.1.rst
index 9281339..4d60ca4 100644
--- a/Help/manual/ctest.1.rst
+++ b/Help/manual/ctest.1.rst
@@ -353,18 +353,32 @@
This allows the user to widen the output to avoid clipping the test
name which can be very annoying.
-.. option:: --interactive-debug-mode [0|1]
+.. option:: --interactive-debug-mode <0|1>
- Set the interactive mode to ``0`` or ``1``.
+ Disable (``0``) or enable (``1``) interactive debug mode.
This option causes CTest to run tests in either an interactive mode
or a non-interactive mode. In dashboard mode (``Experimental``, ``Nightly``,
``Continuous``), the default is non-interactive. In non-interactive mode,
the environment variable :envvar:`DASHBOARD_TEST_FROM_CTEST` is set.
- Prior to CMake 3.11, interactive mode on Windows allowed system debug
- popup windows to appear. Now, due to CTest's use of ``libuv`` to launch
- test processes, all system debug popup windows are always blocked.
+ Interactive Mode allows Windows Error Reporting (WER) to show debug popup
+ windows and to create core dumps. To enable core dumps in tests,
+ use interactive mode, and follow the Windows documentation
+ on `Collecting User-Mode Dumps`_.
+
+ .. versionchanged:: 3.32
+ Windows Error Reporting (WER) is enabled in interactive mode, so
+ test processes may show debug popup windows and create core dumps.
+ This was made possible by updates to ``libuv``.
+
+ .. versionchanged:: 3.11
+ Windows Error Reporting (WER) is disabled in both interactive and
+ non-interactive modes, so test processes do not show popup windows
+ or create core dumps. This is due to launching test processes with
+ ``libuv``.
+
+.. _`Collecting User-Mode Dumps`: https://learn.microsoft.com/en-us/windows/win32/wer/collecting-user-mode-dumps
.. option:: --no-label-summary
@@ -421,11 +435,8 @@
.. option:: --force-new-ctest-process
- Run child CTest instances as new processes.
-
- By default CTest will run child CTest instances within the same
- process. If this behavior is not desired, this argument will
- enforce new processes for child CTest processes.
+ Ignored. This option once disabled a now-removed optimization
+ for tests running ``ctest`` itself.
.. option:: --schedule-random
diff --git a/Help/policy/CMP0147.rst b/Help/policy/CMP0147.rst
index fd5dc5f..1790678 100644
--- a/Help/policy/CMP0147.rst
+++ b/Help/policy/CMP0147.rst
@@ -10,7 +10,8 @@
a ``BuildInParallel`` setting to custom commands in ``.vcxproj`` files.
This policy provides compatibility for projects that have not been updated
to expect this, e.g., because their custom commands were accidentally
-relying on serial execution by MSBuild.
+relying on serial execution by MSBuild. To control this behavior in a more
+precise way, refer to :prop_sf:`VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD`.
The ``OLD`` behavior for this policy is to not add ``BuildInParallel``.
The ``NEW`` behavior for this policy is to add ``BuildInParallel`` for
diff --git a/Help/policy/CMP0181.rst b/Help/policy/CMP0181.rst
new file mode 100644
index 0000000..18fb8db
--- /dev/null
+++ b/Help/policy/CMP0181.rst
@@ -0,0 +1,41 @@
+CMP0181
+-------
+
+.. versionadded:: 3.32
+
+The :variable:`CMAKE_EXE_LINKER_FLAGS`,
+:variable:`CMAKE_EXE_LINKER_FLAGS_<CONFIG>`,
+:variable:`CMAKE_SHARED_LINKER_FLAGS`,
+:variable:`CMAKE_SHARED_LINKER_FLAGS_<CONFIG>`,
+:variable:`CMAKE_MODULE_LINKER_FLAGS`,
+and :variable:`CMAKE_MODULE_LINKER_FLAGS_<CONFIG>` variables are parsed and
+re-quoted and support the ``LINKER:`` prefix.
+
+CMake 3.31 and below use the content of these variables as is.
+
+CMake 3.32 and above parse the content of these variables and manage the
+escaping of special characters. Moreover, the ``LINKER:`` prefix is now
+recognized and expanded.
+
+The ``OLD`` behavior of this policy is to consume the content of the
+:variable:`CMAKE_EXE_LINKER_FLAGS`,
+:variable:`CMAKE_EXE_LINKER_FLAGS_<CONFIG>`,
+:variable:`CMAKE_SHARED_LINKER_FLAGS`,
+:variable:`CMAKE_SHARED_LINKER_FLAGS_<CONFIG>`,
+:variable:`CMAKE_MODULE_LINKER_FLAGS`,
+and :variable:`CMAKE_MODULE_LINKER_FLAGS_<CONFIG>` variables as is.
+
+The ``NEW`` behavior of this policy is to parse and re-quote the content of the
+:variable:`CMAKE_EXE_LINKER_FLAGS`,
+:variable:`CMAKE_EXE_LINKER_FLAGS_<CONFIG>`,
+:variable:`CMAKE_SHARED_LINKER_FLAGS`,
+:variable:`CMAKE_SHARED_LINKER_FLAGS_<CONFIG>`,
+:variable:`CMAKE_MODULE_LINKER_FLAGS`,
+and :variable:`CMAKE_MODULE_LINKER_FLAGS_<CONFIG>` variables as well as to
+expand the ``LINKER:`` prefix.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 3.32
+.. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn
+.. include:: STANDARD_ADVICE.txt
+
+.. include:: DEPRECATED.txt
diff --git a/Help/prop_sf/VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD.rst b/Help/prop_sf/VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD.rst
new file mode 100644
index 0000000..f8bb93d
--- /dev/null
+++ b/Help/prop_sf/VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD.rst
@@ -0,0 +1,9 @@
+VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD
+----------------------------------------
+
+.. versionadded:: 3.32
+
+A boolean property that disables parallel building for the source file in
+Visual Studio if it is built via :command:`add_custom_command` and is the
+``MAIN_DEPENDENCY`` input for the custom command.
+See policy :policy:`CMP0147`.
diff --git a/Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst b/Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst
index 53f5838..73d273b 100644
--- a/Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst
+++ b/Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst
@@ -32,6 +32,8 @@
:prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT` and
:prop_tgt:`INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE` target properties.
+.. include:: ../command/LINK_LIBRARIES_LINKER.txt
+
Creating Relocatable Packages
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst b/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst
index 785b17c..886adf2 100644
--- a/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst
+++ b/Help/prop_tgt/INTERFACE_LINK_OPTIONS.rst
@@ -8,3 +8,9 @@
.. |PROPERTY_INTERFACE_NAME| replace:: ``INTERFACE_LINK_OPTIONS``
.. |PROPERTY_LINK| replace:: :prop_tgt:`LINK_OPTIONS`
.. include:: INTERFACE_BUILD_PROPERTY.txt
+
+.. include:: ../command/DEVICE_LINK_OPTIONS.txt
+
+.. include:: ../command/OPTIONS_SHELL.txt
+
+.. include:: ../command/LINK_OPTIONS_LINKER.txt
diff --git a/Help/prop_tgt/LINK_LIBRARIES.rst b/Help/prop_tgt/LINK_LIBRARIES.rst
index b449aa1..8814980 100644
--- a/Help/prop_tgt/LINK_LIBRARIES.rst
+++ b/Help/prop_tgt/LINK_LIBRARIES.rst
@@ -33,3 +33,5 @@
corresponding :prop_tgt:`LINK_LIBRARIES_STRATEGY` target property
for details on how CMake orders direct link dependencies on linker
command lines.
+
+.. include:: ../command/LINK_LIBRARIES_LINKER.txt
diff --git a/Help/prop_tgt/UNITY_BUILD_RELOCATABLE.rst b/Help/prop_tgt/UNITY_BUILD_RELOCATABLE.rst
new file mode 100644
index 0000000..daac7fd
--- /dev/null
+++ b/Help/prop_tgt/UNITY_BUILD_RELOCATABLE.rst
@@ -0,0 +1,40 @@
+UNITY_BUILD_RELOCATABLE
+-----------------------
+
+.. versionadded:: 3.32
+
+By default, the unity file generated when :prop_tgt:`UNITY_BUILD` is enabled
+uses absolute paths to reference the original source files. This causes the
+unity file to result in a different output depending on the location of the
+source files.
+
+When this property is set to true, the ``#include`` lines inside the generated
+unity source files will attempt to use relative paths to the original source
+files if possible in order to standardize the output of the unity file.
+
+The unity file's path to the original source file will use the following
+priority:
+
+* relative path to the generated unity file if the source file exists
+ directly or in subfolder under the :variable:`CMAKE_BINARY_DIR`
+
+* relative path to :variable:`CMAKE_SOURCE_DIR` if the source file exists
+ directly or in subfolder under the :variable:`CMAKE_SOURCE_DIR`
+
+* absolute path to the source file.
+
+This target property *does not* guarantee a consistent unity file across
+different environments as the final priority is an absolute path.
+
+Example usage:
+
+.. code-block:: cmake
+
+ add_library(example_library
+ source1.cxx
+ source2.cxx
+ source3.cxx)
+
+ set_target_properties(example_library PROPERTIES
+ UNITY_BUILD True
+ UNITY_BUILD_RELOCATABLE TRUE)
diff --git a/Help/release/dev/0-sample-topic.rst b/Help/release/dev/0-sample-topic.rst
new file mode 100644
index 0000000..e4cc01e
--- /dev/null
+++ b/Help/release/dev/0-sample-topic.rst
@@ -0,0 +1,7 @@
+0-sample-topic
+--------------
+
+* This is a sample release note for the change in a topic.
+ Developers should add similar notes for each topic branch
+ making a noteworthy change. Each document should be named
+ and titled to match the topic name to avoid merge conflicts.
diff --git a/Help/release/dev/CMAKE_TYPE_LINKER_FLAGS-LINKER-prefix-support.rst b/Help/release/dev/CMAKE_TYPE_LINKER_FLAGS-LINKER-prefix-support.rst
new file mode 100644
index 0000000..3598dc5
--- /dev/null
+++ b/Help/release/dev/CMAKE_TYPE_LINKER_FLAGS-LINKER-prefix-support.rst
@@ -0,0 +1,13 @@
+CMAKE_TYPE_LINKER_FLAGS-LINKER-prefix-support
+---------------------------------------------
+
+* The :variable:`CMAKE_EXE_LINKER_FLAGS`,
+ :variable:`CMAKE_EXE_LINKER_FLAGS_<CONFIG>`,
+ :variable:`CMAKE_SHARED_LINKER_FLAGS`,
+ :variable:`CMAKE_SHARED_LINKER_FLAGS_<CONFIG>`,
+ :variable:`CMAKE_MODULE_LINKER_FLAGS`,
+ and :variable:`CMAKE_MODULE_LINKER_FLAGS_<CONFIG>` variables learned to
+ support the ``LINKER:`` prefix.
+
+ This support implies to parse and re-quote the content of these variables.
+ This parsing is controlled by :policy:`CMP0181` policy.
diff --git a/Help/release/dev/FindProtobuf-protoc-exe-option.rst b/Help/release/dev/FindProtobuf-protoc-exe-option.rst
new file mode 100644
index 0000000..93d60cb
--- /dev/null
+++ b/Help/release/dev/FindProtobuf-protoc-exe-option.rst
@@ -0,0 +1,5 @@
+FindProtobuf-protoc-exe-option
+------------------------------
+
+* The :module:`FindProtobuf` module :command:`protobuf_generate` command
+ gained a ``PROTOC_EXE`` option to specify a custom ``protoc`` executable.
diff --git a/Help/release/dev/apple-compiler-selection.rst b/Help/release/dev/apple-compiler-selection.rst
new file mode 100644
index 0000000..79727df
--- /dev/null
+++ b/Help/release/dev/apple-compiler-selection.rst
@@ -0,0 +1,19 @@
+apple-compiler-selection
+------------------------
+
+* Builds targeting macOS no longer choose any SDK or pass an ``-isysroot``
+ flag to the compiler by default. Instead, compilers are expected to
+ choose a default macOS SDK on their own. In order to use a compiler that
+ does not do this, users must now specify ``-DCMAKE_OSX_SYSROOT=macosx``
+ when configuring their build.
+
+* On macOS with :ref:`Ninja Generators` and :ref:`Makefile Generators`, when
+ a compiler is found in ``/usr/bin``, it is now used as-is and is no longer
+ mapped to the corresponding compiler inside Xcode. The mapping was
+ introduced by CMake 3.2 to allow build trees to continue to work with their
+ original compiler even when ``xcode-select`` switches to a different
+ Xcode installation. However, the compilers inside Xcode cannot be used
+ without explicit ``-isysroot`` flags and are therefore not suitable for
+ passing to arbitrary third-party build systems. Furthermore, the mapping
+ behavior can override user-specified compiler paths. Therefore, this
+ behavior has been reverted.
diff --git a/Help/release/dev/ctest-crash-handling.rst b/Help/release/dev/ctest-crash-handling.rst
new file mode 100644
index 0000000..266706f
--- /dev/null
+++ b/Help/release/dev/ctest-crash-handling.rst
@@ -0,0 +1,7 @@
+ctest-crash-handling
+--------------------
+
+* The :option:`ctest --interactive-debug-mode` option on Windows
+ now enables Windows Error Reporting by default in test processes,
+ allowing them to creating debug popup windows and core dumps.
+ This restores behavior previously removed by CMake 3.11.
diff --git a/Help/release/dev/ctest-remove-declarative-script-mode.rst b/Help/release/dev/ctest-remove-declarative-script-mode.rst
new file mode 100644
index 0000000..c346abe
--- /dev/null
+++ b/Help/release/dev/ctest-remove-declarative-script-mode.rst
@@ -0,0 +1,14 @@
+ctest-remove-declarative-script-mode
+------------------------------------
+
+* CTest's declarative scripting mode has been removed. This mode used to be
+ triggered by a :option:`ctest -S` script which did not call any
+ :ref:`CTest Commands` unless :variable:`CTEST_RUN_CURRENT_SCRIPT` was
+ explicitly set to ``OFF``. This feature was undocumented and was not covered
+ by any unit tests.
+
+* The :variable:`CTEST_RUN_CURRENT_SCRIPT` variable no longer has any special
+ meaning.
+
+* The :command:`ctest_run_script` command may no longer be called without any
+ arguments.
diff --git a/Help/release/dev/target_link_libraries-LINKER-prefix.rst b/Help/release/dev/target_link_libraries-LINKER-prefix.rst
new file mode 100644
index 0000000..08f36af
--- /dev/null
+++ b/Help/release/dev/target_link_libraries-LINKER-prefix.rst
@@ -0,0 +1,5 @@
+target_link_libraries-LINKER-prefix
+-----------------------------------
+
+* The :command:`target_link_libraries` command gains the support of the
+ ``LINKER:`` prefix.
diff --git a/Help/release/dev/vs-custom-command-disable-parallel-build.rst b/Help/release/dev/vs-custom-command-disable-parallel-build.rst
new file mode 100644
index 0000000..1867a4a
--- /dev/null
+++ b/Help/release/dev/vs-custom-command-disable-parallel-build.rst
@@ -0,0 +1,6 @@
+vs-custom-command-disable-parallel-build
+----------------------------------------
+
+* The :prop_sf:`VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD` source file property
+ was added to tell :ref:`Visual Studio Generators` not to run a custom command
+ in parallel.
diff --git a/Help/release/index.rst b/Help/release/index.rst
index 40767b7..101dd68 100644
--- a/Help/release/index.rst
+++ b/Help/release/index.rst
@@ -7,6 +7,8 @@
This file should include the adjacent "dev.txt" file
in development versions but not in release versions.
+.. include:: dev.txt
+
Releases
========
diff --git a/Help/variable/BUILD_TESTING.rst b/Help/variable/BUILD_TESTING.rst
new file mode 100644
index 0000000..4d460b2
--- /dev/null
+++ b/Help/variable/BUILD_TESTING.rst
@@ -0,0 +1,27 @@
+BUILD_TESTING
+-------------
+
+Control whether the :module:`CTest` module invokes :command:`enable_testing`.
+
+The :module:`CTest` module, when loaded by ``include(CTest)``,
+runs code of the form:
+
+.. code-block:: cmake
+
+ option(BUILD_TESTING "..." ON)
+ if (BUILD_TESTING)
+ # ...
+ enable_testing()
+ # ...
+ endif()
+
+This creates a ``BUILD_TESTING`` option that controls whether the
+:command:`enable_testing` command is invoked to enable generation
+of tests to run using :manual:`ctest(1)`. See the :command:`add_test`
+command to create tests.
+
+.. note::
+
+ Call ``include(CTest)`` in the top-level source directory since
+ :manual:`ctest(1)` expects to find a test file in the top-level
+ build directory.
diff --git a/Help/variable/CMAKE_EXE_LINKER_FLAGS.rst b/Help/variable/CMAKE_EXE_LINKER_FLAGS.rst
index 9e108f8..a978d11 100644
--- a/Help/variable/CMAKE_EXE_LINKER_FLAGS.rst
+++ b/Help/variable/CMAKE_EXE_LINKER_FLAGS.rst
@@ -4,3 +4,5 @@
Linker flags to be used to create executables.
These flags will be used by the linker when creating an executable.
+
+.. include:: ../variable/LINKER_FLAGS.txt
diff --git a/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst b/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst
index 0cd8113..1d74077 100644
--- a/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst
+++ b/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst
@@ -5,3 +5,5 @@
Same as ``CMAKE_C_FLAGS_*`` but used by the linker when creating
executables.
+
+.. include:: ../variable/LINKER_FLAGS.txt
diff --git a/Help/variable/CMAKE_MODULE_LINKER_FLAGS.rst b/Help/variable/CMAKE_MODULE_LINKER_FLAGS.rst
index 6372bbd..eed6b65 100644
--- a/Help/variable/CMAKE_MODULE_LINKER_FLAGS.rst
+++ b/Help/variable/CMAKE_MODULE_LINKER_FLAGS.rst
@@ -4,3 +4,5 @@
Linker flags to be used to create modules.
These flags will be used by the linker when creating a module.
+
+.. include:: ../variable/LINKER_FLAGS.txt
diff --git a/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst b/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst
index 393263e..fd0769c 100644
--- a/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst
+++ b/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst
@@ -4,3 +4,5 @@
Flags to be used when linking a module.
Same as ``CMAKE_C_FLAGS_*`` but used by the linker when creating modules.
+
+.. include:: ../variable/LINKER_FLAGS.txt
diff --git a/Help/variable/CMAKE_SHARED_LINKER_FLAGS.rst b/Help/variable/CMAKE_SHARED_LINKER_FLAGS.rst
index fce950c..45748ff 100644
--- a/Help/variable/CMAKE_SHARED_LINKER_FLAGS.rst
+++ b/Help/variable/CMAKE_SHARED_LINKER_FLAGS.rst
@@ -4,3 +4,5 @@
Linker flags to be used to create shared libraries.
These flags will be used by the linker when creating a shared library.
+
+.. include:: ../variable/LINKER_FLAGS.txt
diff --git a/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst b/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst
index 4bf87a0..b968820 100644
--- a/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst
+++ b/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst
@@ -5,3 +5,5 @@
Same as ``CMAKE_C_FLAGS_*`` but used by the linker when creating shared
libraries.
+
+.. include:: ../variable/LINKER_FLAGS.txt
diff --git a/Help/variable/CTEST_RUN_CURRENT_SCRIPT.rst b/Help/variable/CTEST_RUN_CURRENT_SCRIPT.rst
index 8cb6eaa..616324e 100644
--- a/Help/variable/CTEST_RUN_CURRENT_SCRIPT.rst
+++ b/Help/variable/CTEST_RUN_CURRENT_SCRIPT.rst
@@ -1,7 +1,5 @@
CTEST_RUN_CURRENT_SCRIPT
------------------------
-.. versionadded:: 3.11
-
-Setting this to 0 prevents :manual:`ctest(1)` from being run again when it
-reaches the end of a script run by calling :option:`ctest -S`.
+Removed. This variable once supported an undocumented feature that has since
+been removed.
diff --git a/Help/variable/LINKER_FLAGS.txt b/Help/variable/LINKER_FLAGS.txt
new file mode 100644
index 0000000..7b0630a
--- /dev/null
+++ b/Help/variable/LINKER_FLAGS.txt
@@ -0,0 +1,5 @@
+
+.. include:: ../command/LINK_LIBRARIES_LINKER.txt
+
+This support implies to parse and re-quote the content of the variable. See
+policy :policy:`CMP0181`.
diff --git a/Modules/CMakeDetermineCompiler.cmake b/Modules/CMakeDetermineCompiler.cmake
index fc0b714..6036897 100644
--- a/Modules/CMakeDetermineCompiler.cmake
+++ b/Modules/CMakeDetermineCompiler.cmake
@@ -82,34 +82,6 @@
endif()
unset(_${lang}_COMPILER_HINTS)
unset(_languages)
-
- # Look for a make tool provided by Xcode
- if(CMAKE_HOST_APPLE)
- macro(_query_xcrun compiler_name result_var_keyword result_var)
- if(NOT "x${result_var_keyword}" STREQUAL "xRESULT_VAR")
- message(FATAL_ERROR "Bad arguments to macro")
- endif()
- execute_process(COMMAND xcrun --find ${compiler_name}
- OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE
- ERROR_VARIABLE _xcrun_err)
- set("${result_var}" "${_xcrun_out}")
- endmacro()
-
- set(xcrun_result)
- if (CMAKE_${lang}_COMPILER MATCHES "^/usr/bin/(.+)$")
- _query_xcrun("${CMAKE_MATCH_1}" RESULT_VAR xcrun_result)
- elseif (CMAKE_${lang}_COMPILER STREQUAL "CMAKE_${lang}_COMPILER-NOTFOUND")
- foreach(comp IN LISTS CMAKE_${lang}_COMPILER_LIST)
- _query_xcrun("${comp}" RESULT_VAR xcrun_result)
- if(xcrun_result)
- break()
- endif()
- endforeach()
- endif()
- if (xcrun_result)
- set_property(CACHE CMAKE_${lang}_COMPILER PROPERTY VALUE "${xcrun_result}")
- endif()
- endif()
endmacro()
macro(_cmake_find_compiler_path lang)
diff --git a/Modules/CMakeDetermineCompilerABI.cmake b/Modules/CMakeDetermineCompilerABI.cmake
index 4a75e25..806f0b7 100644
--- a/Modules/CMakeDetermineCompilerABI.cmake
+++ b/Modules/CMakeDetermineCompilerABI.cmake
@@ -52,14 +52,21 @@
__TestCompiler_setTryCompileTargetType()
- # Avoid failing ABI detection on warnings.
+ # Avoid failing ABI detection caused by non-functionally relevant
+ # compiler arguments
if(CMAKE_TRY_COMPILE_CONFIGURATION)
string(TOUPPER "${CMAKE_TRY_COMPILE_CONFIGURATION}" _tc_config)
else()
set(_tc_config "DEBUG")
endif()
foreach(v CMAKE_${lang}_FLAGS CMAKE_${lang}_FLAGS_${_tc_config})
+ # Avoid failing ABI detection on warnings.
string(REGEX REPLACE "(^| )-Werror([= ][^-][^ ]*)?( |$)" " " ${v} "${${v}}")
+ # Avoid passing of "-pipe" when determining the compiler internals. With
+ # "-pipe" GCC will use pipes to pass data between the involved
+ # executables. This may lead to issues when their stderr output (which
+ # contains the relevant compiler internals) becomes interweaved.
+ string(REGEX REPLACE "(^| )-pipe( |$)" " " ${v} "${${v}}")
endforeach()
# Save the current LC_ALL, LC_MESSAGES, and LANG environment variables
diff --git a/Modules/CMakeUnixFindMake.cmake b/Modules/CMakeUnixFindMake.cmake
index 1165656..58dedee 100644
--- a/Modules/CMakeUnixFindMake.cmake
+++ b/Modules/CMakeUnixFindMake.cmake
@@ -4,13 +4,3 @@
find_program(CMAKE_MAKE_PROGRAM NAMES gmake make smake)
mark_as_advanced(CMAKE_MAKE_PROGRAM)
-
-# Look for a make tool provided by Xcode
-if(NOT CMAKE_MAKE_PROGRAM AND CMAKE_HOST_APPLE)
- execute_process(COMMAND xcrun --find make
- OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE
- ERROR_VARIABLE _xcrun_err)
- if(_xcrun_out)
- set_property(CACHE CMAKE_MAKE_PROGRAM PROPERTY VALUE "${_xcrun_out}")
- endif()
-endif()
diff --git a/Modules/CTest.cmake b/Modules/CTest.cmake
index 16283d6..6829d66 100644
--- a/Modules/CTest.cmake
+++ b/Modules/CTest.cmake
@@ -8,15 +8,24 @@
Configure a project for testing with CTest/CDash
Include this module in the top CMakeLists.txt file of a project to
-enable testing with CTest and dashboard submissions to CDash::
+enable testing with CTest and dashboard submissions to CDash:
+
+.. code-block:: cmake
project(MyProject)
...
include(CTest)
-The module automatically creates a ``BUILD_TESTING`` option that selects
-whether to enable testing support (``ON`` by default). After including
-the module, use code like::
+The module automatically creates the following variables:
+
+:variable:`BUILD_TESTING`
+
+ Option selecting whether ``include(CTest)`` calls :command:`enable_testing`.
+ The option is ``ON`` by default when created by the module.
+
+After including the module, use code like:
+
+.. code-block:: cmake
if(BUILD_TESTING)
# ... CMake code to create tests ...
@@ -25,7 +34,9 @@
to creating tests when testing is enabled.
To enable submissions to a CDash server, create a ``CTestConfig.cmake``
-file at the top of the project with content such as::
+file at the top of the project with content such as:
+
+.. code-block:: cmake
set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")
set(CTEST_SUBMIT_URL "http://my.cdash.org/submit.php?project=MyProject")
@@ -40,7 +51,9 @@
context from the build log. This generic approach works for all build
tools, but does not give details about the command invocation that
produced a given problem. One may get more detailed reports by setting
-the :variable:`CTEST_USE_LAUNCHERS` variable::
+the :variable:`CTEST_USE_LAUNCHERS` variable:
+
+.. code-block:: cmake
set(CTEST_USE_LAUNCHERS 1)
diff --git a/Modules/CheckTypeSize.cmake b/Modules/CheckTypeSize.cmake
index ee54d92..c2e131c 100644
--- a/Modules/CheckTypeSize.cmake
+++ b/Modules/CheckTypeSize.cmake
@@ -54,6 +54,7 @@
``LANGUAGE <language>``
Use the ``<language>`` compiler to perform the check.
Acceptable values are ``C`` and ``CXX``.
+ If not specified, it defaults to ``C``.
Despite the name of the macro you may use it to check the size of more
complex expressions, too. To check e.g. for the size of a struct
@@ -83,6 +84,62 @@
``CMAKE_EXTRA_INCLUDE_FILES``
list of extra headers to include.
+
+Examples
+^^^^^^^^
+
+Consider the code:
+
+.. code-block:: cmake
+
+ include(CheckTypeSize)
+
+ # Check for size of long.
+ check_type_size(long SIZEOF_LONG)
+ message("HAVE_SIZEOF_LONG: ${HAVE_SIZEOF_LONG}")
+ message("SIZEOF_LONG: ${SIZEOF_LONG}")
+ message("SIZEOF_LONG_CODE: ${SIZEOF_LONG_CODE}")
+
+On a 64-bit architecture, the output may look something like this::
+
+ HAVE_SIZEOF_LONG: TRUE
+ SIZEOF_LONG: 8
+ SIZEOF_LONG_CODE: #define SIZEOF_LONG 8
+
+On Apple platforms, when :variable:`CMAKE_OSX_ARCHITECTURES` has multiple
+architectures, types may have architecture-dependent sizes.
+For example, with the code
+
+.. code-block:: cmake
+
+ include(CheckTypeSize)
+
+ check_type_size(long SIZEOF_LONG)
+ message("HAVE_SIZEOF_LONG: ${HAVE_SIZEOF_LONG}")
+ message("SIZEOF_LONG: ${SIZEOF_LONG}")
+ foreach(key IN LISTS SIZE_OF_LONG_KEYS)
+ message("key: ${key}")
+ message("value: ${SIZE_OF_LONG-${key}}")
+ endforeach()
+ message("SIZEOF_LONG_CODE:
+ ${SIZEOF_LONG_CODE}")
+
+the result may be::
+
+ HAVE_SIZEOF_LONG: TRUE
+ SIZEOF_LONG: 0
+ key: __i386
+ value: 4
+ key: __x86_64
+ value: 8
+ SIZEOF_LONG_CODE:
+ #if defined(__i386)
+ # define SIZE_OF_LONG 4
+ #elif defined(__x86_64)
+ # define SIZE_OF_LONG 8
+ #else
+ # error SIZE_OF_LONG unknown
+ #endif
#]=======================================================================]
include(CheckIncludeFile)
diff --git a/Modules/FindBISON.cmake b/Modules/FindBISON.cmake
index 3515bf0..6d0ace7 100644
--- a/Modules/FindBISON.cmake
+++ b/Modules/FindBISON.cmake
@@ -281,7 +281,8 @@
VERBATIM
DEPENDS ${_BisonInput}
COMMENT "[BISON][${Name}] Building parser with bison ${BISON_VERSION}"
- WORKING_DIRECTORY ${_BISON_WORKING_DIRECTORY})
+ WORKING_DIRECTORY ${_BISON_WORKING_DIRECTORY}
+ COMMAND_EXPAND_LISTS)
unset(_BISON_WORKING_DIRECTORY)
diff --git a/Modules/FindCURL.cmake b/Modules/FindCURL.cmake
index 5ce8a90..f736130 100644
--- a/Modules/FindCURL.cmake
+++ b/Modules/FindCURL.cmake
@@ -239,9 +239,24 @@
IMPORTED_LOCATION_DEBUG "${CURL_LIBRARY_DEBUG}")
endif()
- if(CURL_USE_STATIC_LIBS AND MSVC)
- set_target_properties(CURL::libcurl PROPERTIES
- INTERFACE_LINK_LIBRARIES "normaliz.lib;ws2_32.lib;wldap32.lib")
+ if(PC_CURL_FOUND)
+ if(PC_CURL_LINK_LIBRARIES)
+ set_property(TARGET CURL::libcurl PROPERTY
+ INTERFACE_LINK_LIBRARIES "${PC_CURL_LINK_LIBRARIES}")
+ endif()
+ if(PC_CURL_LDFLAGS_OTHER)
+ set_property(TARGET CURL::libcurl PROPERTY
+ INTERFACE_LINK_OPTIONS "${PC_CURL_LDFLAGS_OTHER}")
+ endif()
+ if(PC_CURL_CFLAGS_OTHER)
+ set_property(TARGET CURL::libcurl PROPERTY
+ INTERFACE_COMPILE_OPTIONS "${PC_CURL_CFLAGS_OTHER}")
+ endif()
+ else()
+ if(CURL_USE_STATIC_LIBS AND MSVC)
+ set_target_properties(CURL::libcurl PROPERTIES
+ INTERFACE_LINK_LIBRARIES "normaliz.lib;ws2_32.lib;wldap32.lib")
+ endif()
endif()
endif()
diff --git a/Modules/FindProtobuf.cmake b/Modules/FindProtobuf.cmake
index 197e71f..1d69c57 100644
--- a/Modules/FindProtobuf.cmake
+++ b/Modules/FindProtobuf.cmake
@@ -108,20 +108,27 @@
Add custom commands to process ``.proto`` files to C++::
- protobuf_generate_cpp (<SRCS> <HDRS>
- [DESCRIPTORS <DESC>] [EXPORT_MACRO <MACRO>] [<ARGN>...])
+ protobuf_generate_cpp (
+ <srcs-var> <hdrs-var>
+ [DESCRIPTORS <var>]
+ [EXPORT_MACRO <macro>]
+ [<proto-file>...])
- ``SRCS``
+ ``<srcs-var>``
Variable to define with autogenerated source files
- ``HDRS``
+
+ ``<hdrs-var>``
Variable to define with autogenerated header files
- ``DESCRIPTORS``
+
+ ``DESCRIPTORS <var>``
.. versionadded:: 3.10
Variable to define with autogenerated descriptor files, if requested.
- ``EXPORT_MACRO``
+
+ ``EXPORT_MACRO <macro>``
is a macro which should expand to ``__declspec(dllexport)`` or
``__declspec(dllimport)`` depending on what is being compiled.
- ``ARGN``
+
+ ``<proto-file>...``
``.proto`` files
.. command:: protobuf_generate_python
@@ -130,11 +137,12 @@
Add custom commands to process ``.proto`` files to Python::
- protobuf_generate_python (<PY> [<ARGN>...])
+ protobuf_generate_python (<py-srcs-var> [<proto-file>...])
- ``PY``
+ ``<py-srcs-var>``
Variable to define with autogenerated Python files
- ``ARGN``
+
+ ``<proto-file>...``
``.proto`` files
.. command:: protobuf_generate
@@ -146,63 +154,82 @@
protobuf_generate (
TARGET <target>
[LANGUAGE <lang>]
- [OUT_VAR <out_var>]
+ [OUT_VAR <var>]
[EXPORT_MACRO <macro>]
[PROTOC_OUT_DIR <dir>]
[PLUGIN <plugin>]
- [PLUGIN_OPTIONS <plugin_options>]
- [DEPENDENCIES <depends]
- [PROTOS <protobuf_files>]
- [IMPORT_DIRS <dirs>]
- [GENERATE_EXTENSIONS <extensions>]
- [PROTOC_OPTIONS <protoc_options>]
+ [PLUGIN_OPTIONS <plugin-options>]
+ [DEPENDENCIES <dependencies>]
+ [PROTOS <proto-file>...]
+ [IMPORT_DIRS <dir>...]
+ [GENERATE_EXTENSIONS <extension>...]
+ [PROTOC_OPTIONS <option>...]
+ [PROTOC_EXE <executable>]
[APPEND_PATH])
``APPEND_PATH``
A flag that causes the base path of all proto schema files to be added to
``IMPORT_DIRS``.
- ``LANGUAGE``
+
+ ``LANGUAGE <lang>``
A single value: cpp or python. Determines what kind of source files are
being generated. Defaults to cpp.
- ``OUT_VAR``
+
+ ``OUT_VAR <var>``
Name of a CMake variable that will be filled with the paths to the generated
source files.
- ``EXPORT_MACRO``
+
+ ``EXPORT_MACRO <macro>``
Name of a macro that is applied to all generated Protobuf message classes
and extern variables. It can, for example, be used to declare DLL exports.
- ``PROTOC_OUT_DIR``
+
+ ``PROTOC_OUT_DIR <dir>``
Output directory of generated source files. Defaults to ``CMAKE_CURRENT_BINARY_DIR``.
- ``PLUGIN``
+
+ ``PLUGIN <plugin>``
.. versionadded:: 3.21
An optional plugin executable. This could, for example, be the path to
``grpc_cpp_plugin``.
- ``PLUGIN_OPTIONS``
+
+ ``PLUGIN_OPTIONS <plugin-options>``
.. versionadded:: 3.28
Additional options provided to the plugin, such as ``generate_mock_code=true``
for the gRPC cpp plugin.
- ``DEPENDENCIES``
+
+ ``DEPENDENCIES <dependencies>``
.. versionadded:: 3.28
Arguments forwarded to the ``DEPENDS`` of the underlying ``add_custom_command``
invocation.
- ``TARGET``
+
+ ``TARGET <target>``
CMake target that will have the generated files added as sources.
- ``PROTOS``
+
+ ``PROTOS <proto-file>...``
List of proto schema files. If omitted, then every source file ending in *proto* of ``TARGET`` will be used.
- ``IMPORT_DIRS``
+
+ ``IMPORT_DIRS <dir>...``
A common parent directory for the schema files. For example, if the schema file is
``proto/helloworld/helloworld.proto`` and the import directory ``proto/`` then the
generated files are ``${PROTOC_OUT_DIR}/helloworld/helloworld.pb.h`` and
``${PROTOC_OUT_DIR}/helloworld/helloworld.pb.cc``.
- ``GENERATE_EXTENSIONS``
+
+ ``GENERATE_EXTENSIONS <extension>...``
If LANGUAGE is omitted then this must be set to the extensions that protoc generates.
- ``PROTOC_OPTIONS``
+
+ ``PROTOC_OPTIONS <option>...``
.. versionadded:: 3.28
Additional arguments that are forwarded to protoc.
+ ``PROTOC_EXE <executable>``
+ .. versionadded:: 3.32
+
+ Command name, path, or CMake executable used to generate protobuf bindings.
+ If omitted, ``protobuf::protoc`` is used.
+
Example::
find_package(gRPC CONFIG REQUIRED)
@@ -223,7 +250,7 @@
function(protobuf_generate)
set(_options APPEND_PATH DESCRIPTORS)
- set(_singleargs LANGUAGE OUT_VAR EXPORT_MACRO PROTOC_OUT_DIR PLUGIN PLUGIN_OPTIONS DEPENDENCIES)
+ set(_singleargs LANGUAGE OUT_VAR EXPORT_MACRO PROTOC_OUT_DIR PLUGIN PLUGIN_OPTIONS DEPENDENCIES PROTOC_EXE)
if(COMMAND target_sources)
list(APPEND _singleargs TARGET)
endif()
@@ -292,10 +319,14 @@
return()
endif()
- if(NOT TARGET protobuf::protoc)
- message(SEND_ERROR "protoc executable not found. "
- "Please define the Protobuf_PROTOC_EXECUTABLE variable or ensure that protoc is in CMake's search path.")
- return()
+ if(NOT protobuf_generate_PROTOC_EXE)
+ if(NOT TARGET protobuf::protoc)
+ message(SEND_ERROR "protoc executable not found. "
+ "Please define the Protobuf_PROTOC_EXECUTABLE variable, or pass PROTOC_EXE to protobuf_generate, or ensure that protoc is in CMake's search path.")
+ return()
+ endif()
+ # Default to using the CMake executable
+ set(protobuf_generate_PROTOC_EXE protobuf::protoc)
endif()
if(protobuf_generate_APPEND_PATH)
@@ -368,7 +399,7 @@
add_custom_command(
OUTPUT ${_generated_srcs}
- COMMAND protobuf::protoc
+ COMMAND ${protobuf_generate_PROTOC_EXE}
ARGS ${protobuf_generate_PROTOC_OPTIONS} --${protobuf_generate_LANGUAGE}_out ${_plugin_options}:${protobuf_generate_PROTOC_OUT_DIR} ${_plugin} ${_dll_desc_out} ${_protobuf_include_path} ${_abs_file}
DEPENDS ${_abs_file} protobuf::protoc ${protobuf_generate_DEPENDENCIES}
COMMENT ${_comment}
diff --git a/Modules/Platform/Darwin-Initialize.cmake b/Modules/Platform/Darwin-Initialize.cmake
index 1b9cece..1a47d9a 100644
--- a/Modules/Platform/Darwin-Initialize.cmake
+++ b/Modules/Platform/Darwin-Initialize.cmake
@@ -80,50 +80,8 @@
set(_CMAKE_OSX_SYSROOT_DEFAULT "xros")
elseif(CMAKE_SYSTEM_NAME STREQUAL watchOS)
set(_CMAKE_OSX_SYSROOT_DEFAULT "watchos")
-elseif("${CMAKE_GENERATOR}" MATCHES Xcode
- OR CMAKE_OSX_DEPLOYMENT_TARGET
- OR CMAKE_OSX_ARCHITECTURES MATCHES "[^;]"
- OR NOT EXISTS "/usr/include/sys/types.h")
- # Find installed SDKs in either Xcode-4.3+ or pre-4.3 SDKs directory.
- set(_CMAKE_OSX_SDKS_DIR "")
- if(OSX_DEVELOPER_ROOT)
- foreach(_d Platforms/MacOSX.platform/Developer/SDKs SDKs)
- file(GLOB _CMAKE_OSX_SDKS ${OSX_DEVELOPER_ROOT}/${_d}/*)
- if(_CMAKE_OSX_SDKS)
- set(_CMAKE_OSX_SDKS_DIR ${OSX_DEVELOPER_ROOT}/${_d})
- break()
- endif()
- endforeach()
- endif()
-
- if(_CMAKE_OSX_SDKS_DIR)
- # Find the latest SDK as recommended by Apple (Technical Q&A QA1806)
- set(_CMAKE_OSX_LATEST_SDK_VERSION "0.0")
- file(GLOB _CMAKE_OSX_SDKS RELATIVE "${_CMAKE_OSX_SDKS_DIR}" "${_CMAKE_OSX_SDKS_DIR}/MacOSX*.sdk")
- foreach(_SDK ${_CMAKE_OSX_SDKS})
- if(IS_DIRECTORY "${_CMAKE_OSX_SDKS_DIR}/${_SDK}"
- AND _SDK MATCHES "MacOSX([0-9]+\\.[0-9]+)[^/]*\\.sdk"
- AND CMAKE_MATCH_1 VERSION_GREATER ${_CMAKE_OSX_LATEST_SDK_VERSION})
- set(_CMAKE_OSX_LATEST_SDK_VERSION "${CMAKE_MATCH_1}")
- endif()
- endforeach()
-
- if(NOT _CMAKE_OSX_LATEST_SDK_VERSION STREQUAL "0.0")
- set(_CMAKE_OSX_SYSROOT_DEFAULT "${_CMAKE_OSX_SDKS_DIR}/MacOSX${_CMAKE_OSX_LATEST_SDK_VERSION}.sdk")
- else()
- message(WARNING "Could not find any valid SDKs in ${_CMAKE_OSX_SDKS_DIR}")
- endif()
-
- if(NOT CMAKE_CROSSCOMPILING AND NOT CMAKE_OSX_DEPLOYMENT_TARGET
- AND (_CURRENT_OSX_VERSION VERSION_LESS _CMAKE_OSX_LATEST_SDK_VERSION
- OR _CMAKE_OSX_LATEST_SDK_VERSION STREQUAL "0.0"))
- set(CMAKE_OSX_DEPLOYMENT_TARGET ${_CURRENT_OSX_VERSION} CACHE STRING
- "Minimum OS X version to target for deployment (at runtime); newer APIs weak linked. Set to empty string for default value." FORCE)
- endif()
- else()
- # Assume developer files are in root (such as Xcode 4.5 command-line tools).
- set(_CMAKE_OSX_SYSROOT_DEFAULT "")
- endif()
+else()
+ set(_CMAKE_OSX_SYSROOT_DEFAULT "")
endif()
# Set cache variable - end user may change this during ccmake or cmake-gui configure.
@@ -244,7 +202,7 @@
return() # Only apply to multi-arch
endif()
- if(CMAKE_OSX_SYSROOT STREQUAL "macosx")
+ if(NOT CMAKE_OSX_SYSROOT OR CMAKE_OSX_SYSROOT STREQUAL "macosx")
# macOS doesn't have a simulator sdk / sysroot, so there is no need to handle per-sdk arches.
return()
endif()
@@ -256,7 +214,7 @@
return()
endif()
- string(REPLACE "os" "simulator" _simulator_sdk ${CMAKE_OSX_SYSROOT})
+ string(REPLACE "os" "simulator" _simulator_sdk "${CMAKE_OSX_SYSROOT}")
set(_sdks "${CMAKE_OSX_SYSROOT};${_simulator_sdk}")
foreach(sdk ${_sdks})
_apple_resolve_sdk_path(${sdk} _sdk_path)
@@ -302,25 +260,36 @@
_apple_resolve_multi_arch_sysroots()
-# Transform CMAKE_OSX_SYSROOT to absolute path
-set(_CMAKE_OSX_SYSROOT_PATH "")
-if(CMAKE_OSX_SYSROOT)
- if("x${CMAKE_OSX_SYSROOT}" MATCHES "/")
- # This is a path to the SDK. Make sure it exists.
- if(NOT IS_DIRECTORY "${CMAKE_OSX_SYSROOT}")
- message(WARNING "Ignoring CMAKE_OSX_SYSROOT value:\n ${CMAKE_OSX_SYSROOT}\n"
- "because the directory does not exist.")
- set(CMAKE_OSX_SYSROOT "")
- endif()
- set(_CMAKE_OSX_SYSROOT_PATH "${CMAKE_OSX_SYSROOT}")
- else()
- _apple_resolve_sdk_path(${CMAKE_OSX_SYSROOT} _sdk_path)
- if(IS_DIRECTORY "${_sdk_path}")
- set(_CMAKE_OSX_SYSROOT_PATH "${_sdk_path}")
- # For non-Xcode generators use the path.
- if(NOT "${CMAKE_GENERATOR}" MATCHES "Xcode")
- set(CMAKE_OSX_SYSROOT "${_CMAKE_OSX_SYSROOT_PATH}")
- endif()
- endif()
+if(CMAKE_OSX_SYSROOT MATCHES "/")
+ # This is a path to a SDK. Make sure it exists.
+ if(NOT IS_DIRECTORY "${CMAKE_OSX_SYSROOT}")
+ message(WARNING "Ignoring CMAKE_OSX_SYSROOT value:\n ${CMAKE_OSX_SYSROOT}\n"
+ "because the directory does not exist.")
+ set(CMAKE_OSX_SYSROOT "")
endif()
+ set(_CMAKE_OSX_SYSROOT_PATH "${CMAKE_OSX_SYSROOT}")
+elseif(CMAKE_OSX_SYSROOT)
+ # This is the name of a SDK. Transform it to a path.
+ _apple_resolve_sdk_path("${CMAKE_OSX_SYSROOT}" _CMAKE_OSX_SYSROOT_PATH)
+ # Use the path for non-Xcode generators.
+ if(IS_DIRECTORY "${_CMAKE_OSX_SYSROOT_PATH}" AND NOT CMAKE_GENERATOR MATCHES "Xcode")
+ set(CMAKE_OSX_SYSROOT "${_CMAKE_OSX_SYSROOT_PATH}")
+ endif()
+endif()
+if(NOT CMAKE_OSX_SYSROOT)
+ # Without any explicit SDK we rely on the toolchain default,
+ # which we assume to be what wrappers like /usr/bin/cc use.
+ if(CMAKE_GENERATOR STREQUAL "Xcode")
+ set(_sdk_macosx --sdk macosx)
+ else()
+ set(_sdk_macosx)
+ endif()
+ execute_process(
+ COMMAND xcrun ${_sdk_macosx} --show-sdk-path
+ OUTPUT_VARIABLE _CMAKE_OSX_SYSROOT_PATH
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_VARIABLE _stderr
+ RESULT_VARIABLE _result
+ )
+ unset(_sdk_macosx)
endif()
diff --git a/Modules/UseJava/javaTargets.cmake.in b/Modules/UseJava/javaTargets.cmake.in
index 6002d4e..11f1f06 100644
--- a/Modules/UseJava/javaTargets.cmake.in
+++ b/Modules/UseJava/javaTargets.cmake.in
@@ -1,5 +1,5 @@
cmake_policy(PUSH)
-cmake_policy(VERSION 2.8.12...3.29)
+cmake_policy(VERSION 2.8.12...3.30)
#----------------------------------------------------------------
# Generated CMake Java target import file.
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index c4cd101..30e6b94 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -412,6 +412,8 @@
cmNewLineStyle.cxx
cmOrderDirectories.cxx
cmOrderDirectories.h
+ cmPathResolver.cxx
+ cmPathResolver.h
cmPlistParser.cxx
cmPlistParser.h
cmPolicies.h
@@ -508,8 +510,6 @@
cmake.cxx
cmake.h
- cmCommand.cxx
- cmCommand.h
cmCommands.cxx
cmCommands.h
cmAddCompileDefinitionsCommand.cxx
@@ -1071,9 +1071,10 @@
cmCTest.cxx
CTest/cmProcess.cxx
CTest/cmCTestBinPacker.cxx
- CTest/cmCTestBuildAndTestHandler.cxx
+ CTest/cmCTestBuildAndTest.cxx
CTest/cmCTestBuildCommand.cxx
CTest/cmCTestBuildHandler.cxx
+ CTest/cmCTestCommand.cxx
CTest/cmCTestConfigureCommand.cxx
CTest/cmCTestConfigureHandler.cxx
CTest/cmCTestCoverageCommand.cxx
@@ -1109,10 +1110,10 @@
CTest/cmCTestTestCommand.cxx
CTest/cmCTestTestHandler.cxx
CTest/cmCTestTestMeasurementXMLParser.cxx
+ CTest/cmCTestTypes.cxx
CTest/cmCTestUpdateCommand.cxx
CTest/cmCTestUpdateHandler.cxx
CTest/cmCTestUploadCommand.cxx
- CTest/cmCTestUploadHandler.cxx
CTest/cmCTestVC.cxx
CTest/cmCTestVC.h
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 5755e5a..01a06e0 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 31)
-set(CMake_VERSION_PATCH 0)
+set(CMake_VERSION_PATCH 20241113)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
diff --git a/Source/CPack/WiX/cmWIXAccessControlList.cxx b/Source/CPack/WiX/cmWIXAccessControlList.cxx
index 0ebe2f4..5d0df06 100644
--- a/Source/CPack/WiX/cmWIXAccessControlList.cxx
+++ b/Source/CPack/WiX/cmWIXAccessControlList.cxx
@@ -50,14 +50,13 @@
user = user_and_domain;
}
- std::vector<std::string> permissions = cmTokenize(permission_string, ",");
-
this->SourceWriter.BeginElement("Permission");
this->SourceWriter.AddAttribute("User", std::string(user));
if (!domain.empty()) {
this->SourceWriter.AddAttribute("Domain", std::string(domain));
}
- for (std::string const& permission : permissions) {
+ for (auto permission :
+ cmTokenizedView(permission_string, ',', cmTokenizerMode::New)) {
this->EmitBooleanAttribute(entry, cmTrimWhitespace(permission));
}
this->SourceWriter.EndElement("Permission");
diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx
index c70a2f1..bb1545b 100644
--- a/Source/CPack/cmCPackArchiveGenerator.cxx
+++ b/Source/CPack/cmCPackArchiveGenerator.cxx
@@ -2,7 +2,6 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCPackArchiveGenerator.h"
-#include <cstring>
#include <map>
#include <ostream>
#include <unordered_map>
@@ -192,15 +191,16 @@
std::string componentUpper(cmSystemTools::UpperCase(component));
std::string packageFileName;
- if (this->IsSet("CPACK_ARCHIVE_" + componentUpper + "_FILE_NAME")) {
+ if (cmValue v = this->GetOptionIfSet("CPACK_ARCHIVE_" + componentUpper +
+ "_FILE_NAME")) {
+ packageFileName += *v;
+ } else if ((v = this->GetOptionIfSet("CPACK_ARCHIVE_FILE_NAME"))) {
packageFileName +=
- *this->GetOption("CPACK_ARCHIVE_" + componentUpper + "_FILE_NAME");
- } else if (this->IsSet("CPACK_ARCHIVE_FILE_NAME")) {
- packageFileName += this->GetComponentPackageFileName(
- *this->GetOption("CPACK_ARCHIVE_FILE_NAME"), component, isGroupName);
+ this->GetComponentPackageFileName(*v, component, isGroupName);
} else {
- packageFileName += this->GetComponentPackageFileName(
- *this->GetOption("CPACK_PACKAGE_FILE_NAME"), component, isGroupName);
+ v = this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ packageFileName +=
+ this->GetComponentPackageFileName(*v, component, isGroupName);
}
packageFileName += this->GetOutputExtension();
@@ -238,10 +238,7 @@
// Change to local toplevel
cmWorkingDirectory workdir(localToplevel);
if (workdir.Failed()) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Failed to change working directory to "
- << localToplevel << " : "
- << std::strerror(workdir.GetLastResult()) << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_ERROR, workdir.GetError() << std::endl);
return 0;
}
std::string filePrefix;
@@ -398,10 +395,11 @@
this->packageFileNames.emplace_back(this->toplevel);
this->packageFileNames[0] += "/";
- if (this->IsSet("CPACK_ARCHIVE_FILE_NAME")) {
- this->packageFileNames[0] += *this->GetOption("CPACK_ARCHIVE_FILE_NAME");
+ if (cmValue v = this->GetOptionIfSet("CPACK_ARCHIVE_FILE_NAME")) {
+ this->packageFileNames[0] += *v;
} else {
- this->packageFileNames[0] += *this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ v = this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ this->packageFileNames[0] += *v;
}
this->packageFileNames[0] += this->GetOutputExtension();
@@ -448,10 +446,7 @@
DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0], archive);
cmWorkingDirectory workdir(this->toplevel);
if (workdir.Failed()) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Failed to change working directory to "
- << this->toplevel << " : "
- << std::strerror(workdir.GetLastResult()) << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_ERROR, workdir.GetError() << std::endl);
return 0;
}
for (std::string const& file : this->files) {
@@ -488,10 +483,10 @@
int threads = 1;
// CPACK_ARCHIVE_THREADS overrides CPACK_THREADS
- if (this->IsSet("CPACK_ARCHIVE_THREADS")) {
- threads = std::stoi(*this->GetOption("CPACK_ARCHIVE_THREADS"));
- } else if (this->IsSet("CPACK_THREADS")) {
- threads = std::stoi(*this->GetOption("CPACK_THREADS"));
+ if (cmValue v = this->GetOptionIfSet("CPACK_ARCHIVE_THREADS")) {
+ threads = std::stoi(*v);
+ } else if (cmValue v2 = this->GetOptionIfSet("CPACK_THREADS")) {
+ threads = std::stoi(*v2);
}
return threads;
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
index 4c518ac..038104e 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.cxx
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -101,13 +101,12 @@
}
this->SetOptionIfNotSet("CPACK_COMMAND_REZ", rez_path);
- if (this->IsSet("CPACK_DMG_SLA_DIR")) {
- slaDirectory = this->GetOption("CPACK_DMG_SLA_DIR");
+ if (cmValue v = this->GetOptionIfSet("CPACK_DMG_SLA_DIR")) {
+ slaDirectory = *v;
if (!slaDirectory.empty() &&
this->IsOn("CPACK_DMG_SLA_USE_RESOURCE_FILE_LICENSE") &&
- this->IsSet("CPACK_RESOURCE_FILE_LICENSE")) {
- std::string license_file =
- this->GetOption("CPACK_RESOURCE_FILE_LICENSE");
+ (v = this->GetOptionIfSet("CPACK_RESOURCE_FILE_LICENSE"))) {
+ std::string license_file = *v;
if (!license_file.empty() &&
(license_file.find("CPack.GenericLicense.txt") ==
std::string::npos)) {
@@ -119,7 +118,8 @@
singleLicense = true;
}
}
- if (!this->IsSet("CPACK_DMG_SLA_LANGUAGES")) {
+ cmValue lang = this->GetOptionIfSet("CPACK_DMG_SLA_LANGUAGES");
+ if (!lang) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"CPACK_DMG_SLA_DIR set but no languages defined "
"(set CPACK_DMG_SLA_LANGUAGES)"
@@ -132,7 +132,7 @@
return 0;
}
- cmList languages{ this->GetOption("CPACK_DMG_SLA_LANGUAGES") };
+ cmList languages{ *lang };
if (languages.empty()) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"CPACK_DMG_SLA_LANGUAGES set but empty" << std::endl);
@@ -742,8 +742,8 @@
std::string componentFileName = cmStrCat(
"CPACK_DMG_", cmSystemTools::UpperCase(componentName), "_FILE_NAME");
- if (this->IsSet(componentFileName)) {
- return this->GetOption(componentFileName);
+ if (cmValue v = this->GetOptionIfSet(componentFileName)) {
+ return *v;
}
return GetComponentPackageFileName(package_file_name, componentName, false);
}
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index 44d0ece..82116b3 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -3,7 +3,6 @@
#include "cmCPackGenerator.h"
#include <algorithm>
-#include <cstring>
#include <memory>
#include <utility>
@@ -52,10 +51,9 @@
}
void cmCPackGenerator::DisplayVerboseOutput(const std::string& msg,
- float progress)
+ float /*unused*/)
{
- (void)progress;
- cmCPackLogger(cmCPackLog::LOG_VERBOSE, "" << msg << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, msg << std::endl);
}
int cmCPackGenerator::PrepareNames()
@@ -434,10 +432,7 @@
cmWorkingDirectory workdir(goToDir);
if (workdir.Failed()) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Failed to change working directory to "
- << goToDir << " : "
- << std::strerror(workdir.GetLastResult())
- << std::endl);
+ workdir.GetError() << std::endl);
return 0;
}
for (auto const& symlinked : symlinkedFiles) {
@@ -1323,6 +1318,15 @@
return this->MakefileMap->IsSet(name);
}
+cmValue cmCPackGenerator::GetOptionIfSet(const std::string& name) const
+{
+ cmValue ret = this->MakefileMap->GetDefinition(name);
+ if (!ret || ret->empty() || cmIsNOTFOUND(*ret)) {
+ return {};
+ }
+ return ret;
+}
+
bool cmCPackGenerator::IsOn(const std::string& name) const
{
return this->GetOption(name).IsOn();
diff --git a/Source/CPack/cmCPackGenerator.h b/Source/CPack/cmCPackGenerator.h
index 980ab8f..30e8451 100644
--- a/Source/CPack/cmCPackGenerator.h
+++ b/Source/CPack/cmCPackGenerator.h
@@ -103,6 +103,7 @@
cmValue GetOption(const std::string& op) const;
std::vector<std::string> GetOptions() const;
bool IsSet(const std::string& name) const;
+ cmValue GetOptionIfSet(const std::string& name) const;
bool IsOn(const std::string& name) const;
bool IsSetToOff(const std::string& op) const;
bool IsSetToEmpty(const std::string& op) const;
diff --git a/Source/CPack/cmCPackInnoSetupGenerator.cxx b/Source/CPack/cmCPackInnoSetupGenerator.cxx
index 35d126f..df99e15 100644
--- a/Source/CPack/cmCPackInnoSetupGenerator.cxx
+++ b/Source/CPack/cmCPackInnoSetupGenerator.cxx
@@ -97,9 +97,8 @@
int cmCPackInnoSetupGenerator::PackageFiles()
{
// Includes
- if (IsSet("CPACK_INNOSETUP_EXTRA_SCRIPTS")) {
- const cmList extraScripts(GetOption("CPACK_INNOSETUP_EXTRA_SCRIPTS"));
-
+ if (cmValue v = GetOptionIfSet("CPACK_INNOSETUP_EXTRA_SCRIPTS")) {
+ const cmList extraScripts(*v);
for (const std::string& i : extraScripts) {
includeDirectives.emplace_back(cmStrCat(
"#include ", QuotePath(cmSystemTools::CollapseFullPath(i, toplevel))));
@@ -133,9 +132,8 @@
}
// [Code] section
- if (IsSet("CPACK_INNOSETUP_CODE_FILES")) {
- const cmList codeFiles(GetOption("CPACK_INNOSETUP_CODE_FILES"));
-
+ if (cmValue v = GetOptionIfSet("CPACK_INNOSETUP_CODE_FILES")) {
+ const cmList codeFiles(*v);
for (const std::string& i : codeFiles) {
codeIncludes.emplace_back(cmStrCat(
"#include ", QuotePath(cmSystemTools::CollapseFullPath(i, toplevel))));
@@ -168,26 +166,26 @@
}
setupDirectives["AppPublisher"] = GetOption("CPACK_PACKAGE_VENDOR");
- if (IsSet("CPACK_PACKAGE_HOMEPAGE_URL")) {
- setupDirectives["AppPublisherURL"] =
- GetOption("CPACK_PACKAGE_HOMEPAGE_URL");
- setupDirectives["AppSupportURL"] = GetOption("CPACK_PACKAGE_HOMEPAGE_URL");
- setupDirectives["AppUpdatesURL"] = GetOption("CPACK_PACKAGE_HOMEPAGE_URL");
+ if (cmValue v = GetOptionIfSet("CPACK_PACKAGE_HOMEPAGE_URL")) {
+ setupDirectives["AppPublisherURL"] = *v;
+ setupDirectives["AppSupportURL"] = *v;
+ setupDirectives["AppUpdatesURL"] = *v;
}
SetOptionIfNotSet("CPACK_INNOSETUP_IGNORE_LICENSE_PAGE", "OFF");
- if (IsSet("CPACK_RESOURCE_FILE_LICENSE") &&
- !GetOption("CPACK_INNOSETUP_IGNORE_LICENSE_PAGE").IsOn()) {
- setupDirectives["LicenseFile"] = cmSystemTools::ConvertToWindowsOutputPath(
- GetOption("CPACK_RESOURCE_FILE_LICENSE"));
+ if (!GetOption("CPACK_INNOSETUP_IGNORE_LICENSE_PAGE").IsOn()) {
+ if (cmValue v = GetOptionIfSet("CPACK_RESOURCE_FILE_LICENSE")) {
+ setupDirectives["LicenseFile"] =
+ cmSystemTools::ConvertToWindowsOutputPath(*v);
+ }
}
SetOptionIfNotSet("CPACK_INNOSETUP_IGNORE_README_PAGE", "ON");
- if (IsSet("CPACK_RESOURCE_FILE_README") &&
- !GetOption("CPACK_INNOSETUP_IGNORE_README_PAGE").IsOn()) {
- setupDirectives["InfoBeforeFile"] =
- cmSystemTools::ConvertToWindowsOutputPath(
- GetOption("CPACK_RESOURCE_FILE_README"));
+ if (!GetOption("CPACK_INNOSETUP_IGNORE_README_PAGE").IsOn()) {
+ if (cmValue v = GetOptionIfSet("CPACK_RESOURCE_FILE_README")) {
+ setupDirectives["InfoBeforeFile"] =
+ cmSystemTools::ConvertToWindowsOutputPath(*v);
+ }
}
SetOptionIfNotSet("CPACK_INNOSETUP_USE_MODERN_WIZARD", "OFF");
@@ -201,16 +199,14 @@
setupDirectives["SetupIconFile"] = "compiler:SetupClassicIcon.ico";
}
- if (IsSet("CPACK_INNOSETUP_ICON_FILE")) {
+ if (cmValue v = GetOptionIfSet("CPACK_INNOSETUP_ICON_FILE")) {
setupDirectives["SetupIconFile"] =
- cmSystemTools::ConvertToWindowsOutputPath(
- GetOption("CPACK_INNOSETUP_ICON_FILE"));
+ cmSystemTools::ConvertToWindowsOutputPath(*v);
}
- if (IsSet("CPACK_PACKAGE_ICON")) {
+ if (cmValue v = GetOptionIfSet("CPACK_PACKAGE_ICON")) {
setupDirectives["WizardSmallImageFile"] =
- cmSystemTools::ConvertToWindowsOutputPath(
- GetOption("CPACK_PACKAGE_ICON"));
+ cmSystemTools::ConvertToWindowsOutputPath(*v);
}
if (!RequireOption("CPACK_PACKAGE_INSTALL_DIRECTORY")) {
@@ -238,8 +234,8 @@
toplevelProgramFolder = false;
}
- if (IsSet("CPACK_INNOSETUP_PASSWORD")) {
- setupDirectives["Password"] = GetOption("CPACK_INNOSETUP_PASSWORD");
+ if (cmValue v = GetOptionIfSet("CPACK_INNOSETUP_PASSWORD")) {
+ setupDirectives["Password"] = *v;
setupDirectives["Encryption"] = "yes";
}
@@ -306,9 +302,9 @@
bool cmCPackInnoSetupGenerator::ProcessFiles()
{
std::map<std::string, std::string> customFileInstructions;
- if (IsSet("CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS")) {
- const cmList instructions(
- GetOption("CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS"));
+ if (cmValue v =
+ GetOptionIfSet("CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS")) {
+ const cmList instructions(*v);
if (instructions.size() % 2 != 0) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS should "
@@ -328,8 +324,8 @@
toplevelProgramFolder ? "{autoprograms}\\" : "{group}\\";
std::map<std::string, std::string> icons;
- if (IsSet("CPACK_PACKAGE_EXECUTABLES")) {
- const cmList executables(GetOption("CPACK_PACKAGE_EXECUTABLES"));
+ if (cmValue v = GetOptionIfSet("CPACK_PACKAGE_EXECUTABLES")) {
+ const cmList executables(*v);
if (executables.size() % 2 != 0) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"CPACK_PACKAGE_EXECUTABLES should should contain pairs of "
@@ -345,13 +341,13 @@
}
std::vector<std::string> desktopIcons;
- if (IsSet("CPACK_CREATE_DESKTOP_LINKS")) {
- cmExpandList(GetOption("CPACK_CREATE_DESKTOP_LINKS"), desktopIcons);
+ if (cmValue v = GetOptionIfSet("CPACK_CREATE_DESKTOP_LINKS")) {
+ cmExpandList(*v, desktopIcons);
}
std::vector<std::string> runExecutables;
- if (IsSet("CPACK_INNOSETUP_RUN_EXECUTABLES")) {
- cmExpandList(GetOption("CPACK_INNOSETUP_RUN_EXECUTABLES"), runExecutables);
+ if (cmValue v = GetOptionIfSet("CPACK_INNOSETUP_RUN_EXECUTABLES")) {
+ cmExpandList(*v, runExecutables);
}
for (const std::string& i : files) {
@@ -507,8 +503,8 @@
static cmsys::RegularExpression urlRegex(
"^(mailto:|(ftps?|https?|news)://).*$");
- if (IsSet("CPACK_INNOSETUP_MENU_LINKS")) {
- const cmList menuIcons(GetOption("CPACK_INNOSETUP_MENU_LINKS"));
+ if (cmValue v = GetOptionIfSet("CPACK_INNOSETUP_MENU_LINKS")) {
+ const cmList menuIcons(*v);
if (menuIcons.size() % 2 != 0) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"CPACK_INNOSETUP_MENU_LINKS should "
@@ -784,8 +780,7 @@
const std::string& defaultMessage =
"; CPack didn't find any entries for this section";
- if (IsSet("CPACK_CREATE_DESKTOP_LINKS") &&
- !GetOption("CPACK_CREATE_DESKTOP_LINKS").Get()->empty()) {
+ if (!IsSetToEmpty("CPACK_CREATE_DESKTOP_LINKS")) {
cmCPackInnoSetupKeyValuePairs tasks;
tasks["Name"] = "\"desktopicon\"";
tasks["Description"] = "\"{cm:CreateDesktopIcon}\"";
@@ -858,9 +853,8 @@
}
}
- if (IsSet("CPACK_INNOSETUP_EXECUTABLE_ARGUMENTS")) {
- const cmList args(GetOption("CPACK_INNOSETUP_EXECUTABLE_ARGUMENTS"));
-
+ if (cmValue v = GetOptionIfSet("CPACK_INNOSETUP_EXECUTABLE_ARGUMENTS")) {
+ const cmList args(*v);
isccArgs.insert(isccArgs.end(), args.begin(), args.end());
}
@@ -986,7 +980,7 @@
"Problem running certutil command: " << hashCmd
<< std::endl);
}
- *hash = cmTrimWhitespace(cmTokenize(hashOutput, "\n").at(1));
+ *hash = cmTrimWhitespace(cmTokenizedView(hashOutput, '\n').at(1));
if (hash->length() != 64) {
cmCPackLogger(cmCPackLog::LOG_WARNING,
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
index 53871ee..8d81183 100644
--- a/Source/CPack/cmCPackNSISGenerator.cxx
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -130,23 +130,20 @@
if (this->IsSet("CPACK_NSIS_MUI_ICON") ||
this->IsSet("CPACK_NSIS_MUI_UNIICON")) {
std::string installerIconCode;
- if (this->IsSet("CPACK_NSIS_MUI_ICON")) {
- installerIconCode += cmStrCat(
- "!define MUI_ICON \"", this->GetOption("CPACK_NSIS_MUI_ICON"), "\"\n");
+ if (cmValue icon = this->GetOptionIfSet("CPACK_NSIS_MUI_ICON")) {
+ installerIconCode += cmStrCat("!define MUI_ICON \"", *icon, "\"\n");
}
- if (this->IsSet("CPACK_NSIS_MUI_UNIICON")) {
- installerIconCode +=
- cmStrCat("!define MUI_UNICON \"",
- this->GetOption("CPACK_NSIS_MUI_UNIICON"), "\"\n");
+ if (cmValue icon = this->GetOptionIfSet("CPACK_NSIS_MUI_UNIICON")) {
+ installerIconCode += cmStrCat("!define MUI_UNICON \"", *icon, "\"\n");
}
this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_ICON_CODE",
installerIconCode.c_str());
}
std::string installerHeaderImage;
- if (this->IsSet("CPACK_NSIS_MUI_HEADERIMAGE")) {
- installerHeaderImage = *this->GetOption("CPACK_NSIS_MUI_HEADERIMAGE");
- } else if (this->IsSet("CPACK_PACKAGE_ICON")) {
- installerHeaderImage = *this->GetOption("CPACK_PACKAGE_ICON");
+ if (cmValue img = this->GetOptionIfSet("CPACK_NSIS_MUI_HEADERIMAGE")) {
+ installerHeaderImage = *img;
+ } else if (cmValue icon = this->GetOptionIfSet("CPACK_PACKAGE_ICON")) {
+ installerHeaderImage = *icon;
}
if (!installerHeaderImage.empty()) {
std::string installerIconCode = cmStrCat(
@@ -155,35 +152,33 @@
installerIconCode);
}
- if (this->IsSet("CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP")) {
- std::string installerBitmapCode = cmStrCat(
- "!define MUI_WELCOMEFINISHPAGE_BITMAP \"",
- this->GetOption("CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP"), "\"\n");
+ if (cmValue v =
+ this->GetOptionIfSet("CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP")) {
+ std::string installerBitmapCode =
+ cmStrCat("!define MUI_WELCOMEFINISHPAGE_BITMAP \"", *v, "\"\n");
this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_WELCOMEFINISH_CODE",
installerBitmapCode);
}
- if (this->IsSet("CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP")) {
- std::string installerBitmapCode = cmStrCat(
- "!define MUI_UNWELCOMEFINISHPAGE_BITMAP \"",
- this->GetOption("CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP"), "\"\n");
+ if (cmValue v =
+ this->GetOptionIfSet("CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP")) {
+ std::string installerBitmapCode =
+ cmStrCat("!define MUI_UNWELCOMEFINISHPAGE_BITMAP \"", *v, "\"\n");
this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_UNWELCOMEFINISH_CODE",
installerBitmapCode);
}
- if (this->IsSet("CPACK_NSIS_MUI_FINISHPAGE_RUN")) {
- std::string installerRunCode =
- cmStrCat("!define MUI_FINISHPAGE_RUN \"$INSTDIR\\",
- this->GetOption("CPACK_NSIS_EXECUTABLES_DIRECTORY"), '\\',
- this->GetOption("CPACK_NSIS_MUI_FINISHPAGE_RUN"), "\"\n");
+ if (cmValue v = this->GetOptionIfSet("CPACK_NSIS_MUI_FINISHPAGE_RUN")) {
+ std::string installerRunCode = cmStrCat(
+ "!define MUI_FINISHPAGE_RUN \"$INSTDIR\\",
+ this->GetOption("CPACK_NSIS_EXECUTABLES_DIRECTORY"), '\\', *v, "\"\n");
this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE",
installerRunCode);
}
- if (this->IsSet("CPACK_NSIS_WELCOME_TITLE")) {
+ if (cmValue v = this->GetOptionIfSet("CPACK_NSIS_WELCOME_TITLE")) {
std::string welcomeTitleCode =
- cmStrCat("!define MUI_WELCOMEPAGE_TITLE \"",
- this->GetOption("CPACK_NSIS_WELCOME_TITLE"), "\"");
+ cmStrCat("!define MUI_WELCOMEPAGE_TITLE \"", *v, "\"");
this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_WELCOME_TITLE_CODE",
welcomeTitleCode);
}
@@ -193,10 +188,9 @@
"!define MUI_WELCOMEPAGE_TITLE_3LINES");
}
- if (this->IsSet("CPACK_NSIS_FINISH_TITLE")) {
+ if (cmValue v = this->GetOptionIfSet("CPACK_NSIS_FINISH_TITLE")) {
std::string finishTitleCode =
- cmStrCat("!define MUI_FINISHPAGE_TITLE \"",
- this->GetOption("CPACK_NSIS_FINISH_TITLE"), "\"");
+ cmStrCat("!define MUI_FINISHPAGE_TITLE \"", *v, "\"");
this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_FINISH_TITLE_CODE",
finishTitleCode);
}
@@ -211,28 +205,28 @@
"ManifestDPIAware true");
}
- if (this->IsSet("CPACK_NSIS_BRANDING_TEXT")) {
+ if (cmValue brandingText =
+ this->GetOptionIfSet("CPACK_NSIS_BRANDING_TEXT")) {
// Default position to LEFT
std::string brandingTextPosition = "LEFT";
- if (this->IsSet("CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION")) {
- std::string wantedPosition =
- this->GetOption("CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION");
- if (!wantedPosition.empty()) {
+ if (cmValue wantedPosition =
+ this->GetOptionIfSet("CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION")) {
+ if (!wantedPosition->empty()) {
const std::set<std::string> possiblePositions{ "CENTER", "LEFT",
"RIGHT" };
- if (possiblePositions.find(wantedPosition) ==
+ if (possiblePositions.find(*wantedPosition) ==
possiblePositions.end()) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Unsupported branding text trim position "
- << wantedPosition << std::endl);
+ << *wantedPosition << std::endl);
return false;
}
- brandingTextPosition = wantedPosition;
+ brandingTextPosition = *wantedPosition;
}
}
std::string brandingTextCode =
cmStrCat("BrandingText /TRIM", brandingTextPosition, " \"",
- this->GetOption("CPACK_NSIS_BRANDING_TEXT"), "\"\n");
+ *brandingText, "\"\n");
this->SetOptionIfNotSet("CPACK_NSIS_BRANDING_TEXT_CODE", brandingTextCode);
}
diff --git a/Source/CPack/cmCPackProductBuildGenerator.cxx b/Source/CPack/cmCPackProductBuildGenerator.cxx
index ae3c50e..b5b70dc 100644
--- a/Source/CPack/cmCPackProductBuildGenerator.cxx
+++ b/Source/CPack/cmCPackProductBuildGenerator.cxx
@@ -60,10 +60,8 @@
std::string resDir = cmStrCat(packageDirFileName, "/Contents");
- if (this->IsSet("CPACK_PRODUCTBUILD_RESOURCES_DIR")) {
- std::string userResDir =
- this->GetOption("CPACK_PRODUCTBUILD_RESOURCES_DIR");
-
+ if (cmValue v = this->GetOptionIfSet("CPACK_PRODUCTBUILD_RESOURCES_DIR")) {
+ std::string userResDir = *v;
if (!cmSystemTools::CopyADirectory(userResDir, resDir)) {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Problem copying the resource files" << std::endl);
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index 305ac56..9979dfa 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -113,7 +113,7 @@
log.SetOutputPrefix("CPack: ");
log.SetVerbosePrefix("CPack Verbose: ");
- if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
+ if (cmSystemTools::GetLogicalWorkingDirectory().empty()) {
cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
"Current working directory cannot be established.\n");
return 1;
@@ -208,6 +208,7 @@
CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
CommandArgument::setToTrue(listPresets) },
CommandArgument{ "-D", CommandArgument::Values::One,
+ CommandArgument::RequiresSeparator::No,
[&log, &definitions](const std::string& arg, cmake*,
cmMakefile*) -> bool {
std::string value = arg;
@@ -254,7 +255,7 @@
// Set up presets
if (!preset.empty() || listPresets) {
- const auto workingDirectory = cmSystemTools::GetCurrentWorkingDirectory();
+ const auto workingDirectory = cmSystemTools::GetLogicalWorkingDirectory();
auto const presetGeneratorsPresent =
[&generators](const cmCMakePresetsGraph::PackagePreset& p) {
@@ -349,7 +350,8 @@
return 1;
}
- cmSystemTools::ChangeDirectory(expandedConfigurePreset->BinaryDir);
+ cmSystemTools::SetLogicalWorkingDirectory(
+ expandedConfigurePreset->BinaryDir);
auto presetEnvironment = expandedPreset->Environment;
for (auto const& var : presetEnvironment) {
@@ -405,9 +407,9 @@
bool cpackConfigFileSpecified = true;
if (!cpackConfigFile.empty()) {
- cpackConfigFile = cmSystemTools::CollapseFullPath(cpackConfigFile);
+ cpackConfigFile = cmSystemTools::ToNormalizedPathOnDisk(cpackConfigFile);
} else {
- cpackConfigFile = cmStrCat(cmSystemTools::GetCurrentWorkingDirectory(),
+ cpackConfigFile = cmStrCat(cmSystemTools::GetLogicalWorkingDirectory(),
"/CPackConfig.cmake");
cpackConfigFileSpecified = false;
}
@@ -479,7 +481,7 @@
if (!cpackProjectDirectory.empty()) {
// The value has been set on the command line. Ensure it is absolute.
cpackProjectDirectory =
- cmSystemTools::CollapseFullPath(cpackProjectDirectory);
+ cmSystemTools::ToNormalizedPathOnDisk(cpackProjectDirectory);
} else {
// The value has not been set on the command line. Check config file.
if (cmValue pd = globalMF.GetDefinition("CPACK_PACKAGE_DIRECTORY")) {
@@ -487,7 +489,7 @@
cpackProjectDirectory = cmSystemTools::CollapseFullPath(*pd);
} else {
// Default to the current working directory.
- cpackProjectDirectory = cmSystemTools::GetCurrentWorkingDirectory();
+ cpackProjectDirectory = cmSystemTools::GetLogicalWorkingDirectory();
}
}
globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY", cpackProjectDirectory);
diff --git a/Source/CTest/cmCTestBuildAndTest.cxx b/Source/CTest/cmCTestBuildAndTest.cxx
new file mode 100644
index 0000000..a142445
--- /dev/null
+++ b/Source/CTest/cmCTestBuildAndTest.cxx
@@ -0,0 +1,341 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestBuildAndTest.h"
+
+#include <chrono>
+#include <cstdint>
+#include <iostream>
+#include <ratio>
+#include <utility>
+
+#include <cm3p/uv.h>
+
+#include "cmBuildOptions.h"
+#include "cmCTest.h"
+#include "cmCTestTestHandler.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProcessOutput.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVProcessChain.h"
+#include "cmUVStream.h"
+#include "cmWorkingDirectory.h"
+#include "cmake.h"
+
+struct cmMessageMetadata;
+
+cmCTestBuildAndTest::cmCTestBuildAndTest(cmCTest* ctest)
+ : CTest(ctest)
+{
+}
+
+bool cmCTestBuildAndTest::RunCMake(cmake* cm)
+{
+ std::vector<std::string> args;
+ args.push_back(cmSystemTools::GetCMakeCommand());
+ args.push_back(this->SourceDir);
+ if (!this->BuildGenerator.empty()) {
+ args.push_back("-G" + this->BuildGenerator);
+ }
+ if (!this->BuildGeneratorPlatform.empty()) {
+ args.push_back("-A" + this->BuildGeneratorPlatform);
+ }
+ if (!this->BuildGeneratorToolset.empty()) {
+ args.push_back("-T" + this->BuildGeneratorToolset);
+ }
+
+ const char* config = nullptr;
+ if (!this->CTest->GetConfigType().empty()) {
+ config = this->CTest->GetConfigType().c_str();
+ }
+
+ if (config) {
+ args.push_back("-DCMAKE_BUILD_TYPE:STRING=" + std::string(config));
+ }
+ if (!this->BuildMakeProgram.empty() &&
+ (this->BuildGenerator.find("Make") != std::string::npos ||
+ this->BuildGenerator.find("Ninja") != std::string::npos)) {
+ args.push_back("-DCMAKE_MAKE_PROGRAM:FILEPATH=" + this->BuildMakeProgram);
+ }
+
+ for (std::string const& opt : this->BuildOptions) {
+ args.push_back(opt);
+ }
+ std::cout << "======== CMake output ======\n";
+ if (cm->Run(args) != 0) {
+ std::cout << "======== End CMake output ======\n"
+ "Error: cmake execution failed\n";
+ return false;
+ }
+ // do another config?
+ if (this->BuildTwoConfig) {
+ if (cm->Run(args) != 0) {
+ std::cout << "======== End CMake output ======\n"
+ "Error: cmake execution failed\n";
+ return false;
+ }
+ }
+ std::cout << "======== End CMake output ======\n";
+ return true;
+}
+
+bool cmCTestBuildAndTest::RunTest(std::vector<std::string> const& argv,
+ int* retVal, cmDuration timeout)
+{
+ cmUVProcessChainBuilder builder;
+ builder.AddCommand(argv).SetMergedBuiltinStreams();
+ auto chain = builder.Start();
+
+ cmProcessOutput processOutput(cmProcessOutput::Auto);
+ cm::uv_pipe_ptr outputStream;
+ outputStream.init(chain.GetLoop(), 0);
+ uv_pipe_open(outputStream, chain.OutputStream());
+ auto outputHandle = cmUVStreamRead(
+ outputStream,
+ [&processOutput](std::vector<char> data) {
+ std::string decoded;
+ processOutput.DecodeText(data.data(), data.size(), decoded);
+ std::cout << decoded << std::flush;
+ },
+ []() {});
+
+ bool complete = chain.Wait(static_cast<uint64_t>(timeout.count() * 1000.0));
+
+ bool result = false;
+
+ if (complete) {
+ auto const& status = chain.GetStatus(0);
+ auto exception = status.GetException();
+ switch (exception.first) {
+ case cmUVProcessChain::ExceptionCode::None:
+ *retVal = static_cast<int>(status.ExitStatus);
+ result = true;
+ break;
+ case cmUVProcessChain::ExceptionCode::Spawn: {
+ std::cout << "\n*** ERROR executing: " << exception.second;
+ } break;
+ default: {
+ *retVal = status.TermSignal;
+ std::cout << "\n*** Exception executing: " << exception.second;
+ } break;
+ }
+ }
+
+ return result;
+}
+
+class cmCTestBuildAndTestCaptureRAII
+{
+ cmake& CM;
+
+public:
+ cmCTestBuildAndTestCaptureRAII(cmake& cm)
+ : CM(cm)
+ {
+ cmSystemTools::SetMessageCallback(
+ [](const std::string& msg, const cmMessageMetadata& /* unused */) {
+ std::cout << msg << std::endl;
+ });
+
+ cmSystemTools::SetStdoutCallback(
+ [](std::string const& m) { std::cout << m << std::flush; });
+ cmSystemTools::SetStderrCallback(
+ [](std::string const& m) { std::cout << m << std::flush; });
+
+ this->CM.SetProgressCallback([](const std::string& msg, float prog) {
+ if (prog < 0) {
+ std::cout << msg << std::endl;
+ }
+ });
+ }
+
+ ~cmCTestBuildAndTestCaptureRAII()
+ {
+ this->CM.SetProgressCallback(nullptr);
+ cmSystemTools::SetStderrCallback(nullptr);
+ cmSystemTools::SetStdoutCallback(nullptr);
+ cmSystemTools::SetMessageCallback(nullptr);
+ }
+
+ cmCTestBuildAndTestCaptureRAII(const cmCTestBuildAndTestCaptureRAII&) =
+ delete;
+ cmCTestBuildAndTestCaptureRAII& operator=(
+ const cmCTestBuildAndTestCaptureRAII&) = delete;
+};
+
+int cmCTestBuildAndTest::Run()
+{
+ // if the generator and make program are not specified then it is an error
+ if (this->BuildGenerator.empty()) {
+ std::cout << "--build-and-test requires that the generator "
+ "be provided using the --build-generator "
+ "command line option.\n";
+ return 1;
+ }
+
+ cmake cm(cmake::RoleProject, cmState::Project);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cmCTestBuildAndTestCaptureRAII captureRAII(cm);
+ static_cast<void>(captureRAII);
+
+ if (this->CTest->GetConfigType().empty() && !this->ConfigSample.empty()) {
+ // use the config sample to set the ConfigType
+ std::string fullPath;
+ std::string resultingConfig;
+ std::vector<std::string> extraPaths;
+ std::vector<std::string> failed;
+ fullPath = cmCTestTestHandler::FindExecutable(
+ this->CTest, this->ConfigSample, resultingConfig, extraPaths, failed);
+ if (!fullPath.empty() && !resultingConfig.empty()) {
+ this->CTest->SetConfigType(resultingConfig);
+ }
+ std::cout << "Using config sample with results: " << fullPath << " and "
+ << resultingConfig << std::endl;
+ }
+
+ // we need to honor the timeout specified, the timeout include cmake, build
+ // and test time
+ auto clock_start = std::chrono::steady_clock::now();
+
+ // make sure the binary dir is there
+ std::cout << "Internal cmake changing into directory: " << this->BinaryDir
+ << std::endl;
+ if (!cmSystemTools::FileIsDirectory(this->BinaryDir)) {
+ cmSystemTools::MakeDirectory(this->BinaryDir);
+ }
+ cmWorkingDirectory workdir(this->BinaryDir);
+ if (workdir.Failed()) {
+ std::cout << workdir.GetError() << '\n';
+ return 1;
+ }
+
+ if (this->BuildNoCMake) {
+ // Make the generator available for the Build call below.
+ cm.SetGlobalGenerator(cm.CreateGlobalGenerator(this->BuildGenerator));
+ if (!this->BuildGeneratorPlatform.empty()) {
+ cmMakefile mf(cm.GetGlobalGenerator(), cm.GetCurrentSnapshot());
+ if (!cm.GetGlobalGenerator()->SetGeneratorPlatform(
+ this->BuildGeneratorPlatform, &mf)) {
+ return 1;
+ }
+ }
+
+ // Load the cache to make CMAKE_MAKE_PROGRAM available.
+ cm.LoadCache(this->BinaryDir);
+ } else {
+ // do the cmake step, no timeout here since it is not a sub process
+ if (!this->RunCMake(&cm)) {
+ return 1;
+ }
+ }
+
+ // do the build
+ if (this->BuildTargets.empty()) {
+ this->BuildTargets.emplace_back();
+ }
+ for (std::string const& tar : this->BuildTargets) {
+ cmDuration remainingTime = std::chrono::seconds(0);
+ if (this->Timeout > cmDuration::zero()) {
+ remainingTime =
+ this->Timeout - (std::chrono::steady_clock::now() - clock_start);
+ if (remainingTime <= std::chrono::seconds(0)) {
+ std::cout << "--build-and-test timeout exceeded. ";
+ return 1;
+ }
+ }
+ const char* config = nullptr;
+ if (!this->CTest->GetConfigType().empty()) {
+ config = this->CTest->GetConfigType().c_str();
+ }
+ if (!config) {
+ config = "Debug";
+ }
+
+ cmBuildOptions buildOptions(!this->BuildNoClean, false,
+ PackageResolveMode::Disable);
+ int retVal = cm.GetGlobalGenerator()->Build(
+ cmake::NO_BUILD_PARALLEL_LEVEL, this->SourceDir, this->BinaryDir,
+ this->BuildProject, { tar }, std::cout, this->BuildMakeProgram, config,
+ buildOptions, false, remainingTime, cmSystemTools::OUTPUT_PASSTHROUGH);
+ // if the build failed then return
+ if (retVal) {
+ return 1;
+ }
+ }
+
+ // if no test was specified then we are done
+ if (this->TestCommand.empty()) {
+ return 0;
+ }
+
+ // now run the compiled test if we can find it
+ // store the final location in fullPath
+ std::string fullPath;
+ std::string resultingConfig;
+ std::vector<std::string> extraPaths;
+ // if this->ExecutableDirectory is set try that as well
+ if (!this->ExecutableDirectory.empty()) {
+ std::string tempPath =
+ cmStrCat(this->ExecutableDirectory, '/', this->TestCommand);
+ extraPaths.push_back(tempPath);
+ }
+ std::vector<std::string> failed;
+ fullPath = cmCTestTestHandler::FindExecutable(
+ this->CTest, this->TestCommand, resultingConfig, extraPaths, failed);
+
+ if (!cmSystemTools::FileExists(fullPath)) {
+ std::cout
+ << "Could not find path to executable, perhaps it was not built: "
+ << this->TestCommand << "\n"
+ << "tried to find it in these places:\n"
+ << fullPath << '\n';
+ for (std::string const& fail : failed) {
+ std::cout << fail << '\n';
+ }
+ return 1;
+ }
+
+ std::vector<std::string> testCommand;
+ testCommand.push_back(fullPath);
+ for (std::string const& testCommandArg : this->TestCommandArgs) {
+ testCommand.push_back(testCommandArg);
+ }
+ int retval = 0;
+ // run the test from the this->BuildRunDir if set
+ if (!this->BuildRunDir.empty()) {
+ std::cout << "Run test in directory: " << this->BuildRunDir << '\n';
+ if (!workdir.SetDirectory(this->BuildRunDir)) {
+ std::cout << workdir.GetError() << '\n';
+ return 1;
+ }
+ }
+ std::cout << "Running test command: \"" << fullPath << '"';
+ for (std::string const& testCommandArg : this->TestCommandArgs) {
+ std::cout << " \"" << testCommandArg << '"';
+ }
+ std::cout << '\n';
+
+ // how much time is remaining
+ cmDuration remainingTime = std::chrono::seconds(0);
+ if (this->Timeout > cmDuration::zero()) {
+ remainingTime =
+ this->Timeout - (std::chrono::steady_clock::now() - clock_start);
+ if (remainingTime <= std::chrono::seconds(0)) {
+ std::cout << "--build-and-test timeout exceeded. ";
+ return 1;
+ }
+ }
+
+ bool runTestRes = this->RunTest(testCommand, &retval, remainingTime);
+
+ if (!runTestRes || retval != 0) {
+ std::cout << "\nTest command failed: " << testCommand[0] << '\n';
+ retval = 1;
+ }
+
+ return retval;
+}
diff --git a/Source/CTest/cmCTestBuildAndTest.h b/Source/CTest/cmCTestBuildAndTest.h
new file mode 100644
index 0000000..f680bc2
--- /dev/null
+++ b/Source/CTest/cmCTestBuildAndTest.h
@@ -0,0 +1,56 @@
+/* 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 <string>
+#include <vector>
+
+#include "cmDuration.h"
+
+class cmake;
+class cmCTest;
+
+/** \class cmCTestBuildAndTest
+ * \brief A class that handles ctest -S invocations
+ *
+ */
+class cmCTestBuildAndTest
+{
+public:
+ /*
+ * The main entry point for this class
+ */
+ int Run();
+
+ cmCTestBuildAndTest(cmCTest* ctest);
+
+private:
+ cmCTest* CTest;
+
+ bool RunCMake(cmake* cm);
+ bool RunTest(std::vector<std::string> const& args, int* retVal,
+ cmDuration timeout);
+
+ std::string BuildGenerator;
+ std::string BuildGeneratorPlatform;
+ std::string BuildGeneratorToolset;
+ std::vector<std::string> BuildOptions;
+ bool BuildTwoConfig = false;
+ std::string BuildMakeProgram;
+ std::string ConfigSample;
+ std::string SourceDir;
+ std::string BinaryDir;
+ std::string BuildProject;
+ std::string TestCommand;
+ bool BuildNoClean = false;
+ std::string BuildRunDir;
+ std::string ExecutableDirectory;
+ std::vector<std::string> TestCommandArgs;
+ std::vector<std::string> BuildTargets;
+ bool BuildNoCMake = false;
+ cmDuration Timeout = cmDuration::zero();
+
+ friend class cmCTest;
+};
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
deleted file mode 100644
index 9faabf7..0000000
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ /dev/null
@@ -1,453 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmCTestBuildAndTestHandler.h"
-
-#include <chrono>
-#include <cstdlib>
-#include <cstring>
-#include <ratio>
-
-#include "cmBuildOptions.h"
-#include "cmCTest.h"
-#include "cmCTestTestHandler.h"
-#include "cmGlobalGenerator.h"
-#include "cmMakefile.h"
-#include "cmState.h"
-#include "cmStringAlgorithms.h"
-#include "cmSystemTools.h"
-#include "cmWorkingDirectory.h"
-#include "cmake.h"
-
-struct cmMessageMetadata;
-
-cmCTestBuildAndTestHandler::cmCTestBuildAndTestHandler()
-{
- this->BuildTwoConfig = false;
- this->BuildNoClean = false;
- this->BuildNoCMake = false;
- this->Timeout = cmDuration::zero();
-}
-
-void cmCTestBuildAndTestHandler::Initialize()
-{
- this->BuildTargets.clear();
- this->Superclass::Initialize();
-}
-
-const char* cmCTestBuildAndTestHandler::GetOutput()
-{
- return this->Output.c_str();
-}
-int cmCTestBuildAndTestHandler::ProcessHandler()
-{
- this->Output.clear();
- std::string output;
- cmSystemTools::ResetErrorOccurredFlag();
- int retv = this->RunCMakeAndTest(&this->Output);
- cmSystemTools::ResetErrorOccurredFlag();
- return retv;
-}
-
-int cmCTestBuildAndTestHandler::RunCMake(std::string* outstring,
- std::ostringstream& out,
- std::string& cmakeOutString,
- cmake* cm)
-{
- std::vector<std::string> args;
- args.push_back(cmSystemTools::GetCMakeCommand());
- args.push_back(this->SourceDir);
- if (!this->BuildGenerator.empty()) {
- args.push_back("-G" + this->BuildGenerator);
- }
- if (!this->BuildGeneratorPlatform.empty()) {
- args.push_back("-A" + this->BuildGeneratorPlatform);
- }
- if (!this->BuildGeneratorToolset.empty()) {
- args.push_back("-T" + this->BuildGeneratorToolset);
- }
-
- const char* config = nullptr;
- if (!this->CTest->GetConfigType().empty()) {
- config = this->CTest->GetConfigType().c_str();
- }
-
- if (config) {
- args.push_back("-DCMAKE_BUILD_TYPE:STRING=" + std::string(config));
- }
- if (!this->BuildMakeProgram.empty() &&
- (this->BuildGenerator.find("Make") != std::string::npos ||
- this->BuildGenerator.find("Ninja") != std::string::npos)) {
- args.push_back("-DCMAKE_MAKE_PROGRAM:FILEPATH=" + this->BuildMakeProgram);
- }
-
- for (std::string const& opt : this->BuildOptions) {
- args.push_back(opt);
- }
- if (cm->Run(args) != 0) {
- out << "Error: cmake execution failed\n";
- out << cmakeOutString << "\n";
- if (outstring) {
- *outstring = out.str();
- } else {
- cmCTestLog(this->CTest, ERROR_MESSAGE, out.str() << std::endl);
- }
- return 1;
- }
- // do another config?
- if (this->BuildTwoConfig) {
- if (cm->Run(args) != 0) {
- out << "Error: cmake execution failed\n";
- out << cmakeOutString << "\n";
- if (outstring) {
- *outstring = out.str();
- } else {
- cmCTestLog(this->CTest, ERROR_MESSAGE, out.str() << std::endl);
- }
- return 1;
- }
- }
- out << "======== CMake output ======\n";
- out << cmakeOutString;
- out << "======== End CMake output ======\n";
- return 0;
-}
-
-class cmCTestBuildAndTestCaptureRAII
-{
- cmake& CM;
-
-public:
- cmCTestBuildAndTestCaptureRAII(cmake& cm, std::string& s)
- : CM(cm)
- {
- cmSystemTools::SetMessageCallback(
- [&s](const std::string& msg, const cmMessageMetadata& /* unused */) {
- s += msg;
- s += "\n";
- });
-
- cmSystemTools::SetStdoutCallback([&s](std::string const& m) { s += m; });
- cmSystemTools::SetStderrCallback([&s](std::string const& m) { s += m; });
-
- this->CM.SetProgressCallback([&s](const std::string& msg, float prog) {
- if (prog < 0) {
- s += msg;
- s += "\n";
- }
- });
- }
-
- ~cmCTestBuildAndTestCaptureRAII()
- {
- this->CM.SetProgressCallback(nullptr);
- cmSystemTools::SetStderrCallback(nullptr);
- cmSystemTools::SetStdoutCallback(nullptr);
- cmSystemTools::SetMessageCallback(nullptr);
- }
-
- cmCTestBuildAndTestCaptureRAII(const cmCTestBuildAndTestCaptureRAII&) =
- delete;
- cmCTestBuildAndTestCaptureRAII& operator=(
- const cmCTestBuildAndTestCaptureRAII&) = delete;
-};
-
-int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
-{
- // if the generator and make program are not specified then it is an error
- if (this->BuildGenerator.empty()) {
- if (outstring) {
- *outstring = "--build-and-test requires that the generator "
- "be provided using the --build-generator "
- "command line option.\n";
- }
- return 1;
- }
-
- cmake cm(cmake::RoleProject, cmState::Project);
- cm.SetHomeDirectory("");
- cm.SetHomeOutputDirectory("");
- std::string cmakeOutString;
- cmCTestBuildAndTestCaptureRAII captureRAII(cm, cmakeOutString);
- static_cast<void>(captureRAII);
- std::ostringstream out;
-
- if (this->CTest->GetConfigType().empty() && !this->ConfigSample.empty()) {
- // use the config sample to set the ConfigType
- std::string fullPath;
- std::string resultingConfig;
- std::vector<std::string> extraPaths;
- std::vector<std::string> failed;
- fullPath = cmCTestTestHandler::FindExecutable(
- this->CTest, this->ConfigSample, resultingConfig, extraPaths, failed);
- if (!fullPath.empty() && !resultingConfig.empty()) {
- this->CTest->SetConfigType(resultingConfig);
- }
- out << "Using config sample with results: " << fullPath << " and "
- << resultingConfig << std::endl;
- }
-
- // we need to honor the timeout specified, the timeout include cmake, build
- // and test time
- auto clock_start = std::chrono::steady_clock::now();
-
- // make sure the binary dir is there
- out << "Internal cmake changing into directory: " << this->BinaryDir
- << std::endl;
- if (!cmSystemTools::FileIsDirectory(this->BinaryDir)) {
- cmSystemTools::MakeDirectory(this->BinaryDir);
- }
- cmWorkingDirectory workdir(this->BinaryDir);
- if (workdir.Failed()) {
- auto msg = "Failed to change working directory to " + this->BinaryDir +
- " : " + std::strerror(workdir.GetLastResult()) + "\n";
- if (outstring) {
- *outstring = msg;
- } else {
- cmCTestLog(this->CTest, ERROR_MESSAGE, msg);
- }
- return 1;
- }
-
- if (this->BuildNoCMake) {
- // Make the generator available for the Build call below.
- cm.SetGlobalGenerator(cm.CreateGlobalGenerator(this->BuildGenerator));
- if (!this->BuildGeneratorPlatform.empty()) {
- cmMakefile mf(cm.GetGlobalGenerator(), cm.GetCurrentSnapshot());
- if (!cm.GetGlobalGenerator()->SetGeneratorPlatform(
- this->BuildGeneratorPlatform, &mf)) {
- return 1;
- }
- }
-
- // Load the cache to make CMAKE_MAKE_PROGRAM available.
- cm.LoadCache(this->BinaryDir);
- } else {
- // do the cmake step, no timeout here since it is not a sub process
- if (this->RunCMake(outstring, out, cmakeOutString, &cm)) {
- return 1;
- }
- }
-
- // do the build
- if (this->BuildTargets.empty()) {
- this->BuildTargets.emplace_back();
- }
- for (std::string const& tar : this->BuildTargets) {
- cmDuration remainingTime = std::chrono::seconds(0);
- if (this->Timeout > cmDuration::zero()) {
- remainingTime =
- this->Timeout - (std::chrono::steady_clock::now() - clock_start);
- if (remainingTime <= std::chrono::seconds(0)) {
- if (outstring) {
- *outstring = "--build-and-test timeout exceeded. ";
- }
- return 1;
- }
- }
- const char* config = nullptr;
- if (!this->CTest->GetConfigType().empty()) {
- config = this->CTest->GetConfigType().c_str();
- }
- if (!config) {
- config = "Debug";
- }
-
- cmBuildOptions buildOptions(!this->BuildNoClean, false,
- PackageResolveMode::Disable);
- int retVal = cm.GetGlobalGenerator()->Build(
- cmake::NO_BUILD_PARALLEL_LEVEL, this->SourceDir, this->BinaryDir,
- this->BuildProject, { tar }, out, this->BuildMakeProgram, config,
- buildOptions, false, remainingTime);
- // if the build failed then return
- if (retVal) {
- if (outstring) {
- *outstring = out.str();
- }
- return 1;
- }
- }
- if (outstring) {
- *outstring = out.str();
- }
-
- // if no test was specified then we are done
- if (this->TestCommand.empty()) {
- return 0;
- }
-
- // now run the compiled test if we can find it
- // store the final location in fullPath
- std::string fullPath;
- std::string resultingConfig;
- std::vector<std::string> extraPaths;
- // if this->ExecutableDirectory is set try that as well
- if (!this->ExecutableDirectory.empty()) {
- std::string tempPath =
- cmStrCat(this->ExecutableDirectory, '/', this->TestCommand);
- extraPaths.push_back(tempPath);
- }
- std::vector<std::string> failed;
- fullPath = cmCTestTestHandler::FindExecutable(
- this->CTest, this->TestCommand, resultingConfig, extraPaths, failed);
-
- if (!cmSystemTools::FileExists(fullPath)) {
- out << "Could not find path to executable, perhaps it was not built: "
- << this->TestCommand << "\n";
- out << "tried to find it in these places:\n";
- out << fullPath << "\n";
- for (std::string const& fail : failed) {
- out << fail << "\n";
- }
- if (outstring) {
- *outstring = out.str();
- } else {
- cmCTestLog(this->CTest, ERROR_MESSAGE, out.str());
- }
- return 1;
- }
-
- std::vector<std::string> testCommand;
- testCommand.push_back(fullPath);
- for (std::string const& testCommandArg : this->TestCommandArgs) {
- testCommand.push_back(testCommandArg);
- }
- std::string outs;
- int retval = 0;
- // run the test from the this->BuildRunDir if set
- if (!this->BuildRunDir.empty()) {
- out << "Run test in directory: " << this->BuildRunDir << "\n";
- if (!workdir.SetDirectory(this->BuildRunDir)) {
- out << "Failed to change working directory : "
- << std::strerror(workdir.GetLastResult()) << "\n";
- if (outstring) {
- *outstring = out.str();
- } else {
- cmCTestLog(this->CTest, ERROR_MESSAGE, out.str());
- }
- return 1;
- }
- }
- out << "Running test command: \"" << fullPath << "\"";
- for (std::string const& testCommandArg : this->TestCommandArgs) {
- out << " \"" << testCommandArg << "\"";
- }
- out << "\n";
-
- // how much time is remaining
- cmDuration remainingTime = std::chrono::seconds(0);
- if (this->Timeout > cmDuration::zero()) {
- remainingTime =
- this->Timeout - (std::chrono::steady_clock::now() - clock_start);
- if (remainingTime <= std::chrono::seconds(0)) {
- if (outstring) {
- *outstring = "--build-and-test timeout exceeded. ";
- }
- return 1;
- }
- }
-
- bool runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, nullptr,
- remainingTime, nullptr);
-
- if (!runTestRes || retval != 0) {
- out << "Test command failed: " << testCommand[0] << "\n";
- retval = 1;
- }
-
- out << outs << "\n";
- if (outstring) {
- *outstring = out.str();
- } else {
- cmCTestLog(this->CTest, OUTPUT, out.str() << std::endl);
- }
- return retval;
-}
-
-int cmCTestBuildAndTestHandler::ProcessCommandLineArguments(
- const std::string& currentArg, size_t& idx,
- const std::vector<std::string>& allArgs, bool& validArg)
-{
- bool buildAndTestArg = true;
- // --build-and-test options
- if (cmHasLiteralPrefix(currentArg, "--build-and-test") &&
- idx < allArgs.size() - 1) {
- if (idx + 2 < allArgs.size()) {
- idx++;
- this->SourceDir = allArgs[idx];
- idx++;
- this->BinaryDir = allArgs[idx];
- // dir must exist before CollapseFullPath is called
- cmSystemTools::MakeDirectory(this->BinaryDir);
- this->BinaryDir = cmSystemTools::CollapseFullPath(this->BinaryDir);
- this->SourceDir = cmSystemTools::CollapseFullPath(this->SourceDir);
- } else {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "--build-and-test must have source and binary dir"
- << std::endl);
- return 0;
- }
- } else if (cmHasLiteralPrefix(currentArg, "--build-target") &&
- idx < allArgs.size() - 1) {
- idx++;
- this->BuildTargets.push_back(allArgs[idx]);
- } else if (cmHasLiteralPrefix(currentArg, "--build-nocmake")) {
- this->BuildNoCMake = true;
- } else if (cmHasLiteralPrefix(currentArg, "--build-run-dir") &&
- idx < allArgs.size() - 1) {
- idx++;
- this->BuildRunDir = allArgs[idx];
- } else if (cmHasLiteralPrefix(currentArg, "--build-two-config")) {
- this->BuildTwoConfig = true;
- } else if (cmHasLiteralPrefix(currentArg, "--build-exe-dir") &&
- idx < allArgs.size() - 1) {
- idx++;
- this->ExecutableDirectory = allArgs[idx];
- } else if (cmHasLiteralPrefix(currentArg, "--test-timeout") &&
- idx < allArgs.size() - 1) {
- idx++;
- this->Timeout = cmDuration(atof(allArgs[idx].c_str()));
- } else if (currentArg == "--build-generator" && idx < allArgs.size() - 1) {
- idx++;
- this->BuildGenerator = allArgs[idx];
- } else if (currentArg == "--build-generator-platform" &&
- idx < allArgs.size() - 1) {
- idx++;
- this->BuildGeneratorPlatform = allArgs[idx];
- } else if (currentArg == "--build-generator-toolset" &&
- idx < allArgs.size() - 1) {
- idx++;
- this->BuildGeneratorToolset = allArgs[idx];
- } else if (cmHasLiteralPrefix(currentArg, "--build-project") &&
- idx < allArgs.size() - 1) {
- idx++;
- this->BuildProject = allArgs[idx];
- } else if (cmHasLiteralPrefix(currentArg, "--build-makeprogram") &&
- idx < allArgs.size() - 1) {
- idx++;
- this->BuildMakeProgram = allArgs[idx];
- } else if (cmHasLiteralPrefix(currentArg, "--build-config-sample") &&
- idx < allArgs.size() - 1) {
- idx++;
- this->ConfigSample = allArgs[idx];
- } else if (cmHasLiteralPrefix(currentArg, "--build-noclean")) {
- this->BuildNoClean = true;
- } else if (cmHasLiteralPrefix(currentArg, "--build-options")) {
- while (idx + 1 < allArgs.size() && allArgs[idx + 1] != "--build-target" &&
- allArgs[idx + 1] != "--test-command") {
- ++idx;
- this->BuildOptions.push_back(allArgs[idx]);
- }
- } else if (cmHasLiteralPrefix(currentArg, "--test-command") &&
- idx < allArgs.size() - 1) {
- ++idx;
- this->TestCommand = allArgs[idx];
- while (idx + 1 < allArgs.size()) {
- ++idx;
- this->TestCommandArgs.push_back(allArgs[idx]);
- }
- } else {
- buildAndTestArg = false;
- }
- validArg = validArg || buildAndTestArg;
- return 1;
-}
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.h b/Source/CTest/cmCTestBuildAndTestHandler.h
deleted file mode 100644
index 60b3a11..0000000
--- a/Source/CTest/cmCTestBuildAndTestHandler.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* 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 <cstddef>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include "cmCTestGenericHandler.h"
-#include "cmDuration.h"
-
-class cmake;
-
-/** \class cmCTestBuildAndTestHandler
- * \brief A class that handles ctest -S invocations
- *
- */
-class cmCTestBuildAndTestHandler : public cmCTestGenericHandler
-{
-public:
- using Superclass = cmCTestGenericHandler;
-
- /*
- * The main entry point for this class
- */
- int ProcessHandler() override;
-
- //! Set all the build and test arguments
- int ProcessCommandLineArguments(const std::string& currentArg, size_t& idx,
- const std::vector<std::string>& allArgs,
- bool& validArg) override;
-
- /*
- * Get the output variable
- */
- const char* GetOutput();
-
- cmCTestBuildAndTestHandler();
-
- void Initialize() override;
-
-protected:
- //! Run CMake and build a test and then run it as a single test.
- int RunCMakeAndTest(std::string* output);
- int RunCMake(std::string* outstring, std::ostringstream& out,
- std::string& cmakeOutString, cmake* cm);
-
- std::string Output;
-
- std::string BuildGenerator;
- std::string BuildGeneratorPlatform;
- std::string BuildGeneratorToolset;
- std::vector<std::string> BuildOptions;
- bool BuildTwoConfig;
- std::string BuildMakeProgram;
- std::string ConfigSample;
- std::string SourceDir;
- std::string BinaryDir;
- std::string BuildProject;
- std::string TestCommand;
- bool BuildNoClean;
- std::string BuildRunDir;
- std::string ExecutableDirectory;
- std::vector<std::string> TestCommandArgs;
- std::vector<std::string> BuildTargets;
- bool BuildNoCMake;
- cmDuration Timeout;
-};
diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx
index d8ef195..b57c903 100644
--- a/Source/CTest/cmCTestBuildCommand.cxx
+++ b/Source/CTest/cmCTestBuildCommand.cxx
@@ -5,11 +5,14 @@
#include <sstream>
#include <utility>
+#include <cm/memory>
#include <cmext/string_view>
+#include "cmArgumentParser.h"
#include "cmCTest.h"
#include "cmCTestBuildHandler.h"
-#include "cmCommand.h"
+#include "cmCTestGenericHandler.h"
+#include "cmExecutionStatus.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
@@ -18,45 +21,37 @@
#include "cmValue.h"
#include "cmake.h"
-class cmExecutionStatus;
-
-std::unique_ptr<cmCommand> cmCTestBuildCommand::Clone()
+bool cmCTestBuildCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) const
{
- auto ni = cm::make_unique<cmCTestBuildCommand>();
- ni->CTest = this->CTest;
- ni->CTestScriptHandler = this->CTestScriptHandler;
- return std::unique_ptr<cmCommand>(std::move(ni));
+ static auto const parser =
+ cmArgumentParser<BuildArguments>{ MakeHandlerParser<BuildArguments>() }
+ .Bind("NUMBER_ERRORS"_s, &BuildArguments::NumberErrors)
+ .Bind("NUMBER_WARNINGS"_s, &BuildArguments::NumberWarnings)
+ .Bind("TARGET"_s, &BuildArguments::Target)
+ .Bind("CONFIGURATION"_s, &BuildArguments::Configuration)
+ .Bind("FLAGS"_s, &BuildArguments::Flags)
+ .Bind("PROJECT_NAME"_s, &BuildArguments::ProjectName)
+ .Bind("PARALLEL_LEVEL"_s, &BuildArguments::ParallelLevel);
+
+ return this->Invoke(parser, args, status, [&](BuildArguments& a) {
+ return this->ExecuteHandlerCommand(a, status);
+ });
}
-void cmCTestBuildCommand::BindArguments()
+std::unique_ptr<cmCTestGenericHandler> cmCTestBuildCommand::InitializeHandler(
+ HandlerArguments& arguments, cmExecutionStatus& status) const
{
- this->cmCTestHandlerCommand::BindArguments();
- this->Bind("NUMBER_ERRORS"_s, this->NumberErrors);
- this->Bind("NUMBER_WARNINGS"_s, this->NumberWarnings);
- this->Bind("TARGET"_s, this->Target);
- this->Bind("CONFIGURATION"_s, this->Configuration);
- this->Bind("FLAGS"_s, this->Flags);
- this->Bind("PROJECT_NAME"_s, this->ProjectName);
- this->Bind("PARALLEL_LEVEL"_s, this->ParallelLevel);
-}
+ cmMakefile& mf = status.GetMakefile();
+ auto const& args = static_cast<BuildArguments&>(arguments);
+ auto handler = cm::make_unique<cmCTestBuildHandler>(this->CTest);
-cmCTestBuildCommand::~cmCTestBuildCommand() = default;
-
-cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler()
-{
- cmCTestBuildHandler* handler = this->CTest->GetBuildHandler();
- handler->Initialize();
-
- this->Handler = handler;
-
- cmValue ctestBuildCommand =
- this->Makefile->GetDefinition("CTEST_BUILD_COMMAND");
+ cmValue ctestBuildCommand = mf.GetDefinition("CTEST_BUILD_COMMAND");
if (cmNonempty(ctestBuildCommand)) {
this->CTest->SetCTestConfiguration("MakeCommand", *ctestBuildCommand,
- this->Quiet);
+ args.Quiet);
} else {
- cmValue cmakeGeneratorName =
- this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR");
+ cmValue cmakeGeneratorName = mf.GetDefinition("CTEST_CMAKE_GENERATOR");
// Build configuration is determined by: CONFIGURATION argument,
// or CTEST_BUILD_CONFIGURATION script variable, or
@@ -64,54 +59,46 @@
// line argument... in that order.
//
cmValue ctestBuildConfiguration =
- this->Makefile->GetDefinition("CTEST_BUILD_CONFIGURATION");
- std::string cmakeBuildConfiguration = cmNonempty(this->Configuration)
- ? this->Configuration
+ mf.GetDefinition("CTEST_BUILD_CONFIGURATION");
+ std::string cmakeBuildConfiguration = cmNonempty(args.Configuration)
+ ? args.Configuration
: cmNonempty(ctestBuildConfiguration) ? *ctestBuildConfiguration
: this->CTest->GetConfigType();
- const std::string& cmakeBuildAdditionalFlags = cmNonempty(this->Flags)
- ? this->Flags
- : this->Makefile->GetSafeDefinition("CTEST_BUILD_FLAGS");
- const std::string& cmakeBuildTarget = cmNonempty(this->Target)
- ? this->Target
- : this->Makefile->GetSafeDefinition("CTEST_BUILD_TARGET");
+ const std::string& cmakeBuildAdditionalFlags = cmNonempty(args.Flags)
+ ? args.Flags
+ : mf.GetSafeDefinition("CTEST_BUILD_FLAGS");
+ const std::string& cmakeBuildTarget = cmNonempty(args.Target)
+ ? args.Target
+ : mf.GetSafeDefinition("CTEST_BUILD_TARGET");
if (cmNonempty(cmakeGeneratorName)) {
if (cmakeBuildConfiguration.empty()) {
cmakeBuildConfiguration = "Release";
}
- if (this->GlobalGenerator) {
- if (this->GlobalGenerator->GetName() != *cmakeGeneratorName) {
- this->GlobalGenerator.reset();
- }
- }
- if (!this->GlobalGenerator) {
- this->GlobalGenerator =
- this->Makefile->GetCMakeInstance()->CreateGlobalGenerator(
- *cmakeGeneratorName);
- if (!this->GlobalGenerator) {
- std::string e = cmStrCat("could not create generator named \"",
- *cmakeGeneratorName, '"');
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e);
- cmSystemTools::SetFatalErrorOccurred();
- return nullptr;
- }
+
+ auto globalGenerator =
+ mf.GetCMakeInstance()->CreateGlobalGenerator(*cmakeGeneratorName);
+ if (!globalGenerator) {
+ std::string e = cmStrCat("could not create generator named \"",
+ *cmakeGeneratorName, '"');
+ mf.IssueMessage(MessageType::FATAL_ERROR, e);
+ cmSystemTools::SetFatalErrorOccurred();
+ return nullptr;
}
if (cmakeBuildConfiguration.empty()) {
cmakeBuildConfiguration = "Debug";
}
std::string dir = this->CTest->GetCTestConfiguration("BuildDirectory");
- std::string buildCommand =
- this->GlobalGenerator->GenerateCMakeBuildCommand(
- cmakeBuildTarget, cmakeBuildConfiguration, this->ParallelLevel,
- cmakeBuildAdditionalFlags, this->Makefile->IgnoreErrorsCMP0061());
+ std::string buildCommand = globalGenerator->GenerateCMakeBuildCommand(
+ cmakeBuildTarget, cmakeBuildConfiguration, args.ParallelLevel,
+ cmakeBuildAdditionalFlags, mf.IgnoreErrorsCMP0061());
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"SetMakeCommand:" << buildCommand << "\n",
- this->Quiet);
+ args.Quiet);
this->CTest->SetCTestConfiguration("MakeCommand", buildCommand,
- this->Quiet);
+ args.Quiet);
} else {
std::ostringstream ostr;
/* clang-format off */
@@ -120,38 +107,39 @@
"is set. Otherwise, set CTEST_BUILD_COMMAND to build the project "
"with a custom command line.";
/* clang-format on */
- this->SetError(ostr.str());
+ status.SetError(ostr.str());
return nullptr;
}
}
- if (cmValue useLaunchers =
- this->Makefile->GetDefinition("CTEST_USE_LAUNCHERS")) {
+ if (cmValue useLaunchers = mf.GetDefinition("CTEST_USE_LAUNCHERS")) {
this->CTest->SetCTestConfiguration("UseLaunchers", *useLaunchers,
- this->Quiet);
+ args.Quiet);
}
if (cmValue labelsForSubprojects =
- this->Makefile->GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
+ mf.GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
this->CTest->SetCTestConfiguration("LabelsForSubprojects",
- *labelsForSubprojects, this->Quiet);
+ *labelsForSubprojects, args.Quiet);
}
- handler->SetQuiet(this->Quiet);
- return handler;
+ handler->SetQuiet(args.Quiet);
+ return std::unique_ptr<cmCTestGenericHandler>(std::move(handler));
}
-bool cmCTestBuildCommand::InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& status)
+void cmCTestBuildCommand::ProcessAdditionalValues(
+ cmCTestGenericHandler* generic, HandlerArguments const& arguments,
+ cmExecutionStatus& status) const
{
- bool ret = this->cmCTestHandlerCommand::InitialPass(args, status);
- if (!this->NumberErrors.empty()) {
- this->Makefile->AddDefinition(
- this->NumberErrors, std::to_string(this->Handler->GetTotalErrors()));
+ cmMakefile& mf = status.GetMakefile();
+ auto const& args = static_cast<BuildArguments const&>(arguments);
+ auto const* handler = static_cast<cmCTestBuildHandler*>(generic);
+ if (!args.NumberErrors.empty()) {
+ mf.AddDefinition(args.NumberErrors,
+ std::to_string(handler->GetTotalErrors()));
}
- if (!this->NumberWarnings.empty()) {
- this->Makefile->AddDefinition(
- this->NumberWarnings, std::to_string(this->Handler->GetTotalWarnings()));
+ if (!args.NumberWarnings.empty()) {
+ mf.AddDefinition(args.NumberWarnings,
+ std::to_string(handler->GetTotalWarnings()));
}
- return ret;
}
diff --git a/Source/CTest/cmCTestBuildCommand.h b/Source/CTest/cmCTestBuildCommand.h
index 3b7f4f9..a23966d 100644
--- a/Source/CTest/cmCTestBuildCommand.h
+++ b/Source/CTest/cmCTestBuildCommand.h
@@ -4,54 +4,42 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <memory>
#include <string>
#include <vector>
-#include <cm/memory>
-
#include "cmCTestHandlerCommand.h"
-class cmCommand;
-class cmCTestBuildHandler;
-class cmCTestGenericHandler;
class cmExecutionStatus;
-class cmGlobalGenerator;
+class cmCTestGenericHandler;
-/** \class cmCTestBuild
- * \brief Run a ctest script
- *
- * cmCTestBuildCommand defineds the command to build the project.
- */
class cmCTestBuildCommand : public cmCTestHandlerCommand
{
public:
- ~cmCTestBuildCommand() override;
-
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override;
-
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- std::string GetName() const override { return "ctest_build"; }
-
- bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& status) override;
-
- std::unique_ptr<cmGlobalGenerator> GlobalGenerator;
+ using cmCTestHandlerCommand::cmCTestHandlerCommand;
protected:
- cmCTestBuildHandler* Handler;
- void BindArguments() override;
- cmCTestGenericHandler* InitializeHandler() override;
+ struct BuildArguments : HandlerArguments
+ {
+ std::string NumberErrors;
+ std::string NumberWarnings;
+ std::string Target;
+ std::string Configuration;
+ std::string Flags;
+ std::string ProjectName;
+ std::string ParallelLevel;
+ };
- std::string NumberErrors;
- std::string NumberWarnings;
- std::string Target;
- std::string Configuration;
- std::string Flags;
- std::string ProjectName;
- std::string ParallelLevel;
+private:
+ std::string GetName() const override { return "ctest_build"; }
+
+ std::unique_ptr<cmCTestGenericHandler> InitializeHandler(
+ HandlerArguments& arguments, cmExecutionStatus& status) const override;
+
+ void ProcessAdditionalValues(cmCTestGenericHandler* handler,
+ HandlerArguments const& arguments,
+ cmExecutionStatus& status) const override;
+
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) const override;
};
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index e962cc7..d5d269e 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -176,62 +176,10 @@
{ nullptr, 0, 0 }
};
-cmCTestBuildHandler::cmCTestBuildHandler()
+cmCTestBuildHandler::cmCTestBuildHandler(cmCTest* ctest)
+ : Superclass(ctest)
+ , LastErrorOrWarning(this->ErrorsAndWarnings.end())
{
- this->MaxPreContext = 10;
- this->MaxPostContext = 10;
-
- this->MaxErrors = 50;
- this->MaxWarnings = 50;
-
- this->LastErrorOrWarning = this->ErrorsAndWarnings.end();
-
- this->UseCTestLaunch = false;
-}
-
-void cmCTestBuildHandler::Initialize()
-{
- this->Superclass::Initialize();
- this->StartBuild.clear();
- this->EndBuild.clear();
- this->CustomErrorMatches.clear();
- this->CustomErrorExceptions.clear();
- this->CustomWarningMatches.clear();
- this->CustomWarningExceptions.clear();
- this->ReallyCustomWarningMatches.clear();
- this->ReallyCustomWarningExceptions.clear();
- this->ErrorWarningFileLineRegex.clear();
-
- this->ErrorMatchRegex.clear();
- this->ErrorExceptionRegex.clear();
- this->WarningMatchRegex.clear();
- this->WarningExceptionRegex.clear();
- this->BuildProcessingQueue.clear();
- this->BuildProcessingErrorQueue.clear();
- this->BuildOutputLogSize = 0;
- this->CurrentProcessingLine.clear();
-
- this->SimplifySourceDir.clear();
- this->SimplifyBuildDir.clear();
- this->OutputLineCounter = 0;
- this->ErrorsAndWarnings.clear();
- this->LastErrorOrWarning = this->ErrorsAndWarnings.end();
- this->PostContextCount = 0;
- this->MaxPreContext = 10;
- this->MaxPostContext = 10;
- this->PreContext.clear();
-
- this->TotalErrors = 0;
- this->TotalWarnings = 0;
- this->LastTickChar = 0;
-
- this->ErrorQuotaReached = false;
- this->WarningQuotaReached = false;
-
- this->MaxErrors = 50;
- this->MaxWarnings = 50;
-
- this->UseCTestLaunch = false;
}
void cmCTestBuildHandler::PopulateCustomVectors(cmMakefile* mf)
@@ -502,7 +450,7 @@
void cmCTestBuildHandler::GenerateXMLHeader(cmXMLWriter& xml)
{
- this->CTest->StartXML(xml, this->AppendXML);
+ this->CTest->StartXML(xml, this->CMake, this->AppendXML);
this->CTest->GenerateSubprojectsOutput(xml);
xml.StartElement("Build");
xml.Element("StartDateTime", this->StartBuild);
@@ -580,9 +528,6 @@
int numErrorsAllowed = this->MaxErrors;
int numWarningsAllowed = this->MaxWarnings;
std::string srcdir = this->CTest->GetCTestConfiguration("SourceDirectory");
- // make sure the source dir is in the correct case on windows
- // via a call to collapse full path.
- srcdir = cmStrCat(cmSystemTools::CollapseFullPath(srcdir), '/');
for (it = ew.begin();
it != ew.end() && (numErrorsAllowed || numWarningsAllowed); it++) {
cmCTestBuildErrorWarning* cm = &(*it);
@@ -613,8 +558,9 @@
}
} else {
// make sure it is a full path with the correct case
- cm->SourceFile = cmSystemTools::CollapseFullPath(cm->SourceFile);
- cmSystemTools::ReplaceString(cm->SourceFile, srcdir.c_str(), "");
+ cm->SourceFile =
+ cmSystemTools::ToNormalizedPathOnDisk(cm->SourceFile);
+ cmSystemTools::ReplaceString(cm->SourceFile, srcdir, "");
}
cm->LineNumber = atoi(re->match(rit.LineIndex).c_str());
break;
diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h
index 90945b1..98fe2da 100644
--- a/Source/CTest/cmCTestBuildHandler.h
+++ b/Source/CTest/cmCTestBuildHandler.h
@@ -20,6 +20,7 @@
class cmMakefile;
class cmStringReplaceHelper;
class cmXMLWriter;
+class cmCTest;
/** \class cmCTestBuildHandler
* \brief A class that handles ctest -S invocations
@@ -36,17 +37,12 @@
*/
int ProcessHandler() override;
- cmCTestBuildHandler();
+ cmCTestBuildHandler(cmCTest* ctest);
void PopulateCustomVectors(cmMakefile* mf) override;
- /**
- * Initialize handler
- */
- void Initialize() override;
-
- int GetTotalErrors() { return this->TotalErrors; }
- int GetTotalWarnings() { return this->TotalWarnings; }
+ int GetTotalErrors() const { return this->TotalErrors; }
+ int GetTotalWarnings() const { return this->TotalWarnings; }
private:
std::string GetMakeCommand();
@@ -120,34 +116,34 @@
t_BuildProcessingQueueType BuildProcessingQueue;
t_BuildProcessingQueueType BuildProcessingErrorQueue;
- size_t BuildOutputLogSize;
+ size_t BuildOutputLogSize = 0;
std::vector<char> CurrentProcessingLine;
std::string SimplifySourceDir;
std::string SimplifyBuildDir;
- size_t OutputLineCounter;
+ size_t OutputLineCounter = 0;
using t_ErrorsAndWarningsVector = std::vector<cmCTestBuildErrorWarning>;
t_ErrorsAndWarningsVector ErrorsAndWarnings;
t_ErrorsAndWarningsVector::iterator LastErrorOrWarning;
- size_t PostContextCount;
- size_t MaxPreContext;
- size_t MaxPostContext;
+ size_t PostContextCount = 0;
+ size_t MaxPreContext = 10;
+ size_t MaxPostContext = 10;
std::deque<std::string> PreContext;
- int TotalErrors;
- int TotalWarnings;
- char LastTickChar;
+ int TotalErrors = 0;
+ int TotalWarnings = 0;
+ char LastTickChar = '\0';
- bool ErrorQuotaReached;
- bool WarningQuotaReached;
+ bool ErrorQuotaReached = false;
+ bool WarningQuotaReached = false;
- int MaxErrors;
- int MaxWarnings;
+ int MaxErrors = 50;
+ int MaxWarnings = 50;
// Used to remove ANSI color codes before checking for errors and warnings.
cmStringReplaceHelper* ColorRemover;
- bool UseCTestLaunch;
+ bool UseCTestLaunch = false;
std::string CTestLaunchDir;
class LaunchHelper;
diff --git a/Source/CTest/cmCTestCommand.cxx b/Source/CTest/cmCTestCommand.cxx
new file mode 100644
index 0000000..6ecd18b
--- /dev/null
+++ b/Source/CTest/cmCTestCommand.cxx
@@ -0,0 +1,19 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCTestCommand.h"
+
+#include "cmExecutionStatus.h"
+#include "cmMakefile.h"
+
+bool cmCTestCommand::operator()(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status) const
+{
+ cmMakefile& mf = status.GetMakefile();
+ std::vector<std::string> expandedArguments;
+ if (!mf.ExpandArguments(args, expandedArguments)) {
+ // There was an error expanding arguments. It was already
+ // reported, so we can skip this command without error.
+ return true;
+ }
+ return this->InitialPass(expandedArguments, status);
+}
diff --git a/Source/CTest/cmCTestCommand.h b/Source/CTest/cmCTestCommand.h
index 007378d..777910a 100644
--- a/Source/CTest/cmCTestCommand.h
+++ b/Source/CTest/cmCTestCommand.h
@@ -2,10 +2,14 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
-#include "cmCommand.h"
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
class cmCTest;
-class cmCTestScriptHandler;
+class cmExecutionStatus;
+struct cmListFileArgument;
/** \class cmCTestCommand
* \brief A superclass for all commands added to the CTestScriptHandler
@@ -14,15 +18,25 @@
* the ctest script handlers parser.
*
*/
-class cmCTestCommand : public cmCommand
+class cmCTestCommand
{
public:
- cmCTestCommand()
+ cmCTestCommand(cmCTest* ctest)
+ : CTest(ctest)
{
- this->CTest = nullptr;
- this->CTestScriptHandler = nullptr;
}
- cmCTest* CTest;
- cmCTestScriptHandler* CTestScriptHandler;
+ virtual ~cmCTestCommand() = default;
+ cmCTestCommand(cmCTestCommand const&) = default;
+ cmCTestCommand& operator=(cmCTestCommand const&) = default;
+
+ bool operator()(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status) const;
+
+private:
+ virtual bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus&) const = 0;
+
+protected:
+ cmCTest* CTest = nullptr;
};
diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx
index e0326a9..6255416 100644
--- a/Source/CTest/cmCTestConfigureCommand.cxx
+++ b/Source/CTest/cmCTestConfigureCommand.cxx
@@ -4,12 +4,17 @@
#include <cstring>
#include <sstream>
+#include <utility>
#include <vector>
+#include <cm/memory>
#include <cmext/string_view>
+#include "cmArgumentParser.h"
#include "cmCTest.h"
#include "cmCTestConfigureHandler.h"
+#include "cmCTestGenericHandler.h"
+#include "cmExecutionStatus.h"
#include "cmGlobalGenerator.h"
#include "cmList.h"
#include "cmMakefile.h"
@@ -18,42 +23,38 @@
#include "cmValue.h"
#include "cmake.h"
-void cmCTestConfigureCommand::BindArguments()
+std::unique_ptr<cmCTestGenericHandler>
+cmCTestConfigureCommand::InitializeHandler(HandlerArguments& arguments,
+ cmExecutionStatus& status) const
{
- this->cmCTestHandlerCommand::BindArguments();
- this->Bind("OPTIONS"_s, this->Options);
-}
-
-cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler()
-{
+ cmMakefile& mf = status.GetMakefile();
+ auto const& args = static_cast<ConfigureArguments&>(arguments);
cmList options;
- if (!this->Options.empty()) {
- options.assign(this->Options);
+ if (!args.Options.empty()) {
+ options.assign(args.Options);
}
if (this->CTest->GetCTestConfiguration("BuildDirectory").empty()) {
- this->SetError(
+ status.SetError(
"Build directory not specified. Either use BUILD "
"argument to CTEST_CONFIGURE command or set CTEST_BINARY_DIRECTORY "
"variable");
return nullptr;
}
- cmValue ctestConfigureCommand =
- this->Makefile->GetDefinition("CTEST_CONFIGURE_COMMAND");
+ cmValue ctestConfigureCommand = mf.GetDefinition("CTEST_CONFIGURE_COMMAND");
if (cmNonempty(ctestConfigureCommand)) {
this->CTest->SetCTestConfiguration("ConfigureCommand",
- *ctestConfigureCommand, this->Quiet);
+ *ctestConfigureCommand, args.Quiet);
} else {
- cmValue cmakeGeneratorName =
- this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR");
+ cmValue cmakeGeneratorName = mf.GetDefinition("CTEST_CMAKE_GENERATOR");
if (cmNonempty(cmakeGeneratorName)) {
const std::string& source_dir =
this->CTest->GetCTestConfiguration("SourceDirectory");
if (source_dir.empty()) {
- this->SetError(
+ status.SetError(
"Source directory not specified. Either use SOURCE "
"argument to CTEST_CONFIGURE command or set CTEST_SOURCE_DIRECTORY "
"variable");
@@ -64,15 +65,15 @@
if (!cmSystemTools::FileExists(cmakelists_file)) {
std::ostringstream e;
e << "CMakeLists.txt file does not exist [" << cmakelists_file << "]";
- this->SetError(e.str());
+ status.SetError(e.str());
return nullptr;
}
bool multiConfig = false;
bool cmakeBuildTypeInOptions = false;
- auto gg = this->Makefile->GetCMakeInstance()->CreateGlobalGenerator(
- *cmakeGeneratorName);
+ auto gg =
+ mf.GetCMakeInstance()->CreateGlobalGenerator(*cmakeGeneratorName);
if (gg) {
multiConfig = gg->IsMultiConfig();
gg.reset();
@@ -99,7 +100,7 @@
cmakeConfigureCommand += "\"";
}
- if (this->Makefile->IsOn("CTEST_USE_LAUNCHERS")) {
+ if (mf.IsOn("CTEST_USE_LAUNCHERS")) {
cmakeConfigureCommand += " \"-DCTEST_USE_LAUNCHERS:BOOL=TRUE\"";
}
@@ -108,7 +109,7 @@
cmakeConfigureCommand += "\"";
cmValue cmakeGeneratorPlatform =
- this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR_PLATFORM");
+ mf.GetDefinition("CTEST_CMAKE_GENERATOR_PLATFORM");
if (cmNonempty(cmakeGeneratorPlatform)) {
cmakeConfigureCommand += " \"-A";
cmakeConfigureCommand += *cmakeGeneratorPlatform;
@@ -116,7 +117,7 @@
}
cmValue cmakeGeneratorToolset =
- this->Makefile->GetDefinition("CTEST_CMAKE_GENERATOR_TOOLSET");
+ mf.GetDefinition("CTEST_CMAKE_GENERATOR_TOOLSET");
if (cmNonempty(cmakeGeneratorToolset)) {
cmakeConfigureCommand += " \"-T";
cmakeConfigureCommand += *cmakeGeneratorToolset;
@@ -133,9 +134,9 @@
cmakeConfigureCommand += "\"";
this->CTest->SetCTestConfiguration("ConfigureCommand",
- cmakeConfigureCommand, this->Quiet);
+ cmakeConfigureCommand, args.Quiet);
} else {
- this->SetError(
+ status.SetError(
"Configure command is not specified. If this is a "
"\"built with CMake\" project, set CTEST_CMAKE_GENERATOR. If not, "
"set CTEST_CONFIGURE_COMMAND.");
@@ -144,13 +145,25 @@
}
if (cmValue labelsForSubprojects =
- this->Makefile->GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
+ mf.GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
this->CTest->SetCTestConfiguration("LabelsForSubprojects",
- *labelsForSubprojects, this->Quiet);
+ *labelsForSubprojects, args.Quiet);
}
- cmCTestConfigureHandler* handler = this->CTest->GetConfigureHandler();
- handler->Initialize();
- handler->SetQuiet(this->Quiet);
- return handler;
+ auto handler = cm::make_unique<cmCTestConfigureHandler>(this->CTest);
+ handler->SetQuiet(args.Quiet);
+ return std::unique_ptr<cmCTestGenericHandler>(std::move(handler));
+}
+
+bool cmCTestConfigureCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) const
+{
+ using Args = ConfigureArguments;
+ static auto const parser =
+ cmArgumentParser<Args>{ MakeHandlerParser<Args>() } //
+ .Bind("OPTIONS"_s, &ConfigureArguments::Options);
+
+ return this->Invoke(parser, args, status, [&](ConfigureArguments& a) {
+ return this->ExecuteHandlerCommand(a, status);
+ });
}
diff --git a/Source/CTest/cmCTestConfigureCommand.h b/Source/CTest/cmCTestConfigureCommand.h
index f338637..c2c6b3a 100644
--- a/Source/CTest/cmCTestConfigureCommand.h
+++ b/Source/CTest/cmCTestConfigureCommand.h
@@ -4,43 +4,32 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <memory>
#include <string>
-#include <utility>
-
-#include <cm/memory>
+#include <vector>
#include "cmCTestHandlerCommand.h"
-#include "cmCommand.h"
+class cmExecutionStatus;
class cmCTestGenericHandler;
-/** \class cmCTestConfigure
- * \brief Run a ctest script
- *
- * cmCTestConfigureCommand defineds the command to configures the project.
- */
class cmCTestConfigureCommand : public cmCTestHandlerCommand
{
public:
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- auto ni = cm::make_unique<cmCTestConfigureCommand>();
- ni->CTest = this->CTest;
- ni->CTestScriptHandler = this->CTestScriptHandler;
- return std::unique_ptr<cmCommand>(std::move(ni));
- }
-
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- std::string GetName() const override { return "ctest_configure"; }
+ using cmCTestHandlerCommand::cmCTestHandlerCommand;
protected:
- void BindArguments() override;
- cmCTestGenericHandler* InitializeHandler() override;
+ struct ConfigureArguments : HandlerArguments
+ {
+ std::string Options;
+ };
- std::string Options;
+private:
+ std::string GetName() const override { return "ctest_configure"; }
+
+ std::unique_ptr<cmCTestGenericHandler> InitializeHandler(
+ HandlerArguments& arguments, cmExecutionStatus& status) const override;
+
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) const override;
};
diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx
index dd8952f..35b6dce 100644
--- a/Source/CTest/cmCTestConfigureHandler.cxx
+++ b/Source/CTest/cmCTestConfigureHandler.cxx
@@ -11,11 +11,9 @@
#include "cmGeneratedFileStream.h"
#include "cmXMLWriter.h"
-cmCTestConfigureHandler::cmCTestConfigureHandler() = default;
-
-void cmCTestConfigureHandler::Initialize()
+cmCTestConfigureHandler::cmCTestConfigureHandler(cmCTest* ctest)
+ : Superclass(ctest)
{
- this->Superclass::Initialize();
}
// clearly it would be nice if this were broken up into a few smaller
@@ -71,7 +69,7 @@
if (os) {
cmXMLWriter xml(os);
- this->CTest->StartXML(xml, this->AppendXML);
+ this->CTest->StartXML(xml, this->CMake, this->AppendXML);
this->CTest->GenerateSubprojectsOutput(xml);
xml.StartElement("Configure");
xml.Element("StartDateTime", start_time);
diff --git a/Source/CTest/cmCTestConfigureHandler.h b/Source/CTest/cmCTestConfigureHandler.h
index 2aad98c..bcbead7 100644
--- a/Source/CTest/cmCTestConfigureHandler.h
+++ b/Source/CTest/cmCTestConfigureHandler.h
@@ -6,6 +6,8 @@
#include "cmCTestGenericHandler.h"
+class cmCTest;
+
/** \class cmCTestConfigureHandler
* \brief A class that handles ctest -S invocations
*
@@ -20,7 +22,5 @@
*/
int ProcessHandler() override;
- cmCTestConfigureHandler();
-
- void Initialize() override;
+ cmCTestConfigureHandler(cmCTest* ctest);
};
diff --git a/Source/CTest/cmCTestCoverageCommand.cxx b/Source/CTest/cmCTestCoverageCommand.cxx
index 97b0a89..6bed1a3 100644
--- a/Source/CTest/cmCTestCoverageCommand.cxx
+++ b/Source/CTest/cmCTestCoverageCommand.cxx
@@ -3,36 +3,50 @@
#include "cmCTestCoverageCommand.h"
#include <set>
+#include <utility>
+#include <cm/memory>
#include <cmext/string_view>
+#include "cmArgumentParser.h"
#include "cmCTest.h"
#include "cmCTestCoverageHandler.h"
+#include "cmCTestGenericHandler.h"
+#include "cmExecutionStatus.h"
-class cmCTestGenericHandler;
+class cmMakefile;
-void cmCTestCoverageCommand::BindArguments()
+std::unique_ptr<cmCTestGenericHandler>
+cmCTestCoverageCommand::InitializeHandler(HandlerArguments& arguments,
+ cmExecutionStatus& status) const
{
- this->cmCTestHandlerCommand::BindArguments();
- this->Bind("LABELS"_s, this->Labels);
-}
-
-cmCTestGenericHandler* cmCTestCoverageCommand::InitializeHandler()
-{
+ cmMakefile& mf = status.GetMakefile();
+ auto& args = static_cast<CoverageArguments&>(arguments);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "CoverageCommand", "CTEST_COVERAGE_COMMAND", this->Quiet);
+ &mf, "CoverageCommand", "CTEST_COVERAGE_COMMAND", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "CoverageExtraFlags", "CTEST_COVERAGE_EXTRA_FLAGS",
- this->Quiet);
- cmCTestCoverageHandler* handler = this->CTest->GetCoverageHandler();
- handler->Initialize();
+ &mf, "CoverageExtraFlags", "CTEST_COVERAGE_EXTRA_FLAGS", args.Quiet);
+ auto handler = cm::make_unique<cmCTestCoverageHandler>(this->CTest);
// If a LABELS option was given, select only files with the labels.
- if (this->Labels) {
+ if (args.Labels) {
handler->SetLabelFilter(
- std::set<std::string>(this->Labels->begin(), this->Labels->end()));
+ std::set<std::string>(args.Labels->begin(), args.Labels->end()));
}
- handler->SetQuiet(this->Quiet);
- return handler;
+ handler->SetQuiet(args.Quiet);
+ return std::unique_ptr<cmCTestGenericHandler>(std::move(handler));
+}
+
+bool cmCTestCoverageCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) const
+{
+ using Args = CoverageArguments;
+ static auto const parser =
+ cmArgumentParser<Args>{ MakeHandlerParser<Args>() } //
+ .Bind("LABELS"_s, &CoverageArguments::Labels);
+
+ return this->Invoke(parser, args, status, [&](CoverageArguments& a) {
+ return this->ExecuteHandlerCommand(a, status);
+ });
}
diff --git a/Source/CTest/cmCTestCoverageCommand.h b/Source/CTest/cmCTestCoverageCommand.h
index 55c68b2..dfbb9be 100644
--- a/Source/CTest/cmCTestCoverageCommand.h
+++ b/Source/CTest/cmCTestCoverageCommand.h
@@ -4,46 +4,35 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <memory>
#include <string>
-#include <utility>
#include <vector>
-#include <cm/memory>
#include <cm/optional>
#include "cmArgumentParserTypes.h" // IWYU pragma: keep
#include "cmCTestHandlerCommand.h"
-#include "cmCommand.h"
+class cmExecutionStatus;
class cmCTestGenericHandler;
-/** \class cmCTestCoverage
- * \brief Run a ctest script
- *
- * cmCTestCoverageCommand defineds the command to test the project.
- */
class cmCTestCoverageCommand : public cmCTestHandlerCommand
{
public:
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- auto ni = cm::make_unique<cmCTestCoverageCommand>();
- ni->CTest = this->CTest;
- ni->CTestScriptHandler = this->CTestScriptHandler;
- return std::unique_ptr<cmCommand>(std::move(ni));
- }
-
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- std::string GetName() const override { return "ctest_coverage"; }
+ using cmCTestHandlerCommand::cmCTestHandlerCommand;
protected:
- void BindArguments() override;
- cmCTestGenericHandler* InitializeHandler() override;
+ struct CoverageArguments : HandlerArguments
+ {
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Labels;
+ };
- cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Labels;
+private:
+ std::string GetName() const override { return "ctest_coverage"; }
+
+ std::unique_ptr<cmCTestGenericHandler> InitializeHandler(
+ HandlerArguments& arguments, cmExecutionStatus& status) const override;
+
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) const override;
};
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index cec4a7e..2e63fc8 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -6,7 +6,6 @@
#include <chrono>
#include <cstdio>
#include <cstdlib>
-#include <cstring>
#include <iomanip>
#include <iterator>
#include <memory>
@@ -41,17 +40,9 @@
#define SAFEDIV(x, y) (((y) != 0) ? ((x) / (y)) : (0))
-cmCTestCoverageHandler::cmCTestCoverageHandler() = default;
-
-void cmCTestCoverageHandler::Initialize()
+cmCTestCoverageHandler::cmCTestCoverageHandler(cmCTest* ctest)
+ : Superclass(ctest)
{
- this->Superclass::Initialize();
- this->CustomCoverageExclude.clear();
- this->SourceLabels.clear();
- this->TargetDirs.clear();
- this->LabelIdMap.clear();
- this->Labels.clear();
- this->LabelFilter.clear();
}
void cmCTestCoverageHandler::CleanCoverageLogFiles(std::ostream& log)
@@ -100,7 +91,7 @@
void cmCTestCoverageHandler::StartCoverageLogXML(cmXMLWriter& xml)
{
- this->CTest->StartXML(xml, this->AppendXML);
+ this->CTest->StartXML(xml, this->CMake, this->AppendXML);
xml.StartElement("CoverageLog");
xml.Element("StartDateTime", this->CTest->CurrentTime());
xml.Element("StartTime", std::chrono::system_clock::now());
@@ -331,7 +322,7 @@
covSumFile.setf(std::ios::fixed, std::ios::floatfield);
covSumFile.precision(2);
- this->CTest->StartXML(covSumXML, this->AppendXML);
+ this->CTest->StartXML(covSumXML, this->CMake, this->AppendXML);
// Produce output xml files
covSumXML.StartElement("Coverage");
@@ -1325,10 +1316,7 @@
std::string fileDir = cmSystemTools::GetFilenamePath(f);
cmWorkingDirectory workdir(fileDir);
if (workdir.Failed()) {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Unable to change working directory to "
- << fileDir << " : "
- << std::strerror(workdir.GetLastResult()) << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE, workdir.GetError() << std::endl);
cont->Error++;
continue;
}
@@ -1550,9 +1538,7 @@
std::string buildDir = this->CTest->GetCTestConfiguration("BuildDirectory");
cmWorkingDirectory workdir(buildDir);
if (workdir.Failed()) {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Unable to change working directory to " << buildDir
- << std::endl);
+ cmCTestLog(this->CTest, ERROR_MESSAGE, workdir.GetError() << std::endl);
return false;
}
@@ -1915,7 +1901,7 @@
"Cannot open coverage summary file." << std::endl);
return 0;
}
- this->CTest->StartXML(xml, this->AppendXML);
+ this->CTest->StartXML(xml, this->CMake, this->AppendXML);
auto elapsed_time_start = std::chrono::steady_clock::now();
std::string coverage_start_time = this->CTest->CurrentTime();
xml.StartElement("Coverage");
diff --git a/Source/CTest/cmCTestCoverageHandler.h b/Source/CTest/cmCTestCoverageHandler.h
index 8732723..89969ce 100644
--- a/Source/CTest/cmCTestCoverageHandler.h
+++ b/Source/CTest/cmCTestCoverageHandler.h
@@ -17,6 +17,7 @@
class cmGeneratedFileStream;
class cmMakefile;
class cmXMLWriter;
+class cmCTest;
class cmCTestCoverageHandlerContainer
{
@@ -44,9 +45,7 @@
*/
int ProcessHandler() override;
- cmCTestCoverageHandler();
-
- void Initialize() override;
+ cmCTestCoverageHandler(cmCTest* ctest);
/**
* This method is called when reading CTest custom file
diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
index 2c92d77..5ae89a1 100644
--- a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
+++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
@@ -2,22 +2,98 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestEmptyBinaryDirectoryCommand.h"
-#include "cmCTestScriptHandler.h"
+#include "cmsys/Directory.hxx"
+
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
-bool cmCTestEmptyBinaryDirectoryCommand::InitialPass(
- std::vector<std::string> const& args, cmExecutionStatus& status)
+namespace {
+
+// Try to remove the binary directory once
+cmsys::Status TryToRemoveBinaryDirectoryOnce(const std::string& directoryPath)
+{
+ cmsys::Directory directory;
+ directory.Load(directoryPath);
+
+ // Make sure that CMakeCache.txt is deleted last.
+ for (unsigned long i = 0; i < directory.GetNumberOfFiles(); ++i) {
+ std::string path = directory.GetFile(i);
+
+ if (path == "." || path == ".." || path == "CMakeCache.txt") {
+ continue;
+ }
+
+ std::string fullPath = cmStrCat(directoryPath, "/", path);
+
+ bool isDirectory = cmSystemTools::FileIsDirectory(fullPath) &&
+ !cmSystemTools::FileIsSymlink(fullPath);
+
+ cmsys::Status status;
+ if (isDirectory) {
+ status = cmSystemTools::RemoveADirectory(fullPath);
+ } else {
+ status = cmSystemTools::RemoveFile(fullPath);
+ }
+ if (!status) {
+ return status;
+ }
+ }
+
+ return cmSystemTools::RemoveADirectory(directoryPath);
+}
+
+/*
+ * Empty Binary Directory
+ */
+bool EmptyBinaryDirectory(const std::string& sname, std::string& err)
+{
+ // try to avoid deleting root
+ if (sname.size() < 2) {
+ err = "path too short";
+ return false;
+ }
+
+ // consider non existing target directory a success
+ if (!cmSystemTools::FileExists(sname)) {
+ return true;
+ }
+
+ // try to avoid deleting directories that we shouldn't
+ std::string check = cmStrCat(sname, "/CMakeCache.txt");
+
+ if (!cmSystemTools::FileExists(check)) {
+ err = "path does not contain an existing CMakeCache.txt file";
+ return false;
+ }
+
+ cmsys::Status status;
+ for (int i = 0; i < 5; ++i) {
+ status = TryToRemoveBinaryDirectoryOnce(sname);
+ if (status) {
+ return true;
+ }
+ cmSystemTools::Delay(100);
+ }
+
+ err = status.GetString();
+ return false;
+}
+
+} // namespace
+
+bool cmCTestEmptyBinaryDirectoryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
{
if (args.size() != 1) {
- this->SetError("called with incorrect number of arguments");
+ status.SetError("called with incorrect number of arguments");
return false;
}
std::string err;
- if (!cmCTestScriptHandler::EmptyBinaryDirectory(args[0], err)) {
+ if (!EmptyBinaryDirectory(args[0], err)) {
status.GetMakefile().IssueMessage(
MessageType::FATAL_ERROR,
cmStrCat("Did not remove the binary directory:\n ", args[0],
diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h
index ba2b0eb..d19ae98 100644
--- a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h
+++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.h
@@ -5,42 +5,9 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <string>
-#include <utility>
#include <vector>
-#include <cm/memory>
-
-#include "cmCTestCommand.h"
-#include "cmCommand.h"
-
class cmExecutionStatus;
-/** \class cmCTestEmptyBinaryDirectory
- * \brief Run a ctest script
- *
- * cmLibrarysCommand defines a list of executable (i.e., test)
- * programs to create.
- */
-class cmCTestEmptyBinaryDirectoryCommand : public cmCTestCommand
-{
-public:
- cmCTestEmptyBinaryDirectoryCommand() {}
-
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- auto ni = cm::make_unique<cmCTestEmptyBinaryDirectoryCommand>();
- ni->CTest = this->CTest;
- ni->CTestScriptHandler = this->CTestScriptHandler;
- return std::unique_ptr<cmCommand>(std::move(ni));
- }
-
- /**
- * This is called when the command is first encountered in
- * the CMakeLists.txt file.
- */
- bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& status) override;
-};
+bool cmCTestEmptyBinaryDirectoryCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx
index 99c5a2b..3a5ec04 100644
--- a/Source/CTest/cmCTestGIT.cxx
+++ b/Source/CTest/cmCTestGIT.cxx
@@ -146,7 +146,7 @@
!cdup.empty()) {
top_dir += "/";
top_dir += cdup;
- top_dir = cmSystemTools::CollapseFullPath(top_dir);
+ top_dir = cmSystemTools::ToNormalizedPathOnDisk(top_dir);
}
return top_dir;
}
diff --git a/Source/CTest/cmCTestGenericHandler.cxx b/Source/CTest/cmCTestGenericHandler.cxx
index dd69968..e4acbef 100644
--- a/Source/CTest/cmCTestGenericHandler.cxx
+++ b/Source/CTest/cmCTestGenericHandler.cxx
@@ -3,113 +3,20 @@
#include "cmCTestGenericHandler.h"
#include <sstream>
-#include <utility>
#include "cmCTest.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
-cmCTestGenericHandler::cmCTestGenericHandler()
+cmCTestGenericHandler::cmCTestGenericHandler(cmCTest* ctest)
+ : CTest(ctest)
{
- this->HandlerVerbose = cmSystemTools::OUTPUT_NONE;
- this->CTest = nullptr;
- this->SubmitIndex = 0;
- this->AppendXML = false;
- this->Quiet = false;
- this->TestLoad = 0;
+ this->SetVerbose(ctest->GetExtraVerbose());
+ this->SetSubmitIndex(ctest->GetSubmitIndex());
}
cmCTestGenericHandler::~cmCTestGenericHandler() = default;
-namespace {
-/* Modify the given `map`, setting key `op` to `value` if `value`
- * is non-null, otherwise removing key `op` (if it exists).
- */
-void SetMapValue(cmCTestGenericHandler::t_StringToString& map,
- const std::string& op, const std::string& value)
-{
- map[op] = value;
-}
-void SetMapValue(cmCTestGenericHandler::t_StringToString& map,
- const std::string& op, cmValue value)
-{
- if (!value) {
- map.erase(op);
- return;
- }
-
- map[op] = *value;
-}
-}
-
-void cmCTestGenericHandler::SetOption(const std::string& op,
- const std::string& value)
-{
- SetMapValue(this->Options, op, value);
-}
-void cmCTestGenericHandler::SetOption(const std::string& op, cmValue value)
-{
- SetMapValue(this->Options, op, value);
-}
-
-void cmCTestGenericHandler::SetPersistentOption(const std::string& op,
- const std::string& value)
-{
- this->SetOption(op, value);
- SetMapValue(this->PersistentOptions, op, value);
-}
-void cmCTestGenericHandler::SetPersistentOption(const std::string& op,
- cmValue value)
-{
- this->SetOption(op, value);
- SetMapValue(this->PersistentOptions, op, value);
-}
-
-void cmCTestGenericHandler::AddMultiOption(const std::string& op,
- const std::string& value)
-{
- if (!value.empty()) {
- this->MultiOptions[op].emplace_back(value);
- }
-}
-
-void cmCTestGenericHandler::AddPersistentMultiOption(const std::string& op,
- const std::string& value)
-{
- if (!value.empty()) {
- this->MultiOptions[op].emplace_back(value);
- this->PersistentMultiOptions[op].emplace_back(value);
- }
-}
-
-void cmCTestGenericHandler::Initialize()
-{
- this->AppendXML = false;
- this->TestLoad = 0;
- this->Options = this->PersistentOptions;
- this->MultiOptions = this->PersistentMultiOptions;
-}
-
-cmValue cmCTestGenericHandler::GetOption(const std::string& op)
-{
- auto remit = this->Options.find(op);
- if (remit == this->Options.end()) {
- return nullptr;
- }
- return cmValue(remit->second);
-}
-
-std::vector<std::string> cmCTestGenericHandler::GetMultiOption(
- const std::string& optionName) const
-{
- // Avoid inserting a key, which MultiOptions[op] would do.
- auto remit = this->MultiOptions.find(optionName);
- if (remit == this->MultiOptions.end()) {
- return {};
- }
- return remit->second;
-}
-
bool cmCTestGenericHandler::StartResultingXML(cmCTest::Part part,
const char* name,
cmGeneratedFileStream& xofs)
diff --git a/Source/CTest/cmCTestGenericHandler.h b/Source/CTest/cmCTestGenericHandler.h
index a189d60..24251c0 100644
--- a/Source/CTest/cmCTestGenericHandler.h
+++ b/Source/CTest/cmCTestGenericHandler.h
@@ -4,17 +4,15 @@
#include "cmConfigure.h" // IWYU pragma: keep
-#include <cstddef>
#include <map>
#include <string>
-#include <vector>
#include "cmCTest.h"
#include "cmSystemTools.h"
-#include "cmValue.h"
class cmGeneratedFileStream;
class cmMakefile;
+class cmake;
/** \class cmCTestGenericHandler
* \brief A superclass of all CTest Handlers
@@ -44,69 +42,17 @@
virtual int ProcessHandler() = 0;
/**
- * Process command line arguments that are applicable for the handler
+ * Get the CTest instance
*/
- virtual int ProcessCommandLineArguments(
- const std::string& /*currentArg*/, size_t& /*idx*/,
- const std::vector<std::string>& /*allArgs*/, bool& /*valid*/)
- {
- return 1;
- }
-
- /**
- * Initialize handler
- */
- virtual void Initialize();
-
- /**
- * Set the CTest instance
- */
- void SetCTestInstance(cmCTest* ctest) { this->CTest = ctest; }
cmCTest* GetCTestInstance() { return this->CTest; }
/**
* Construct handler
*/
- cmCTestGenericHandler();
+ cmCTestGenericHandler(cmCTest* ctest);
virtual ~cmCTestGenericHandler();
using t_StringToString = std::map<std::string, std::string>;
- using t_StringToMultiString =
- std::map<std::string, std::vector<std::string>>;
-
- /**
- * Options collect a single value from flags; passing the
- * flag multiple times on the command-line *overwrites* values,
- * and only the last one specified counts. Set an option to
- * nullptr to "unset" it.
- *
- * The value is stored as a string. The values set for single
- * and multi-options (see below) live in different spaces,
- * so calling a single-getter for a key that has only been set
- * as a multi-value will return nullptr.
- */
- void SetPersistentOption(const std::string& op, const std::string& value);
- void SetPersistentOption(const std::string& op, cmValue value);
- void SetOption(const std::string& op, const std::string& value);
- void SetOption(const std::string& op, cmValue value);
- cmValue GetOption(const std::string& op);
-
- /**
- * Multi-Options collect one or more values from flags; passing
- * the flag multiple times on the command-line *adds* values,
- * rather than overwriting the previous values.
- *
- * Adding an empty value does nothing.
- *
- * The value is stored as a vector of strings. The values set for single
- * (see above) and multi-options live in different spaces,
- * so calling a multi-getter for a key that has only been set
- * as a single-value will return an empty vector.
- */
- void AddPersistentMultiOption(const std::string& optionName,
- const std::string& value);
- void AddMultiOption(const std::string& optionName, const std::string& value);
- std::vector<std::string> GetMultiOption(const std::string& op) const;
void SetSubmitIndex(int idx) { this->SubmitIndex = idx; }
int GetSubmitIndex() { return this->SubmitIndex; }
@@ -117,21 +63,20 @@
void SetTestLoad(unsigned long load) { this->TestLoad = load; }
unsigned long GetTestLoad() const { return this->TestLoad; }
+ void SetCMakeInstance(cmake* cm) { this->CMake = cm; }
+
protected:
bool StartResultingXML(cmCTest::Part part, const char* name,
cmGeneratedFileStream& xofs);
bool StartLogFile(const char* name, cmGeneratedFileStream& xofs);
- bool AppendXML;
- bool Quiet;
- unsigned long TestLoad;
- cmSystemTools::OutputOption HandlerVerbose;
+ bool AppendXML = false;
+ bool Quiet = false;
+ unsigned long TestLoad = 0;
+ cmSystemTools::OutputOption HandlerVerbose = cmSystemTools::OUTPUT_NONE;
cmCTest* CTest;
- t_StringToString Options;
- t_StringToString PersistentOptions;
- t_StringToMultiString MultiOptions;
- t_StringToMultiString PersistentMultiOptions;
t_StringToString LogFileNames;
+ cmake* CMake = nullptr;
- int SubmitIndex;
+ int SubmitIndex = 0;
};
diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx
index c377d68..6847672 100644
--- a/Source/CTest/cmCTestHandlerCommand.cxx
+++ b/Source/CTest/cmCTestHandlerCommand.cxx
@@ -4,17 +4,14 @@
#include <algorithm>
#include <cstdlib>
-#include <cstring>
#include <sstream>
#include <cm/string_view>
-#include <cmext/string_view>
#include "cmCTest.h"
#include "cmCTestGenericHandler.h"
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
-#include "cmMessageType.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmValue.h"
@@ -72,176 +69,150 @@
};
}
-bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& status)
+bool cmCTestHandlerCommand::InvokeImpl(
+ BasicArguments& args, std::vector<std::string> const& unparsed,
+ cmExecutionStatus& status, std::function<bool()> handler) const
{
// save error state and restore it if needed
SaveRestoreErrorState errorState;
- // Allocate space for argument values.
- this->BindArguments();
-
- // Process input arguments.
- std::vector<std::string> unparsedArguments;
- this->Parse(args, &unparsedArguments);
- this->CheckArguments();
-
- std::sort(this->ParsedKeywords.begin(), this->ParsedKeywords.end());
- auto it = std::adjacent_find(this->ParsedKeywords.begin(),
- this->ParsedKeywords.end());
- if (it != this->ParsedKeywords.end()) {
- this->Makefile->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("Called with more than one value for ", *it));
- }
-
- bool const foundBadArgument = !unparsedArguments.empty();
- if (foundBadArgument) {
- this->SetError(cmStrCat("called with unknown argument \"",
- unparsedArguments.front(), "\"."));
- }
- bool const captureCMakeError = !this->CaptureCMakeError.empty();
- // now that arguments are parsed check to see if there is a
- // CAPTURE_CMAKE_ERROR specified let the errorState object know.
- if (captureCMakeError) {
+ if (!args.CaptureCMakeError.empty()) {
errorState.CaptureCMakeError();
}
- // if we found a bad argument then exit before running command
- if (foundBadArgument) {
- // store the cmake error
- if (captureCMakeError) {
- this->Makefile->AddDefinition(this->CaptureCMakeError, "-1");
- std::string const err = this->GetName() + " " + status.GetError();
- if (!cmSystemTools::FindLastString(err.c_str(), "unknown error.")) {
- cmCTestLog(this->CTest, ERROR_MESSAGE, err << " error from command\n");
- }
- // return success because failure is recorded in CAPTURE_CMAKE_ERROR
+
+ bool success = [&]() -> bool {
+ if (args.MaybeReportError(status.GetMakefile())) {
return true;
}
- // return failure because of bad argument
- return false;
+
+ std::sort(args.ParsedKeywords.begin(), args.ParsedKeywords.end());
+ auto const it = std::adjacent_find(args.ParsedKeywords.begin(),
+ args.ParsedKeywords.end());
+ if (it != args.ParsedKeywords.end()) {
+ status.SetError(cmStrCat("called with more than one value for ", *it));
+ return false;
+ }
+
+ if (!unparsed.empty()) {
+ status.SetError(
+ cmStrCat("called with unknown argument \"", unparsed.front(), "\"."));
+ return false;
+ }
+
+ return handler();
+ }();
+
+ if (args.CaptureCMakeError.empty()) {
+ return success;
}
+ if (!success) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ this->GetName() << ' ' << status.GetError() << '\n');
+ }
+
+ cmMakefile& mf = status.GetMakefile();
+ success = success && !cmSystemTools::GetErrorOccurredFlag();
+ mf.AddDefinition(args.CaptureCMakeError, success ? "0" : "-1");
+ return true;
+}
+
+bool cmCTestHandlerCommand::ExecuteHandlerCommand(
+ HandlerArguments& args, cmExecutionStatus& status) const
+{
+ cmMakefile& mf = status.GetMakefile();
+
+ // Process input arguments.
+ this->CheckArguments(args, status);
+
// Set the config type of this ctest to the current value of the
// CTEST_CONFIGURATION_TYPE script variable if it is defined.
// The current script value trumps the -C argument on the command
// line.
- cmValue ctestConfigType =
- this->Makefile->GetDefinition("CTEST_CONFIGURATION_TYPE");
+ cmValue ctestConfigType = mf.GetDefinition("CTEST_CONFIGURATION_TYPE");
if (ctestConfigType) {
this->CTest->SetConfigType(*ctestConfigType);
}
- if (!this->Build.empty()) {
+ if (!args.Build.empty()) {
this->CTest->SetCTestConfiguration(
- "BuildDirectory", cmSystemTools::CollapseFullPath(this->Build),
- this->Quiet);
+ "BuildDirectory", cmSystemTools::CollapseFullPath(args.Build),
+ args.Quiet);
} else {
- std::string const& bdir =
- this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY");
+ std::string const& bdir = mf.GetSafeDefinition("CTEST_BINARY_DIRECTORY");
if (!bdir.empty()) {
this->CTest->SetCTestConfiguration(
- "BuildDirectory", cmSystemTools::CollapseFullPath(bdir), this->Quiet);
+ "BuildDirectory", cmSystemTools::CollapseFullPath(bdir), args.Quiet);
} else {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"CTEST_BINARY_DIRECTORY not set" << std::endl);
}
}
- if (!this->Source.empty()) {
+ if (!args.Source.empty()) {
cmCTestLog(this->CTest, DEBUG,
- "Set source directory to: " << this->Source << std::endl);
+ "Set source directory to: " << args.Source << std::endl);
this->CTest->SetCTestConfiguration(
- "SourceDirectory", cmSystemTools::CollapseFullPath(this->Source),
- this->Quiet);
+ "SourceDirectory", cmSystemTools::CollapseFullPath(args.Source),
+ args.Quiet);
} else {
this->CTest->SetCTestConfiguration(
"SourceDirectory",
cmSystemTools::CollapseFullPath(
- this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY")),
- this->Quiet);
+ mf.GetSafeDefinition("CTEST_SOURCE_DIRECTORY")),
+ args.Quiet);
}
- if (cmValue changeId = this->Makefile->GetDefinition("CTEST_CHANGE_ID")) {
- this->CTest->SetCTestConfiguration("ChangeId", *changeId, this->Quiet);
+ if (cmValue changeId = mf.GetDefinition("CTEST_CHANGE_ID")) {
+ this->CTest->SetCTestConfiguration("ChangeId", *changeId, args.Quiet);
}
cmCTestLog(this->CTest, DEBUG, "Initialize handler" << std::endl);
- cmCTestGenericHandler* handler = this->InitializeHandler();
+ auto handler = this->InitializeHandler(args, status);
if (!handler) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Cannot instantiate test handler " << this->GetName()
<< std::endl);
- if (captureCMakeError) {
- this->Makefile->AddDefinition(this->CaptureCMakeError, "-1");
- std::string const& err = status.GetError();
- if (!cmSystemTools::FindLastString(err.c_str(), "unknown error.")) {
- cmCTestLog(this->CTest, ERROR_MESSAGE, err << " error from command\n");
- }
- return true;
- }
return false;
}
- handler->SetAppendXML(this->Append);
+ handler->SetAppendXML(args.Append);
- handler->PopulateCustomVectors(this->Makefile);
- if (!this->SubmitIndex.empty()) {
- handler->SetSubmitIndex(atoi(this->SubmitIndex.c_str()));
+ handler->PopulateCustomVectors(&mf);
+ if (!args.SubmitIndex.empty()) {
+ handler->SetSubmitIndex(atoi(args.SubmitIndex.c_str()));
}
cmWorkingDirectory workdir(
this->CTest->GetCTestConfiguration("BuildDirectory"));
if (workdir.Failed()) {
- this->SetError("failed to change directory to " +
- this->CTest->GetCTestConfiguration("BuildDirectory") +
- " : " + std::strerror(workdir.GetLastResult()));
- if (captureCMakeError) {
- this->Makefile->AddDefinition(this->CaptureCMakeError, "-1");
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- this->GetName() << " " << status.GetError() << "\n");
- // return success because failure is recorded in CAPTURE_CMAKE_ERROR
- return true;
- }
+ status.SetError(workdir.GetError());
return false;
}
+ // reread time limit, as the variable may have been modified.
+ this->CTest->SetTimeLimit(mf.GetDefinition("CTEST_TIME_LIMIT"));
+ handler->SetCMakeInstance(mf.GetCMakeInstance());
+
int res = handler->ProcessHandler();
- if (!this->ReturnValue.empty()) {
- this->Makefile->AddDefinition(this->ReturnValue, std::to_string(res));
+ if (!args.ReturnValue.empty()) {
+ mf.AddDefinition(args.ReturnValue, std::to_string(res));
}
- this->ProcessAdditionalValues(handler);
- // log the error message if there was an error
- if (captureCMakeError) {
- const char* returnString = "0";
- if (cmSystemTools::GetErrorOccurredFlag()) {
- returnString = "-1";
- std::string const& err = status.GetError();
- // print out the error if it is not "unknown error" which means
- // there was no message
- if (!cmSystemTools::FindLastString(err.c_str(), "unknown error.")) {
- cmCTestLog(this->CTest, ERROR_MESSAGE, err);
- }
- }
- // store the captured cmake error state 0 or -1
- this->Makefile->AddDefinition(this->CaptureCMakeError, returnString);
- }
+ this->ProcessAdditionalValues(handler.get(), args, status);
return true;
}
-void cmCTestHandlerCommand::ProcessAdditionalValues(cmCTestGenericHandler*)
+void cmCTestHandlerCommand::CheckArguments(HandlerArguments&,
+ cmExecutionStatus&) const
{
}
-void cmCTestHandlerCommand::BindArguments()
+std::unique_ptr<cmCTestGenericHandler>
+cmCTestHandlerCommand::InitializeHandler(HandlerArguments&,
+ cmExecutionStatus&) const
{
- this->BindParsedKeywords(this->ParsedKeywords);
- this->Bind("APPEND"_s, this->Append);
- this->Bind("QUIET"_s, this->Quiet);
- this->Bind("RETURN_VALUE"_s, this->ReturnValue);
- this->Bind("CAPTURE_CMAKE_ERROR"_s, this->CaptureCMakeError);
- this->Bind("SOURCE"_s, this->Source);
- this->Bind("BUILD"_s, this->Build);
- this->Bind("SUBMIT_INDEX"_s, this->SubmitIndex);
-}
+ return nullptr;
+};
-void cmCTestHandlerCommand::CheckArguments()
+void cmCTestHandlerCommand::ProcessAdditionalValues(cmCTestGenericHandler*,
+ HandlerArguments const&,
+ cmExecutionStatus&) const
{
}
diff --git a/Source/CTest/cmCTestHandlerCommand.h b/Source/CTest/cmCTestHandlerCommand.h
index ed6d9af..c0a2fbc 100644
--- a/Source/CTest/cmCTestHandlerCommand.h
+++ b/Source/CTest/cmCTestHandlerCommand.h
@@ -4,59 +4,95 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <functional>
+#include <memory>
#include <string>
+#include <type_traits>
#include <vector>
#include <cm/string_view>
+#include <cmext/string_view>
#include "cmArgumentParser.h"
#include "cmCTestCommand.h"
-class cmCTestGenericHandler;
class cmExecutionStatus;
+class cmCTestGenericHandler;
-/** \class cmCTestHandler
- * \brief Run a ctest script
- *
- * cmCTestHandlerCommand defineds the command to test the project.
- */
-class cmCTestHandlerCommand
- : public cmCTestCommand
- , public cmArgumentParser<void>
+class cmCTestHandlerCommand : public cmCTestCommand
{
public:
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- virtual std::string GetName() const = 0;
-
- /**
- * This is called when the command is first encountered in
- * the CMakeLists.txt file.
- */
- bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& status) override;
+ using cmCTestCommand::cmCTestCommand;
protected:
- virtual cmCTestGenericHandler* InitializeHandler() = 0;
+ struct BasicArguments : ArgumentParser::ParseResult
+ {
+ std::string CaptureCMakeError;
+ std::vector<cm::string_view> ParsedKeywords;
+ };
- virtual void ProcessAdditionalValues(cmCTestGenericHandler* handler);
+ template <typename Args>
+ static auto MakeBasicParser() -> cmArgumentParser<Args>
+ {
+ static_assert(std::is_base_of<BasicArguments, Args>::value, "");
+ return cmArgumentParser<Args>{}
+ .Bind("CAPTURE_CMAKE_ERROR"_s, &BasicArguments::CaptureCMakeError)
+ .BindParsedKeywords(&BasicArguments::ParsedKeywords);
+ }
- // Command argument handling.
- virtual void BindArguments();
- virtual void CheckArguments();
+ struct HandlerArguments : BasicArguments
+ {
+ bool Append = false;
+ bool Quiet = false;
+ std::string ReturnValue;
+ std::string Build;
+ std::string Source;
+ std::string SubmitIndex;
+ };
- std::vector<cm::string_view> ParsedKeywords;
- bool Append = false;
- bool Quiet = false;
- std::string CaptureCMakeError;
- std::string ReturnValue;
- std::string Build;
- std::string Source;
- std::string SubmitIndex;
+ template <typename Args>
+ static auto MakeHandlerParser() -> cmArgumentParser<Args>
+ {
+ static_assert(std::is_base_of<HandlerArguments, Args>::value, "");
+ return cmArgumentParser<Args>{ MakeBasicParser<Args>() }
+ .Bind("APPEND"_s, &HandlerArguments::Append)
+ .Bind("QUIET"_s, &HandlerArguments::Quiet)
+ .Bind("RETURN_VALUE"_s, &HandlerArguments::ReturnValue)
+ .Bind("SOURCE"_s, &HandlerArguments::Source)
+ .Bind("BUILD"_s, &HandlerArguments::Build)
+ .Bind("SUBMIT_INDEX"_s, &HandlerArguments::SubmitIndex);
+ }
+
+protected:
+ template <typename Args, typename Handler>
+ bool Invoke(cmArgumentParser<Args> const& parser,
+ std::vector<std::string> const& arguments,
+ cmExecutionStatus& status, Handler handler) const
+ {
+ std::vector<std::string> unparsed;
+ Args args = parser.Parse(arguments, &unparsed);
+ return this->InvokeImpl(args, unparsed, status,
+ [&]() -> bool { return handler(args); });
+ };
+
+ bool ExecuteHandlerCommand(HandlerArguments& args,
+ cmExecutionStatus& status) const;
+
+private:
+ bool InvokeImpl(BasicArguments& args,
+ std::vector<std::string> const& unparsed,
+ cmExecutionStatus& status,
+ std::function<bool()> handler) const;
+
+ virtual std::string GetName() const = 0;
+
+ virtual void CheckArguments(HandlerArguments& arguments,
+ cmExecutionStatus& status) const;
+
+ virtual std::unique_ptr<cmCTestGenericHandler> InitializeHandler(
+ HandlerArguments& arguments, cmExecutionStatus& status) const;
+
+ virtual void ProcessAdditionalValues(cmCTestGenericHandler*,
+ HandlerArguments const& arguments,
+ cmExecutionStatus& status) const;
};
-
-#define CTEST_COMMAND_APPEND_OPTION_DOCS \
- "The APPEND option marks results for append to those previously " \
- "submitted to a dashboard server since the last ctest_start. " \
- "Append semantics are defined by the dashboard server in use."
diff --git a/Source/CTest/cmCTestLaunchReporter.cxx b/Source/CTest/cmCTestLaunchReporter.cxx
index 4b4e5c5..4156294 100644
--- a/Source/CTest/cmCTestLaunchReporter.cxx
+++ b/Source/CTest/cmCTestLaunchReporter.cxx
@@ -25,7 +25,7 @@
this->Passthru = true;
this->Status.Finished = true;
this->ExitCode = 1;
- this->CWD = cmSystemTools::GetCurrentWorkingDirectory();
+ this->CWD = cmSystemTools::GetLogicalWorkingDirectory();
this->ComputeFileNames();
diff --git a/Source/CTest/cmCTestMemCheckCommand.cxx b/Source/CTest/cmCTestMemCheckCommand.cxx
index 37b3628..28d7158 100644
--- a/Source/CTest/cmCTestMemCheckCommand.cxx
+++ b/Source/CTest/cmCTestMemCheckCommand.cxx
@@ -2,49 +2,65 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestMemCheckCommand.h"
+#include <utility>
+
+#include <cm/memory>
#include <cmext/string_view>
+#include "cmArgumentParser.h"
#include "cmCTest.h"
#include "cmCTestMemCheckHandler.h"
+#include "cmCTestTestHandler.h"
+#include "cmExecutionStatus.h"
#include "cmMakefile.h"
-void cmCTestMemCheckCommand::BindArguments()
+std::unique_ptr<cmCTestTestHandler>
+cmCTestMemCheckCommand::InitializeActualHandler(
+ HandlerArguments& args, cmExecutionStatus& status) const
{
- this->cmCTestTestCommand::BindArguments();
- this->Bind("DEFECT_COUNT"_s, this->DefectCount);
-}
-
-cmCTestTestHandler* cmCTestMemCheckCommand::InitializeActualHandler()
-{
- cmCTestMemCheckHandler* handler = this->CTest->GetMemCheckHandler();
- handler->Initialize();
+ cmMakefile& mf = status.GetMakefile();
+ auto handler = cm::make_unique<cmCTestMemCheckHandler>(this->CTest);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "MemoryCheckType", "CTEST_MEMORYCHECK_TYPE", this->Quiet);
+ &mf, "MemoryCheckType", "CTEST_MEMORYCHECK_TYPE", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "MemoryCheckSanitizerOptions",
- "CTEST_MEMORYCHECK_SANITIZER_OPTIONS", this->Quiet);
+ &mf, "MemoryCheckSanitizerOptions", "CTEST_MEMORYCHECK_SANITIZER_OPTIONS",
+ args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "MemoryCheckCommand", "CTEST_MEMORYCHECK_COMMAND",
- this->Quiet);
+ &mf, "MemoryCheckCommand", "CTEST_MEMORYCHECK_COMMAND", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "MemoryCheckCommandOptions",
- "CTEST_MEMORYCHECK_COMMAND_OPTIONS", this->Quiet);
+ &mf, "MemoryCheckCommandOptions", "CTEST_MEMORYCHECK_COMMAND_OPTIONS",
+ args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "MemoryCheckSuppressionFile",
- "CTEST_MEMORYCHECK_SUPPRESSIONS_FILE", this->Quiet);
+ &mf, "MemoryCheckSuppressionFile", "CTEST_MEMORYCHECK_SUPPRESSIONS_FILE",
+ args.Quiet);
- handler->SetQuiet(this->Quiet);
- return handler;
+ handler->SetQuiet(args.Quiet);
+ return std::unique_ptr<cmCTestTestHandler>(std::move(handler));
}
void cmCTestMemCheckCommand::ProcessAdditionalValues(
- cmCTestGenericHandler* handler)
+ cmCTestGenericHandler* handler, HandlerArguments const& arguments,
+ cmExecutionStatus& status) const
{
- if (!this->DefectCount.empty()) {
- this->Makefile->AddDefinition(
- this->DefectCount,
+ cmMakefile& mf = status.GetMakefile();
+ auto const& args = static_cast<MemCheckArguments const&>(arguments);
+ if (!args.DefectCount.empty()) {
+ mf.AddDefinition(
+ args.DefectCount,
std::to_string(
static_cast<cmCTestMemCheckHandler*>(handler)->GetDefectCount()));
}
}
+
+bool cmCTestMemCheckCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) const
+{
+ static auto const parser =
+ cmArgumentParser<MemCheckArguments>{ MakeTestParser<MemCheckArguments>() }
+ .Bind("DEFECT_COUNT"_s, &MemCheckArguments::DefectCount);
+
+ return this->Invoke(parser, args, status, [&](MemCheckArguments& a) {
+ return this->ExecuteHandlerCommand(a, status);
+ });
+}
diff --git a/Source/CTest/cmCTestMemCheckCommand.h b/Source/CTest/cmCTestMemCheckCommand.h
index ee39e49..0f3a7fc 100644
--- a/Source/CTest/cmCTestMemCheckCommand.h
+++ b/Source/CTest/cmCTestMemCheckCommand.h
@@ -4,42 +4,37 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <memory>
#include <string>
-#include <utility>
-
-#include <cm/memory>
+#include <vector>
#include "cmCTestTestCommand.h"
-#include "cmCommand.h"
+class cmExecutionStatus;
class cmCTestGenericHandler;
class cmCTestTestHandler;
-/** \class cmCTestMemCheck
- * \brief Run a ctest script
- *
- * cmCTestMemCheckCommand defineds the command to test the project.
- */
class cmCTestMemCheckCommand : public cmCTestTestCommand
{
public:
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- auto ni = cm::make_unique<cmCTestMemCheckCommand>();
- ni->CTest = this->CTest;
- ni->CTestScriptHandler = this->CTestScriptHandler;
- return std::unique_ptr<cmCommand>(std::move(ni));
- }
+ using cmCTestTestCommand::cmCTestTestCommand;
protected:
- void BindArguments() override;
+ struct MemCheckArguments : TestArguments
+ {
+ std::string DefectCount;
+ };
- cmCTestTestHandler* InitializeActualHandler() override;
+private:
+ std::string GetName() const override { return "ctest_memcheck"; }
- void ProcessAdditionalValues(cmCTestGenericHandler* handler) override;
+ std::unique_ptr<cmCTestTestHandler> InitializeActualHandler(
+ HandlerArguments& arguments, cmExecutionStatus& status) const override;
- std::string DefectCount;
+ void ProcessAdditionalValues(cmCTestGenericHandler* handler,
+ HandlerArguments const& arguments,
+ cmExecutionStatus& status) const override;
+
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) const override;
};
diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx
index 8596ffa..e494163 100644
--- a/Source/CTest/cmCTestMemCheckHandler.cxx
+++ b/Source/CTest/cmCTestMemCheckHandler.cxx
@@ -118,26 +118,12 @@
#define BOUNDS_CHECKER_MARKER \
"******######*****Begin BOUNDS CHECKER XML******######******"
-cmCTestMemCheckHandler::cmCTestMemCheckHandler()
+cmCTestMemCheckHandler::cmCTestMemCheckHandler(cmCTest* ctest)
+ : Superclass(ctest)
{
this->MemCheck = true;
- this->CustomMaximumPassedTestOutputSize = 0;
- this->CustomMaximumFailedTestOutputSize = 0;
- this->LogWithPID = false;
-}
-
-void cmCTestMemCheckHandler::Initialize()
-{
- this->Superclass::Initialize();
- this->LogWithPID = false;
- this->CustomMaximumPassedTestOutputSize = 0;
- this->CustomMaximumFailedTestOutputSize = 0;
- this->MemoryTester.clear();
- this->MemoryTesterDynamicOptions.clear();
- this->MemoryTesterOptions.clear();
- this->MemoryTesterStyle = UNKNOWN;
- this->MemoryTesterOutputFile.clear();
- this->DefectCount = 0;
+ this->TestOptions.OutputSizePassed = 0;
+ this->TestOptions.OutputSizeFailed = 0;
}
int cmCTestMemCheckHandler::PreProcessHandler()
@@ -311,7 +297,7 @@
if (!this->CTest->GetProduceXML()) {
return;
}
- this->CTest->StartXML(xml, this->AppendXML);
+ this->CTest->StartXML(xml, this->CMake, this->AppendXML);
this->CTest->GenerateSubprojectsOutput(xml);
xml.StartElement("DynamicAnalysis");
switch (this->MemoryTesterStyle) {
@@ -371,9 +357,8 @@
continue;
}
this->CleanTestOutput(
- memcheckstr,
- static_cast<size_t>(this->CustomMaximumFailedTestOutputSize),
- this->TestOutputTruncation);
+ memcheckstr, static_cast<size_t>(this->TestOptions.OutputSizeFailed),
+ this->TestOptions.OutputTruncation);
this->WriteTestResultHeader(xml, result);
xml.StartElement("Results");
int memoryErrors = 0;
@@ -929,7 +914,7 @@
cmsys::SystemTools::Split(str, lines);
bool unlimitedOutput = false;
if (str.find("CTEST_FULL_OUTPUT") != std::string::npos ||
- this->CustomMaximumFailedTestOutputSize == 0) {
+ this->TestOptions.OutputSizeFailed == 0) {
unlimitedOutput = true;
}
@@ -1029,7 +1014,7 @@
ostr << lines[i] << std::endl;
if (!unlimitedOutput &&
totalOutputSize >
- static_cast<size_t>(this->CustomMaximumFailedTestOutputSize)) {
+ static_cast<size_t>(this->TestOptions.OutputSizeFailed)) {
ostr << "....\n";
ostr << "Test Output for this test has been truncated see testing"
" machine logs for full output,\n";
@@ -1143,7 +1128,7 @@
cmsys::SystemTools::Split(str, lines);
bool unlimitedOutput = false;
if (str.find("CTEST_FULL_OUTPUT") != std::string::npos ||
- this->CustomMaximumFailedTestOutputSize == 0) {
+ this->TestOptions.OutputSizeFailed == 0) {
unlimitedOutput = true;
}
@@ -1243,7 +1228,7 @@
ostr << lines[i] << std::endl;
if (!unlimitedOutput &&
totalOutputSize >
- static_cast<size_t>(this->CustomMaximumFailedTestOutputSize)) {
+ static_cast<size_t>(this->TestOptions.OutputSizeFailed)) {
ostr << "....\n";
ostr << "Test Output for this test has been truncated see testing"
" machine logs for full output,\n";
diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h
index a63a24d..1971330 100644
--- a/Source/CTest/cmCTestMemCheckHandler.h
+++ b/Source/CTest/cmCTestMemCheckHandler.h
@@ -11,6 +11,7 @@
class cmMakefile;
class cmXMLWriter;
+class cmCTest;
/** \class cmCTestMemCheckHandler
* \brief A class that handles ctest -S invocations
@@ -25,9 +26,7 @@
void PopulateCustomVectors(cmMakefile* mf) override;
- cmCTestMemCheckHandler();
-
- void Initialize() override;
+ cmCTestMemCheckHandler(cmCTest* ctest);
int GetDefectCount() const;
@@ -100,15 +99,15 @@
std::string MemoryTester;
std::vector<std::string> MemoryTesterDynamicOptions;
std::vector<std::string> MemoryTesterOptions;
- int MemoryTesterStyle;
+ int MemoryTesterStyle = UNKNOWN;
std::string MemoryTesterOutputFile;
std::string MemoryTesterEnvironmentVariable;
// these are used to store the types of errors that can show up
std::vector<std::string> ResultStrings;
std::vector<std::string> ResultStringsLong;
std::vector<int> GlobalResults;
- bool LogWithPID; // does log file add pid
- int DefectCount;
+ bool LogWithPID = false; // does log file add pid
+ int DefectCount = 0;
std::vector<int>::size_type FindOrAddWarning(const std::string& warning);
// initialize the ResultStrings and ResultStringsLong for
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 84ea32b..ac74697 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -8,7 +8,6 @@
#include <cmath>
#include <cstddef> // IWYU pragma: keep
#include <cstdlib>
-#include <cstring>
#include <iomanip>
#include <iostream>
#include <list>
@@ -279,9 +278,7 @@
cmWorkingDirectory workdir(this->Properties[test]->Directory);
if (workdir.Failed()) {
cmCTestRunTest::StartFailure(std::move(testRun), this->Total,
- "Failed to change working directory to " +
- this->Properties[test]->Directory + " : " +
- std::strerror(workdir.GetLastResult()),
+ workdir.GetError(),
"Failed to change working directory");
return;
}
@@ -501,7 +498,7 @@
inline size_t cmCTestMultiProcessHandler::GetProcessorsUsed(int test)
{
- size_t processors = static_cast<int>(this->Properties[test]->Processors);
+ size_t processors = this->Properties[test]->Processors;
size_t const parallelLevel = this->GetParallelLevel();
// If processors setting is set higher than the -j
// setting, we default to using all of the process slots.
diff --git a/Source/CTest/cmCTestReadCustomFilesCommand.cxx b/Source/CTest/cmCTestReadCustomFilesCommand.cxx
index a25cca4..992676f 100644
--- a/Source/CTest/cmCTestReadCustomFilesCommand.cxx
+++ b/Source/CTest/cmCTestReadCustomFilesCommand.cxx
@@ -3,19 +3,21 @@
#include "cmCTestReadCustomFilesCommand.h"
#include "cmCTest.h"
+#include "cmExecutionStatus.h"
-class cmExecutionStatus;
+class cmMakefile;
bool cmCTestReadCustomFilesCommand::InitialPass(
- std::vector<std::string> const& args, cmExecutionStatus& /*unused*/)
+ std::vector<std::string> const& args, cmExecutionStatus& status) const
{
if (args.empty()) {
- this->SetError("called with incorrect number of arguments");
+ status.SetError("called with incorrect number of arguments");
return false;
}
+ cmMakefile& mf = status.GetMakefile();
for (std::string const& arg : args) {
- this->CTest->ReadCustomConfigurationFileTree(arg, this->Makefile);
+ this->CTest->ReadCustomConfigurationFileTree(arg, &mf);
}
return true;
diff --git a/Source/CTest/cmCTestReadCustomFilesCommand.h b/Source/CTest/cmCTestReadCustomFilesCommand.h
index 03714f6..bf12e9e 100644
--- a/Source/CTest/cmCTestReadCustomFilesCommand.h
+++ b/Source/CTest/cmCTestReadCustomFilesCommand.h
@@ -5,13 +5,9 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <string>
-#include <utility>
#include <vector>
-#include <cm/memory>
-
#include "cmCTestCommand.h"
-#include "cmCommand.h"
class cmExecutionStatus;
@@ -24,22 +20,12 @@
class cmCTestReadCustomFilesCommand : public cmCTestCommand
{
public:
- cmCTestReadCustomFilesCommand() {}
-
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- auto ni = cm::make_unique<cmCTestReadCustomFilesCommand>();
- ni->CTest = this->CTest;
- return std::unique_ptr<cmCommand>(std::move(ni));
- }
+ using cmCTestCommand::cmCTestCommand;
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& status) override;
+ cmExecutionStatus& status) const override;
};
diff --git a/Source/CTest/cmCTestRunScriptCommand.cxx b/Source/CTest/cmCTestRunScriptCommand.cxx
index 7661d4d..74620a2 100644
--- a/Source/CTest/cmCTestRunScriptCommand.cxx
+++ b/Source/CTest/cmCTestRunScriptCommand.cxx
@@ -3,18 +3,19 @@
#include "cmCTestRunScriptCommand.h"
#include "cmCTestScriptHandler.h"
+#include "cmExecutionStatus.h"
#include "cmMakefile.h"
-
-class cmExecutionStatus;
+#include "cmSystemTools.h"
bool cmCTestRunScriptCommand::InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& /*unused*/)
+ cmExecutionStatus& status) const
{
if (args.empty()) {
- this->CTestScriptHandler->RunCurrentScript();
- return true;
+ status.SetError("called with incorrect number of arguments");
+ return false;
}
+ cmMakefile& mf = status.GetMakefile();
bool np = false;
unsigned int i = 0;
if (args[i] == "NEW_PROCESS") {
@@ -37,9 +38,9 @@
++i;
} else {
int ret;
- cmCTestScriptHandler::RunScript(this->CTest, this->Makefile, args[i],
- !np, &ret);
- this->Makefile->AddDefinition(returnVariable, std::to_string(ret));
+ cmCTestScriptHandler::RunScript(
+ this->CTest, &mf, cmSystemTools::CollapseFullPath(args[i]), !np, &ret);
+ mf.AddDefinition(returnVariable, std::to_string(ret));
}
}
return true;
diff --git a/Source/CTest/cmCTestRunScriptCommand.h b/Source/CTest/cmCTestRunScriptCommand.h
index 510b748..2ccc0e7 100644
--- a/Source/CTest/cmCTestRunScriptCommand.h
+++ b/Source/CTest/cmCTestRunScriptCommand.h
@@ -5,13 +5,9 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <string>
-#include <utility>
#include <vector>
-#include <cm/memory>
-
#include "cmCTestCommand.h"
-#include "cmCommand.h"
class cmExecutionStatus;
@@ -24,23 +20,12 @@
class cmCTestRunScriptCommand : public cmCTestCommand
{
public:
- cmCTestRunScriptCommand() {}
-
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- auto ni = cm::make_unique<cmCTestRunScriptCommand>();
- ni->CTest = this->CTest;
- ni->CTestScriptHandler = this->CTestScriptHandler;
- return std::unique_ptr<cmCommand>(std::move(ni));
- }
+ using cmCTestCommand::cmCTestCommand;
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& status) override;
+ cmExecutionStatus& status) const override;
};
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 483b3b4..1ca9807 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -7,7 +7,6 @@
#include <cstddef> // IWYU pragma: keep
#include <cstdint>
#include <cstdio>
-#include <cstring>
#include <iomanip>
#include <ratio>
#include <sstream>
@@ -297,11 +296,11 @@
if (!this->TestHandler->MemCheck && started) {
this->TestHandler->CleanTestOutput(
this->ProcessOutput,
- static_cast<size_t>(
- this->TestResult.Status == cmCTestTestHandler::COMPLETED
- ? this->TestHandler->CustomMaximumPassedTestOutputSize
- : this->TestHandler->CustomMaximumFailedTestOutputSize),
- this->TestHandler->TestOutputTruncation);
+ static_cast<size_t>(this->TestResult.Status ==
+ cmCTestTestHandler::COMPLETED
+ ? this->TestHandler->TestOptions.OutputSizePassed
+ : this->TestHandler->TestOptions.OutputSizeFailed),
+ this->TestHandler->TestOptions.OutputTruncation);
}
this->TestResult.Reason = reason;
if (this->TestHandler->LogFile) {
@@ -398,10 +397,7 @@
// change to tests directory
cmWorkingDirectory workdir(testRun->TestProperties->Directory);
if (workdir.Failed()) {
- testRun->StartFailure(testRun->TotalNumberOfTests,
- "Failed to change working directory to " +
- testRun->TestProperties->Directory + " : " +
- std::strerror(workdir.GetLastResult()),
+ testRun->StartFailure(testRun->TotalNumberOfTests, workdir.GetError(),
"Failed to change working directory");
return true;
}
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index ed567d4..7d7fa94 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -2,7 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestScriptHandler.h"
-#include <cstdio>
+#include <chrono>
#include <cstdlib>
#include <map>
#include <ratio>
@@ -13,11 +13,8 @@
#include <cm3p/uv.h>
-#include "cmsys/Directory.hxx"
-
#include "cmCTest.h"
#include "cmCTestBuildCommand.h"
-#include "cmCTestCommand.h"
#include "cmCTestConfigureCommand.h"
#include "cmCTestCoverageCommand.h"
#include "cmCTestEmptyBinaryDirectoryCommand.h"
@@ -30,63 +27,20 @@
#include "cmCTestTestCommand.h"
#include "cmCTestUpdateCommand.h"
#include "cmCTestUploadCommand.h"
-#include "cmCommand.h"
#include "cmDuration.h"
-#include "cmGeneratedFileStream.h"
#include "cmGlobalGenerator.h"
-#include "cmList.h"
#include "cmMakefile.h"
#include "cmState.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
-#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmUVHandlePtr.h"
#include "cmUVProcessChain.h"
-#include "cmValue.h"
#include "cmake.h"
-#ifdef _WIN32
-# include <windows.h>
-#else
-# include <unistd.h>
-#endif
-
-cmCTestScriptHandler::cmCTestScriptHandler() = default;
-
-void cmCTestScriptHandler::Initialize()
+cmCTestScriptHandler::cmCTestScriptHandler(cmCTest* ctest)
+ : CTest(ctest)
{
- this->Superclass::Initialize();
- this->Backup = false;
- this->EmptyBinDir = false;
- this->EmptyBinDirOnce = false;
-
- this->SourceDir.clear();
- this->BinaryDir.clear();
- this->BackupSourceDir.clear();
- this->BackupBinaryDir.clear();
- this->CTestRoot.clear();
- this->CVSCheckOut.clear();
- this->CTestCmd.clear();
- this->UpdateCmd.clear();
- this->CTestEnv.clear();
- this->InitialCache.clear();
- this->CMakeCmd.clear();
- this->CMOutFile.clear();
- this->ExtraUpdates.clear();
-
- this->MinimumInterval = 20 * 60;
- this->ContinuousDuration = -1;
-
- // what time in seconds did this script start running
- this->ScriptStartTime = std::chrono::steady_clock::time_point();
-
- this->Makefile.reset();
- this->ParentMakefile = nullptr;
-
- this->GlobalGenerator.reset();
-
- this->CMake.reset();
}
cmCTestScriptHandler::~cmCTestScriptHandler() = default;
@@ -106,9 +60,8 @@
int res = 0;
for (size_t i = 0; i < this->ConfigurationScripts.size(); ++i) {
// for each script run it
- res |= this->RunConfigurationScript(
- cmSystemTools::CollapseFullPath(this->ConfigurationScripts[i]),
- this->ScriptProcessScope[i]);
+ res |= this->RunConfigurationScript(this->ConfigurationScripts[i],
+ this->ScriptProcessScope[i]);
}
if (res) {
return -1;
@@ -120,21 +73,12 @@
{
if (this->Makefile) {
// set the current elapsed time
- auto itime = cmDurationTo<unsigned int>(std::chrono::steady_clock::now() -
- this->ScriptStartTime);
+ auto itime = cmDurationTo<unsigned int>(this->CTest->GetElapsedTime());
auto timeString = std::to_string(itime);
this->Makefile->AddDefinition("CTEST_ELAPSED_TIME", timeString);
}
}
-void cmCTestScriptHandler::AddCTestCommand(
- std::string const& name, std::unique_ptr<cmCTestCommand> command)
-{
- command->CTest = this->CTest;
- command->CTestScriptHandler = this;
- this->CMake->GetState()->AddBuiltinCommand(name, std::move(command));
-}
-
int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg)
{
// execute the script passing in the arguments to the script as well as the
@@ -235,7 +179,7 @@
cm::make_unique<cmGlobalGenerator>(this->CMake.get());
cmStateSnapshot snapshot = this->CMake->GetCurrentSnapshot();
- std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ std::string cwd = cmSystemTools::GetLogicalWorkingDirectory();
snapshot.GetDirectory().SetCurrentSource(cwd);
snapshot.GetDirectory().SetCurrentBinary(cwd);
this->Makefile =
@@ -252,28 +196,26 @@
}
});
- this->AddCTestCommand("ctest_build", cm::make_unique<cmCTestBuildCommand>());
- this->AddCTestCommand("ctest_configure",
- cm::make_unique<cmCTestConfigureCommand>());
- this->AddCTestCommand("ctest_coverage",
- cm::make_unique<cmCTestCoverageCommand>());
- this->AddCTestCommand("ctest_empty_binary_directory",
- cm::make_unique<cmCTestEmptyBinaryDirectoryCommand>());
- this->AddCTestCommand("ctest_memcheck",
- cm::make_unique<cmCTestMemCheckCommand>());
- this->AddCTestCommand("ctest_read_custom_files",
- cm::make_unique<cmCTestReadCustomFilesCommand>());
- this->AddCTestCommand("ctest_run_script",
- cm::make_unique<cmCTestRunScriptCommand>());
- this->AddCTestCommand("ctest_sleep", cm::make_unique<cmCTestSleepCommand>());
- this->AddCTestCommand("ctest_start", cm::make_unique<cmCTestStartCommand>());
- this->AddCTestCommand("ctest_submit",
- cm::make_unique<cmCTestSubmitCommand>());
- this->AddCTestCommand("ctest_test", cm::make_unique<cmCTestTestCommand>());
- this->AddCTestCommand("ctest_update",
- cm::make_unique<cmCTestUpdateCommand>());
- this->AddCTestCommand("ctest_upload",
- cm::make_unique<cmCTestUploadCommand>());
+ cmState* state = this->CMake->GetState();
+ state->AddBuiltinCommand("ctest_build", cmCTestBuildCommand(this->CTest));
+ state->AddBuiltinCommand("ctest_configure",
+ cmCTestConfigureCommand(this->CTest));
+ state->AddBuiltinCommand("ctest_coverage",
+ cmCTestCoverageCommand(this->CTest));
+ state->AddBuiltinCommand("ctest_empty_binary_directory",
+ cmCTestEmptyBinaryDirectoryCommand);
+ state->AddBuiltinCommand("ctest_memcheck",
+ cmCTestMemCheckCommand(this->CTest));
+ state->AddBuiltinCommand("ctest_read_custom_files",
+ cmCTestReadCustomFilesCommand(this->CTest));
+ state->AddBuiltinCommand("ctest_run_script",
+ cmCTestRunScriptCommand(this->CTest));
+ state->AddBuiltinCommand("ctest_sleep", cmCTestSleepCommand);
+ state->AddBuiltinCommand("ctest_start", cmCTestStartCommand(this->CTest));
+ state->AddBuiltinCommand("ctest_submit", cmCTestSubmitCommand(this->CTest));
+ state->AddBuiltinCommand("ctest_test", cmCTestTestCommand(this->CTest));
+ state->AddBuiltinCommand("ctest_update", cmCTestUpdateCommand(this->CTest));
+ state->AddBuiltinCommand("ctest_upload", cmCTestUploadCommand(this->CTest));
}
// this sets up some variables for the script to use, creates the required
@@ -314,8 +256,6 @@
cmSystemTools::GetCTestCommand());
this->Makefile->AddDefinition("CMAKE_EXECUTABLE_NAME",
cmSystemTools::GetCMakeCommand());
- this->Makefile->AddDefinitionBool("CTEST_RUN_CURRENT_SCRIPT", true);
- this->SetRunCurrentScript(true);
this->UpdateElapsedTime();
// set the CTEST_CONFIGURATION_TYPE variable to the current value of the
@@ -366,113 +306,6 @@
return 0;
}
-// extract variables from the script to set ivars
-int cmCTestScriptHandler::ExtractVariables()
-{
- // Temporary variables
- cmValue minInterval;
- cmValue contDuration;
-
- this->SourceDir =
- this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY");
- this->BinaryDir =
- this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY");
-
- // add in translations for src and bin
- cmSystemTools::AddKeepPath(this->SourceDir);
- cmSystemTools::AddKeepPath(this->BinaryDir);
-
- this->CTestCmd = this->Makefile->GetSafeDefinition("CTEST_COMMAND");
- this->CVSCheckOut = this->Makefile->GetSafeDefinition("CTEST_CVS_CHECKOUT");
- this->CTestRoot = this->Makefile->GetSafeDefinition("CTEST_DASHBOARD_ROOT");
- this->UpdateCmd = this->Makefile->GetSafeDefinition("CTEST_UPDATE_COMMAND");
- if (this->UpdateCmd.empty()) {
- this->UpdateCmd = this->Makefile->GetSafeDefinition("CTEST_CVS_COMMAND");
- }
- this->CTestEnv = this->Makefile->GetSafeDefinition("CTEST_ENVIRONMENT");
- this->InitialCache =
- this->Makefile->GetSafeDefinition("CTEST_INITIAL_CACHE");
- this->CMakeCmd = this->Makefile->GetSafeDefinition("CTEST_CMAKE_COMMAND");
- this->CMOutFile =
- this->Makefile->GetSafeDefinition("CTEST_CMAKE_OUTPUT_FILE_NAME");
-
- this->Backup = this->Makefile->IsOn("CTEST_BACKUP_AND_RESTORE");
- this->EmptyBinDir =
- this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY");
- this->EmptyBinDirOnce =
- this->Makefile->IsOn("CTEST_START_WITH_EMPTY_BINARY_DIRECTORY_ONCE");
-
- minInterval =
- this->Makefile->GetDefinition("CTEST_CONTINUOUS_MINIMUM_INTERVAL");
- contDuration = this->Makefile->GetDefinition("CTEST_CONTINUOUS_DURATION");
-
- char updateVar[40];
- int i;
- for (i = 1; i < 10; ++i) {
- snprintf(updateVar, sizeof(updateVar), "CTEST_EXTRA_UPDATES_%i", i);
- cmValue updateVal = this->Makefile->GetDefinition(updateVar);
- if (updateVal) {
- if (this->UpdateCmd.empty()) {
- cmSystemTools::Error(
- std::string(updateVar) +
- " specified without specifying CTEST_CVS_COMMAND.");
- return 12;
- }
- this->ExtraUpdates.emplace_back(*updateVal);
- }
- }
-
- // in order to backup and restore we also must have the cvs root
- if (this->Backup && this->CVSCheckOut.empty()) {
- cmSystemTools::Error(
- "Backup was requested without specifying CTEST_CVS_CHECKOUT.");
- return 3;
- }
-
- // make sure the required info is here
- if (this->SourceDir.empty() || this->BinaryDir.empty() ||
- this->CTestCmd.empty()) {
- std::string msg =
- cmStrCat("CTEST_SOURCE_DIRECTORY = ",
- (!this->SourceDir.empty()) ? this->SourceDir.c_str() : "(Null)",
- "\nCTEST_BINARY_DIRECTORY = ",
- (!this->BinaryDir.empty()) ? this->BinaryDir.c_str() : "(Null)",
- "\nCTEST_COMMAND = ",
- (!this->CTestCmd.empty()) ? this->CTestCmd.c_str() : "(Null)");
- cmSystemTools::Error(
- "Some required settings in the configuration file were missing:\n" +
- msg);
- return 4;
- }
-
- // if the dashboard root isn't specified then we can compute it from the
- // this->SourceDir
- if (this->CTestRoot.empty()) {
- this->CTestRoot = cmSystemTools::GetFilenamePath(this->SourceDir);
- }
-
- // the script may override the minimum continuous interval
- if (minInterval) {
- this->MinimumInterval = 60 * atof(minInterval->c_str());
- }
- if (contDuration) {
- this->ContinuousDuration = 60.0 * atof(contDuration->c_str());
- }
-
- this->UpdateElapsedTime();
-
- return 0;
-}
-
-void cmCTestScriptHandler::SleepInSeconds(unsigned int secondsToWait)
-{
-#if defined(_WIN32)
- Sleep(1000 * secondsToWait);
-#else
- sleep(secondsToWait);
-#endif
-}
-
// run a specific script
int cmCTestScriptHandler::RunConfigurationScript(
const std::string& total_script_arg, bool pscope)
@@ -483,8 +316,6 @@
int result;
- this->ScriptStartTime = std::chrono::steady_clock::now();
-
// read in the script
if (pscope) {
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
@@ -495,361 +326,15 @@
"Executing Script: " << total_script_arg << std::endl);
result = this->ExecuteScript(total_script_arg);
}
- if (result) {
- return result;
- }
-
- // only run the current script if we should
- if (this->Makefile && this->Makefile->IsOn("CTEST_RUN_CURRENT_SCRIPT") &&
- this->ShouldRunCurrentScript) {
- return this->RunCurrentScript();
- }
- return result;
-}
-
-int cmCTestScriptHandler::RunCurrentScript()
-{
- int result;
-
- // do not run twice
- this->SetRunCurrentScript(false);
-
- // no popup widows
- cmSystemTools::SetRunCommandHideConsole(true);
-
- // extract the vars from the cache and store in ivars
- result = this->ExtractVariables();
- if (result) {
- return result;
- }
-
- // set any environment variables
- if (!this->CTestEnv.empty()) {
- cmList envArgs{ this->CTestEnv };
- cmSystemTools::AppendEnv(envArgs);
- }
-
- // now that we have done most of the error checking finally run the
- // dashboard, we may be asked to repeatedly run this dashboard, such as
- // for a continuous, do we need to run it more than once?
- if (this->ContinuousDuration >= 0) {
- this->UpdateElapsedTime();
- auto ending_time =
- std::chrono::steady_clock::now() + cmDuration(this->ContinuousDuration);
- if (this->EmptyBinDirOnce) {
- this->EmptyBinDir = true;
- }
- do {
- auto startOfInterval = std::chrono::steady_clock::now();
- result = this->RunConfigurationDashboard();
- auto interval = std::chrono::steady_clock::now() - startOfInterval;
- auto minimumInterval = cmDuration(this->MinimumInterval);
- if (interval < minimumInterval) {
- auto sleepTime =
- cmDurationTo<unsigned int>(minimumInterval - interval);
- this->SleepInSeconds(sleepTime);
- }
- if (this->EmptyBinDirOnce) {
- this->EmptyBinDir = false;
- }
- } while (std::chrono::steady_clock::now() < ending_time);
- }
- // otherwise just run it once
- else {
- result = this->RunConfigurationDashboard();
- }
return result;
}
-int cmCTestScriptHandler::CheckOutSourceDir()
-{
- std::string output;
- int retVal;
-
- if (!cmSystemTools::FileExists(this->SourceDir) &&
- !this->CVSCheckOut.empty()) {
- // we must now checkout the src dir
- output.clear();
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Run cvs: " << this->CVSCheckOut << std::endl);
- bool res = cmSystemTools::RunSingleCommand(
- this->CVSCheckOut, &output, &output, &retVal, this->CTestRoot.c_str(),
- this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
- if (!res || retVal != 0) {
- cmSystemTools::Error("Unable to perform cvs checkout:\n" + output);
- return 6;
- }
- }
- return 0;
-}
-
-int cmCTestScriptHandler::BackupDirectories()
-{
- // compute the backup names
- this->BackupSourceDir = cmStrCat(this->SourceDir, "_CMakeBackup");
- this->BackupBinaryDir = cmStrCat(this->BinaryDir, "_CMakeBackup");
-
- // backup the binary and src directories if requested
- if (this->Backup) {
- // if for some reason those directories exist then first delete them
- if (cmSystemTools::FileExists(this->BackupSourceDir)) {
- cmSystemTools::RemoveADirectory(this->BackupSourceDir);
- }
- if (cmSystemTools::FileExists(this->BackupBinaryDir)) {
- cmSystemTools::RemoveADirectory(this->BackupBinaryDir);
- }
-
- // first rename the src and binary directories
- rename(this->SourceDir.c_str(), this->BackupSourceDir.c_str());
- rename(this->BinaryDir.c_str(), this->BackupBinaryDir.c_str());
-
- // we must now checkout the src dir
- int retVal = this->CheckOutSourceDir();
- if (retVal) {
- this->RestoreBackupDirectories();
- return retVal;
- }
- }
-
- return 0;
-}
-
-int cmCTestScriptHandler::PerformExtraUpdates()
-{
- std::string command;
- std::string output;
- int retVal;
- bool res;
-
- // do an initial cvs update as required
- command = this->UpdateCmd;
- for (std::string const& eu : this->ExtraUpdates) {
- cmList cvsArgs{ eu };
- if (cvsArgs.size() == 2) {
- std::string fullCommand = cmStrCat(command, " update ", cvsArgs[1]);
- output.clear();
- retVal = 0;
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Run Update: " << fullCommand << std::endl);
- res = cmSystemTools::RunSingleCommand(
- fullCommand, &output, &output, &retVal, cvsArgs[0].c_str(),
- this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
- if (!res || retVal != 0) {
- cmSystemTools::Error(cmStrCat("Unable to perform extra updates:\n", eu,
- "\nWith output:\n", output));
- return 0;
- }
- }
- }
- return 0;
-}
-
-// run a single dashboard entry
-int cmCTestScriptHandler::RunConfigurationDashboard()
-{
- // local variables
- std::string command;
- std::string output;
- int retVal;
- bool res;
-
- // make sure the src directory is there, if it isn't then we might be able
- // to check it out from cvs
- retVal = this->CheckOutSourceDir();
- if (retVal) {
- return retVal;
- }
-
- // backup the dirs if requested
- retVal = this->BackupDirectories();
- if (retVal) {
- return retVal;
- }
-
- // clear the binary directory?
- if (this->EmptyBinDir) {
- std::string err;
- if (!cmCTestScriptHandler::EmptyBinaryDirectory(this->BinaryDir, err)) {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Problem removing the binary directory ("
- << err << "): " << this->BinaryDir << std::endl);
- }
- }
-
- // make sure the binary directory exists if it isn't the srcdir
- if (!cmSystemTools::FileExists(this->BinaryDir) &&
- this->SourceDir != this->BinaryDir) {
- if (!cmSystemTools::MakeDirectory(this->BinaryDir)) {
- cmSystemTools::Error("Unable to create the binary directory:\n" +
- this->BinaryDir);
- this->RestoreBackupDirectories();
- return 7;
- }
- }
-
- // if the binary directory and the source directory are the same,
- // and we are starting with an empty binary directory, then that means
- // we must check out the source tree
- if (this->EmptyBinDir && this->SourceDir == this->BinaryDir) {
- // make sure we have the required info
- if (this->CVSCheckOut.empty()) {
- cmSystemTools::Error(
- "You have specified the source and binary "
- "directories to be the same (an in source build). You have also "
- "specified that the binary directory is to be erased. This means "
- "that the source will have to be checked out from CVS. But you have "
- "not specified CTEST_CVS_CHECKOUT");
- return 8;
- }
-
- // we must now checkout the src dir
- retVal = this->CheckOutSourceDir();
- if (retVal) {
- this->RestoreBackupDirectories();
- return retVal;
- }
- }
-
- // backup the dirs if requested
- retVal = this->PerformExtraUpdates();
- if (retVal) {
- return retVal;
- }
-
- // put the initial cache into the bin dir
- if (!this->InitialCache.empty()) {
- if (!cmCTestScriptHandler::WriteInitialCache(this->BinaryDir,
- this->InitialCache)) {
- this->RestoreBackupDirectories();
- return 9;
- }
- }
-
- // do an initial cmake to setup the DartConfig file
- int cmakeFailed = 0;
- std::string cmakeFailedOuput;
- if (!this->CMakeCmd.empty()) {
- command = cmStrCat(this->CMakeCmd, " \"", this->SourceDir);
- output.clear();
- command += "\"";
- retVal = 0;
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Run cmake command: " << command << std::endl);
- res = cmSystemTools::RunSingleCommand(
- command, &output, &output, &retVal, this->BinaryDir.c_str(),
- this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
-
- if (!this->CMOutFile.empty()) {
- std::string cmakeOutputFile = this->CMOutFile;
- if (!cmSystemTools::FileIsFullPath(cmakeOutputFile)) {
- cmakeOutputFile = this->BinaryDir + "/" + cmakeOutputFile;
- }
-
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Write CMake output to file: " << cmakeOutputFile
- << std::endl);
- cmGeneratedFileStream fout(cmakeOutputFile);
- if (fout) {
- fout << output.c_str();
- } else {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot open CMake output file: "
- << cmakeOutputFile << " for writing" << std::endl);
- }
- }
- if (!res || retVal != 0) {
- // even if this fails continue to the next step
- cmakeFailed = 1;
- cmakeFailedOuput = output;
- }
- }
-
- // run ctest, it may be more than one command in here
- cmList ctestCommands{ this->CTestCmd };
- // for each variable/argument do a putenv
- for (std::string const& ctestCommand : ctestCommands) {
- command = ctestCommand;
- output.clear();
- retVal = 0;
- cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
- "Run ctest command: " << command << std::endl);
- res = cmSystemTools::RunSingleCommand(
- command, &output, &output, &retVal, this->BinaryDir.c_str(),
- this->HandlerVerbose, cmDuration::zero() /*this->TimeOut*/);
-
- // did something critical fail in ctest
- if (!res || cmakeFailed || retVal & cmCTest::BUILD_ERRORS) {
- this->RestoreBackupDirectories();
- if (cmakeFailed) {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Unable to run cmake:" << std::endl
- << cmakeFailedOuput << std::endl);
- return 10;
- }
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Unable to run ctest:" << std::endl
- << "command: " << command << std::endl
- << "output: " << output << std::endl);
- if (!res) {
- return 11;
- }
- return retVal * 100;
- }
- }
-
- // if all was successful, delete the backup dirs to free up disk space
- if (this->Backup) {
- cmSystemTools::RemoveADirectory(this->BackupSourceDir);
- cmSystemTools::RemoveADirectory(this->BackupBinaryDir);
- }
-
- return 0;
-}
-
-bool cmCTestScriptHandler::WriteInitialCache(const std::string& directory,
- const std::string& text)
-{
- std::string cacheFile = cmStrCat(directory, "/CMakeCache.txt");
- cmGeneratedFileStream fout(cacheFile);
- if (!fout) {
- return false;
- }
-
- fout.write(text.data(), text.size());
-
- // Make sure the operating system has finished writing the file
- // before closing it. This will ensure the file is finished before
- // the check below.
- fout.flush();
- fout.close();
- return true;
-}
-
-void cmCTestScriptHandler::RestoreBackupDirectories()
-{
- // if we backed up the dirs and the build failed, then restore
- // the backed up dirs
- if (this->Backup) {
- // if for some reason those directories exist then first delete them
- if (cmSystemTools::FileExists(this->SourceDir)) {
- cmSystemTools::RemoveADirectory(this->SourceDir);
- }
- if (cmSystemTools::FileExists(this->BinaryDir)) {
- cmSystemTools::RemoveADirectory(this->BinaryDir);
- }
- // rename the src and binary directories
- rename(this->BackupSourceDir.c_str(), this->SourceDir.c_str());
- rename(this->BackupBinaryDir.c_str(), this->BinaryDir.c_str());
- }
-}
-
bool cmCTestScriptHandler::RunScript(cmCTest* ctest, cmMakefile* mf,
const std::string& sname, bool InProcess,
int* returnValue)
{
- auto sh = cm::make_unique<cmCTestScriptHandler>();
- sh->SetCTestInstance(ctest);
+ auto sh = cm::make_unique<cmCTestScriptHandler>(ctest);
sh->ParentMakefile = mf;
sh->AddConfigurationScript(sname, InProcess);
int res = sh->ProcessHandler();
@@ -858,94 +343,3 @@
}
return true;
}
-
-bool cmCTestScriptHandler::EmptyBinaryDirectory(const std::string& sname,
- std::string& err)
-{
- // try to avoid deleting root
- if (sname.size() < 2) {
- err = "path too short";
- return false;
- }
-
- // consider non existing target directory a success
- if (!cmSystemTools::FileExists(sname)) {
- return true;
- }
-
- // try to avoid deleting directories that we shouldn't
- std::string check = cmStrCat(sname, "/CMakeCache.txt");
-
- if (!cmSystemTools::FileExists(check)) {
- err = "path does not contain an existing CMakeCache.txt file";
- return false;
- }
-
- cmsys::Status status;
- for (int i = 0; i < 5; ++i) {
- status = TryToRemoveBinaryDirectoryOnce(sname);
- if (status) {
- return true;
- }
- cmSystemTools::Delay(100);
- }
-
- err = status.GetString();
- return false;
-}
-
-cmsys::Status cmCTestScriptHandler::TryToRemoveBinaryDirectoryOnce(
- const std::string& directoryPath)
-{
- cmsys::Directory directory;
- directory.Load(directoryPath);
-
- for (unsigned long i = 0; i < directory.GetNumberOfFiles(); ++i) {
- std::string path = directory.GetFile(i);
-
- if (path == "." || path == ".." || path == "CMakeCache.txt") {
- continue;
- }
-
- std::string fullPath = cmStrCat(directoryPath, "/", path);
-
- bool isDirectory = cmSystemTools::FileIsDirectory(fullPath) &&
- !cmSystemTools::FileIsSymlink(fullPath);
-
- cmsys::Status status;
- if (isDirectory) {
- status = cmSystemTools::RemoveADirectory(fullPath);
- } else {
- status = cmSystemTools::RemoveFile(fullPath);
- }
- if (!status) {
- return status;
- }
- }
-
- return cmSystemTools::RemoveADirectory(directoryPath);
-}
-
-cmDuration cmCTestScriptHandler::GetRemainingTimeAllowed()
-{
- if (!this->Makefile) {
- return cmCTest::MaxDuration();
- }
-
- cmValue timelimitS = this->Makefile->GetDefinition("CTEST_TIME_LIMIT");
-
- if (!timelimitS) {
- return cmCTest::MaxDuration();
- }
-
- auto timelimit = cmDuration(atof(timelimitS->c_str()));
-
- auto duration = std::chrono::duration_cast<cmDuration>(
- std::chrono::steady_clock::now() - this->ScriptStartTime);
- return (timelimit - duration);
-}
-
-void cmCTestScriptHandler::SetRunCurrentScript(bool value)
-{
- this->ShouldRunCurrentScript = value;
-}
diff --git a/Source/CTest/cmCTestScriptHandler.h b/Source/CTest/cmCTestScriptHandler.h
index 7747750..bcb3933 100644
--- a/Source/CTest/cmCTestScriptHandler.h
+++ b/Source/CTest/cmCTestScriptHandler.h
@@ -4,63 +4,21 @@
#include "cmConfigure.h" // IWYU pragma: keep
-#include <chrono>
#include <memory>
#include <string>
#include <vector>
-#include "cmsys/Status.hxx"
-
-#include "cmCTestGenericHandler.h"
-#include "cmDuration.h"
-
class cmCTest;
-class cmCTestCommand;
class cmGlobalGenerator;
class cmMakefile;
class cmake;
/** \class cmCTestScriptHandler
* \brief A class that handles ctest -S invocations
- *
- * CTest script is controlled using several variables that script has to
- * specify and some optional ones. Required ones are:
- * CTEST_SOURCE_DIRECTORY - Source directory of the project
- * CTEST_BINARY_DIRECTORY - Binary directory of the project
- * CTEST_COMMAND - Testing commands
- *
- * Optional variables are:
- * CTEST_BACKUP_AND_RESTORE
- * CTEST_CMAKE_COMMAND
- * CTEST_CMAKE_OUTPUT_FILE_NAME
- * CTEST_CONTINUOUS_DURATION
- * CTEST_CONTINUOUS_MINIMUM_INTERVAL
- * CTEST_CVS_CHECKOUT
- * CTEST_CVS_COMMAND
- * CTEST_UPDATE_COMMAND
- * CTEST_DASHBOARD_ROOT
- * CTEST_ENVIRONMENT
- * CTEST_INITIAL_CACHE
- * CTEST_START_WITH_EMPTY_BINARY_DIRECTORY
- * CTEST_START_WITH_EMPTY_BINARY_DIRECTORY_ONCE
- *
- * In addition the following variables can be used. The number can be 1-10.
- * CTEST_EXTRA_UPDATES_1
- * CTEST_EXTRA_UPDATES_2
- * ...
- * CTEST_EXTRA_UPDATES_10
- *
- * CTest script can use the following arguments CTest provides:
- * CTEST_SCRIPT_ARG
- * CTEST_SCRIPT_DIRECTORY
- * CTEST_SCRIPT_NAME
- *
*/
-class cmCTestScriptHandler : public cmCTestGenericHandler
+class cmCTestScriptHandler
{
public:
- using Superclass = cmCTestGenericHandler;
-
/**
* Add a script to run, and if is should run in the current process
*/
@@ -69,7 +27,7 @@
/**
* Run a dashboard using a specified configuration script
*/
- int ProcessHandler() override;
+ int ProcessHandler();
/*
* Run a script
@@ -77,104 +35,32 @@
static bool RunScript(cmCTest* ctest, cmMakefile* mf,
const std::string& script, bool InProcess,
int* returnValue);
- int RunCurrentScript();
-
- /*
- * Empty Binary Directory
- */
- static bool EmptyBinaryDirectory(const std::string& dir, std::string& err);
-
- /*
- * Write an initial CMakeCache.txt from the given contents.
- */
- static bool WriteInitialCache(const std::string& directory,
- const std::string& text);
/*
* Some elapsed time handling functions
*/
- static void SleepInSeconds(unsigned int secondsToWait);
void UpdateElapsedTime();
- /**
- * Return the time remaianing that the script is allowed to run in
- * seconds if the user has set the variable CTEST_TIME_LIMIT. If that has
- * not been set it returns a very large value.
- */
- cmDuration GetRemainingTimeAllowed();
-
- cmCTestScriptHandler();
+ cmCTestScriptHandler(cmCTest* ctest);
cmCTestScriptHandler(const cmCTestScriptHandler&) = delete;
const cmCTestScriptHandler& operator=(const cmCTestScriptHandler&) = delete;
- ~cmCTestScriptHandler() override;
-
- void Initialize() override;
+ ~cmCTestScriptHandler();
void CreateCMake();
cmake* GetCMake() { return this->CMake.get(); }
-
- void SetRunCurrentScript(bool value);
+ cmMakefile* GetMakefile() { return this->Makefile.get(); }
private:
// reads in a script
int ReadInScript(const std::string& total_script_arg);
int ExecuteScript(const std::string& total_script_arg);
- // extract vars from the script to set ivars
- int ExtractVariables();
-
- // perform a CVS checkout of the source dir
- int CheckOutSourceDir();
-
- // perform any extra cvs updates that were requested
- int PerformExtraUpdates();
-
- // backup and restore dirs
- int BackupDirectories();
- void RestoreBackupDirectories();
-
int RunConfigurationScript(const std::string& script, bool pscope);
- int RunConfigurationDashboard();
- // Add ctest command
- void AddCTestCommand(std::string const& name,
- std::unique_ptr<cmCTestCommand> command);
-
- // Try to remove the binary directory once
- static cmsys::Status TryToRemoveBinaryDirectoryOnce(
- const std::string& directoryPath);
-
+ cmCTest* CTest = nullptr;
std::vector<std::string> ConfigurationScripts;
std::vector<bool> ScriptProcessScope;
- bool ShouldRunCurrentScript;
-
- bool Backup = false;
- bool EmptyBinDir = false;
- bool EmptyBinDirOnce = false;
-
- std::string SourceDir;
- std::string BinaryDir;
- std::string BackupSourceDir;
- std::string BackupBinaryDir;
- std::string CTestRoot;
- std::string CVSCheckOut;
- std::string CTestCmd;
- std::string UpdateCmd;
- std::string CTestEnv;
- std::string InitialCache;
- std::string CMakeCmd;
- std::string CMOutFile;
- std::vector<std::string> ExtraUpdates;
-
- // the *60 is because the settings are in minutes but GetTime is seconds
- double MinimumInterval = 30 * 60;
- double ContinuousDuration = -1;
-
- // what time in seconds did this script start running
- std::chrono::steady_clock::time_point ScriptStartTime =
- std::chrono::steady_clock::time_point();
-
std::unique_ptr<cmMakefile> Makefile;
cmMakefile* ParentMakefile = nullptr;
std::unique_ptr<cmGlobalGenerator> GlobalGenerator;
diff --git a/Source/CTest/cmCTestSleepCommand.cxx b/Source/CTest/cmCTestSleepCommand.cxx
index 623d3b6..f57d856 100644
--- a/Source/CTest/cmCTestSleepCommand.cxx
+++ b/Source/CTest/cmCTestSleepCommand.cxx
@@ -2,42 +2,34 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestSleepCommand.h"
+#include <chrono>
#include <cstdlib>
+#include <thread>
-#include "cmCTestScriptHandler.h"
+#include "cmExecutionStatus.h"
-class cmExecutionStatus;
-
-bool cmCTestSleepCommand::InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& /*unused*/)
+bool cmCTestSleepCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
{
- if (args.empty()) {
- this->SetError("called with incorrect number of arguments");
- return false;
- }
-
// sleep for specified seconds
- unsigned int time1 = atoi(args[0].c_str());
if (args.size() == 1) {
- cmCTestScriptHandler::SleepInSeconds(time1);
- // update the elapsed time since it could have slept for a while
- this->CTestScriptHandler->UpdateElapsedTime();
+ unsigned int duration = atoi(args[0].c_str());
+ std::this_thread::sleep_for(std::chrono::seconds(duration));
return true;
}
// sleep up to a duration
if (args.size() == 3) {
+ unsigned int time1 = atoi(args[0].c_str());
unsigned int duration = atoi(args[1].c_str());
unsigned int time2 = atoi(args[2].c_str());
if (time1 + duration > time2) {
duration = (time1 + duration - time2);
- cmCTestScriptHandler::SleepInSeconds(duration);
- // update the elapsed time since it could have slept for a while
- this->CTestScriptHandler->UpdateElapsedTime();
+ std::this_thread::sleep_for(std::chrono::seconds(duration));
}
return true;
}
- this->SetError("called with incorrect number of arguments");
+ status.SetError("called with incorrect number of arguments");
return false;
}
diff --git a/Source/CTest/cmCTestSleepCommand.h b/Source/CTest/cmCTestSleepCommand.h
index 9425576..3d4eb1e 100644
--- a/Source/CTest/cmCTestSleepCommand.h
+++ b/Source/CTest/cmCTestSleepCommand.h
@@ -5,42 +5,9 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <string>
-#include <utility>
#include <vector>
-#include <cm/memory>
-
-#include "cmCTestCommand.h"
-#include "cmCommand.h"
-
class cmExecutionStatus;
-/** \class cmCTestSleep
- * \brief Run a ctest script
- *
- * cmLibrarysCommand defines a list of executable (i.e., test)
- * programs to create.
- */
-class cmCTestSleepCommand : public cmCTestCommand
-{
-public:
- cmCTestSleepCommand() {}
-
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- auto ni = cm::make_unique<cmCTestSleepCommand>();
- ni->CTest = this->CTest;
- ni->CTestScriptHandler = this->CTestScriptHandler;
- return std::unique_ptr<cmCommand>(std::move(ni));
- }
-
- /**
- * This is called when the command is first encountered in
- * the CMakeLists.txt file.
- */
- bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& status) override;
-};
+bool cmCTestSleepCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status);
diff --git a/Source/CTest/cmCTestStartCommand.cxx b/Source/CTest/cmCTestStartCommand.cxx
index 84d12d7..3f610d0 100644
--- a/Source/CTest/cmCTestStartCommand.cxx
+++ b/Source/CTest/cmCTestStartCommand.cxx
@@ -7,28 +7,24 @@
#include "cmCTest.h"
#include "cmCTestVC.h"
+#include "cmExecutionStatus.h"
#include "cmGeneratedFileStream.h"
#include "cmMakefile.h"
+#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmValue.h"
-class cmExecutionStatus;
-
-cmCTestStartCommand::cmCTestStartCommand()
-{
- this->CreateNewTag = true;
- this->Quiet = false;
-}
-
bool cmCTestStartCommand::InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& /*unused*/)
+ cmExecutionStatus& status) const
{
if (args.empty()) {
- this->SetError("called with incorrect number of arguments");
+ status.SetError("called with incorrect number of arguments");
return false;
}
size_t cnt = 0;
+ bool append = false;
+ bool quiet = false;
const char* smodel = nullptr;
cmValue src_dir;
cmValue bld_dir;
@@ -40,17 +36,17 @@
args[cnt] == "QUIET") {
std::ostringstream e;
e << args[cnt - 1] << " argument missing group name";
- this->SetError(e.str());
+ status.SetError(e.str());
return false;
}
this->CTest->SetSpecificGroup(args[cnt].c_str());
cnt++;
} else if (args[cnt] == "APPEND") {
cnt++;
- this->CreateNewTag = false;
+ append = true;
} else if (args[cnt] == "QUIET") {
cnt++;
- this->Quiet = true;
+ quiet = true;
} else if (!smodel) {
smodel = args[cnt].c_str();
cnt++;
@@ -61,43 +57,42 @@
bld_dir = cmValue(args[cnt]);
cnt++;
} else {
- this->SetError("Too many arguments");
+ status.SetError("Too many arguments");
return false;
}
}
- if (!src_dir) {
- src_dir = this->Makefile->GetDefinition("CTEST_SOURCE_DIRECTORY");
- }
- if (!bld_dir) {
- bld_dir = this->Makefile->GetDefinition("CTEST_BINARY_DIRECTORY");
- }
- if (!src_dir) {
- this->SetError("source directory not specified. Specify source directory "
- "as an argument or set CTEST_SOURCE_DIRECTORY");
- return false;
- }
- if (!bld_dir) {
- this->SetError("binary directory not specified. Specify binary directory "
- "as an argument or set CTEST_BINARY_DIRECTORY");
- return false;
- }
- if (!smodel && this->CreateNewTag) {
- this->SetError("no test model specified and APPEND not specified. Specify "
- "either a test model or the APPEND argument");
- return false;
- }
+ cmMakefile& mf = status.GetMakefile();
- cmSystemTools::AddKeepPath(*src_dir);
- cmSystemTools::AddKeepPath(*bld_dir);
+ if (!src_dir) {
+ src_dir = mf.GetDefinition("CTEST_SOURCE_DIRECTORY");
+ }
+ if (!bld_dir) {
+ bld_dir = mf.GetDefinition("CTEST_BINARY_DIRECTORY");
+ }
+ if (!src_dir) {
+ status.SetError("source directory not specified. Specify source directory "
+ "as an argument or set CTEST_SOURCE_DIRECTORY");
+ return false;
+ }
+ if (!bld_dir) {
+ status.SetError("binary directory not specified. Specify binary directory "
+ "as an argument or set CTEST_BINARY_DIRECTORY");
+ return false;
+ }
+ if (!smodel && !append) {
+ status.SetError(
+ "no test model specified and APPEND not specified. Specify "
+ "either a test model or the APPEND argument");
+ return false;
+ }
this->CTest->EmptyCTestConfiguration();
std::string sourceDir = cmSystemTools::CollapseFullPath(*src_dir);
std::string binaryDir = cmSystemTools::CollapseFullPath(*bld_dir);
- this->CTest->SetCTestConfiguration("SourceDirectory", sourceDir,
- this->Quiet);
- this->CTest->SetCTestConfiguration("BuildDirectory", binaryDir, this->Quiet);
+ this->CTest->SetCTestConfiguration("SourceDirectory", sourceDir, quiet);
+ this->CTest->SetCTestConfiguration("BuildDirectory", binaryDir, quiet);
if (smodel) {
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
@@ -105,7 +100,7 @@
<< smodel << std::endl
<< " Source directory: " << *src_dir << std::endl
<< " Build directory: " << *bld_dir << std::endl,
- this->Quiet);
+ quiet);
} else {
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
"Run dashboard with "
@@ -113,12 +108,12 @@
<< std::endl
<< " Source directory: " << *src_dir << std::endl
<< " Build directory: " << *bld_dir << std::endl,
- this->Quiet);
+ quiet);
}
const char* group = this->CTest->GetSpecificGroup();
if (group) {
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
- " Group: " << group << std::endl, this->Quiet);
+ " Group: " << group << std::endl, quiet);
}
// Log startup actions.
@@ -131,7 +126,7 @@
}
// Make sure the source directory exists.
- if (!this->InitialCheckout(ofs, sourceDir)) {
+ if (!this->InitialCheckout(ofs, sourceDir, status)) {
return false;
}
if (!cmSystemTools::FileIsDirectory(sourceDir)) {
@@ -140,11 +135,10 @@
<< " " << sourceDir << "\n"
<< "which is not an existing directory. "
<< "Set CTEST_CHECKOUT_COMMAND to a command line to create it.";
- this->SetError(e.str());
+ status.SetError(e.str());
return false;
}
- this->CTest->SetRunCurrentScript(false);
this->CTest->SetSuppressUpdatingCTestConfiguration(true);
int model;
if (smodel) {
@@ -155,18 +149,90 @@
this->CTest->SetTestModel(model);
this->CTest->SetProduceXML(true);
- return this->CTest->InitializeFromCommand(this);
+ std::string fname;
+
+ std::string src_dir_fname = cmStrCat(sourceDir, "/CTestConfig.cmake");
+ cmSystemTools::ConvertToUnixSlashes(src_dir_fname);
+
+ std::string bld_dir_fname = cmStrCat(binaryDir, "/CTestConfig.cmake");
+ cmSystemTools::ConvertToUnixSlashes(bld_dir_fname);
+
+ if (cmSystemTools::FileExists(bld_dir_fname)) {
+ fname = bld_dir_fname;
+ } else if (cmSystemTools::FileExists(src_dir_fname)) {
+ fname = src_dir_fname;
+ }
+
+ if (!fname.empty()) {
+ cmCTestOptionalLog(
+ this->CTest, OUTPUT,
+ " Reading ctest configuration file: " << fname << std::endl, quiet);
+ bool readit = mf.ReadDependentFile(fname);
+ if (!readit) {
+ std::string m = cmStrCat("Could not find include file: ", fname);
+ status.SetError(m);
+ return false;
+ }
+ }
+
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ &mf, "NightlyStartTime", "CTEST_NIGHTLY_START_TIME", quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(&mf, "Site",
+ "CTEST_SITE", quiet);
+ this->CTest->SetCTestConfigurationFromCMakeVariable(
+ &mf, "BuildName", "CTEST_BUILD_NAME", quiet);
+
+ this->CTest->Initialize(bld_dir);
+ this->CTest->UpdateCTestConfiguration();
+
+ cmCTestOptionalLog(
+ this->CTest, OUTPUT,
+ " Site: " << this->CTest->GetCTestConfiguration("Site") << std::endl
+ << " Build name: "
+ << cmCTest::SafeBuildIdField(
+ this->CTest->GetCTestConfiguration("BuildName"))
+ << std::endl,
+ quiet);
+
+ if (this->CTest->GetTestModel() == cmCTest::NIGHTLY &&
+ this->CTest->GetCTestConfiguration("NightlyStartTime").empty()) {
+ cmCTestOptionalLog(
+ this->CTest, WARNING,
+ "WARNING: No nightly start time found please set in CTestConfig.cmake"
+ " or DartConfig.cmake"
+ << std::endl,
+ quiet);
+ return false;
+ }
+
+ this->CTest->ReadCustomConfigurationFileTree(bld_dir, &mf);
+
+ if (append) {
+ if (!this->CTest->ReadExistingTag(quiet)) {
+ return false;
+ }
+ } else {
+ if (!this->CTest->CreateNewTag(quiet)) {
+ return false;
+ }
+ }
+
+ cmCTestOptionalLog(this->CTest, OUTPUT,
+ " Use " << this->CTest->GetTestGroupString() << " tag: "
+ << this->CTest->GetCurrentTag() << std::endl,
+ quiet);
+ return true;
}
bool cmCTestStartCommand::InitialCheckout(std::ostream& ofs,
- std::string const& sourceDir)
+ std::string const& sourceDir,
+ cmExecutionStatus& status) const
{
+ cmMakefile& mf = status.GetMakefile();
// Use the user-provided command to create the source tree.
- cmValue initialCheckoutCommand =
- this->Makefile->GetDefinition("CTEST_CHECKOUT_COMMAND");
+ cmValue initialCheckoutCommand = mf.GetDefinition("CTEST_CHECKOUT_COMMAND");
if (!initialCheckoutCommand) {
- initialCheckoutCommand =
- this->Makefile->GetDefinition("CTEST_CVS_CHECKOUT");
+ initialCheckoutCommand = mf.GetDefinition("CTEST_CVS_CHECKOUT");
}
if (initialCheckoutCommand) {
// Use a generic VC object to run and log the command.
diff --git a/Source/CTest/cmCTestStartCommand.h b/Source/CTest/cmCTestStartCommand.h
index b3d06a7..325471a 100644
--- a/Source/CTest/cmCTestStartCommand.h
+++ b/Source/CTest/cmCTestStartCommand.h
@@ -6,13 +6,9 @@
#include <iosfwd>
#include <string>
-#include <utility>
#include <vector>
-#include <cm/memory>
-
#include "cmCTestCommand.h"
-#include "cmCommand.h"
class cmExecutionStatus;
@@ -24,40 +20,16 @@
class cmCTestStartCommand : public cmCTestCommand
{
public:
- cmCTestStartCommand();
-
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- auto ni = cm::make_unique<cmCTestStartCommand>();
- ni->CTest = this->CTest;
- ni->CTestScriptHandler = this->CTestScriptHandler;
- ni->CreateNewTag = this->CreateNewTag;
- ni->Quiet = this->Quiet;
- return std::unique_ptr<cmCommand>(std::move(ni));
- }
+ using cmCTestCommand::cmCTestCommand;
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& status) override;
-
- /**
- * Will this invocation of ctest_start create a new TAG file?
- */
- bool ShouldCreateNewTag() { return this->CreateNewTag; }
-
- /**
- * Should this invocation of ctest_start output non-error messages?
- */
- bool ShouldBeQuiet() { return this->Quiet; }
+ cmExecutionStatus& status) const override;
private:
- bool InitialCheckout(std::ostream& ofs, std::string const& sourceDir);
- bool CreateNewTag;
- bool Quiet;
+ bool InitialCheckout(std::ostream& ofs, std::string const& sourceDir,
+ cmExecutionStatus& status) const;
};
diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx
index 029f81f..8ae0f4c 100644
--- a/Source/CTest/cmCTestSubmitCommand.cxx
+++ b/Source/CTest/cmCTestSubmitCommand.cxx
@@ -10,9 +10,11 @@
#include <cm/vector>
#include <cmext/string_view>
+#include "cmArgumentParser.h"
#include "cmCTest.h"
+#include "cmCTestGenericHandler.h"
#include "cmCTestSubmitHandler.h"
-#include "cmCommand.h"
+#include "cmExecutionStatus.h"
#include "cmList.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
@@ -20,117 +22,101 @@
#include "cmSystemTools.h"
#include "cmValue.h"
-class cmExecutionStatus;
-
-/**
- * This is a virtual constructor for the command.
- */
-std::unique_ptr<cmCommand> cmCTestSubmitCommand::Clone()
+std::unique_ptr<cmCTestGenericHandler> cmCTestSubmitCommand::InitializeHandler(
+ HandlerArguments& arguments, cmExecutionStatus& status) const
{
- auto ni = cm::make_unique<cmCTestSubmitCommand>();
- ni->CTest = this->CTest;
- ni->CTestScriptHandler = this->CTestScriptHandler;
- return std::unique_ptr<cmCommand>(std::move(ni));
-}
-
-cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler()
-{
- cmValue submitURL = !this->SubmitURL.empty()
- ? cmValue(this->SubmitURL)
- : this->Makefile->GetDefinition("CTEST_SUBMIT_URL");
+ cmMakefile& mf = status.GetMakefile();
+ auto const& args = static_cast<SubmitArguments&>(arguments);
+ cmValue submitURL = !args.SubmitURL.empty()
+ ? cmValue(args.SubmitURL)
+ : mf.GetDefinition("CTEST_SUBMIT_URL");
if (submitURL) {
- this->CTest->SetCTestConfiguration("SubmitURL", *submitURL, this->Quiet);
+ this->CTest->SetCTestConfiguration("SubmitURL", *submitURL, args.Quiet);
} else {
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "DropMethod", "CTEST_DROP_METHOD", this->Quiet);
+ &mf, "DropMethod", "CTEST_DROP_METHOD", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "DropSiteUser", "CTEST_DROP_SITE_USER", this->Quiet);
+ &mf, "DropSiteUser", "CTEST_DROP_SITE_USER", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "DropSitePassword", "CTEST_DROP_SITE_PASSWORD",
- this->Quiet);
+ &mf, "DropSitePassword", "CTEST_DROP_SITE_PASSWORD", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "DropSite", "CTEST_DROP_SITE", this->Quiet);
+ &mf, "DropSite", "CTEST_DROP_SITE", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "DropLocation", "CTEST_DROP_LOCATION", this->Quiet);
+ &mf, "DropLocation", "CTEST_DROP_LOCATION", args.Quiet);
}
if (!this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "TLSVersion", "CTEST_TLS_VERSION", this->Quiet)) {
- if (cmValue tlsVersionVar =
- this->Makefile->GetDefinition("CMAKE_TLS_VERSION")) {
+ &mf, "TLSVersion", "CTEST_TLS_VERSION", args.Quiet)) {
+ if (cmValue tlsVersionVar = mf.GetDefinition("CMAKE_TLS_VERSION")) {
cmCTestOptionalLog(
this->CTest, HANDLER_VERBOSE_OUTPUT,
"SetCTestConfiguration from CMAKE_TLS_VERSION:TLSVersion:"
<< *tlsVersionVar << std::endl,
- this->Quiet);
+ args.Quiet);
this->CTest->SetCTestConfiguration("TLSVersion", *tlsVersionVar,
- this->Quiet);
+ args.Quiet);
} else if (cm::optional<std::string> tlsVersionEnv =
cmSystemTools::GetEnvVar("CMAKE_TLS_VERSION")) {
cmCTestOptionalLog(
this->CTest, HANDLER_VERBOSE_OUTPUT,
"SetCTestConfiguration from ENV{CMAKE_TLS_VERSION}:TLSVersion:"
<< *tlsVersionEnv << std::endl,
- this->Quiet);
+ args.Quiet);
this->CTest->SetCTestConfiguration("TLSVersion", *tlsVersionEnv,
- this->Quiet);
+ args.Quiet);
}
}
if (!this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "TLSVerify", "CTEST_TLS_VERIFY", this->Quiet)) {
- if (cmValue tlsVerifyVar =
- this->Makefile->GetDefinition("CMAKE_TLS_VERIFY")) {
+ &mf, "TLSVerify", "CTEST_TLS_VERIFY", args.Quiet)) {
+ if (cmValue tlsVerifyVar = mf.GetDefinition("CMAKE_TLS_VERIFY")) {
cmCTestOptionalLog(
this->CTest, HANDLER_VERBOSE_OUTPUT,
"SetCTestConfiguration from CMAKE_TLS_VERIFY:TLSVerify:"
<< *tlsVerifyVar << std::endl,
- this->Quiet);
+ args.Quiet);
this->CTest->SetCTestConfiguration("TLSVerify", *tlsVerifyVar,
- this->Quiet);
+ args.Quiet);
} else if (cm::optional<std::string> tlsVerifyEnv =
cmSystemTools::GetEnvVar("CMAKE_TLS_VERIFY")) {
cmCTestOptionalLog(
this->CTest, HANDLER_VERBOSE_OUTPUT,
"SetCTestConfiguration from ENV{CMAKE_TLS_VERIFY}:TLSVerify:"
<< *tlsVerifyEnv << std::endl,
- this->Quiet);
+ args.Quiet);
this->CTest->SetCTestConfiguration("TLSVerify", *tlsVerifyEnv,
- this->Quiet);
+ args.Quiet);
}
}
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "CurlOptions", "CTEST_CURL_OPTIONS", this->Quiet);
+ &mf, "CurlOptions", "CTEST_CURL_OPTIONS", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "SubmitInactivityTimeout",
- "CTEST_SUBMIT_INACTIVITY_TIMEOUT", this->Quiet);
+ &mf, "SubmitInactivityTimeout", "CTEST_SUBMIT_INACTIVITY_TIMEOUT",
+ args.Quiet);
- cmValue notesFilesVariable =
- this->Makefile->GetDefinition("CTEST_NOTES_FILES");
+ cmValue notesFilesVariable = mf.GetDefinition("CTEST_NOTES_FILES");
if (notesFilesVariable) {
cmList notesFiles{ *notesFilesVariable };
- this->CTest->GenerateNotesFile(notesFiles);
+ this->CTest->GenerateNotesFile(mf.GetCMakeInstance(), notesFiles);
}
- cmValue extraFilesVariable =
- this->Makefile->GetDefinition("CTEST_EXTRA_SUBMIT_FILES");
+ cmValue extraFilesVariable = mf.GetDefinition("CTEST_EXTRA_SUBMIT_FILES");
if (extraFilesVariable) {
cmList extraFiles{ *extraFilesVariable };
if (!this->CTest->SubmitExtraFiles(extraFiles)) {
- this->SetError("problem submitting extra files.");
+ status.SetError("problem submitting extra files.");
return nullptr;
}
}
- cmCTestSubmitHandler* handler = this->CTest->GetSubmitHandler();
- handler->Initialize();
+ auto handler = cm::make_unique<cmCTestSubmitHandler>(this->CTest);
// If no FILES or PARTS given, *all* PARTS are submitted by default.
//
// If FILES are given, but not PARTS, only the FILES are submitted
// and *no* PARTS are submitted.
// (This is why we select the empty "noParts" set in the
- // if(this->Files) block below...)
+ // if(args.Files) block below...)
//
// If PARTS are given, only the selected PARTS are submitted.
//
@@ -139,7 +125,7 @@
// If given explicit FILES to submit, pass them to the handler.
//
- if (this->Files) {
+ if (args.Files) {
// Intentionally select *no* PARTS. (Pass an empty set.) If PARTS
// were also explicitly mentioned, they will be selected below...
// But FILES with no PARTS mentioned should just submit the FILES
@@ -147,99 +133,111 @@
//
handler->SelectParts(std::set<cmCTest::Part>());
handler->SelectFiles(
- std::set<std::string>(this->Files->begin(), this->Files->end()));
+ std::set<std::string>(args.Files->begin(), args.Files->end()));
}
// If a PARTS option was given, select only the named parts for submission.
//
- if (this->Parts) {
+ if (args.Parts) {
auto parts =
- cmMakeRange(*(this->Parts)).transform([this](std::string const& arg) {
+ cmMakeRange(*(args.Parts)).transform([this](std::string const& arg) {
return this->CTest->GetPartFromName(arg);
});
handler->SelectParts(std::set<cmCTest::Part>(parts.begin(), parts.end()));
}
// Pass along any HTTPHEADER to the handler if this option was given.
- if (!this->HttpHeaders.empty()) {
- handler->SetHttpHeaders(this->HttpHeaders);
+ if (!args.HttpHeaders.empty()) {
+ handler->SetHttpHeaders(args.HttpHeaders);
}
- handler->SetOption("RetryDelay", this->RetryDelay);
- handler->SetOption("RetryCount", this->RetryCount);
- handler->SetOption("InternalTest", this->InternalTest ? "ON" : "OFF");
+ handler->RetryDelay = args.RetryDelay;
+ handler->RetryCount = args.RetryCount;
+ handler->InternalTest = args.InternalTest;
- handler->SetQuiet(this->Quiet);
+ handler->SetQuiet(args.Quiet);
- if (this->CDashUpload) {
- handler->SetOption("CDashUploadFile", this->CDashUploadFile);
- handler->SetOption("CDashUploadType", this->CDashUploadType);
+ if (args.CDashUpload) {
+ handler->CDashUpload = true;
+ handler->CDashUploadFile = args.CDashUploadFile;
+ handler->CDashUploadType = args.CDashUploadType;
}
- return handler;
+ return std::unique_ptr<cmCTestGenericHandler>(std::move(handler));
}
bool cmCTestSubmitCommand::InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& status)
+ cmExecutionStatus& status) const
{
- this->CDashUpload = !args.empty() && args[0] == "CDASH_UPLOAD";
-
- bool ret = this->cmCTestHandlerCommand::InitialPass(args, status);
-
- if (!this->BuildID.empty()) {
- this->Makefile->AddDefinition(this->BuildID, this->CTest->GetBuildID());
- }
-
- return ret;
-}
-
-void cmCTestSubmitCommand::BindArguments()
-{
- if (this->CDashUpload) {
- // Arguments specific to the CDASH_UPLOAD signature.
- this->Bind("CDASH_UPLOAD", this->CDashUploadFile);
- this->Bind("CDASH_UPLOAD_TYPE", this->CDashUploadType);
- } else {
- // Arguments that cannot be used with CDASH_UPLOAD.
- this->Bind("PARTS"_s, this->Parts);
- this->Bind("FILES"_s, this->Files);
- }
// Arguments used by both modes.
- this->Bind("BUILD_ID"_s, this->BuildID);
- this->Bind("HTTPHEADER"_s, this->HttpHeaders);
- this->Bind("RETRY_COUNT"_s, this->RetryCount);
- this->Bind("RETRY_DELAY"_s, this->RetryDelay);
- this->Bind("SUBMIT_URL"_s, this->SubmitURL);
- this->Bind("INTERNAL_TEST_CHECKSUM", this->InternalTest);
+ static auto const parserBase =
+ cmArgumentParser<SubmitArguments>{ MakeHandlerParser<SubmitArguments>() }
+ .Bind("BUILD_ID"_s, &SubmitArguments::BuildID)
+ .Bind("HTTPHEADER"_s, &SubmitArguments::HttpHeaders)
+ .Bind("RETRY_COUNT"_s, &SubmitArguments::RetryCount)
+ .Bind("RETRY_DELAY"_s, &SubmitArguments::RetryDelay)
+ .Bind("SUBMIT_URL"_s, &SubmitArguments::SubmitURL)
+ .Bind("INTERNAL_TEST_CHECKSUM"_s, &SubmitArguments::InternalTest);
- // Look for other arguments.
- this->cmCTestHandlerCommand::BindArguments();
+ // Arguments specific to the CDASH_UPLOAD signature.
+ static auto const uploadParser =
+ cmArgumentParser<SubmitArguments>{ parserBase }
+ .Bind("CDASH_UPLOAD"_s, &SubmitArguments::CDashUploadFile)
+ .Bind("CDASH_UPLOAD_TYPE"_s, &SubmitArguments::CDashUploadType);
+
+ // Arguments that cannot be used with CDASH_UPLOAD.
+ static auto const partsParser =
+ cmArgumentParser<SubmitArguments>{ parserBase }
+ .Bind("PARTS"_s, &SubmitArguments::Parts)
+ .Bind("FILES"_s, &SubmitArguments::Files);
+
+ bool const cdashUpload = !args.empty() && args[0] == "CDASH_UPLOAD";
+ auto const& parser = cdashUpload ? uploadParser : partsParser;
+
+ return this->Invoke(parser, args, status, [&](SubmitArguments& a) -> bool {
+ a.CDashUpload = cdashUpload;
+ return this->ExecuteHandlerCommand(a, status);
+ });
}
-void cmCTestSubmitCommand::CheckArguments()
+void cmCTestSubmitCommand::CheckArguments(HandlerArguments& arguments,
+ cmExecutionStatus& status) const
{
- if (this->Parts) {
- cm::erase_if(*(this->Parts), [this](std::string const& arg) -> bool {
+ cmMakefile& mf = status.GetMakefile();
+ auto& args = static_cast<SubmitArguments&>(arguments);
+ if (args.Parts) {
+ cm::erase_if(*(args.Parts), [this, &mf](std::string const& arg) -> bool {
cmCTest::Part p = this->CTest->GetPartFromName(arg);
if (p == cmCTest::PartCount) {
std::ostringstream e;
e << "Part name \"" << arg << "\" is invalid.";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ mf.IssueMessage(MessageType::FATAL_ERROR, e.str());
return true;
}
return false;
});
}
- if (this->Files) {
- cm::erase_if(*(this->Files), [this](std::string const& arg) -> bool {
+ if (args.Files) {
+ cm::erase_if(*(args.Files), [&mf](std::string const& arg) -> bool {
if (!cmSystemTools::FileExists(arg)) {
std::ostringstream e;
e << "File \"" << arg << "\" does not exist. Cannot submit "
<< "a non-existent file.";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ mf.IssueMessage(MessageType::FATAL_ERROR, e.str());
return true;
}
return false;
});
}
}
+
+void cmCTestSubmitCommand::ProcessAdditionalValues(
+ cmCTestGenericHandler*, HandlerArguments const& arguments,
+ cmExecutionStatus& status) const
+{
+ cmMakefile& mf = status.GetMakefile();
+ auto const& args = static_cast<SubmitArguments const&>(arguments);
+ if (!args.BuildID.empty()) {
+ mf.AddDefinition(args.BuildID, this->CTest->GetBuildID());
+ }
+}
diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h
index b67f182..9c02fc8 100644
--- a/Source/CTest/cmCTestSubmitCommand.h
+++ b/Source/CTest/cmCTestSubmitCommand.h
@@ -13,45 +13,45 @@
#include "cmArgumentParserTypes.h"
#include "cmCTestHandlerCommand.h"
-class cmCommand;
-class cmCTestGenericHandler;
class cmExecutionStatus;
+class cmCTestGenericHandler;
-/** \class cmCTestSubmit
- * \brief Run a ctest script
- *
- * cmCTestSubmitCommand defineds the command to submit the test results for
- * the project.
- */
class cmCTestSubmitCommand : public cmCTestHandlerCommand
{
public:
- std::unique_ptr<cmCommand> Clone() override;
-
- bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus& status) override;
-
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- std::string GetName() const override { return "ctest_submit"; }
+ using cmCTestHandlerCommand::cmCTestHandlerCommand;
protected:
- void BindArguments() override;
- void CheckArguments() override;
- cmCTestGenericHandler* InitializeHandler() override;
+ struct SubmitArguments : HandlerArguments
+ {
+ bool CDashUpload = false;
+ bool InternalTest = false;
- bool CDashUpload = false;
- bool InternalTest = false;
+ std::string BuildID;
+ std::string CDashUploadFile;
+ std::string CDashUploadType;
+ std::string RetryCount;
+ std::string RetryDelay;
+ std::string SubmitURL;
- std::string BuildID;
- std::string CDashUploadFile;
- std::string CDashUploadType;
- std::string RetryCount;
- std::string RetryDelay;
- std::string SubmitURL;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Files;
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> HttpHeaders;
+ cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Parts;
+ };
- cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Files;
- ArgumentParser::MaybeEmpty<std::vector<std::string>> HttpHeaders;
- cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Parts;
+private:
+ std::string GetName() const override { return "ctest_submit"; }
+
+ void CheckArguments(HandlerArguments& arguments,
+ cmExecutionStatus& status) const override;
+
+ std::unique_ptr<cmCTestGenericHandler> InitializeHandler(
+ HandlerArguments& arguments, cmExecutionStatus& status) const override;
+
+ void ProcessAdditionalValues(cmCTestGenericHandler* handler,
+ HandlerArguments const& arguments,
+ cmExecutionStatus& status) const override;
+
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) const override;
};
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index 91dea55..1564c0e 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -19,7 +19,6 @@
#include "cmAlgorithms.h"
#include "cmCTest.h"
#include "cmCTestCurl.h"
-#include "cmCTestScriptHandler.h"
#include "cmCryptoHash.h"
#include "cmCurl.h"
#include "cmDuration.h"
@@ -117,40 +116,15 @@
return 0;
}
-cmCTestSubmitHandler::cmCTestSubmitHandler()
-{
- this->Initialize();
-}
-
-void cmCTestSubmitHandler::Initialize()
+cmCTestSubmitHandler::cmCTestSubmitHandler(cmCTest* ctest)
+ : Superclass(ctest)
+ , HttpHeaders(ctest->GetCommandLineHttpHeaders())
{
// We submit all available parts by default.
for (cmCTest::Part p = cmCTest::PartStart; p != cmCTest::PartCount;
p = static_cast<cmCTest::Part>(p + 1)) {
this->SubmitPart[p] = true;
}
- this->HasWarnings = false;
- this->HasErrors = false;
- this->Superclass::Initialize();
- this->HTTPProxy.clear();
- this->HTTPProxyType = 0;
- this->HTTPProxyAuth.clear();
- this->LogFile = nullptr;
- this->Files.clear();
-}
-
-int cmCTestSubmitHandler::ProcessCommandLineArguments(
- const std::string& currentArg, size_t& idx,
- const std::vector<std::string>& allArgs, bool& validArg)
-{
- if (cmHasLiteralPrefix(currentArg, "--http-header") &&
- idx < allArgs.size() - 1) {
- ++idx;
- this->HttpHeaders.push_back(allArgs[idx]);
- this->CommandLineHttpHeaders.push_back(allArgs[idx]);
- validArg = true;
- }
- return 1;
}
bool cmCTestSubmitHandler::SubmitUsingHTTP(
@@ -275,10 +249,8 @@
upload_as += "&stamp=";
upload_as += ctest_curl.Escape(this->CTest->GetCurrentTag());
upload_as += "-";
- upload_as += ctest_curl.Escape(this->CTest->GetTestModelString());
- cmCTestScriptHandler* ch = this->CTest->GetScriptHandler();
- cmake* cm = ch->GetCMake();
- if (cm) {
+ upload_as += ctest_curl.Escape(this->CTest->GetTestGroupString());
+ if (cmake* cm = this->CMake) {
cmValue subproject = cm->GetState()->GetGlobalProperty("SubProject");
if (subproject) {
upload_as += "&subproject=";
@@ -300,7 +272,7 @@
upload_as += "&MD5=";
- if (this->GetOption("InternalTest").IsOn()) {
+ if (this->InternalTest) {
upload_as += "ffffffffffffffffffffffffffffffff";
} else {
cmCryptoHash hasher(cmCryptoHash::AlgoMD5);
@@ -382,8 +354,8 @@
bool successful_submission = response_code == 200;
if (!successful_submission || this->HasErrors) {
- std::string retryDelay = *this->GetOption("RetryDelay");
- std::string retryCount = *this->GetOption("RetryCount");
+ std::string retryDelay = this->RetryDelay;
+ std::string retryCount = this->RetryCount;
auto delay = cmDuration(
retryDelay.empty()
@@ -512,10 +484,6 @@
int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file,
std::string const& typeString)
{
- if (file.empty()) {
- cmCTestLog(this->CTest, ERROR_MESSAGE, "Upload file not specified\n");
- return -1;
- }
if (!cmSystemTools::FileExists(file)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Upload file not found: '" << file << "'\n");
@@ -542,11 +510,11 @@
fields = url.substr(pos + 1);
url.erase(pos);
}
- bool internalTest = this->GetOption("InternalTest").IsOn();
+ bool internalTest = this->InternalTest;
// Get RETRY_COUNT and RETRY_DELAY values if they were set.
- std::string retryDelayString = *this->GetOption("RetryDelay");
- std::string retryCountString = *this->GetOption("RetryCount");
+ std::string retryDelayString = this->RetryDelay;
+ std::string retryCountString = this->RetryCount;
auto retryDelay = std::chrono::seconds(0);
if (!retryDelayString.empty()) {
unsigned long retryDelayValue = 0;
@@ -573,9 +541,8 @@
// has already been uploaded
// TODO I added support for subproject. You would need to add
// a "&subproject=subprojectname" to the first POST.
- cmCTestScriptHandler* ch = this->CTest->GetScriptHandler();
- cmake* cm = ch->GetCMake();
- cmValue subproject = cm->GetState()->GetGlobalProperty("SubProject");
+ cmValue subproject =
+ this->CMake->GetState()->GetGlobalProperty("SubProject");
// TODO: Encode values for a URL instead of trusting caller.
std::ostringstream str;
if (subproject) {
@@ -584,18 +551,18 @@
auto timeNow =
std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
str << "stamp=" << curl.Escape(this->CTest->GetCurrentTag()) << "-"
- << curl.Escape(this->CTest->GetTestModelString()) << "&"
- << "model=" << curl.Escape(this->CTest->GetTestModelString()) << "&"
+ << curl.Escape(this->CTest->GetTestGroupString()) << "&"
+ << "model=" << curl.Escape(this->CTest->GetTestGroupString()) << "&"
<< "build="
<< curl.Escape(this->CTest->GetCTestConfiguration("BuildName")) << "&"
<< "site=" << curl.Escape(this->CTest->GetCTestConfiguration("Site"))
<< "&"
- << "group=" << curl.Escape(this->CTest->GetTestModelString())
+ << "group=" << curl.Escape(this->CTest->GetTestGroupString())
<< "&"
// For now, we send both "track" and "group" to CDash in case we're
// submitting to an older instance that still expects the prior
// terminology.
- << "track=" << curl.Escape(this->CTest->GetTestModelString()) << "&"
+ << "track=" << curl.Escape(this->CTest->GetTestGroupString()) << "&"
<< "starttime=" << timeNow << "&"
<< "endtime=" << timeNow << "&"
<< "datafilesmd5[0]=" << md5sum << "&"
@@ -735,10 +702,9 @@
int cmCTestSubmitHandler::ProcessHandler()
{
- cmValue cdashUploadFile = this->GetOption("CDashUploadFile");
- cmValue cdashUploadType = this->GetOption("CDashUploadType");
- if (cdashUploadFile && cdashUploadType) {
- return this->HandleCDashUploadFile(*cdashUploadFile, *cdashUploadType);
+ if (this->CDashUpload) {
+ return this->HandleCDashUploadFile(this->CDashUploadFile,
+ this->CDashUploadType);
}
const std::string& buildDirectory =
@@ -906,7 +872,7 @@
cmCTest::SafeBuildIdField(this->CTest->GetCTestConfiguration("BuildName"));
std::string name = this->CTest->GetCTestConfiguration("Site") + "___" +
buildname + "___" + this->CTest->GetCurrentTag() + "-" +
- this->CTest->GetTestModelString() + "___XML___";
+ this->CTest->GetTestGroupString() + "___XML___";
return name;
}
diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h
index d152b71..86067f6 100644
--- a/Source/CTest/cmCTestSubmitHandler.h
+++ b/Source/CTest/cmCTestSubmitHandler.h
@@ -4,7 +4,6 @@
#include "cmConfigure.h" // IWYU pragma: keep
-#include <cstddef>
#include <iosfwd>
#include <set>
#include <string>
@@ -24,7 +23,7 @@
public:
using Superclass = cmCTestGenericHandler;
- cmCTestSubmitHandler();
+ cmCTestSubmitHandler(cmCTest* ctest);
~cmCTestSubmitHandler() override { this->LogFile = nullptr; }
/*
@@ -32,13 +31,6 @@
*/
int ProcessHandler() override;
- void Initialize() override;
-
- //! Set all the submit arguments
- int ProcessCommandLineArguments(const std::string& currentArg, size_t& idx,
- const std::vector<std::string>& allArgs,
- bool& validArg) override;
-
/** Specify a set of parts (by name) to submit. */
void SelectParts(std::set<cmCTest::Part> const& parts);
@@ -50,12 +42,7 @@
void SetHttpHeaders(std::vector<std::string> const& v)
{
- if (this->CommandLineHttpHeaders.empty()) {
- this->HttpHeaders = v;
- } else {
- this->HttpHeaders = this->CommandLineHttpHeaders;
- this->HttpHeaders.insert(this->HttpHeaders.end(), v.begin(), v.end());
- }
+ this->HttpHeaders.insert(this->HttpHeaders.end(), v.begin(), v.end());
}
private:
@@ -79,13 +66,22 @@
class ResponseParser;
std::string HTTPProxy;
- int HTTPProxyType;
+ int HTTPProxyType = 0;
std::string HTTPProxyAuth;
- std::ostream* LogFile;
+ std::ostream* LogFile = nullptr;
bool SubmitPart[cmCTest::PartCount];
- bool HasWarnings;
- bool HasErrors;
+ bool HasWarnings = false;
+ bool HasErrors = false;
std::set<std::string> Files;
- std::vector<std::string> CommandLineHttpHeaders;
std::vector<std::string> HttpHeaders;
+
+ bool CDashUpload = false;
+ bool InternalTest = false;
+
+ std::string CDashUploadFile;
+ std::string CDashUploadType;
+ std::string RetryCount;
+ std::string RetryDelay;
+
+ friend class cmCTestSubmitCommand;
};
diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx
index 98ce862..ef3c80f 100644
--- a/Source/CTest/cmCTestTestCommand.cxx
+++ b/Source/CTest/cmCTestTestCommand.cxx
@@ -6,44 +6,26 @@
#include <cstdlib>
#include <ratio>
#include <sstream>
+#include <utility>
+#include <vector>
-#include <cmext/string_view>
+#include <cm/memory>
#include "cmCTest.h"
+#include "cmCTestGenericHandler.h"
#include "cmCTestTestHandler.h"
#include "cmDuration.h"
+#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmStringAlgorithms.h"
#include "cmValue.h"
-void cmCTestTestCommand::BindArguments()
+std::unique_ptr<cmCTestGenericHandler> cmCTestTestCommand::InitializeHandler(
+ HandlerArguments& arguments, cmExecutionStatus& status) const
{
- this->cmCTestHandlerCommand::BindArguments();
- this->Bind("START"_s, this->Start);
- this->Bind("END"_s, this->End);
- this->Bind("STRIDE"_s, this->Stride);
- this->Bind("EXCLUDE"_s, this->Exclude);
- this->Bind("INCLUDE"_s, this->Include);
- this->Bind("EXCLUDE_LABEL"_s, this->ExcludeLabel);
- this->Bind("INCLUDE_LABEL"_s, this->IncludeLabel);
- this->Bind("EXCLUDE_FROM_FILE"_s, this->ExcludeTestsFromFile);
- this->Bind("INCLUDE_FROM_FILE"_s, this->IncludeTestsFromFile);
- this->Bind("EXCLUDE_FIXTURE"_s, this->ExcludeFixture);
- this->Bind("EXCLUDE_FIXTURE_SETUP"_s, this->ExcludeFixtureSetup);
- this->Bind("EXCLUDE_FIXTURE_CLEANUP"_s, this->ExcludeFixtureCleanup);
- this->Bind("PARALLEL_LEVEL"_s, this->ParallelLevel);
- this->Bind("REPEAT"_s, this->Repeat);
- this->Bind("SCHEDULE_RANDOM"_s, this->ScheduleRandom);
- this->Bind("STOP_TIME"_s, this->StopTime);
- this->Bind("TEST_LOAD"_s, this->TestLoad);
- this->Bind("RESOURCE_SPEC_FILE"_s, this->ResourceSpecFile);
- this->Bind("STOP_ON_FAILURE"_s, this->StopOnFailure);
- this->Bind("OUTPUT_JUNIT"_s, this->OutputJUnit);
-}
-
-cmCTestGenericHandler* cmCTestTestCommand::InitializeHandler()
-{
- cmValue ctestTimeout = this->Makefile->GetDefinition("CTEST_TEST_TIMEOUT");
+ cmMakefile& mf = status.GetMakefile();
+ auto& args = static_cast<TestArguments&>(arguments);
+ cmValue ctestTimeout = mf.GetDefinition("CTEST_TEST_TIMEOUT");
cmDuration timeout;
if (ctestTimeout) {
@@ -57,80 +39,77 @@
}
this->CTest->SetTimeOut(timeout);
- cmValue resourceSpecFile =
- this->Makefile->GetDefinition("CTEST_RESOURCE_SPEC_FILE");
- if (this->ResourceSpecFile.empty() && resourceSpecFile) {
- this->ResourceSpecFile = *resourceSpecFile;
+ cmValue resourceSpecFile = mf.GetDefinition("CTEST_RESOURCE_SPEC_FILE");
+ if (args.ResourceSpecFile.empty() && resourceSpecFile) {
+ args.ResourceSpecFile = *resourceSpecFile;
}
- cmCTestTestHandler* handler = this->InitializeActualHandler();
- if (!this->Start.empty() || !this->End.empty() || !this->Stride.empty()) {
- handler->SetOption(
- "TestsToRunInformation",
- cmStrCat(this->Start, ',', this->End, ',', this->Stride));
+ auto handler = this->InitializeActualHandler(args, status);
+ if (!args.Start.empty() || !args.End.empty() || !args.Stride.empty()) {
+ handler->TestOptions.TestsToRunInformation =
+ cmStrCat(args.Start, ',', args.End, ',', args.Stride);
}
- if (!this->Exclude.empty()) {
- handler->SetOption("ExcludeRegularExpression", this->Exclude);
+ if (!args.Exclude.empty()) {
+ handler->TestOptions.ExcludeRegularExpression = args.Exclude;
}
- if (!this->Include.empty()) {
- handler->SetOption("IncludeRegularExpression", this->Include);
+ if (!args.Include.empty()) {
+ handler->TestOptions.IncludeRegularExpression = args.Include;
}
- if (!this->ExcludeLabel.empty()) {
- handler->AddMultiOption("ExcludeLabelRegularExpression",
- this->ExcludeLabel);
+ if (!args.ExcludeLabel.empty()) {
+ handler->TestOptions.ExcludeLabelRegularExpression.push_back(
+ args.ExcludeLabel);
}
- if (!this->IncludeLabel.empty()) {
- handler->AddMultiOption("LabelRegularExpression", this->IncludeLabel);
+ if (!args.IncludeLabel.empty()) {
+ handler->TestOptions.LabelRegularExpression.push_back(args.IncludeLabel);
}
- if (!this->ExcludeTestsFromFile.empty()) {
- handler->SetOption("ExcludeTestListFile", this->ExcludeTestsFromFile);
+ if (!args.ExcludeTestsFromFile.empty()) {
+ handler->TestOptions.ExcludeTestListFile = args.ExcludeTestsFromFile;
}
- if (!this->IncludeTestsFromFile.empty()) {
- handler->SetOption("TestListFile", this->IncludeTestsFromFile);
+ if (!args.IncludeTestsFromFile.empty()) {
+ handler->TestOptions.TestListFile = args.IncludeTestsFromFile;
}
- if (!this->ExcludeFixture.empty()) {
- handler->SetOption("ExcludeFixtureRegularExpression",
- this->ExcludeFixture);
+ if (!args.ExcludeFixture.empty()) {
+ handler->TestOptions.ExcludeFixtureRegularExpression = args.ExcludeFixture;
}
- if (!this->ExcludeFixtureSetup.empty()) {
- handler->SetOption("ExcludeFixtureSetupRegularExpression",
- this->ExcludeFixtureSetup);
+ if (!args.ExcludeFixtureSetup.empty()) {
+ handler->TestOptions.ExcludeFixtureSetupRegularExpression =
+ args.ExcludeFixtureSetup;
}
- if (!this->ExcludeFixtureCleanup.empty()) {
- handler->SetOption("ExcludeFixtureCleanupRegularExpression",
- this->ExcludeFixtureCleanup);
+ if (!args.ExcludeFixtureCleanup.empty()) {
+ handler->TestOptions.ExcludeFixtureCleanupRegularExpression =
+ args.ExcludeFixtureCleanup;
}
- if (this->StopOnFailure) {
- handler->SetOption("StopOnFailure", "ON");
+ if (args.StopOnFailure) {
+ handler->TestOptions.StopOnFailure = true;
}
- if (this->ParallelLevel) {
- handler->SetOption("ParallelLevel", *this->ParallelLevel);
+ if (args.ParallelLevel) {
+ handler->ParallelLevel = *args.ParallelLevel;
}
- if (!this->Repeat.empty()) {
- handler->SetOption("Repeat", this->Repeat);
+ if (!args.Repeat.empty()) {
+ handler->Repeat = args.Repeat;
}
- if (!this->ScheduleRandom.empty()) {
- handler->SetOption("ScheduleRandom", this->ScheduleRandom);
+ if (!args.ScheduleRandom.empty()) {
+ handler->TestOptions.ScheduleRandom = cmValue(args.ScheduleRandom).IsOn();
}
- if (!this->ResourceSpecFile.empty()) {
- handler->SetOption("ResourceSpecFile", this->ResourceSpecFile);
+ if (!args.ResourceSpecFile.empty()) {
+ handler->TestOptions.ResourceSpecFile = args.ResourceSpecFile;
}
- if (!this->StopTime.empty()) {
- this->CTest->SetStopTime(this->StopTime);
+ if (!args.StopTime.empty()) {
+ this->CTest->SetStopTime(args.StopTime);
}
// Test load is determined by: TEST_LOAD argument,
// or CTEST_TEST_LOAD script variable, or ctest --test-load
// command line argument... in that order.
unsigned long testLoad;
- cmValue ctestTestLoad = this->Makefile->GetDefinition("CTEST_TEST_LOAD");
- if (!this->TestLoad.empty()) {
- if (!cmStrToULong(this->TestLoad, &testLoad)) {
+ cmValue ctestTestLoad = mf.GetDefinition("CTEST_TEST_LOAD");
+ if (!args.TestLoad.empty()) {
+ if (!cmStrToULong(args.TestLoad, &testLoad)) {
testLoad = 0;
cmCTestLog(this->CTest, WARNING,
- "Invalid value for 'TEST_LOAD' : " << this->TestLoad
+ "Invalid value for 'TEST_LOAD' : " << args.TestLoad
<< std::endl);
}
} else if (cmNonempty(ctestTestLoad)) {
@@ -146,22 +125,32 @@
handler->SetTestLoad(testLoad);
if (cmValue labelsForSubprojects =
- this->Makefile->GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
+ mf.GetDefinition("CTEST_LABELS_FOR_SUBPROJECTS")) {
this->CTest->SetCTestConfiguration("LabelsForSubprojects",
- *labelsForSubprojects, this->Quiet);
+ *labelsForSubprojects, args.Quiet);
}
- if (!this->OutputJUnit.empty()) {
- handler->SetJUnitXMLFileName(this->OutputJUnit);
+ if (!args.OutputJUnit.empty()) {
+ handler->SetJUnitXMLFileName(args.OutputJUnit);
}
- handler->SetQuiet(this->Quiet);
- return handler;
+ handler->SetQuiet(args.Quiet);
+ return std::unique_ptr<cmCTestGenericHandler>(std::move(handler));
}
-cmCTestTestHandler* cmCTestTestCommand::InitializeActualHandler()
+std::unique_ptr<cmCTestTestHandler>
+cmCTestTestCommand::InitializeActualHandler(HandlerArguments&,
+ cmExecutionStatus&) const
{
- cmCTestTestHandler* handler = this->CTest->GetTestHandler();
- handler->Initialize();
- return handler;
+ return cm::make_unique<cmCTestTestHandler>(this->CTest);
+}
+
+bool cmCTestTestCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) const
+{
+ static auto const parser = MakeTestParser<TestArguments>();
+
+ return this->Invoke(parser, args, status, [&](TestArguments& a) {
+ return this->ExecuteHandlerCommand(a, status);
+ });
}
diff --git a/Source/CTest/cmCTestTestCommand.h b/Source/CTest/cmCTestTestCommand.h
index 23661c5..038d219 100644
--- a/Source/CTest/cmCTestTestCommand.h
+++ b/Source/CTest/cmCTestTestCommand.h
@@ -4,66 +4,88 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <memory>
#include <string>
-#include <utility>
+#include <type_traits>
+#include <vector>
-#include <cm/memory>
#include <cm/optional>
+#include <cmext/string_view>
+#include "cmArgumentParser.h"
#include "cmArgumentParserTypes.h"
#include "cmCTestHandlerCommand.h"
-#include "cmCommand.h"
+class cmExecutionStatus;
class cmCTestGenericHandler;
class cmCTestTestHandler;
-/** \class cmCTestTest
- * \brief Run a ctest script
- *
- * cmCTestTestCommand defineds the command to test the project.
- */
class cmCTestTestCommand : public cmCTestHandlerCommand
{
public:
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- auto ni = cm::make_unique<cmCTestTestCommand>();
- ni->CTest = this->CTest;
- ni->CTestScriptHandler = this->CTestScriptHandler;
- return std::unique_ptr<cmCommand>(std::move(ni));
- }
-
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- std::string GetName() const override { return "ctest_test"; }
+ using cmCTestHandlerCommand::cmCTestHandlerCommand;
protected:
- void BindArguments() override;
- virtual cmCTestTestHandler* InitializeActualHandler();
- cmCTestGenericHandler* InitializeHandler() override;
+ struct TestArguments : HandlerArguments
+ {
+ std::string Start;
+ std::string End;
+ std::string Stride;
+ std::string Exclude;
+ std::string Include;
+ std::string ExcludeLabel;
+ std::string IncludeLabel;
+ std::string IncludeTestsFromFile;
+ std::string ExcludeTestsFromFile;
+ std::string ExcludeFixture;
+ std::string ExcludeFixtureSetup;
+ std::string ExcludeFixtureCleanup;
+ cm::optional<ArgumentParser::Maybe<std::string>> ParallelLevel;
+ std::string Repeat;
+ std::string ScheduleRandom;
+ std::string StopTime;
+ std::string TestLoad;
+ std::string ResourceSpecFile;
+ std::string OutputJUnit;
+ bool StopOnFailure = false;
+ };
- std::string Start;
- std::string End;
- std::string Stride;
- std::string Exclude;
- std::string Include;
- std::string ExcludeLabel;
- std::string IncludeLabel;
- std::string IncludeTestsFromFile;
- std::string ExcludeTestsFromFile;
- std::string ExcludeFixture;
- std::string ExcludeFixtureSetup;
- std::string ExcludeFixtureCleanup;
- cm::optional<ArgumentParser::Maybe<std::string>> ParallelLevel;
- std::string Repeat;
- std::string ScheduleRandom;
- std::string StopTime;
- std::string TestLoad;
- std::string ResourceSpecFile;
- std::string OutputJUnit;
- bool StopOnFailure = false;
+ template <typename Args>
+ static auto MakeTestParser() -> cmArgumentParser<Args>
+ {
+ static_assert(std::is_base_of<TestArguments, Args>::value, "");
+ return cmArgumentParser<Args>{ MakeHandlerParser<Args>() }
+ .Bind("START"_s, &TestArguments::Start)
+ .Bind("END"_s, &TestArguments::End)
+ .Bind("STRIDE"_s, &TestArguments::Stride)
+ .Bind("EXCLUDE"_s, &TestArguments::Exclude)
+ .Bind("INCLUDE"_s, &TestArguments::Include)
+ .Bind("EXCLUDE_LABEL"_s, &TestArguments::ExcludeLabel)
+ .Bind("INCLUDE_LABEL"_s, &TestArguments::IncludeLabel)
+ .Bind("EXCLUDE_FROM_FILE"_s, &TestArguments::ExcludeTestsFromFile)
+ .Bind("INCLUDE_FROM_FILE"_s, &TestArguments::IncludeTestsFromFile)
+ .Bind("EXCLUDE_FIXTURE"_s, &TestArguments::ExcludeFixture)
+ .Bind("EXCLUDE_FIXTURE_SETUP"_s, &TestArguments::ExcludeFixtureSetup)
+ .Bind("EXCLUDE_FIXTURE_CLEANUP"_s, &TestArguments::ExcludeFixtureCleanup)
+ .Bind("PARALLEL_LEVEL"_s, &TestArguments::ParallelLevel)
+ .Bind("REPEAT"_s, &TestArguments::Repeat)
+ .Bind("SCHEDULE_RANDOM"_s, &TestArguments::ScheduleRandom)
+ .Bind("STOP_TIME"_s, &TestArguments::StopTime)
+ .Bind("TEST_LOAD"_s, &TestArguments::TestLoad)
+ .Bind("RESOURCE_SPEC_FILE"_s, &TestArguments::ResourceSpecFile)
+ .Bind("STOP_ON_FAILURE"_s, &TestArguments::StopOnFailure)
+ .Bind("OUTPUT_JUNIT"_s, &TestArguments::OutputJUnit);
+ }
+
+private:
+ std::string GetName() const override { return "ctest_test"; }
+
+ virtual std::unique_ptr<cmCTestTestHandler> InitializeActualHandler(
+ HandlerArguments& arguments, cmExecutionStatus& status) const;
+
+ std::unique_ptr<cmCTestGenericHandler> InitializeHandler(
+ HandlerArguments& arguments, cmExecutionStatus& status) const override;
+
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) const override;
};
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index c7875cd..f42d84e 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -8,7 +8,6 @@
#include <cstddef> // IWYU pragma: keep
#include <cstdio>
#include <cstdlib>
-#include <cstring>
#include <ctime>
#include <functional>
#include <iomanip>
@@ -97,8 +96,7 @@
{
cmWorkingDirectory workdir(fname);
if (workdir.Failed()) {
- status.SetError("Failed to change directory to " + fname + " : " +
- std::strerror(workdir.GetLastResult()));
+ status.SetError(workdir.GetError());
return false;
}
const char* testFilename;
@@ -130,7 +128,7 @@
status.SetError("called with incorrect number of arguments");
return false;
}
- std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ std::string cwd = cmSystemTools::GetLogicalWorkingDirectory();
for (std::string const& arg : args) {
std::string fname;
@@ -156,7 +154,7 @@
}
std::string fname =
- cmStrCat(cmSystemTools::GetCurrentWorkingDirectory(), '/', args[0]);
+ cmStrCat(cmSystemTools::GetLogicalWorkingDirectory(), '/', args[0]);
return ReadSubdirectory(std::move(fname), status);
}
@@ -276,25 +274,10 @@
} // namespace
-cmCTestTestHandler::cmCTestTestHandler()
+cmCTestTestHandler::cmCTestTestHandler(cmCTest* ctest)
+ : Superclass(ctest)
+ , TestOptions(ctest->GetTestOptions())
{
- this->UseUnion = false;
-
- this->UseIncludeRegExpFlag = false;
- this->UseExcludeRegExpFlag = false;
- this->UseExcludeRegExpFirst = false;
-
- this->CustomMaximumPassedTestOutputSize = 1 * 1024;
- this->CustomMaximumFailedTestOutputSize = 300 * 1024;
- this->TestOutputTruncation = cmCTestTypes::TruncationMode::Tail;
-
- this->MemCheck = false;
-
- this->LogFile = nullptr;
-
- // Support for JUnit XML output.
- this->JUnitXMLFileName = "";
-
// Regular expressions to scan test output for custom measurements.
// Capture the whole section of test output from the first opening
@@ -315,46 +298,6 @@
this->CustomLabelRegex.compile("<CTestLabel>(.*)</CTestLabel>");
}
-void cmCTestTestHandler::Initialize()
-{
- this->Superclass::Initialize();
-
- this->ElapsedTestingTime = cmDuration();
-
- this->TestResults.clear();
-
- this->CustomTestsIgnore.clear();
- this->StartTest.clear();
- this->EndTest.clear();
-
- this->CustomPreTest.clear();
- this->CustomPostTest.clear();
- this->CustomMaximumPassedTestOutputSize = 1 * 1024;
- this->CustomMaximumFailedTestOutputSize = 300 * 1024;
- this->TestOutputTruncation = cmCTestTypes::TruncationMode::Tail;
-
- this->TestsToRun.clear();
-
- this->UseIncludeRegExpFlag = false;
- this->UseExcludeRegExpFlag = false;
- this->UseExcludeRegExpFirst = false;
- this->IncludeLabelRegularExpressions.clear();
- this->ExcludeLabelRegularExpressions.clear();
- this->IncludeRegExp.clear();
- this->ExcludeRegExp.clear();
- this->ExcludeFixtureRegExp.clear();
- this->ExcludeFixtureSetupRegExp.clear();
- this->ExcludeFixtureCleanupRegExp.clear();
- this->TestListFile.clear();
- this->ExcludeTestListFile.clear();
- this->TestsToRunByName.reset();
- this->TestsToExcludeByName.reset();
-
- this->TestsToRunString.clear();
- this->UseUnion = false;
- this->TestList.clear();
-}
-
void cmCTestTestHandler::PopulateCustomVectors(cmMakefile* mf)
{
this->CTest->PopulateCustomVector(mf, "CTEST_CUSTOM_PRE_TEST",
@@ -365,14 +308,14 @@
this->CustomTestsIgnore);
this->CTest->PopulateCustomInteger(
mf, "CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE",
- this->CustomMaximumPassedTestOutputSize);
+ this->TestOptions.OutputSizePassed);
this->CTest->PopulateCustomInteger(
mf, "CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE",
- this->CustomMaximumFailedTestOutputSize);
+ this->TestOptions.OutputSizeFailed);
cmValue dval = mf->GetDefinition("CTEST_CUSTOM_TEST_OUTPUT_TRUNCATION");
if (dval) {
- if (!this->SetTestOutputTruncation(*dval)) {
+ if (!SetTruncationMode(this->TestOptions.OutputTruncation, *dval)) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Invalid value for CTEST_CUSTOM_TEST_OUTPUT_TRUNCATION: "
<< *dval << std::endl);
@@ -411,7 +354,7 @@
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
(this->MemCheck ? "Memory check" : "Test")
<< " project "
- << cmSystemTools::GetCurrentWorkingDirectory()
+ << cmSystemTools::GetLogicalWorkingDirectory()
<< std::endl,
this->Quiet);
if (!this->PreProcessHandler()) {
@@ -521,12 +464,11 @@
bool cmCTestTestHandler::ProcessOptions()
{
// Update internal data structure from generic one
- this->SetTestsToRunInformation(this->GetOption("TestsToRunInformation"));
- this->SetUseUnion(this->GetOption("UseUnion").IsOn());
- if (this->GetOption("ScheduleRandom").IsOn()) {
+ this->SetTestsToRunInformation(this->TestOptions.TestsToRunInformation);
+ if (this->TestOptions.ScheduleRandom) {
this->CTest->SetScheduleType("Random");
}
- if (cmValue repeat = this->GetOption("Repeat")) {
+ if (auto repeat = this->Repeat) {
cmsys::RegularExpression repeatRegex(
"^(UNTIL_FAIL|UNTIL_PASS|AFTER_TIMEOUT):([0-9]+)$");
if (repeatRegex.find(*repeat)) {
@@ -550,8 +492,8 @@
return false;
}
}
- if (cmValue parallelLevel = this->GetOption("ParallelLevel")) {
- if (parallelLevel.IsEmpty()) {
+ if (auto parallelLevel = this->ParallelLevel) {
+ if (parallelLevel->empty()) {
// An empty value tells ctest to choose a default.
this->CTest->SetParallelLevel(cm::nullopt);
} else {
@@ -567,50 +509,20 @@
}
}
- if (this->GetOption("StopOnFailure")) {
+ if (this->TestOptions.StopOnFailure) {
this->CTest->SetStopOnFailure(true);
}
- BuildLabelRE(this->GetMultiOption("LabelRegularExpression"),
+ BuildLabelRE(this->TestOptions.LabelRegularExpression,
this->IncludeLabelRegularExpressions);
- BuildLabelRE(this->GetMultiOption("ExcludeLabelRegularExpression"),
+ BuildLabelRE(this->TestOptions.ExcludeLabelRegularExpression,
this->ExcludeLabelRegularExpressions);
- cmValue val = this->GetOption("IncludeRegularExpression");
- if (val) {
+ if (!this->TestOptions.IncludeRegularExpression.empty()) {
this->UseIncludeRegExp();
- this->SetIncludeRegExp(*val);
}
- val = this->GetOption("ExcludeRegularExpression");
- if (val) {
+ if (!this->TestOptions.ExcludeRegularExpression.empty()) {
this->UseExcludeRegExp();
- this->SetExcludeRegExp(*val);
}
- val = this->GetOption("ExcludeFixtureRegularExpression");
- if (val) {
- this->ExcludeFixtureRegExp = *val;
- }
- val = this->GetOption("ExcludeFixtureSetupRegularExpression");
- if (val) {
- this->ExcludeFixtureSetupRegExp = *val;
- }
- val = this->GetOption("ExcludeFixtureCleanupRegularExpression");
- if (val) {
- this->ExcludeFixtureCleanupRegExp = *val;
- }
- val = this->GetOption("ResourceSpecFile");
- if (val) {
- this->ResourceSpecFile = *val;
- }
- val = this->GetOption("TestListFile");
- if (val) {
- this->TestListFile = val;
- }
- val = this->GetOption("ExcludeTestListFile");
- if (val) {
- this->ExcludeTestListFile = val;
- }
- this->SetRerunFailed(this->GetOption("RerunFailed").IsOn());
-
return true;
}
@@ -922,7 +834,7 @@
return false;
}
- if (this->RerunFailed) {
+ if (this->TestOptions.RerunFailed) {
return this->ComputeTestListForRerunFailed();
}
@@ -936,7 +848,7 @@
}
}
// expand the test list based on the union flag
- if (this->UseUnion) {
+ if (this->TestOptions.UseUnion) {
this->ExpandTestsToRunInformation(static_cast<int>(tmsize));
} else {
this->ExpandTestsToRunInformation(inREcnt);
@@ -951,7 +863,7 @@
inREcnt++;
}
- if (this->UseUnion) {
+ if (this->TestOptions.UseUnion) {
// if it is not in the list and not in the regexp then skip
if ((!this->TestsToRun.empty() &&
!cm::contains(this->TestsToRun, cnt)) &&
@@ -1034,22 +946,24 @@
this->Quiet);
// Prepare regular expression evaluators
- std::string setupRegExp(this->ExcludeFixtureRegExp);
- std::string cleanupRegExp(this->ExcludeFixtureRegExp);
- if (!this->ExcludeFixtureSetupRegExp.empty()) {
+ std::string setupRegExp(this->TestOptions.ExcludeFixtureRegularExpression);
+ std::string cleanupRegExp(this->TestOptions.ExcludeFixtureRegularExpression);
+ if (!this->TestOptions.ExcludeFixtureSetupRegularExpression.empty()) {
if (setupRegExp.empty()) {
- setupRegExp = this->ExcludeFixtureSetupRegExp;
+ setupRegExp = this->TestOptions.ExcludeFixtureSetupRegularExpression;
} else {
- setupRegExp.append("(" + setupRegExp + ")|(" +
- this->ExcludeFixtureSetupRegExp + ")");
+ setupRegExp.append(
+ "(" + setupRegExp + ")|(" +
+ this->TestOptions.ExcludeFixtureSetupRegularExpression + ")");
}
}
- if (!this->ExcludeFixtureCleanupRegExp.empty()) {
+ if (!this->TestOptions.ExcludeFixtureCleanupRegularExpression.empty()) {
if (cleanupRegExp.empty()) {
- cleanupRegExp = this->ExcludeFixtureCleanupRegExp;
+ cleanupRegExp = this->TestOptions.ExcludeFixtureCleanupRegularExpression;
} else {
- cleanupRegExp.append("(" + cleanupRegExp + ")|(" +
- this->ExcludeFixtureCleanupRegExp + ")");
+ cleanupRegExp.append(
+ "(" + cleanupRegExp + ")|(" +
+ this->TestOptions.ExcludeFixtureCleanupRegularExpression + ")");
}
}
cmsys::RegularExpression excludeSetupRegex(setupRegExp);
@@ -1431,7 +1345,7 @@
tests[p.Index].Depends = depends;
properties[p.Index] = &p;
}
- parallel->SetResourceSpecFile(this->ResourceSpecFile);
+ parallel->SetResourceSpecFile(this->TestOptions.ResourceSpecFile);
if (!parallel->SetTests(std::move(tests), std::move(properties))) {
return false;
}
@@ -1467,7 +1381,7 @@
return;
}
- this->CTest->StartXML(xml, this->AppendXML);
+ this->CTest->StartXML(xml, this->CMake, this->AppendXML);
this->CTest->GenerateSubprojectsOutput(xml);
xml.StartElement("Testing");
xml.Element("StartDateTime", this->StartTest);
@@ -1761,7 +1675,7 @@
for (unsigned int ai = 0; ai < attempted.size() && fullPath.empty(); ++ai) {
// first check without exe extension
if (cmSystemTools::FileExists(attempted[ai], true)) {
- fullPath = cmSystemTools::CollapseFullPath(attempted[ai]);
+ fullPath = cmSystemTools::ToNormalizedPathOnDisk(attempted[ai]);
resultingConfig = attemptedConfigs[ai];
}
// then try with the exe extension
@@ -1770,7 +1684,7 @@
tempPath =
cmStrCat(attempted[ai], cmSystemTools::GetExecutableExtension());
if (cmSystemTools::FileExists(tempPath, true)) {
- fullPath = cmSystemTools::CollapseFullPath(tempPath);
+ fullPath = cmSystemTools::ToNormalizedPathOnDisk(tempPath);
resultingConfig = attemptedConfigs[ai];
} else {
failed.push_back(tempPath);
@@ -1810,11 +1724,13 @@
bool cmCTestTestHandler::GetListOfTests()
{
- if (!this->IncludeRegExp.empty()) {
- this->IncludeTestsRegularExpression.compile(this->IncludeRegExp);
+ if (!this->TestOptions.IncludeRegularExpression.empty()) {
+ this->IncludeTestsRegularExpression.compile(
+ this->TestOptions.IncludeRegularExpression);
}
- if (!this->ExcludeRegExp.empty()) {
- this->ExcludeTestsRegularExpression.compile(this->ExcludeRegExp);
+ if (!this->TestOptions.ExcludeRegularExpression.empty()) {
+ this->ExcludeTestsRegularExpression.compile(
+ this->TestOptions.ExcludeRegularExpression);
}
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Constructing a list of tests" << std::endl, this->Quiet);
@@ -1864,19 +1780,20 @@
return false;
}
cmValue specFile = mf.GetDefinition("CTEST_RESOURCE_SPEC_FILE");
- if (this->ResourceSpecFile.empty() && specFile) {
- this->ResourceSpecFile = *specFile;
+ if (this->TestOptions.ResourceSpecFile.empty() && specFile) {
+ this->TestOptions.ResourceSpecFile = *specFile;
}
- if (!this->TestListFile.empty()) {
- this->TestsToRunByName = this->ReadTestListFile(this->TestListFile);
+ if (!this->TestOptions.TestListFile.empty()) {
+ this->TestsToRunByName =
+ this->ReadTestListFile(this->TestOptions.TestListFile);
if (!this->TestsToRunByName) {
return false;
}
}
- if (!this->ExcludeTestListFile.empty()) {
+ if (!this->TestOptions.ExcludeTestListFile.empty()) {
this->TestsToExcludeByName =
- this->ReadTestListFile(this->ExcludeTestListFile);
+ this->ReadTestListFile(this->TestOptions.ExcludeTestListFile);
if (!this->TestsToExcludeByName) {
return false;
}
@@ -2153,41 +2070,14 @@
}
}
-void cmCTestTestHandler::SetIncludeRegExp(const std::string& arg)
+void cmCTestTestHandler::SetTestsToRunInformation(std::string const& in)
{
- this->IncludeRegExp = arg;
-}
-
-void cmCTestTestHandler::SetExcludeRegExp(const std::string& arg)
-{
- this->ExcludeRegExp = arg;
-}
-
-bool cmCTestTestHandler::SetTestOutputTruncation(const std::string& mode)
-{
- if (mode == "tail") {
- this->TestOutputTruncation = cmCTestTypes::TruncationMode::Tail;
- } else if (mode == "middle") {
- this->TestOutputTruncation = cmCTestTypes::TruncationMode::Middle;
- } else if (mode == "head") {
- this->TestOutputTruncation = cmCTestTypes::TruncationMode::Head;
- } else {
- return false;
- }
- return true;
-}
-
-void cmCTestTestHandler::SetTestsToRunInformation(cmValue in)
-{
- if (!in) {
- return;
- }
- this->TestsToRunString = *in;
+ this->TestsToRunString = in;
// if the argument is a file, then read it and use the contents as the
// string
- if (cmSystemTools::FileExists(*in)) {
- cmsys::ifstream fin(in->c_str());
- unsigned long filelen = cmSystemTools::FileLength(*in);
+ if (cmSystemTools::FileExists(in)) {
+ cmsys::ifstream fin(in.c_str());
+ unsigned long filelen = cmSystemTools::FileLength(in);
auto buff = cm::make_unique<char[]>(filelen + 1);
fin.getline(buff.get(), filelen);
buff[fin.gcount()] = 0;
@@ -2495,7 +2385,7 @@
}
std::string const& val = *it;
for (cmCTestTestProperties& rt : this->TestList) {
- std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ std::string cwd = cmSystemTools::GetLogicalWorkingDirectory();
if (cwd == rt.Directory) {
if (key == "LABELS"_s) {
cmList DirectoryLabels{ val };
@@ -2559,7 +2449,7 @@
cmCTestTestProperties test;
test.Name = testname;
test.Args = args;
- test.Directory = cmSystemTools::GetCurrentWorkingDirectory();
+ test.Directory = cmSystemTools::GetLogicalWorkingDirectory();
cmCTestOptionalLog(this->CTest, DEBUG,
"Set test directory: " << test.Directory << std::endl,
this->Quiet);
@@ -2590,22 +2480,22 @@
void cmCTestTestHandler::SetJUnitXMLFileName(const std::string& filename)
{
- this->JUnitXMLFileName = filename;
+ this->TestOptions.JUnitXMLFileName = filename;
}
bool cmCTestTestHandler::WriteJUnitXML()
{
- if (this->JUnitXMLFileName.empty()) {
+ if (this->TestOptions.JUnitXMLFileName.empty()) {
return true;
}
// Open new XML file for writing.
cmGeneratedFileStream xmlfile;
xmlfile.SetTempExt("tmp");
- xmlfile.Open(this->JUnitXMLFileName);
+ xmlfile.Open(this->TestOptions.JUnitXMLFileName);
if (!xmlfile) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Problem opening file: " << this->JUnitXMLFileName
+ "Problem opening file: " << this->TestOptions.JUnitXMLFileName
<< std::endl);
return false;
}
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index c35af3f..a9e2d67 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -24,11 +24,39 @@
#include "cmCTestTypes.h" // IWYU pragma: keep
#include "cmDuration.h"
#include "cmListFileCache.h"
-#include "cmValue.h"
class cmMakefile;
class cmXMLWriter;
+struct cmCTestTestOptions
+{
+ bool RerunFailed = false;
+ bool ScheduleRandom = false;
+ bool StopOnFailure = false;
+ bool UseUnion = false;
+
+ int OutputSizePassed = 1 * 1024;
+ int OutputSizeFailed = 300 * 1024;
+ cmCTestTypes::TruncationMode OutputTruncation =
+ cmCTestTypes::TruncationMode::Tail;
+
+ std::string TestsToRunInformation;
+ std::string IncludeRegularExpression;
+ std::string ExcludeRegularExpression;
+
+ std::vector<std::string> LabelRegularExpression;
+ std::vector<std::string> ExcludeLabelRegularExpression;
+
+ std::string ExcludeFixtureRegularExpression;
+ std::string ExcludeFixtureSetupRegularExpression;
+ std::string ExcludeFixtureCleanupRegularExpression;
+
+ std::string TestListFile;
+ std::string ExcludeTestListFile;
+ std::string ResourceSpecFile;
+ std::string JUnitXMLFileName;
+};
+
/** \class cmCTestTestHandler
* \brief A class that handles ctest -S invocations
*
@@ -48,19 +76,6 @@
int ProcessHandler() override;
/**
- * When both -R and -I are used should the resulting test list be the
- * intersection or the union of the lists. By default it is the
- * intersection.
- */
- void SetUseUnion(bool val) { this->UseUnion = val; }
-
- /**
- * Set whether or not CTest should only execute the tests that failed
- * on the previous run. By default this is false.
- */
- void SetRerunFailed(bool val) { this->RerunFailed = val; }
-
- /**
* This method is called when reading CTest custom file
*/
void PopulateCustomVectors(cmMakefile* mf) override;
@@ -69,28 +84,14 @@
/// them on
void UseIncludeRegExp();
void UseExcludeRegExp();
- void SetIncludeRegExp(const std::string&);
- void SetExcludeRegExp(const std::string&);
void SetMaxIndex(int n) { this->MaxIndex = n; }
int GetMaxIndex() { return this->MaxIndex; }
- void SetTestOutputSizePassed(int n)
- {
- this->CustomMaximumPassedTestOutputSize = n;
- }
- void SetTestOutputSizeFailed(int n)
- {
- this->CustomMaximumFailedTestOutputSize = n;
- }
-
- //! Set test output truncation mode. Return false if unknown mode.
- bool SetTestOutputTruncation(const std::string& mode);
-
//! pass the -I argument down
- void SetTestsToRunInformation(cmValue);
+ void SetTestsToRunInformation(std::string const& in);
- cmCTestTestHandler();
+ cmCTestTestHandler(cmCTest* ctest);
/*
* Add the test to the list of tests to be executed
@@ -107,8 +108,6 @@
*/
bool SetDirectoryProperties(const std::vector<std::string>& args);
- void Initialize() override;
-
struct cmCTestTestResourceRequirement
{
std::string ResourceType;
@@ -260,6 +259,8 @@
void CleanTestOutput(std::string& output, size_t length,
cmCTestTypes::TruncationMode truncate);
+ cmCTestTestOptions TestOptions;
+
cmDuration ElapsedTestingTime;
using TestResultsVector = std::vector<cmCTestTestResult>;
@@ -270,10 +271,7 @@
std::string EndTest;
std::chrono::system_clock::time_point StartTestTime;
std::chrono::system_clock::time_point EndTestTime;
- bool MemCheck;
- int CustomMaximumPassedTestOutputSize;
- int CustomMaximumFailedTestOutputSize;
- cmCTestTypes::TruncationMode TestOutputTruncation;
+ bool MemCheck = false;
int MaxIndex;
public:
@@ -350,24 +348,17 @@
std::vector<int> TestsToRun;
- bool UseIncludeRegExpFlag;
- bool UseExcludeRegExpFlag;
- bool UseExcludeRegExpFirst;
- std::string IncludeRegExp;
- std::string ExcludeRegExp;
- std::string ExcludeFixtureRegExp;
- std::string ExcludeFixtureSetupRegExp;
- std::string ExcludeFixtureCleanupRegExp;
+ bool UseIncludeRegExpFlag = false;
+ bool UseExcludeRegExpFlag = false;
+ bool UseExcludeRegExpFirst = false;
std::vector<cmsys::RegularExpression> IncludeLabelRegularExpressions;
std::vector<cmsys::RegularExpression> ExcludeLabelRegularExpressions;
cmsys::RegularExpression IncludeTestsRegularExpression;
cmsys::RegularExpression ExcludeTestsRegularExpression;
- std::string TestListFile;
- std::string ExcludeTestListFile;
cm::optional<std::set<std::string>> TestsToRunByName;
cm::optional<std::set<std::string>> TestsToExcludeByName;
-
- std::string ResourceSpecFile;
+ cm::optional<std::string> ParallelLevel;
+ cm::optional<std::string> Repeat;
void RecordCustomTestMeasurements(cmXMLWriter& xml, std::string content);
void CheckLabelFilter(cmCTestTestProperties& it);
@@ -375,7 +366,6 @@
void CheckLabelFilterInclude(cmCTestTestProperties& it);
std::string TestsToRunString;
- bool UseUnion;
ListOfTests TestList;
size_t TotalNumberOfTests;
cmsys::RegularExpression AllTestMeasurementsRegex;
@@ -383,11 +373,10 @@
cmsys::RegularExpression CustomCompletionStatusRegex;
cmsys::RegularExpression CustomLabelRegex;
- std::ostream* LogFile;
+ std::ostream* LogFile = nullptr;
cmCTest::Repeat RepeatMode = cmCTest::Repeat::Never;
int RepeatCount = 1;
- bool RerunFailed;
- std::string JUnitXMLFileName;
+ friend class cmCTestTestCommand;
};
diff --git a/Source/CTest/cmCTestTypes.cxx b/Source/CTest/cmCTestTypes.cxx
new file mode 100644
index 0000000..9a06cd9
--- /dev/null
+++ b/Source/CTest/cmCTestTypes.cxx
@@ -0,0 +1,24 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include "cmCTestTypes.h"
+
+#include <string>
+
+namespace cmCTestTypes {
+
+bool SetTruncationMode(TruncationMode& mode, cm::string_view str)
+{
+ if (str == "tail") {
+ mode = cmCTestTypes::TruncationMode::Tail;
+ } else if (str == "middle") {
+ mode = cmCTestTypes::TruncationMode::Middle;
+ } else if (str == "head") {
+ mode = cmCTestTypes::TruncationMode::Head;
+ } else {
+ return false;
+ }
+ return true;
+}
+
+} // namespace cmCTestTypes
diff --git a/Source/CTest/cmCTestTypes.h b/Source/CTest/cmCTestTypes.h
index 843d27a..0dfc4a5 100644
--- a/Source/CTest/cmCTestTypes.h
+++ b/Source/CTest/cmCTestTypes.h
@@ -5,12 +5,18 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <cm/string_view>
+
namespace cmCTestTypes {
+// Test output truncation mode
enum class TruncationMode
-{ // Test output truncation mode
+{
Tail,
Middle,
Head
};
-}
+
+bool SetTruncationMode(TruncationMode& mode, cm::string_view str);
+
+} // namespace cmCTestTypes
diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx
index 6655bf7..a691088 100644
--- a/Source/CTest/cmCTestUpdateCommand.cxx
+++ b/Source/CTest/cmCTestUpdateCommand.cxx
@@ -2,84 +2,94 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestUpdateCommand.h"
+#include <utility>
+
+#include <cm/memory>
+
#include "cmCTest.h"
+#include "cmCTestGenericHandler.h"
#include "cmCTestUpdateHandler.h"
+#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
-cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler()
+std::unique_ptr<cmCTestGenericHandler> cmCTestUpdateCommand::InitializeHandler(
+ HandlerArguments& args, cmExecutionStatus& status) const
{
- if (!this->Source.empty()) {
+ cmMakefile& mf = status.GetMakefile();
+ if (!args.Source.empty()) {
this->CTest->SetCTestConfiguration(
- "SourceDirectory", cmSystemTools::CollapseFullPath(this->Source),
- this->Quiet);
+ "SourceDirectory", cmSystemTools::CollapseFullPath(args.Source),
+ args.Quiet);
} else {
this->CTest->SetCTestConfiguration(
"SourceDirectory",
cmSystemTools::CollapseFullPath(
- this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY")),
- this->Quiet);
+ mf.GetSafeDefinition("CTEST_SOURCE_DIRECTORY")),
+ args.Quiet);
}
std::string source_dir =
this->CTest->GetCTestConfiguration("SourceDirectory");
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "UpdateCommand", "CTEST_UPDATE_COMMAND", this->Quiet);
+ &mf, "UpdateCommand", "CTEST_UPDATE_COMMAND", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "UpdateOptions", "CTEST_UPDATE_OPTIONS", this->Quiet);
+ &mf, "UpdateOptions", "CTEST_UPDATE_OPTIONS", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "CVSCommand", "CTEST_CVS_COMMAND", this->Quiet);
+ &mf, "CVSCommand", "CTEST_CVS_COMMAND", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "CVSUpdateOptions", "CTEST_CVS_UPDATE_OPTIONS",
- this->Quiet);
+ &mf, "CVSUpdateOptions", "CTEST_CVS_UPDATE_OPTIONS", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "SVNCommand", "CTEST_SVN_COMMAND", this->Quiet);
+ &mf, "SVNCommand", "CTEST_SVN_COMMAND", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "SVNUpdateOptions", "CTEST_SVN_UPDATE_OPTIONS",
- this->Quiet);
+ &mf, "SVNUpdateOptions", "CTEST_SVN_UPDATE_OPTIONS", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "SVNOptions", "CTEST_SVN_OPTIONS", this->Quiet);
+ &mf, "SVNOptions", "CTEST_SVN_OPTIONS", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "BZRCommand", "CTEST_BZR_COMMAND", this->Quiet);
+ &mf, "BZRCommand", "CTEST_BZR_COMMAND", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "BZRUpdateOptions", "CTEST_BZR_UPDATE_OPTIONS",
- this->Quiet);
+ &mf, "BZRUpdateOptions", "CTEST_BZR_UPDATE_OPTIONS", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "GITCommand", "CTEST_GIT_COMMAND", this->Quiet);
+ &mf, "GITCommand", "CTEST_GIT_COMMAND", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "GITUpdateOptions", "CTEST_GIT_UPDATE_OPTIONS",
- this->Quiet);
+ &mf, "GITUpdateOptions", "CTEST_GIT_UPDATE_OPTIONS", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "GITInitSubmodules", "CTEST_GIT_INIT_SUBMODULES",
- this->Quiet);
+ &mf, "GITInitSubmodules", "CTEST_GIT_INIT_SUBMODULES", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "GITUpdateCustom", "CTEST_GIT_UPDATE_CUSTOM", this->Quiet);
+ &mf, "GITUpdateCustom", "CTEST_GIT_UPDATE_CUSTOM", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "UpdateVersionOnly", "CTEST_UPDATE_VERSION_ONLY",
- this->Quiet);
+ &mf, "UpdateVersionOnly", "CTEST_UPDATE_VERSION_ONLY", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "UpdateVersionOverride", "CTEST_UPDATE_VERSION_OVERRIDE",
- this->Quiet);
+ &mf, "UpdateVersionOverride", "CTEST_UPDATE_VERSION_OVERRIDE", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "HGCommand", "CTEST_HG_COMMAND", this->Quiet);
+ &mf, "HGCommand", "CTEST_HG_COMMAND", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "HGUpdateOptions", "CTEST_HG_UPDATE_OPTIONS", this->Quiet);
+ &mf, "HGUpdateOptions", "CTEST_HG_UPDATE_OPTIONS", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "P4Command", "CTEST_P4_COMMAND", this->Quiet);
+ &mf, "P4Command", "CTEST_P4_COMMAND", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "P4UpdateOptions", "CTEST_P4_UPDATE_OPTIONS", this->Quiet);
+ &mf, "P4UpdateOptions", "CTEST_P4_UPDATE_OPTIONS", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "P4Client", "CTEST_P4_CLIENT", this->Quiet);
+ &mf, "P4Client", "CTEST_P4_CLIENT", args.Quiet);
this->CTest->SetCTestConfigurationFromCMakeVariable(
- this->Makefile, "P4Options", "CTEST_P4_OPTIONS", this->Quiet);
+ &mf, "P4Options", "CTEST_P4_OPTIONS", args.Quiet);
- cmCTestUpdateHandler* handler = this->CTest->GetUpdateHandler();
- handler->Initialize();
+ auto handler = cm::make_unique<cmCTestUpdateHandler>(this->CTest);
if (source_dir.empty()) {
- this->SetError("source directory not specified. Please use SOURCE tag");
+ status.SetError("source directory not specified. Please use SOURCE tag");
return nullptr;
}
- handler->SetOption("SourceDirectory", source_dir);
- handler->SetQuiet(this->Quiet);
- return handler;
+ handler->SourceDirectory = source_dir;
+ handler->SetQuiet(args.Quiet);
+ return std::unique_ptr<cmCTestGenericHandler>(std::move(handler));
+}
+
+bool cmCTestUpdateCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) const
+{
+ static auto const parser = MakeHandlerParser<HandlerArguments>();
+
+ return this->Invoke(parser, args, status, [&](HandlerArguments& a) {
+ return this->ExecuteHandlerCommand(a, status);
+ });
}
diff --git a/Source/CTest/cmCTestUpdateCommand.h b/Source/CTest/cmCTestUpdateCommand.h
index e4c3453..7635aa0 100644
--- a/Source/CTest/cmCTestUpdateCommand.h
+++ b/Source/CTest/cmCTestUpdateCommand.h
@@ -4,40 +4,26 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <memory>
#include <string>
-#include <utility>
-
-#include <cm/memory>
+#include <vector>
#include "cmCTestHandlerCommand.h"
-#include "cmCommand.h"
+class cmExecutionStatus;
class cmCTestGenericHandler;
-/** \class cmCTestUpdate
- * \brief Run a ctest script
- *
- * cmCTestUpdateCommand defineds the command to updates the repository.
- */
class cmCTestUpdateCommand : public cmCTestHandlerCommand
{
public:
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- auto ni = cm::make_unique<cmCTestUpdateCommand>();
- ni->CTest = this->CTest;
- ni->CTestScriptHandler = this->CTestScriptHandler;
- return std::unique_ptr<cmCommand>(std::move(ni));
- }
+ using cmCTestHandlerCommand::cmCTestHandlerCommand;
- /**
- * The name of the command as specified in CMakeList.txt.
- */
+private:
std::string GetName() const override { return "ctest_update"; }
-protected:
- cmCTestGenericHandler* InitializeHandler() override;
+ std::unique_ptr<cmCTestGenericHandler> InitializeHandler(
+ HandlerArguments& args, cmExecutionStatus& status) const override;
+
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) const override;
};
diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx
index 045eb84..8bf71cc 100644
--- a/Source/CTest/cmCTestUpdateHandler.cxx
+++ b/Source/CTest/cmCTestUpdateHandler.cxx
@@ -19,7 +19,6 @@
#include "cmGeneratedFileStream.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
-#include "cmValue.h"
#include "cmVersion.h"
#include "cmXMLWriter.h"
@@ -36,13 +35,9 @@
return cmCTestUpdateHandlerUpdateStrings[type];
}
-cmCTestUpdateHandler::cmCTestUpdateHandler() = default;
-
-void cmCTestUpdateHandler::Initialize()
+cmCTestUpdateHandler::cmCTestUpdateHandler(cmCTest* ctest)
+ : Superclass(ctest)
{
- this->Superclass::Initialize();
- this->UpdateCommand.clear();
- this->UpdateType = e_CVS;
}
int cmCTestUpdateHandler::DetermineType(const char* cmd, const char* type)
@@ -109,8 +104,7 @@
static_cast<void>(fixLocale);
// Get source dir
- cmValue sourceDirectory = this->GetOption("SourceDirectory");
- if (!sourceDirectory) {
+ if (this->SourceDirectory.empty()) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Cannot find SourceDirectory key in the DartConfiguration.tcl"
<< std::endl);
@@ -123,7 +117,7 @@
}
cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT,
- " Updating the repository: " << *sourceDirectory
+ " Updating the repository: " << this->SourceDirectory
<< std::endl,
this->Quiet);
@@ -163,7 +157,7 @@
break;
}
vc->SetCommandLineTool(this->UpdateCommand);
- vc->SetSourceDirectory(*sourceDirectory);
+ vc->SetSourceDirectory(this->SourceDirectory);
// Cleanup the working tree.
vc->Cleanup();
@@ -195,7 +189,7 @@
xml.Element("BuildName", buildname);
xml.Element("BuildStamp",
this->CTest->GetCurrentTag() + "-" +
- this->CTest->GetTestModelString());
+ this->CTest->GetTestGroupString());
xml.Element("StartDateTime", start_time);
xml.Element("StartTime", start_time_time);
xml.Element("UpdateCommand", vc->GetUpdateCommandLine());
@@ -301,7 +295,7 @@
this->UpdateCommand = this->CTest->GetCTestConfiguration("UpdateCommand");
// Detect the VCS managing the source tree.
- this->UpdateType = this->DetectVCS(this->GetOption("SourceDirectory"));
+ this->UpdateType = this->DetectVCS(this->SourceDirectory);
if (this->UpdateType == e_UNKNOWN) {
// The source tree does not have a recognized VCS. Check the
// configuration value or command name.
diff --git a/Source/CTest/cmCTestUpdateHandler.h b/Source/CTest/cmCTestUpdateHandler.h
index 70269ea..7797228 100644
--- a/Source/CTest/cmCTestUpdateHandler.h
+++ b/Source/CTest/cmCTestUpdateHandler.h
@@ -10,6 +10,8 @@
#include "cmCTestGenericHandler.h"
+class cmCTest;
+
/** \class cmCTestUpdateHandler
* \brief A class that handles ctest -S invocations
*
@@ -24,7 +26,7 @@
*/
int ProcessHandler() override;
- cmCTestUpdateHandler();
+ cmCTestUpdateHandler(cmCTest* ctest);
enum
{
@@ -38,11 +40,6 @@
e_LAST
};
- /**
- * Initialize handler
- */
- void Initialize() override;
-
private:
// Some structures needed for update
struct StringPair : public std::pair<std::string, std::string>
@@ -57,8 +54,11 @@
// The VCS command to update the working tree.
std::string UpdateCommand;
- int UpdateType;
+ std::string SourceDirectory;
+ int UpdateType = e_CVS;
int DetectVCS(const std::string& dir);
bool SelectVCS();
+
+ friend class cmCTestUpdateCommand;
};
diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx
index 2ed671c..4ec4201 100644
--- a/Source/CTest/cmCTestUploadCommand.cxx
+++ b/Source/CTest/cmCTestUploadCommand.cxx
@@ -2,45 +2,98 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCTestUploadCommand.h"
-#include <set>
+#include <algorithm>
+#include <chrono>
#include <sstream>
+#include <string>
#include <cm/vector>
#include <cmext/string_view>
+#include "cmArgumentParser.h"
#include "cmCTest.h"
-#include "cmCTestUploadHandler.h"
+#include "cmExecutionStatus.h"
+#include "cmGeneratedFileStream.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmSystemTools.h"
+#include "cmVersion.h"
+#include "cmXMLWriter.h"
-void cmCTestUploadCommand::BindArguments()
+bool cmCTestUploadCommand::ExecuteUpload(UploadArguments& args,
+ cmExecutionStatus& status) const
{
- this->Bind("FILES"_s, this->Files);
- this->Bind("QUIET"_s, this->Quiet);
- this->Bind("CAPTURE_CMAKE_ERROR"_s, this->CaptureCMakeError);
-}
+ cmMakefile& mf = status.GetMakefile();
-void cmCTestUploadCommand::CheckArguments()
-{
- cm::erase_if(this->Files, [this](std::string const& arg) -> bool {
+ std::sort(args.Files.begin(), args.Files.end());
+ args.Files.erase(std::unique(args.Files.begin(), args.Files.end()),
+ args.Files.end());
+
+ cm::erase_if(args.Files, [&mf](std::string const& arg) -> bool {
if (!cmSystemTools::FileExists(arg)) {
std::ostringstream e;
e << "File \"" << arg << "\" does not exist. Cannot submit "
<< "a non-existent file.";
- this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ mf.IssueMessage(MessageType::FATAL_ERROR, e.str());
return true;
}
return false;
});
+
+ cmGeneratedFileStream ofs;
+ if (!this->CTest->OpenOutputFile(this->CTest->GetCurrentTag(), "Upload.xml",
+ ofs)) {
+ cmCTestLog(this->CTest, ERROR_MESSAGE,
+ "Cannot open Upload.xml file" << std::endl);
+ return false;
+ }
+ std::string buildname =
+ cmCTest::SafeBuildIdField(mf.GetSafeDefinition("CTEST_BUILD_NAME"));
+
+ cmXMLWriter xml(ofs);
+ xml.StartDocument();
+ xml.ProcessingInstruction("xml-stylesheet",
+ "type=\"text/xsl\" "
+ "href=\"Dart/Source/Server/XSL/Build.xsl "
+ "<file:///Dart/Source/Server/XSL/Build.xsl> \"");
+ xml.StartElement("Site");
+ xml.Attribute("BuildName", buildname);
+ xml.Attribute("BuildStamp",
+ this->CTest->GetCurrentTag() + "-" +
+ this->CTest->GetTestGroupString());
+ xml.Attribute("Name", mf.GetSafeDefinition("CTEST_SITE"));
+ xml.Attribute("Generator",
+ std::string("ctest-") + cmVersion::GetCMakeVersion());
+ this->CTest->AddSiteProperties(xml, mf.GetCMakeInstance());
+ xml.StartElement("Upload");
+ xml.Element("Time", std::chrono::system_clock::now());
+
+ for (std::string const& file : args.Files) {
+ cmCTestOptionalLog(this->CTest, OUTPUT,
+ "\tUpload file: " << file << std::endl, args.Quiet);
+ xml.StartElement("File");
+ xml.Attribute("filename", file);
+ xml.StartElement("Content");
+ xml.Attribute("encoding", "base64");
+ xml.Content(this->CTest->Base64EncodeFile(file));
+ xml.EndElement(); // Content
+ xml.EndElement(); // File
+ }
+ xml.EndElement(); // Upload
+ xml.EndElement(); // Site
+ xml.EndDocument();
+ return true;
}
-cmCTestGenericHandler* cmCTestUploadCommand::InitializeHandler()
+bool cmCTestUploadCommand::InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) const
{
- cmCTestUploadHandler* handler = this->CTest->GetUploadHandler();
- handler->Initialize();
- handler->SetFiles(
- std::set<std::string>(this->Files.begin(), this->Files.end()));
- handler->SetQuiet(this->Quiet);
- return handler;
+ static auto const parser =
+ cmArgumentParser<UploadArguments>{ MakeBasicParser<UploadArguments>() }
+ .Bind("FILES"_s, &UploadArguments::Files)
+ .Bind("QUIET"_s, &UploadArguments::Quiet);
+
+ return this->Invoke(parser, args, status, [&](UploadArguments& a) {
+ return this->ExecuteUpload(a, status);
+ });
}
diff --git a/Source/CTest/cmCTestUploadCommand.h b/Source/CTest/cmCTestUploadCommand.h
index a9d1dd2..93fbc35 100644
--- a/Source/CTest/cmCTestUploadCommand.h
+++ b/Source/CTest/cmCTestUploadCommand.h
@@ -5,46 +5,30 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <string>
-#include <utility>
#include <vector>
-#include <cm/memory>
-
#include "cmArgumentParserTypes.h"
#include "cmCTestHandlerCommand.h"
-#include "cmCommand.h"
-class cmCTestGenericHandler;
+class cmExecutionStatus;
-/** \class cmCTestUpload
- * \brief Run a ctest script
- *
- * cmCTestUploadCommand defines the command to upload result files for
- * the project.
- */
class cmCTestUploadCommand : public cmCTestHandlerCommand
{
public:
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- auto ni = cm::make_unique<cmCTestUploadCommand>();
- ni->CTest = this->CTest;
- ni->CTestScriptHandler = this->CTestScriptHandler;
- return std::unique_ptr<cmCommand>(std::move(ni));
- }
-
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- std::string GetName() const override { return "ctest_upload"; }
+ using cmCTestHandlerCommand::cmCTestHandlerCommand;
protected:
- void BindArguments() override;
- void CheckArguments() override;
- cmCTestGenericHandler* InitializeHandler() override;
+ struct UploadArguments : BasicArguments
+ {
+ ArgumentParser::MaybeEmpty<std::vector<std::string>> Files;
+ bool Quiet = false;
+ };
- ArgumentParser::MaybeEmpty<std::vector<std::string>> Files;
+private:
+ std::string GetName() const override { return "ctest_upload"; }
+
+ bool ExecuteUpload(UploadArguments& args, cmExecutionStatus& status) const;
+
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) const override;
};
diff --git a/Source/CTest/cmCTestUploadHandler.cxx b/Source/CTest/cmCTestUploadHandler.cxx
deleted file mode 100644
index 59e2b88..0000000
--- a/Source/CTest/cmCTestUploadHandler.cxx
+++ /dev/null
@@ -1,75 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmCTestUploadHandler.h"
-
-#include <chrono>
-#include <ostream>
-#include <string>
-
-#include "cmCTest.h"
-#include "cmGeneratedFileStream.h"
-#include "cmVersion.h"
-#include "cmXMLWriter.h"
-
-cmCTestUploadHandler::cmCTestUploadHandler()
-{
- this->Initialize();
-}
-
-void cmCTestUploadHandler::Initialize()
-{
- this->Superclass::Initialize();
- this->Files.clear();
-}
-
-void cmCTestUploadHandler::SetFiles(std::set<std::string> const& files)
-{
- this->Files = files;
-}
-
-int cmCTestUploadHandler::ProcessHandler()
-{
- cmGeneratedFileStream ofs;
- if (!this->CTest->OpenOutputFile(this->CTest->GetCurrentTag(), "Upload.xml",
- ofs)) {
- cmCTestLog(this->CTest, ERROR_MESSAGE,
- "Cannot open Upload.xml file" << std::endl);
- return -1;
- }
- std::string buildname =
- cmCTest::SafeBuildIdField(this->CTest->GetCTestConfiguration("BuildName"));
-
- cmXMLWriter xml(ofs);
- xml.StartDocument();
- xml.ProcessingInstruction("xml-stylesheet",
- "type=\"text/xsl\" "
- "href=\"Dart/Source/Server/XSL/Build.xsl "
- "<file:///Dart/Source/Server/XSL/Build.xsl> \"");
- xml.StartElement("Site");
- xml.Attribute("BuildName", buildname);
- xml.Attribute("BuildStamp",
- this->CTest->GetCurrentTag() + "-" +
- this->CTest->GetTestModelString());
- xml.Attribute("Name", this->CTest->GetCTestConfiguration("Site"));
- xml.Attribute("Generator",
- std::string("ctest-") + cmVersion::GetCMakeVersion());
- this->CTest->AddSiteProperties(xml);
- xml.StartElement("Upload");
- xml.Element("Time", std::chrono::system_clock::now());
-
- for (std::string const& file : this->Files) {
- cmCTestOptionalLog(this->CTest, OUTPUT,
- "\tUpload file: " << file << std::endl, this->Quiet);
- xml.StartElement("File");
- xml.Attribute("filename", file);
- xml.StartElement("Content");
- xml.Attribute("encoding", "base64");
- xml.Content(this->CTest->Base64EncodeFile(file));
- xml.EndElement(); // Content
- xml.EndElement(); // File
- }
- xml.EndElement(); // Upload
- xml.EndElement(); // Site
- xml.EndDocument();
- return 0;
-}
diff --git a/Source/CTest/cmCTestUploadHandler.h b/Source/CTest/cmCTestUploadHandler.h
deleted file mode 100644
index 55d21c1..0000000
--- a/Source/CTest/cmCTestUploadHandler.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* 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 <set>
-#include <string>
-
-#include "cmCTestGenericHandler.h"
-
-/** \class cmCTestUploadHandler
- * \brief Helper class for CTest
- *
- * Submit arbitrary files
- *
- */
-class cmCTestUploadHandler : public cmCTestGenericHandler
-{
-public:
- using Superclass = cmCTestGenericHandler;
-
- cmCTestUploadHandler();
-
- /*
- * The main entry point for this class
- */
- int ProcessHandler() override;
-
- void Initialize() override;
-
- /** Specify a set of files to submit. */
- void SetFiles(std::set<std::string> const& files);
-
-private:
- std::set<std::string> Files;
-};
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index 2c809b6..7a89ffb 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -106,6 +106,11 @@
options.stdio_count = 3; // in, out and err
options.exit_cb = &cmProcess::OnExitCB;
options.stdio = stdio;
+#if UV_VERSION_MAJOR > 1 || !defined(CMAKE_USE_SYSTEM_LIBUV)
+ if (!this->Runner->GetCTest()->GetInteractiveDebugMode()) {
+ options.flags = UV_PROCESS_WINDOWS_USE_PARENT_ERROR_MODE;
+ }
+#endif
#if !defined(CMAKE_USE_SYSTEM_LIBUV)
std::vector<char> cpumask;
if (affinity && !affinity->empty()) {
diff --git a/Source/Checks/Curses/CMakeLists.txt b/Source/Checks/Curses/CMakeLists.txt
index bd7c415..1f04bd2 100644
--- a/Source/Checks/Curses/CMakeLists.txt
+++ b/Source/Checks/Curses/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.13...3.29 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.13...3.30 FATAL_ERROR)
project(CheckCurses C)
set(CURSES_NEED_NCURSES TRUE)
diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx
index bc21cd0..8f7e515 100644
--- a/Source/CursesDialog/ccmake.cxx
+++ b/Source/CursesDialog/ccmake.cxx
@@ -101,7 +101,7 @@
}
}
- std::string cacheDir = cmSystemTools::GetCurrentWorkingDirectory();
+ std::string cacheDir = cmSystemTools::GetLogicalWorkingDirectory();
for (i = 1; i < args.size(); ++i) {
std::string const& arg = args[i];
if (cmHasPrefix(arg, "-B")) {
diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx
index 21ed8c8..c3adae1 100644
--- a/Source/QtDialog/CMakeSetup.cxx
+++ b/Source/QtDialog/CMakeSetup.cxx
@@ -172,8 +172,8 @@
}
}
- sourceDirectory = cmSystemTools::CollapseFullPath(path.toStdString());
- cmSystemTools::ConvertToUnixSlashes(sourceDirectory);
+ sourceDirectory =
+ cmSystemTools::ToNormalizedPathOnDisk(path.toStdString());
} else if (arg.startsWith("-B")) {
QString path = arg.mid(2);
if (path.isEmpty()) {
@@ -189,8 +189,8 @@
}
}
- binaryDirectory = cmSystemTools::CollapseFullPath(path.toStdString());
- cmSystemTools::ConvertToUnixSlashes(binaryDirectory);
+ binaryDirectory =
+ cmSystemTools::ToNormalizedPathOnDisk(path.toStdString());
} else if (arg.startsWith("--preset=")) {
QString preset = arg.mid(cmStrLen("--preset="));
if (preset.isEmpty()) {
@@ -223,7 +223,7 @@
} else {
if (args.count() == 2) {
std::string filePath =
- cmSystemTools::CollapseFullPath(args[1].toStdString());
+ cmSystemTools::ToNormalizedPathOnDisk(args[1].toStdString());
// check if argument is a directory containing CMakeCache.txt
std::string buildFilePath = cmStrCat(filePath, "/CMakeCache.txt");
@@ -243,7 +243,7 @@
} else if (cmSystemTools::FileExists(srcFilePath.c_str())) {
dialog.setSourceDirectory(QString::fromStdString(filePath));
dialog.setBinaryDirectory(
- QString::fromStdString(cmSystemTools::CollapseFullPath(".")));
+ QString::fromStdString(cmSystemTools::GetLogicalWorkingDirectory()));
}
}
}
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index 45c4717..7c94ea2 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -258,9 +258,7 @@
#endif
// Apply the same transformations that the command-line invocation does
auto sanitizePath = [](QString const& value) -> std::string {
- std::string path = cmSystemTools::CollapseFullPath(value.toStdString());
- cmSystemTools::ConvertToUnixSlashes(path);
- return path;
+ return cmSystemTools::ToNormalizedPathOnDisk(value.toStdString());
};
this->CMakeInstance->SetHomeDirectory(sanitizePath(this->SourceDirectory));
diff --git a/Source/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx
index e67e0c2..94dfa3e 100644
--- a/Source/QtDialog/QCMakeCacheView.cxx
+++ b/Source/QtDialog/QCMakeCacheView.cxx
@@ -189,7 +189,7 @@
static uint qHash(const QCMakeProperty& p)
{
- return static_cast<uint>(qHash(p.Key));
+ return qHash(p.Key);
}
void QCMakeCacheModel::setShowNewProperties(bool f)
@@ -242,7 +242,7 @@
bool b = this->blockSignals(true);
this->clear();
- this->NewPropertyCount = static_cast<int>(newProps.size());
+ this->NewPropertyCount = newProps.size();
if (View == FlatView) {
QCMakePropertyList newP = newProps.values();
diff --git a/Source/QtDialog/QCMakePresetItemModel.cxx b/Source/QtDialog/QCMakePresetItemModel.cxx
index 31a6000..cb96b6b 100644
--- a/Source/QtDialog/QCMakePresetItemModel.cxx
+++ b/Source/QtDialog/QCMakePresetItemModel.cxx
@@ -83,7 +83,7 @@
if (this->m_presets.empty()) {
return 1;
}
- return static_cast<int>(this->m_presets.size() + 2);
+ return this->m_presets.size() + 2;
}
int QCMakePresetItemModel::columnCount(const QModelIndex& parent) const
@@ -144,5 +144,5 @@
index++;
}
- return static_cast<int>(this->m_presets.size() + 1);
+ return this->m_presets.size() + 1;
}
diff --git a/Source/cmCMakePath.h b/Source/cmCMakePath.h
index fd71c1f..52fd6aa 100644
--- a/Source/cmCMakePath.h
+++ b/Source/cmCMakePath.h
@@ -617,19 +617,18 @@
// Non-members
// ===========
- friend inline bool operator==(const cmCMakePath& lhs,
- const cmCMakePath& rhs) noexcept
+ friend bool operator==(const cmCMakePath& lhs,
+ const cmCMakePath& rhs) noexcept
{
return lhs.Compare(rhs) == 0;
}
- friend inline bool operator!=(const cmCMakePath& lhs,
- const cmCMakePath& rhs) noexcept
+ friend bool operator!=(const cmCMakePath& lhs,
+ const cmCMakePath& rhs) noexcept
{
return lhs.Compare(rhs) != 0;
}
- friend inline cmCMakePath operator/(const cmCMakePath& lhs,
- const cmCMakePath& rhs)
+ friend cmCMakePath operator/(const cmCMakePath& lhs, const cmCMakePath& rhs)
{
cmCMakePath result(lhs);
result /= rhs;
diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx
index 2e6cd40..6f101cb 100644
--- a/Source/cmCPluginAPI.cxx
+++ b/Source/cmCPluginAPI.cxx
@@ -168,7 +168,7 @@
static int CCONV cmCommandExists(void* arg, const char* name)
{
cmMakefile* mf = static_cast<cmMakefile*>(arg);
- return static_cast<int>(mf->GetState()->GetCommand(name) ? 1 : 0);
+ return mf->GetState()->GetCommand(name) ? 1 : 0;
}
static void CCONV cmAddDefineFlag(void* arg, const char* definition)
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 829fbf9..83f6eb3 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -10,6 +10,7 @@
#include <cstdlib>
#include <cstring>
#include <ctime>
+#include <initializer_list>
#include <iostream>
#include <map>
#include <ratio>
@@ -31,7 +32,6 @@
#include "cmsys/Base64.h"
#include "cmsys/Directory.hxx"
#include "cmsys/FStream.hxx"
-#include "cmsys/Glob.hxx"
#include "cmsys/RegularExpression.hxx"
#include "cmsys/SystemInformation.hxx"
#if defined(_WIN32)
@@ -41,23 +41,18 @@
#endif
#include "cmCMakePresetsGraph.h"
-#include "cmCTestBuildAndTestHandler.h"
-#include "cmCTestBuildHandler.h"
-#include "cmCTestConfigureHandler.h"
-#include "cmCTestCoverageHandler.h"
-#include "cmCTestGenericHandler.h"
-#include "cmCTestMemCheckHandler.h"
+#include "cmCTestBuildAndTest.h"
#include "cmCTestScriptHandler.h"
-#include "cmCTestStartCommand.h"
-#include "cmCTestSubmitHandler.h"
#include "cmCTestTestHandler.h"
-#include "cmCTestUpdateHandler.h"
-#include "cmCTestUploadHandler.h"
+#include "cmCTestTypes.h"
+#include "cmCommandLineArgument.h"
#include "cmDynamicLoader.h"
+#include "cmExecutionStatus.h"
#include "cmGeneratedFileStream.h"
#include "cmGlobalGenerator.h"
#include "cmJSONState.h"
#include "cmList.h"
+#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmProcessOutput.h"
#include "cmState.h"
@@ -71,6 +66,7 @@
#include "cmValue.h"
#include "cmVersion.h"
#include "cmVersionConfig.h"
+#include "cmWorkingDirectory.h"
#include "cmXMLWriter.h"
#include "cmake.h"
@@ -80,6 +76,11 @@
struct cmCTest::Private
{
+ Private(cmCTest* ctest)
+ : BuildAndTest(ctest)
+ {
+ }
+
/** Representation of one part. */
struct PartInfo
{
@@ -114,44 +115,8 @@
bool FlushTestProgressLine = false;
- bool ForceNewCTestProcess = false;
-
- bool RunConfigurationScript = false;
-
// these are helper classes
- cmCTestBuildHandler BuildHandler;
- cmCTestBuildAndTestHandler BuildAndTestHandler;
- cmCTestCoverageHandler CoverageHandler;
- cmCTestScriptHandler ScriptHandler;
- cmCTestTestHandler TestHandler;
- cmCTestUpdateHandler UpdateHandler;
- cmCTestConfigureHandler ConfigureHandler;
- cmCTestMemCheckHandler MemCheckHandler;
- cmCTestSubmitHandler SubmitHandler;
- cmCTestUploadHandler UploadHandler;
-
- std::vector<cmCTestGenericHandler*> GetTestingHandlers()
- {
- return { &this->BuildHandler, &this->BuildAndTestHandler,
- &this->CoverageHandler, &this->ScriptHandler,
- &this->TestHandler, &this->UpdateHandler,
- &this->ConfigureHandler, &this->MemCheckHandler,
- &this->SubmitHandler, &this->UploadHandler };
- }
-
- std::map<std::string, cmCTestGenericHandler*> GetNamedTestingHandlers()
- {
- return { { "build", &this->BuildHandler },
- { "buildtest", &this->BuildAndTestHandler },
- { "coverage", &this->CoverageHandler },
- { "script", &this->ScriptHandler },
- { "test", &this->TestHandler },
- { "update", &this->UpdateHandler },
- { "configure", &this->ConfigureHandler },
- { "memcheck", &this->MemCheckHandler },
- { "submit", &this->SubmitHandler },
- { "upload", &this->UploadHandler } };
- }
+ cmCTestBuildAndTest BuildAndTest;
bool ShowOnly = false;
bool OutputAsJson = false;
@@ -177,6 +142,10 @@
cmDuration GlobalTimeout = cmDuration::zero();
+ std::chrono::steady_clock::time_point StartTime =
+ std::chrono::steady_clock::now();
+ cmDuration TimeLimit = cmCTest::MaxDuration();
+
int MaxTestNameWidth = 30;
cm::optional<size_t> ParallelLevel = 1;
@@ -199,14 +168,9 @@
bool CompressXMLFiles = false;
bool CompressTestOutput = true;
- // By default we write output to the process output streams.
- std::ostream* StreamOut = &std::cout;
- std::ostream* StreamErr = &std::cerr;
-
bool SuppressUpdatingCTestConfiguration = false;
bool Debug = false;
- bool ShowLineNumbers = false;
bool Quiet = false;
std::string BuildID;
@@ -216,7 +180,7 @@
int SubmitIndex = 0;
std::unique_ptr<cmGeneratedFileStream> OutputLogFile;
- int OutputLogFileLastTag = -1;
+ cm::optional<cmCTest::LogType> OutputLogFileLastTag;
bool OutputTestOutputOnTestFailure = false;
bool OutputColorCode = cmCTest::ColoredOutputSupportedByConsole();
@@ -225,6 +189,9 @@
cmCTest::NoTests NoTestsMode = cmCTest::NoTests::Legacy;
bool NoTestsModeSetInCli = false;
+
+ cmCTestTestOptions TestOptions;
+ std::vector<std::string> CommandLineHttpHeaders;
};
struct tm* cmCTest::GetNightlyTime(std::string const& str, bool tomorrowtag)
@@ -340,7 +307,7 @@
}
cmCTest::cmCTest()
- : Impl(new Private)
+ : Impl(cm::make_unique<Private>(this))
{
std::string envValue;
if (cmSystemTools::GetEnv("CTEST_OUTPUT_ON_FAILURE", envValue)) {
@@ -370,10 +337,6 @@
->PartMap[cmSystemTools::LowerCase(this->Impl->Parts[p].GetName())] = p;
}
- for (auto& handler : this->Impl->GetTestingHandlers()) {
- handler->SetCTestInstance(this);
- }
-
// Make sure we can capture the build tool output.
cmSystemTools::EnableVSConsoleOutput();
}
@@ -418,15 +381,13 @@
return PartCount;
}
-int cmCTest::Initialize(const std::string& binary_dir,
- cmCTestStartCommand* command)
+void cmCTest::Initialize(std::string const& binary_dir)
{
- bool quiet = false;
- if (command && command->ShouldBeQuiet()) {
- quiet = true;
+ this->Impl->BuildID = "";
+ for (Part p = PartStart; p != PartCount; p = static_cast<Part>(p + 1)) {
+ this->Impl->Parts[p].SubmitFiles.clear();
}
- cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
if (!this->Impl->InteractiveDebugMode) {
this->BlockTestErrorDiagnostics();
} else {
@@ -435,269 +396,122 @@
this->Impl->BinaryDir = binary_dir;
cmSystemTools::ConvertToUnixSlashes(this->Impl->BinaryDir);
-
- this->UpdateCTestConfiguration();
-
- cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
- if (this->Impl->ProduceXML) {
- cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl, quiet);
- cmCTestOptionalLog(this, OUTPUT,
- " Site: "
- << this->GetCTestConfiguration("Site") << std::endl
- << " Build name: "
- << cmCTest::SafeBuildIdField(
- this->GetCTestConfiguration("BuildName"))
- << std::endl,
- quiet);
- cmCTestOptionalLog(this, DEBUG, "Produce XML is on" << std::endl, quiet);
- if (this->Impl->TestModel == cmCTest::NIGHTLY &&
- this->GetCTestConfiguration("NightlyStartTime").empty()) {
- cmCTestOptionalLog(
- this, WARNING,
- "WARNING: No nightly start time found please set in CTestConfig.cmake"
- " or DartConfig.cmake"
- << std::endl,
- quiet);
- cmCTestOptionalLog(this, DEBUG, "Here: " << __LINE__ << std::endl,
- quiet);
- return 0;
- }
- }
-
- cmake cm(cmake::RoleScript, cmState::CTest);
- cm.SetHomeDirectory("");
- cm.SetHomeOutputDirectory("");
- cm.GetCurrentSnapshot().SetDefaultDefinitions();
- cmGlobalGenerator gg(&cm);
- cmMakefile mf(&gg, cm.GetCurrentSnapshot());
- if (!this->ReadCustomConfigurationFileTree(this->Impl->BinaryDir, &mf)) {
- cmCTestOptionalLog(
- this, DEBUG, "Cannot find custom configuration file tree" << std::endl,
- quiet);
- return 0;
- }
-
- if (this->Impl->ProduceXML) {
- // Verify "Testing" directory exists:
- //
- std::string testingDir = this->Impl->BinaryDir + "/Testing";
- if (cmSystemTools::FileExists(testingDir)) {
- if (!cmSystemTools::FileIsDirectory(testingDir)) {
- cmCTestLog(this, ERROR_MESSAGE,
- "File " << testingDir
- << " is in the place of the testing directory"
- << std::endl);
- return 0;
- }
- } else {
- if (!cmSystemTools::MakeDirectory(testingDir)) {
- cmCTestLog(this, ERROR_MESSAGE,
- "Cannot create directory " << testingDir << std::endl);
- return 0;
- }
- }
-
- // Create new "TAG" file or read existing one:
- //
- bool createNewTag = true;
- if (command) {
- createNewTag = command->ShouldCreateNewTag();
- }
-
- std::string tagfile = testingDir + "/TAG";
- cmsys::ifstream tfin(tagfile.c_str());
- std::string tag;
-
- if (createNewTag) {
- time_t tctime = time(nullptr);
- if (this->Impl->TomorrowTag) {
- tctime += (24 * 60 * 60);
- }
- struct tm* lctime = gmtime(&tctime);
- if (tfin && cmSystemTools::GetLineFromStream(tfin, tag)) {
- int year = 0;
- int mon = 0;
- int day = 0;
- int hour = 0;
- int min = 0;
- sscanf(tag.c_str(), "%04d%02d%02d-%02d%02d", &year, &mon, &day, &hour,
- &min);
- if (year != lctime->tm_year + 1900 || mon != lctime->tm_mon + 1 ||
- day != lctime->tm_mday) {
- tag.clear();
- }
- std::string group;
- if (cmSystemTools::GetLineFromStream(tfin, group) &&
- !this->Impl->Parts[PartStart] && !command) {
- this->Impl->SpecificGroup = group;
- }
- std::string model;
- if (cmSystemTools::GetLineFromStream(tfin, model) &&
- !this->Impl->Parts[PartStart] && !command) {
- this->Impl->TestModel = GetTestModelFromString(model);
- }
- tfin.close();
- }
- if (tag.empty() || command || this->Impl->Parts[PartStart]) {
- cmCTestOptionalLog(
- this, DEBUG,
- "TestModel: " << this->GetTestModelString() << std::endl, quiet);
- cmCTestOptionalLog(this, DEBUG,
- "TestModel: " << this->Impl->TestModel << std::endl,
- quiet);
- if (this->Impl->TestModel == cmCTest::NIGHTLY) {
- lctime = this->GetNightlyTime(
- this->GetCTestConfiguration("NightlyStartTime"),
- this->Impl->TomorrowTag);
- }
- char datestring[100];
- snprintf(datestring, sizeof(datestring), "%04d%02d%02d-%02d%02d",
- lctime->tm_year + 1900, lctime->tm_mon + 1, lctime->tm_mday,
- lctime->tm_hour, lctime->tm_min);
- tag = datestring;
- cmsys::ofstream ofs(tagfile.c_str());
- if (ofs) {
- ofs << tag << std::endl;
- ofs << this->GetTestModelString() << std::endl;
- switch (this->Impl->TestModel) {
- case cmCTest::EXPERIMENTAL:
- ofs << "Experimental" << std::endl;
- break;
- case cmCTest::NIGHTLY:
- ofs << "Nightly" << std::endl;
- break;
- case cmCTest::CONTINUOUS:
- ofs << "Continuous" << std::endl;
- break;
- }
- }
- ofs.close();
- if (!command) {
- cmCTestOptionalLog(this, OUTPUT,
- "Create new tag: " << tag << " - "
- << this->GetTestModelString()
- << std::endl,
- quiet);
- }
- }
- } else {
- std::string group;
- std::string modelStr;
- int model = cmCTest::UNKNOWN;
-
- if (tfin) {
- cmSystemTools::GetLineFromStream(tfin, tag);
- cmSystemTools::GetLineFromStream(tfin, group);
- if (cmSystemTools::GetLineFromStream(tfin, modelStr)) {
- model = GetTestModelFromString(modelStr);
- }
- tfin.close();
- }
-
- if (tag.empty()) {
- cmCTestLog(this, ERROR_MESSAGE,
- "Cannot read existing TAG file in " << testingDir
- << std::endl);
- return 0;
- }
-
- if (this->Impl->TestModel == cmCTest::UNKNOWN) {
- if (model == cmCTest::UNKNOWN) {
- cmCTestLog(this, ERROR_MESSAGE,
- "TAG file does not contain model and "
- "no model specified in start command"
- << std::endl);
- return 0;
- }
-
- this->SetTestModel(model);
- }
-
- if (model != this->Impl->TestModel && model != cmCTest::UNKNOWN &&
- this->Impl->TestModel != cmCTest::UNKNOWN) {
- cmCTestOptionalLog(this, WARNING,
- "Model given in TAG does not match "
- "model given in ctest_start()"
- << std::endl,
- quiet);
- }
-
- if (!this->Impl->SpecificGroup.empty() &&
- group != this->Impl->SpecificGroup) {
- cmCTestOptionalLog(this, WARNING,
- "Group given in TAG does not match "
- "group given in ctest_start()"
- << std::endl,
- quiet);
- } else {
- this->Impl->SpecificGroup = group;
- }
-
- cmCTestOptionalLog(this, OUTPUT,
- " Use existing tag: " << tag << " - "
- << this->GetTestModelString()
- << std::endl,
- quiet);
- }
-
- this->Impl->CurrentTag = tag;
- }
-
- return 1;
}
-bool cmCTest::InitializeFromCommand(cmCTestStartCommand* command)
+bool cmCTest::CreateNewTag(bool quiet)
{
- std::string src_dir = this->GetCTestConfiguration("SourceDirectory");
- std::string bld_dir = this->GetCTestConfiguration("BuildDirectory");
- this->Impl->BuildID = "";
- for (Part p = PartStart; p != PartCount; p = static_cast<Part>(p + 1)) {
- this->Impl->Parts[p].SubmitFiles.clear();
- }
+ std::string const testingDir = this->Impl->BinaryDir + "/Testing";
+ std::string const tagfile = testingDir + "/TAG";
- cmMakefile* mf = command->GetMakefile();
- std::string fname;
-
- std::string src_dir_fname = cmStrCat(src_dir, "/CTestConfig.cmake");
- cmSystemTools::ConvertToUnixSlashes(src_dir_fname);
-
- std::string bld_dir_fname = cmStrCat(bld_dir, "/CTestConfig.cmake");
- cmSystemTools::ConvertToUnixSlashes(bld_dir_fname);
-
- if (cmSystemTools::FileExists(bld_dir_fname)) {
- fname = bld_dir_fname;
- } else if (cmSystemTools::FileExists(src_dir_fname)) {
- fname = src_dir_fname;
- }
-
- if (!fname.empty()) {
- cmCTestOptionalLog(this, OUTPUT,
- " Reading ctest configuration file: " << fname
- << std::endl,
- command->ShouldBeQuiet());
- bool readit = mf->ReadDependentFile(fname);
- if (!readit) {
- std::string m = cmStrCat("Could not find include file: ", fname);
- command->SetError(m);
- return false;
- }
- }
-
- this->SetCTestConfigurationFromCMakeVariable(mf, "NightlyStartTime",
- "CTEST_NIGHTLY_START_TIME",
- command->ShouldBeQuiet());
- this->SetCTestConfigurationFromCMakeVariable(mf, "Site", "CTEST_SITE",
- command->ShouldBeQuiet());
- this->SetCTestConfigurationFromCMakeVariable(
- mf, "BuildName", "CTEST_BUILD_NAME", command->ShouldBeQuiet());
-
- if (!this->Initialize(bld_dir, command)) {
+ auto const result = cmSystemTools::MakeDirectory(testingDir);
+ if (!result.IsSuccess()) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Cannot create directory \""
+ << testingDir << "\": " << result.GetString() << std::endl);
return false;
}
+
+ cmCTestOptionalLog(this, DEBUG,
+ "TestModel: " << this->GetTestGroupString() << std::endl,
+ quiet);
+ cmCTestOptionalLog(
+ this, DEBUG, "TestModel: " << this->Impl->TestModel << std::endl, quiet);
+
+ struct tm* lctime = [this]() -> tm* {
+ if (this->Impl->TestModel == cmCTest::NIGHTLY) {
+ return this->GetNightlyTime(
+ this->GetCTestConfiguration("NightlyStartTime"),
+ this->Impl->TomorrowTag);
+ }
+ time_t tctime = time(nullptr);
+ if (this->Impl->TomorrowTag) {
+ tctime += (24 * 60 * 60);
+ }
+ return gmtime(&tctime);
+ }();
+
+ char datestring[100];
+ snprintf(datestring, sizeof(datestring), "%04d%02d%02d-%02d%02d",
+ lctime->tm_year + 1900, lctime->tm_mon + 1, lctime->tm_mday,
+ lctime->tm_hour, lctime->tm_min);
+ this->Impl->CurrentTag = datestring;
+
+ cmsys::ofstream ofs(tagfile.c_str());
+ ofs << this->Impl->CurrentTag << std::endl;
+ ofs << this->GetTestGroupString() << std::endl;
+ ofs << this->GetTestModelString() << std::endl;
+
+ return true;
+}
+
+bool cmCTest::ReadExistingTag(bool quiet)
+{
+ std::string const testingDir = this->Impl->BinaryDir + "/Testing";
+ std::string const tagfile = testingDir + "/TAG";
+
+ std::string tag;
+ std::string group;
+ std::string modelStr;
+ int model = cmCTest::UNKNOWN;
+
+ cmsys::ifstream tfin(tagfile.c_str());
+ if (tfin) {
+ cmSystemTools::GetLineFromStream(tfin, tag);
+ cmSystemTools::GetLineFromStream(tfin, group);
+ if (cmSystemTools::GetLineFromStream(tfin, modelStr)) {
+ model = GetTestModelFromString(modelStr);
+ }
+ tfin.close();
+ }
+
+ if (tag.empty()) {
+ if (!quiet) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Cannot read existing TAG file in " << testingDir
+ << std::endl);
+ }
+ return false;
+ }
+
+ if (this->Impl->TestModel == cmCTest::UNKNOWN) {
+ if (model == cmCTest::UNKNOWN) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "TAG file does not contain model and "
+ "no model specified in start command"
+ << std::endl);
+ return false;
+ }
+
+ this->SetTestModel(model);
+ }
+
+ if (model != this->Impl->TestModel && model != cmCTest::UNKNOWN &&
+ this->Impl->TestModel != cmCTest::UNKNOWN) {
+ cmCTestOptionalLog(this, WARNING,
+ "Model given in TAG does not match "
+ "model given in ctest_start()"
+ << std::endl,
+ quiet);
+ }
+
+ if (!this->Impl->SpecificGroup.empty() &&
+ group != this->Impl->SpecificGroup) {
+ cmCTestOptionalLog(this, WARNING,
+ "Group given in TAG does not match "
+ "group given in ctest_start()"
+ << std::endl,
+ quiet);
+ } else {
+ this->Impl->SpecificGroup = group;
+ }
+
cmCTestOptionalLog(this, OUTPUT,
- " Use " << this->GetTestModelString() << " tag: "
- << this->GetCurrentTag() << std::endl,
- command->ShouldBeQuiet());
+ " Use existing tag: " << tag << " - "
+ << this->GetTestGroupString()
+ << std::endl,
+ quiet);
+
+ this->Impl->CurrentTag = tag;
return true;
}
@@ -760,7 +574,7 @@
if (!this->GetCTestConfiguration("BuildDirectory").empty()) {
this->Impl->BinaryDir = this->GetCTestConfiguration("BuildDirectory");
if (this->Impl->TestDir.empty()) {
- cmSystemTools::ChangeDirectory(this->Impl->BinaryDir);
+ cmSystemTools::SetLogicalWorkingDirectory(this->Impl->BinaryDir);
}
}
this->Impl->TimeOut =
@@ -825,10 +639,6 @@
return false;
}
-void cmCTest::Finalize()
-{
-}
-
bool cmCTest::OpenOutputFile(const std::string& path, const std::string& name,
cmGeneratedFileStream& stream, bool compress)
{
@@ -889,166 +699,174 @@
return cmSystemTools::FileExists(testingDir);
}
-cmCTestBuildHandler* cmCTest::GetBuildHandler()
-{
- return &this->Impl->BuildHandler;
-}
-
-cmCTestBuildAndTestHandler* cmCTest::GetBuildAndTestHandler()
-{
- return &this->Impl->BuildAndTestHandler;
-}
-
-cmCTestCoverageHandler* cmCTest::GetCoverageHandler()
-{
- return &this->Impl->CoverageHandler;
-}
-
-cmCTestScriptHandler* cmCTest::GetScriptHandler()
-{
- return &this->Impl->ScriptHandler;
-}
-
-cmCTestTestHandler* cmCTest::GetTestHandler()
-{
- return &this->Impl->TestHandler;
-}
-
-cmCTestUpdateHandler* cmCTest::GetUpdateHandler()
-{
- return &this->Impl->UpdateHandler;
-}
-
-cmCTestConfigureHandler* cmCTest::GetConfigureHandler()
-{
- return &this->Impl->ConfigureHandler;
-}
-
-cmCTestMemCheckHandler* cmCTest::GetMemCheckHandler()
-{
- return &this->Impl->MemCheckHandler;
-}
-
-cmCTestSubmitHandler* cmCTest::GetSubmitHandler()
-{
- return &this->Impl->SubmitHandler;
-}
-
-cmCTestUploadHandler* cmCTest::GetUploadHandler()
-{
- return &this->Impl->UploadHandler;
-}
-
int cmCTest::ProcessSteps()
{
- int res = 0;
- bool notest = true;
- int update_count = 0;
+ this->Impl->ExtraVerbose = this->Impl->Verbose;
+ this->Impl->Verbose = true;
+ this->Impl->ProduceXML = true;
- for (Part p = PartStart; notest && p != PartCount;
- p = static_cast<Part>(p + 1)) {
- notest = !this->Impl->Parts[p];
+ const std::string currDir = cmSystemTools::GetLogicalWorkingDirectory();
+ std::string workDir = currDir;
+ if (!this->Impl->TestDir.empty()) {
+ workDir = cmSystemTools::ToNormalizedPathOnDisk(this->Impl->TestDir);
}
+
+ cmWorkingDirectory changeDir(workDir);
+ if (changeDir.Failed()) {
+ cmCTestLog(this, ERROR_MESSAGE, changeDir.GetError() << std::endl);
+ return 1;
+ }
+
+ this->Impl->BinaryDir = workDir;
+ cmSystemTools::ConvertToUnixSlashes(this->Impl->BinaryDir);
+ this->UpdateCTestConfiguration();
+ this->BlockTestErrorDiagnostics();
+
+ int res = 0;
+ cmCTestScriptHandler script(this);
+ script.CreateCMake();
+ cmMakefile& mf = *script.GetMakefile();
+ this->ReadCustomConfigurationFileTree(this->Impl->BinaryDir, &mf);
+ this->SetTimeLimit(mf.GetDefinition("CTEST_TIME_LIMIT"));
+ this->SetCMakeVariables(mf);
+ std::vector<cmListFileArgument> args{
+ cmListFileArgument("RETURN_VALUE", cmListFileArgument::Unquoted, 0),
+ cmListFileArgument("return_value", cmListFileArgument::Unquoted, 0),
+ };
+
+ if (this->Impl->Parts[PartStart]) {
+ auto const func = cmListFileFunction(
+ "ctest_start", 0, 0,
+ {
+ { this->GetTestModelString(), cmListFileArgument::Unquoted, 0 },
+ { "GROUP", cmListFileArgument::Unquoted, 0 },
+ { this->GetTestGroupString(), cmListFileArgument::Unquoted, 0 },
+ });
+ auto status = cmExecutionStatus(mf);
+ if (!mf.ExecuteCommand(func, status)) {
+ return 12;
+ }
+ } else if (!this->ReadExistingTag(true) && !this->CreateNewTag(false)) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Problem initializing the dashboard." << std::endl);
+ return 12;
+ }
+
if (this->Impl->Parts[PartUpdate] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
- cmCTestUpdateHandler* uphandler = this->GetUpdateHandler();
- uphandler->SetPersistentOption(
- "SourceDirectory", this->GetCTestConfiguration("SourceDirectory"));
- update_count = uphandler->ProcessHandler();
- if (update_count < 0) {
+ auto const func = cmListFileFunction("ctest_update", 0, 0, args);
+ auto status = cmExecutionStatus(mf);
+ if (!mf.ExecuteCommand(func, status)) {
res |= cmCTest::UPDATE_ERRORS;
}
}
- if (this->Impl->TestModel == cmCTest::CONTINUOUS && !update_count) {
+ if (this->Impl->TestModel == cmCTest::CONTINUOUS &&
+ mf.GetDefinition("return_value").IsOff()) {
return 0;
}
if (this->Impl->Parts[PartConfigure] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
- if (this->GetConfigureHandler()->ProcessHandler() < 0) {
+ auto const func = cmListFileFunction("ctest_configure", 0, 0, args);
+ auto status = cmExecutionStatus(mf);
+ if (!mf.ExecuteCommand(func, status) ||
+ std::stoi(mf.GetDefinition("return_value")) < 0) {
res |= cmCTest::CONFIGURE_ERRORS;
}
}
if (this->Impl->Parts[PartBuild] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
this->UpdateCTestConfiguration();
- if (this->GetBuildHandler()->ProcessHandler() < 0) {
+ this->SetCMakeVariables(mf);
+ auto const func = cmListFileFunction("ctest_build", 0, 0, args);
+ auto status = cmExecutionStatus(mf);
+ if (!mf.ExecuteCommand(func, status) ||
+ std::stoi(mf.GetDefinition("return_value")) < 0) {
res |= cmCTest::BUILD_ERRORS;
}
}
- if ((this->Impl->Parts[PartTest] || notest) &&
+ if (this->Impl->Parts[PartTest] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
this->UpdateCTestConfiguration();
- if (this->GetTestHandler()->ProcessHandler() < 0) {
+ this->SetCMakeVariables(mf);
+ auto const func = cmListFileFunction("ctest_test", 0, 0, args);
+ auto status = cmExecutionStatus(mf);
+ if (!mf.ExecuteCommand(func, status) ||
+ std::stoi(mf.GetDefinition("return_value")) < 0) {
res |= cmCTest::TEST_ERRORS;
}
}
if (this->Impl->Parts[PartCoverage] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
this->UpdateCTestConfiguration();
- if (this->GetCoverageHandler()->ProcessHandler() < 0) {
+ this->SetCMakeVariables(mf);
+ auto const func = cmListFileFunction("ctest_coverage", 0, 0, args);
+ auto status = cmExecutionStatus(mf);
+ if (!mf.ExecuteCommand(func, status) ||
+ std::stoi(mf.GetDefinition("return_value")) < 0) {
res |= cmCTest::COVERAGE_ERRORS;
}
}
if (this->Impl->Parts[PartMemCheck] &&
(this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) {
this->UpdateCTestConfiguration();
- if (this->GetMemCheckHandler()->ProcessHandler() < 0) {
+ this->SetCMakeVariables(mf);
+ auto const func = cmListFileFunction("ctest_memcheck", 0, 0, args);
+ auto status = cmExecutionStatus(mf);
+ if (!mf.ExecuteCommand(func, status) ||
+ std::stoi(mf.GetDefinition("return_value")) < 0) {
res |= cmCTest::MEMORY_ERRORS;
}
}
- if (!notest) {
- std::string notes_dir = this->Impl->BinaryDir + "/Testing/Notes";
- if (cmSystemTools::FileIsDirectory(notes_dir)) {
- cmsys::Directory d;
- d.Load(notes_dir);
- unsigned long kk;
- for (kk = 0; kk < d.GetNumberOfFiles(); kk++) {
- const char* file = d.GetFile(kk);
- std::string fullname = notes_dir + "/" + file;
- if (cmSystemTools::FileExists(fullname, true)) {
- if (!this->Impl->NotesFiles.empty()) {
- this->Impl->NotesFiles += ";";
- }
- this->Impl->NotesFiles += fullname;
- this->Impl->Parts[PartNotes].Enable();
+ std::string notes_dir = this->Impl->BinaryDir + "/Testing/Notes";
+ if (cmSystemTools::FileIsDirectory(notes_dir)) {
+ cmsys::Directory d;
+ d.Load(notes_dir);
+ unsigned long kk;
+ for (kk = 0; kk < d.GetNumberOfFiles(); kk++) {
+ const char* file = d.GetFile(kk);
+ std::string fullname = notes_dir + "/" + file;
+ if (cmSystemTools::FileExists(fullname, true)) {
+ if (!this->Impl->NotesFiles.empty()) {
+ this->Impl->NotesFiles += ";";
}
+ this->Impl->NotesFiles += fullname;
+ this->Impl->Parts[PartNotes].Enable();
}
}
}
if (this->Impl->Parts[PartNotes]) {
this->UpdateCTestConfiguration();
if (!this->Impl->NotesFiles.empty()) {
- this->GenerateNotesFile(this->Impl->NotesFiles);
+ this->GenerateNotesFile(script.GetCMake(), this->Impl->NotesFiles);
}
}
if (this->Impl->Parts[PartSubmit]) {
this->UpdateCTestConfiguration();
- if (this->GetSubmitHandler()->ProcessHandler() < 0) {
+ this->SetCMakeVariables(mf);
+
+ std::string count = this->GetCTestConfiguration("CTestSubmitRetryCount");
+ std::string delay = this->GetCTestConfiguration("CTestSubmitRetryDelay");
+ auto const func = cmListFileFunction(
+ "ctest_submit", 0, 0,
+ {
+ cmListFileArgument("RETRY_COUNT", cmListFileArgument::Unquoted, 0),
+ cmListFileArgument(count, cmListFileArgument::Quoted, 0),
+ cmListFileArgument("RETRY_DELAY", cmListFileArgument::Unquoted, 0),
+ cmListFileArgument(delay, cmListFileArgument::Quoted, 0),
+ cmListFileArgument("RETURN_VALUE", cmListFileArgument::Unquoted, 0),
+ cmListFileArgument("return_value", cmListFileArgument::Unquoted, 0),
+ });
+ auto status = cmExecutionStatus(mf);
+ if (!mf.ExecuteCommand(func, status) ||
+ std::stoi(mf.GetDefinition("return_value")) < 0) {
res |= cmCTest::SUBMIT_ERRORS;
}
}
- if (res != 0) {
- cmCTestLog(this, ERROR_MESSAGE, "Errors while running CTest" << std::endl);
- if (!this->Impl->OutputTestOutputOnTestFailure) {
- const std::string lastTestLog =
- this->GetBinaryDir() + "/Testing/Temporary/LastTest.log";
- cmCTestLog(this, ERROR_MESSAGE,
- "Output from these tests are in: " << lastTestLog
- << std::endl);
- cmCTestLog(this, ERROR_MESSAGE,
- "Use \"--rerun-failed --output-on-failure\" to re-run the "
- "failed cases verbosely."
- << std::endl);
- }
- }
return res;
}
-std::string cmCTest::GetTestModelString()
+std::string cmCTest::GetTestModelString() const
{
- if (!this->Impl->SpecificGroup.empty()) {
- return this->Impl->SpecificGroup;
- }
switch (this->Impl->TestModel) {
case cmCTest::NIGHTLY:
return "Nightly";
@@ -1058,6 +876,14 @@
return "Experimental";
}
+std::string cmCTest::GetTestGroupString() const
+{
+ if (!this->Impl->SpecificGroup.empty()) {
+ return this->Impl->SpecificGroup;
+ }
+ return this->GetTestModelString();
+}
+
int cmCTest::GetTestModelFromString(const std::string& str)
{
if (str.empty()) {
@@ -1185,177 +1011,6 @@
return true;
}
-bool cmCTest::RunTest(const std::vector<std::string>& argv,
- std::string* output, int* retVal, std::ostream* log,
- cmDuration testTimeOut,
- std::vector<std::string>* environment, Encoding encoding)
-{
- bool modifyEnv = (environment && !environment->empty());
-
- // determine how much time we have
- cmDuration timeout = this->GetRemainingTimeAllowed();
- if (timeout != cmCTest::MaxDuration()) {
- timeout -= std::chrono::minutes(2);
- }
- if (this->Impl->TimeOut > cmDuration::zero() &&
- this->Impl->TimeOut < timeout) {
- timeout = this->Impl->TimeOut;
- }
- if (testTimeOut > cmDuration::zero() &&
- testTimeOut < this->GetRemainingTimeAllowed()) {
- timeout = testTimeOut;
- }
-
- // always have at least 1 second if we got to here
- if (timeout <= cmDuration::zero()) {
- timeout = std::chrono::seconds(1);
- }
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
- "Test timeout computed to be: "
- << (timeout == cmCTest::MaxDuration()
- ? std::string("infinite")
- : std::to_string(cmDurationTo<unsigned int>(timeout)))
- << "\n");
- if (cmSystemTools::SameFile(argv[0], cmSystemTools::GetCTestCommand()) &&
- !this->Impl->ForceNewCTestProcess) {
- cmCTest inst;
- inst.Impl->ConfigType = this->Impl->ConfigType;
- inst.Impl->TimeOut = timeout;
-
- // Capture output of the child ctest.
- std::ostringstream oss;
- inst.SetStreams(&oss, &oss);
-
- std::vector<std::string> args;
- for (auto const& i : argv) {
- // make sure we pass the timeout in for any build and test
- // invocations. Since --build-generator is required this is a
- // good place to check for it, and to add the arguments in
- if (i == "--build-generator" && timeout != cmCTest::MaxDuration() &&
- timeout > cmDuration::zero()) {
- args.emplace_back("--test-timeout");
- args.push_back(std::to_string(cmDurationTo<unsigned int>(timeout)));
- }
- args.emplace_back(i);
- }
- if (log) {
- *log << "* Run internal CTest" << std::endl;
- }
-
- std::unique_ptr<cmSystemTools::SaveRestoreEnvironment> saveEnv;
- if (modifyEnv) {
- saveEnv = cm::make_unique<cmSystemTools::SaveRestoreEnvironment>();
- cmSystemTools::AppendEnv(*environment);
- }
-
- *retVal = inst.Run(args, output);
- if (output) {
- *output += oss.str();
- }
- if (log && output) {
- *log << *output;
- }
- if (output) {
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
- "Internal cmCTest object used to run test." << std::endl
- << *output
- << std::endl);
- }
-
- return true;
- }
- std::vector<char> tempOutput;
- if (output) {
- output->clear();
- }
-
- std::unique_ptr<cmSystemTools::SaveRestoreEnvironment> saveEnv;
- if (modifyEnv) {
- saveEnv = cm::make_unique<cmSystemTools::SaveRestoreEnvironment>();
- cmSystemTools::AppendEnv(*environment);
- }
-
- cmUVProcessChainBuilder builder;
- builder.AddCommand(argv).SetMergedBuiltinStreams();
- cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
- auto chain = builder.Start();
-
- cmProcessOutput processOutput(encoding);
- cm::uv_pipe_ptr outputStream;
- outputStream.init(chain.GetLoop(), 0);
- uv_pipe_open(outputStream, chain.OutputStream());
- auto outputHandle = cmUVStreamRead(
- outputStream,
- [this, &processOutput, &output, &tempOutput,
- &log](std::vector<char> data) {
- std::string strdata;
- processOutput.DecodeText(data.data(), data.size(), strdata);
- if (output) {
- cm::append(tempOutput, data.data(), data.data() + data.size());
- }
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, strdata);
- if (log) {
- log->write(strdata.c_str(), strdata.size());
- }
- },
- [this, &processOutput, &log]() {
- std::string strdata;
- processOutput.DecodeText(std::string(), strdata);
- if (!strdata.empty()) {
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, strdata);
- if (log) {
- log->write(strdata.c_str(), strdata.size());
- }
- }
- });
-
- bool complete = chain.Wait(static_cast<uint64_t>(timeout.count() * 1000.0));
- processOutput.DecodeText(tempOutput, tempOutput);
- if (output && tempOutput.begin() != tempOutput.end()) {
- output->append(tempOutput.data(), tempOutput.size());
- }
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
- "-- Process completed" << std::endl);
-
- bool result = false;
-
- if (complete) {
- auto const& status = chain.GetStatus(0);
- auto exception = status.GetException();
- switch (exception.first) {
- case cmUVProcessChain::ExceptionCode::None:
- *retVal = static_cast<int>(status.ExitStatus);
- if (*retVal != 0 && this->Impl->OutputTestOutputOnTestFailure) {
- this->OutputTestErrors(tempOutput);
- }
- result = true;
- break;
- case cmUVProcessChain::ExceptionCode::Spawn: {
- std::string outerr =
- cmStrCat("\n*** ERROR executing: ", exception.second);
- if (output) {
- *output += outerr;
- }
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl);
- } break;
- default: {
- if (this->Impl->OutputTestOutputOnTestFailure) {
- this->OutputTestErrors(tempOutput);
- }
- *retVal = status.TermSignal;
- std::string outerr =
- cmStrCat("\n*** Exception executing: ", exception.second);
- if (output) {
- *output += outerr;
- }
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl);
- } break;
- }
- }
-
- return result;
-}
-
std::string cmCTest::SafeBuildIdField(const std::string& value)
{
std::string safevalue(value);
@@ -1386,7 +1041,7 @@
return safevalue;
}
-void cmCTest::StartXML(cmXMLWriter& xml, bool append)
+void cmCTest::StartXML(cmXMLWriter& xml, cmake* cm, bool append)
{
if (this->Impl->CurrentTag.empty()) {
cmCTestLog(this, ERROR_MESSAGE,
@@ -1405,7 +1060,7 @@
std::string buildname =
cmCTest::SafeBuildIdField(this->GetCTestConfiguration("BuildName"));
std::string stamp = cmCTest::SafeBuildIdField(this->Impl->CurrentTag + "-" +
- this->GetTestModelString());
+ this->GetTestGroupString());
std::string site =
cmCTest::SafeBuildIdField(this->GetCTestConfiguration("Site"));
@@ -1448,25 +1103,17 @@
xml.Attribute("ChangeId", changeId);
}
- this->AddSiteProperties(xml);
+ this->AddSiteProperties(xml, cm);
}
-void cmCTest::AddSiteProperties(cmXMLWriter& xml)
+void cmCTest::AddSiteProperties(cmXMLWriter& xml, cmake* cm)
{
- cmCTestScriptHandler* ch = this->GetScriptHandler();
- cmake* cm = ch->GetCMake();
- // if no CMake then this is the old style script and props like
- // this will not work anyway.
- if (!cm) {
- return;
- }
// This code should go when cdash is changed to use labels only
cmValue subproject = cm->GetState()->GetGlobalProperty("SubProject");
if (subproject) {
xml.StartElement("Subproject");
xml.Attribute("name", *subproject);
- cmValue labels =
- ch->GetCMake()->GetState()->GetGlobalProperty("SubProjectLabels");
+ cmValue labels = cm->GetState()->GetGlobalProperty("SubProjectLabels");
if (labels) {
xml.StartElement("Labels");
cmList args{ *labels };
@@ -1518,7 +1165,7 @@
xml.EndDocument();
}
-int cmCTest::GenerateCTestNotesOutput(cmXMLWriter& xml,
+int cmCTest::GenerateCTestNotesOutput(cmXMLWriter& xml, cmake* cm,
std::vector<std::string> const& files)
{
std::string buildname =
@@ -1531,11 +1178,11 @@
xml.StartElement("Site");
xml.Attribute("BuildName", buildname);
xml.Attribute("BuildStamp",
- this->Impl->CurrentTag + "-" + this->GetTestModelString());
+ this->Impl->CurrentTag + "-" + this->GetTestGroupString());
xml.Attribute("Name", this->GetCTestConfiguration("Site"));
xml.Attribute("Generator",
std::string("ctest-") + cmVersion::GetCMakeVersion());
- this->AddSiteProperties(xml);
+ this->AddSiteProperties(xml, cm);
xml.StartElement("Notes");
for (std::string const& file : files) {
@@ -1569,7 +1216,8 @@
return 1;
}
-int cmCTest::GenerateNotesFile(std::vector<std::string> const& files)
+int cmCTest::GenerateNotesFile(cmake* cm,
+ std::vector<std::string> const& files)
{
cmGeneratedFileStream ofs;
if (!this->OpenOutputFile(this->Impl->CurrentTag, "Notes.xml", ofs)) {
@@ -1577,11 +1225,11 @@
return 1;
}
cmXMLWriter xml(ofs);
- this->GenerateCTestNotesOutput(xml, files);
+ this->GenerateCTestNotesOutput(xml, cm, files);
return 0;
}
-int cmCTest::GenerateNotesFile(const std::string& cfiles)
+int cmCTest::GenerateNotesFile(cmake* cm, const std::string& cfiles)
{
if (cfiles.empty()) {
return 1;
@@ -1595,7 +1243,7 @@
return 1;
}
- return this->GenerateNotesFile(files);
+ return this->GenerateNotesFile(cm, files);
}
int cmCTest::GenerateDoneFile()
@@ -1616,31 +1264,14 @@
return 0;
}
-bool cmCTest::TryToChangeDirectory(std::string const& dir)
-{
- cmCTestLog(this, OUTPUT,
- "Internal ctest changing into directory: " << dir << std::endl);
- cmsys::Status status = cmSystemTools::ChangeDirectory(dir);
- if (!status) {
- auto msg = "Failed to change working directory to \"" + dir +
- "\" : " + status.GetString() + "\n";
- cmCTestLog(this, ERROR_MESSAGE, msg);
- return false;
- }
- return true;
-}
-
std::string cmCTest::Base64GzipEncodeFile(std::string const& file)
{
- const std::string currDir = cmSystemTools::GetCurrentWorkingDirectory();
- std::string parentDir = cmSystemTools::GetParentDirectory(file);
-
// Temporarily change to the file's directory so the tar gets created
// with a flat directory structure.
- if (currDir != parentDir) {
- if (!this->TryToChangeDirectory(parentDir)) {
- return "";
- }
+ cmWorkingDirectory workdir(cmSystemTools::GetParentDirectory(file));
+ if (workdir.Failed()) {
+ cmCTestLog(this, ERROR_MESSAGE, workdir.GetError() << std::endl);
+ return "";
}
std::string tarFile = file + "_temp.tar.gz";
@@ -1657,12 +1288,6 @@
}
std::string base64 = this->Base64EncodeFile(tarFile);
cmSystemTools::RemoveFile(tarFile);
-
- // Change back to the directory we started in.
- if (currDir != parentDir) {
- cmSystemTools::ChangeDirectory(currDir);
- }
-
return base64;
}
@@ -1721,7 +1346,7 @@
// for a -D argument convert the next argument into
// the proper list of dashboard steps via SetTest
-bool cmCTest::AddTestsForDashboardType(std::string& targ)
+bool cmCTest::AddTestsForDashboardType(std::string const& targ)
{
if (targ == "Experimental") {
this->SetTestModel(cmCTest::EXPERIMENTAL);
@@ -1844,7 +1469,7 @@
return true;
}
-void cmCTest::ErrorMessageUnknownDashDValue(std::string& val)
+void cmCTest::ErrorMessageUnknownDashDValue(std::string const& val)
{
cmCTestLog(this, ERROR_MESSAGE,
"CTest -D called with incorrect option: " << val << '\n');
@@ -1869,389 +1494,6 @@
return (arg == varg1) || (varg2 && arg == varg2);
}
-// Processes one command line argument (and its arguments if any)
-// for many simple options and then returns
-bool cmCTest::HandleCommandLineArguments(size_t& i,
- std::vector<std::string>& args,
- std::string& errormsg)
-{
- std::string arg = args[i];
- cm::string_view noTestsPrefix = "--no-tests=";
- if (this->CheckArgument(arg, "-F"_s)) {
- this->Impl->Failover = true;
- } else if (this->CheckArgument(arg, "-j"_s, "--parallel")) {
- cm::optional<size_t> parallelLevel;
- // No value or an empty value tells ctest to choose a default.
- if (i + 1 < args.size() && !cmHasLiteralPrefix(args[i + 1], "-")) {
- ++i;
- if (!args[i].empty()) {
- // A non-empty value must be a non-negative integer.
- unsigned long plevel = 0;
- if (!cmStrToULong(args[i], &plevel)) {
- errormsg =
- cmStrCat("'", arg, "' given invalid value '", args[i], "'");
- return false;
- }
- parallelLevel = plevel;
- }
- }
- this->SetParallelLevel(parallelLevel);
- this->Impl->ParallelLevelSetInCli = true;
- } else if (cmHasPrefix(arg, "-j")) {
- // The value must be a non-negative integer.
- unsigned long plevel = 0;
- if (!cmStrToULong(arg.substr(2), &plevel)) {
- errormsg = cmStrCat("'", arg, "' given invalid value '", args[i], "'");
- return false;
- }
- this->SetParallelLevel(plevel);
- this->Impl->ParallelLevelSetInCli = true;
- }
-
- else if (this->CheckArgument(arg, "--repeat-until-fail"_s)) {
- if (i >= args.size() - 1) {
- errormsg = "'--repeat-until-fail' requires an argument";
- return false;
- }
- if (this->Impl->RepeatMode != cmCTest::Repeat::Never) {
- errormsg = "At most one '--repeat' option may be used.";
- return false;
- }
- i++;
- long repeat = 1;
- if (!cmStrToLong(args[i], &repeat)) {
- errormsg = cmStrCat("'--repeat-until-fail' given non-integer value '",
- args[i], "'");
- return false;
- }
- this->Impl->RepeatCount = static_cast<int>(repeat);
- if (repeat > 1) {
- this->Impl->RepeatMode = cmCTest::Repeat::UntilFail;
- }
- }
-
- else if (this->CheckArgument(arg, "--repeat"_s)) {
- if (i >= args.size() - 1) {
- errormsg = "'--repeat' requires an argument";
- return false;
- }
- if (this->Impl->RepeatMode != cmCTest::Repeat::Never) {
- errormsg = "At most one '--repeat' option may be used.";
- return false;
- }
- i++;
- cmsys::RegularExpression repeatRegex(
- "^(until-fail|until-pass|after-timeout):([0-9]+)$");
- if (repeatRegex.find(args[i])) {
- std::string const& count = repeatRegex.match(2);
- unsigned long n = 1;
- cmStrToULong(count, &n); // regex guarantees success
- this->Impl->RepeatCount = static_cast<int>(n);
- if (this->Impl->RepeatCount > 1) {
- std::string const& mode = repeatRegex.match(1);
- if (mode == "until-fail") {
- this->Impl->RepeatMode = cmCTest::Repeat::UntilFail;
- } else if (mode == "until-pass") {
- this->Impl->RepeatMode = cmCTest::Repeat::UntilPass;
- } else if (mode == "after-timeout") {
- this->Impl->RepeatMode = cmCTest::Repeat::AfterTimeout;
- }
- }
- } else {
- errormsg = cmStrCat("'--repeat' given invalid value '", args[i], "'");
- return false;
- }
- }
-
- else if (this->CheckArgument(arg, "--test-load"_s) && i < args.size() - 1) {
- i++;
- unsigned long load;
- if (cmStrToULong(args[i], &load)) {
- this->SetTestLoad(load);
- } else {
- cmCTestLog(this, WARNING,
- "Invalid value for 'Test Load' : " << args[i] << '\n');
- }
- }
-
- else if (this->CheckArgument(arg, "--no-compress-output"_s)) {
- this->Impl->CompressTestOutput = false;
- }
-
- else if (this->CheckArgument(arg, "--print-labels"_s)) {
- this->Impl->PrintLabels = true;
- }
-
- else if (this->CheckArgument(arg, "--http1.0"_s)) {
- this->Impl->UseHTTP10 = true;
- }
-
- else if (this->CheckArgument(arg, "--timeout"_s) && i < args.size() - 1) {
- i++;
- auto timeout = cmDuration(atof(args[i].c_str()));
- this->Impl->GlobalTimeout = timeout;
- }
-
- else if (this->CheckArgument(arg, "--stop-time"_s) && i < args.size() - 1) {
- i++;
- this->SetStopTime(args[i]);
- }
-
- else if (this->CheckArgument(arg, "--stop-on-failure"_s)) {
- this->Impl->StopOnFailure = true;
- }
-
- else if (this->CheckArgument(arg, "-C"_s, "--build-config") &&
- i < args.size() - 1) {
- i++;
- this->SetConfigType(args[i]);
- }
-
- else if (this->CheckArgument(arg, "--debug"_s)) {
- this->Impl->Debug = true;
- this->Impl->ShowLineNumbers = true;
- } else if ((this->CheckArgument(arg, "--group"_s) ||
- // This is an undocumented / deprecated option.
- // "Track" has been renamed to "Group".
- this->CheckArgument(arg, "--track"_s)) &&
- i < args.size() - 1) {
- i++;
- this->Impl->SpecificGroup = args[i];
- } else if (this->CheckArgument(arg, "--show-line-numbers"_s)) {
- this->Impl->ShowLineNumbers = true;
- } else if (this->CheckArgument(arg, "--no-label-summary"_s)) {
- this->Impl->LabelSummary = false;
- } else if (this->CheckArgument(arg, "--no-subproject-summary"_s)) {
- this->Impl->SubprojectSummary = false;
- } else if (this->CheckArgument(arg, "-Q"_s, "--quiet")) {
- this->Impl->Quiet = true;
- } else if (this->CheckArgument(arg, "--progress"_s)) {
- this->Impl->TestProgressOutput = true;
- } else if (this->CheckArgument(arg, "-V"_s, "--verbose")) {
- this->Impl->Verbose = true;
- } else if (this->CheckArgument(arg, "-VV"_s, "--extra-verbose")) {
- this->Impl->ExtraVerbose = true;
- this->Impl->Verbose = true;
- } else if (this->CheckArgument(arg, "--output-on-failure"_s)) {
- this->Impl->OutputTestOutputOnTestFailure = true;
- } else if (this->CheckArgument(arg, "--test-output-size-passed"_s) &&
- i < args.size() - 1) {
- i++;
- long outputSize;
- if (cmStrToLong(args[i], &outputSize)) {
- this->Impl->TestHandler.SetTestOutputSizePassed(
- static_cast<int>(outputSize));
- } else {
- cmCTestLog(this, WARNING,
- "Invalid value for '--test-output-size-passed': " << args[i]
- << "\n");
- }
- } else if (this->CheckArgument(arg, "--test-output-size-failed"_s) &&
- i < args.size() - 1) {
- i++;
- long outputSize;
- if (cmStrToLong(args[i], &outputSize)) {
- this->Impl->TestHandler.SetTestOutputSizeFailed(
- static_cast<int>(outputSize));
- } else {
- cmCTestLog(this, WARNING,
- "Invalid value for '--test-output-size-failed': " << args[i]
- << "\n");
- }
- } else if (this->CheckArgument(arg, "--test-output-truncation"_s) &&
- i < args.size() - 1) {
- i++;
- if (!this->Impl->TestHandler.SetTestOutputTruncation(args[i])) {
- errormsg = "Invalid value for '--test-output-truncation': " + args[i];
- return false;
- }
- } else if (this->CheckArgument(arg, "-N"_s, "--show-only")) {
- this->Impl->ShowOnly = true;
- } else if (cmHasLiteralPrefix(arg, "--show-only=")) {
- this->Impl->ShowOnly = true;
-
- // Check if a specific format is requested. Defaults to human readable
- // text.
- std::string argWithFormat = "--show-only=";
- std::string format = arg.substr(argWithFormat.length());
- if (format == "json-v1") {
- // Force quiet mode so the only output is the json object model.
- this->Impl->Quiet = true;
- this->Impl->OutputAsJson = true;
- this->Impl->OutputAsJsonVersion = 1;
- } else if (format != "human") {
- errormsg = "'--show-only=' given unknown value '" + format + "'";
- return false;
- }
- }
-
- else if (this->CheckArgument(arg, "-O"_s, "--output-log") &&
- i < args.size() - 1) {
- i++;
- this->SetOutputLogFileName(args[i]);
- }
-
- else if (this->CheckArgument(arg, "--tomorrow-tag"_s)) {
- this->Impl->TomorrowTag = true;
- } else if (this->CheckArgument(arg, "--force-new-ctest-process"_s)) {
- this->Impl->ForceNewCTestProcess = true;
- } else if (this->CheckArgument(arg, "-W"_s, "--max-width") &&
- i < args.size() - 1) {
- i++;
- this->Impl->MaxTestNameWidth = atoi(args[i].c_str());
- } else if (this->CheckArgument(arg, "--interactive-debug-mode"_s) &&
- i < args.size() - 1) {
- i++;
- this->Impl->InteractiveDebugMode = cmIsOn(args[i]);
- } else if (this->CheckArgument(arg, "--submit-index"_s) &&
- i < args.size() - 1) {
- i++;
- this->Impl->SubmitIndex = atoi(args[i].c_str());
- if (this->Impl->SubmitIndex < 0) {
- this->Impl->SubmitIndex = 0;
- }
- }
-
- else if (this->CheckArgument(arg, "--overwrite"_s) && i < args.size() - 1) {
- i++;
- this->AddCTestConfigurationOverwrite(args[i]);
- } else if (this->CheckArgument(arg, "-A"_s, "--add-notes") &&
- i < args.size() - 1) {
- this->Impl->ProduceXML = true;
- this->SetTest("Notes");
- i++;
- this->SetNotesFiles(args[i]);
- return true;
- } else if (this->CheckArgument(arg, "--test-dir"_s)) {
- if (i >= args.size() - 1) {
- errormsg = "'--test-dir' requires an argument";
- return false;
- }
- i++;
- this->Impl->TestDir = std::string(args[i]);
- } else if (this->CheckArgument(arg, "--output-junit"_s)) {
- if (i >= args.size() - 1) {
- errormsg = "'--output-junit' requires an argument";
- return false;
- }
- i++;
- this->SetOutputJUnitFileName(std::string(args[i]));
- }
-
- else if (cmHasPrefix(arg, noTestsPrefix)) {
- cm::string_view noTestsMode =
- cm::string_view(arg).substr(noTestsPrefix.length());
- if (noTestsMode == "error") {
- this->Impl->NoTestsMode = cmCTest::NoTests::Error;
- } else if (noTestsMode != "ignore") {
- errormsg =
- cmStrCat("'--no-tests=' given unknown value '", noTestsMode, '\'');
- return false;
- } else {
- this->Impl->NoTestsMode = cmCTest::NoTests::Ignore;
- }
- this->Impl->NoTestsModeSetInCli = true;
- }
-
- // options that control what tests are run
- else if (this->CheckArgument(arg, "-I"_s, "--tests-information") &&
- i < args.size() - 1) {
- i++;
- this->GetTestHandler()->SetPersistentOption("TestsToRunInformation",
- args[i]);
- this->GetMemCheckHandler()->SetPersistentOption("TestsToRunInformation",
- args[i]);
- } else if (this->CheckArgument(arg, "-U"_s, "--union")) {
- this->GetTestHandler()->SetPersistentOption("UseUnion", "true");
- this->GetMemCheckHandler()->SetPersistentOption("UseUnion", "true");
- } else if (this->CheckArgument(arg, "-R"_s, "--tests-regex") &&
- i < args.size() - 1) {
- i++;
- this->GetTestHandler()->SetPersistentOption("IncludeRegularExpression",
- args[i]);
- this->GetMemCheckHandler()->SetPersistentOption("IncludeRegularExpression",
- args[i]);
- } else if (this->CheckArgument(arg, "-L"_s, "--label-regex") &&
- i < args.size() - 1) {
- i++;
- this->GetTestHandler()->AddPersistentMultiOption("LabelRegularExpression",
- args[i]);
- this->GetMemCheckHandler()->AddPersistentMultiOption(
- "LabelRegularExpression", args[i]);
- } else if (this->CheckArgument(arg, "-LE"_s, "--label-exclude") &&
- i < args.size() - 1) {
- i++;
- this->GetTestHandler()->AddPersistentMultiOption(
- "ExcludeLabelRegularExpression", args[i]);
- this->GetMemCheckHandler()->AddPersistentMultiOption(
- "ExcludeLabelRegularExpression", args[i]);
- }
-
- else if (this->CheckArgument(arg, "-E"_s, "--exclude-regex") &&
- i < args.size() - 1) {
- i++;
- this->GetTestHandler()->SetPersistentOption("ExcludeRegularExpression",
- args[i]);
- this->GetMemCheckHandler()->SetPersistentOption("ExcludeRegularExpression",
- args[i]);
- }
-
- else if (this->CheckArgument(arg, "-FA"_s, "--fixture-exclude-any") &&
- i < args.size() - 1) {
- i++;
- this->GetTestHandler()->SetPersistentOption(
- "ExcludeFixtureRegularExpression", args[i]);
- this->GetMemCheckHandler()->SetPersistentOption(
- "ExcludeFixtureRegularExpression", args[i]);
- } else if (this->CheckArgument(arg, "-FS"_s, "--fixture-exclude-setup") &&
- i < args.size() - 1) {
- i++;
- this->GetTestHandler()->SetPersistentOption(
- "ExcludeFixtureSetupRegularExpression", args[i]);
- this->GetMemCheckHandler()->SetPersistentOption(
- "ExcludeFixtureSetupRegularExpression", args[i]);
- } else if (this->CheckArgument(arg, "-FC"_s, "--fixture-exclude-cleanup") &&
- i < args.size() - 1) {
- i++;
- this->GetTestHandler()->SetPersistentOption(
- "ExcludeFixtureCleanupRegularExpression", args[i]);
- this->GetMemCheckHandler()->SetPersistentOption(
- "ExcludeFixtureCleanupRegularExpression", args[i]);
- }
-
- else if (this->CheckArgument(arg, "--resource-spec-file"_s) &&
- i < args.size() - 1) {
- i++;
- this->GetTestHandler()->SetPersistentOption("ResourceSpecFile", args[i]);
- this->GetMemCheckHandler()->SetPersistentOption("ResourceSpecFile",
- args[i]);
- }
-
- else if (this->CheckArgument(arg, "--tests-from-file"_s) &&
- i < args.size() - 1) {
- i++;
- this->GetTestHandler()->SetPersistentOption("TestListFile", args[i]);
- this->GetMemCheckHandler()->SetPersistentOption("TestListFile", args[i]);
- }
-
- else if (this->CheckArgument(arg, "--exclude-from-file"_s) &&
- i < args.size() - 1) {
- i++;
- this->GetTestHandler()->SetPersistentOption("ExcludeTestListFile",
- args[i]);
- this->GetMemCheckHandler()->SetPersistentOption("ExcludeTestListFile",
- args[i]);
- }
-
- else if (this->CheckArgument(arg, "--rerun-failed"_s)) {
- this->GetTestHandler()->SetPersistentOption("RerunFailed", "true");
- this->GetMemCheckHandler()->SetPersistentOption("RerunFailed", "true");
- } else {
- return false;
- }
- return true;
-}
-
#if !defined(_WIN32)
bool cmCTest::ConsoleIsNotDumb()
{
@@ -2296,46 +1538,6 @@
#endif
}
-// handle the -S -SR and -SP arguments
-bool cmCTest::HandleScriptArguments(size_t& i, std::vector<std::string>& args,
- bool& SRArgumentSpecified)
-{
- std::string arg = args[i];
- if (this->CheckArgument(arg, "-SP"_s, "--script-new-process") &&
- i < args.size() - 1) {
- this->Impl->RunConfigurationScript = true;
- i++;
- cmCTestScriptHandler* ch = this->GetScriptHandler();
- // -SR is an internal argument, -SP should be ignored when it is passed
- if (!SRArgumentSpecified) {
- ch->AddConfigurationScript(args[i], false);
- }
- }
-
- else if (this->CheckArgument(arg, "-SR"_s, "--script-run") &&
- i < args.size() - 1) {
- SRArgumentSpecified = true;
- this->Impl->RunConfigurationScript = true;
- i++;
- cmCTestScriptHandler* ch = this->GetScriptHandler();
- ch->AddConfigurationScript(args[i], true);
- }
-
- else if (this->CheckArgument(arg, "-S"_s, "--script") &&
- i < args.size() - 1) {
- this->Impl->RunConfigurationScript = true;
- i++;
- cmCTestScriptHandler* ch = this->GetScriptHandler();
- // -SR is an internal argument, -S should be ignored when it is passed
- if (!SRArgumentSpecified) {
- ch->AddConfigurationScript(args[i], true);
- }
- } else {
- return false;
- }
- return true;
-}
-
bool cmCTest::AddVariableDefinition(const std::string& arg)
{
std::string name;
@@ -2350,28 +1552,10 @@
return false;
}
-void cmCTest::SetPersistentOptionIfNotEmpty(const std::string& value,
- const std::string& optionName)
-{
- if (!value.empty()) {
- this->GetTestHandler()->SetPersistentOption(optionName, value);
- this->GetMemCheckHandler()->SetPersistentOption(optionName, value);
- }
-}
-
-void cmCTest::AddPersistentMultiOptionIfNotEmpty(const std::string& value,
- const std::string& optionName)
-{
- if (!value.empty()) {
- this->GetTestHandler()->AddPersistentMultiOption(optionName, value);
- this->GetMemCheckHandler()->AddPersistentMultiOption(optionName, value);
- }
-}
-
bool cmCTest::SetArgsFromPreset(const std::string& presetName,
bool listPresets)
{
- const auto workingDirectory = cmSystemTools::GetCurrentWorkingDirectory();
+ const auto workingDirectory = cmSystemTools::GetLogicalWorkingDirectory();
cmCMakePresetsGraph settingsFile;
auto result = settingsFile.ReadProjectPresets(workingDirectory);
@@ -2485,8 +1669,6 @@
}
this->Impl->Debug = expandedPreset->Output->Debug.value_or(false);
- this->Impl->ShowLineNumbers =
- expandedPreset->Output->Debug.value_or(false);
this->Impl->OutputTestOutputOnTestFailure =
expandedPreset->Output->OutputOnFailure.value_or(false);
this->Impl->Quiet = expandedPreset->Output->Quiet.value_or(false);
@@ -2504,17 +1686,17 @@
expandedPreset->Output->SubprojectSummary.value_or(true);
if (expandedPreset->Output->MaxPassedTestOutputSize) {
- this->Impl->TestHandler.SetTestOutputSizePassed(
- *expandedPreset->Output->MaxPassedTestOutputSize);
+ this->Impl->TestOptions.OutputSizePassed =
+ *expandedPreset->Output->MaxPassedTestOutputSize;
}
if (expandedPreset->Output->MaxFailedTestOutputSize) {
- this->Impl->TestHandler.SetTestOutputSizeFailed(
- *expandedPreset->Output->MaxFailedTestOutputSize);
+ this->Impl->TestOptions.OutputSizeFailed =
+ *expandedPreset->Output->MaxFailedTestOutputSize;
}
if (expandedPreset->Output->TestOutputTruncation) {
- this->Impl->TestHandler.TestOutputTruncation =
+ this->Impl->TestOptions.OutputTruncation =
*expandedPreset->Output->TestOutputTruncation;
}
@@ -2525,10 +1707,12 @@
if (expandedPreset->Filter) {
if (expandedPreset->Filter->Include) {
- this->SetPersistentOptionIfNotEmpty(
- expandedPreset->Filter->Include->Name, "IncludeRegularExpression");
- this->AddPersistentMultiOptionIfNotEmpty(
- expandedPreset->Filter->Include->Label, "LabelRegularExpression");
+ this->Impl->TestOptions.IncludeRegularExpression =
+ expandedPreset->Filter->Include->Name;
+ if (!expandedPreset->Filter->Include->Label.empty()) {
+ this->Impl->TestOptions.LabelRegularExpression.push_back(
+ expandedPreset->Filter->Include->Label);
+ }
if (expandedPreset->Filter->Include->Index) {
if (expandedPreset->Filter->Include->Index->IndexFile.empty()) {
@@ -2542,38 +1726,32 @@
indexOptions +=
cmJoin(expandedPreset->Filter->Include->Index->SpecificTests, ",");
- this->SetPersistentOptionIfNotEmpty(indexOptions,
- "TestsToRunInformation");
+ this->Impl->TestOptions.TestsToRunInformation = indexOptions;
} else {
- this->SetPersistentOptionIfNotEmpty(
- expandedPreset->Filter->Include->Index->IndexFile,
- "TestsToRunInformation");
+ this->Impl->TestOptions.TestsToRunInformation =
+ expandedPreset->Filter->Include->Index->IndexFile;
}
}
- if (expandedPreset->Filter->Include->UseUnion.value_or(false)) {
- this->GetTestHandler()->SetPersistentOption("UseUnion", "true");
- this->GetMemCheckHandler()->SetPersistentOption("UseUnion", "true");
- }
+ this->Impl->TestOptions.UseUnion =
+ expandedPreset->Filter->Include->UseUnion.value_or(false);
}
if (expandedPreset->Filter->Exclude) {
- this->SetPersistentOptionIfNotEmpty(
- expandedPreset->Filter->Exclude->Name, "ExcludeRegularExpression");
- this->AddPersistentMultiOptionIfNotEmpty(
- expandedPreset->Filter->Exclude->Label,
- "ExcludeLabelRegularExpression");
+ this->Impl->TestOptions.ExcludeRegularExpression =
+ expandedPreset->Filter->Exclude->Name;
+ if (!expandedPreset->Filter->Exclude->Label.empty()) {
+ this->Impl->TestOptions.ExcludeLabelRegularExpression.push_back(
+ expandedPreset->Filter->Exclude->Label);
+ }
if (expandedPreset->Filter->Exclude->Fixtures) {
- this->SetPersistentOptionIfNotEmpty(
- expandedPreset->Filter->Exclude->Fixtures->Any,
- "ExcludeFixtureRegularExpression");
- this->SetPersistentOptionIfNotEmpty(
- expandedPreset->Filter->Exclude->Fixtures->Setup,
- "ExcludeFixtureSetupRegularExpression");
- this->SetPersistentOptionIfNotEmpty(
- expandedPreset->Filter->Exclude->Fixtures->Cleanup,
- "ExcludeFixtureCleanupRegularExpression");
+ this->Impl->TestOptions.ExcludeFixtureRegularExpression =
+ expandedPreset->Filter->Exclude->Fixtures->Any;
+ this->Impl->TestOptions.ExcludeFixtureSetupRegularExpression =
+ expandedPreset->Filter->Exclude->Fixtures->Setup;
+ this->Impl->TestOptions.ExcludeFixtureCleanupRegularExpression =
+ expandedPreset->Filter->Exclude->Fixtures->Cleanup;
}
}
}
@@ -2590,8 +1768,8 @@
this->Impl->ParallelLevelSetInCli = true;
}
- this->SetPersistentOptionIfNotEmpty(
- expandedPreset->Execution->ResourceSpecFile, "ResourceSpecFile");
+ this->Impl->TestOptions.ResourceSpecFile =
+ expandedPreset->Execution->ResourceSpecFile;
if (expandedPreset->Execution->TestLoad) {
auto testLoad = *expandedPreset->Execution->TestLoad;
@@ -2675,12 +1853,13 @@
}
// the main entry point of ctest, called from main
-int cmCTest::Run(std::vector<std::string>& args, std::string* output)
+int cmCTest::Run(std::vector<std::string> const& args)
{
const char* ctestExec = "ctest";
bool cmakeAndTest = false;
- bool executeTests = true;
+ bool processSteps = false;
bool SRArgumentSpecified = false;
+ std::vector<std::pair<std::string, bool>> runScripts;
// copy the command line
cm::append(this->Impl->InitialCommandLineArguments, args);
@@ -2702,10 +1881,10 @@
success = this->SetArgsFromPreset("", listPresets);
} else {
if (cmHasLiteralPrefix(*it, "--preset=")) {
- auto presetName = it->substr(9);
+ auto const& presetName = it->substr(9);
success = this->SetArgsFromPreset(presetName, listPresets);
} else if (++it != args.end()) {
- auto presetName = *it;
+ auto const& presetName = *it;
success = this->SetArgsFromPreset(presetName, listPresets);
} else {
cmSystemTools::Error("'--preset' requires an argument");
@@ -2722,103 +1901,678 @@
}
}
+ auto const dashD = [this, &processSteps](std::string const& targ) -> bool {
+ // AddTestsForDashboard parses the dashboard type and converts it
+ // into the separate stages
+ if (this->AddTestsForDashboardType(targ)) {
+ processSteps = true;
+ return true;
+ }
+ if (this->AddVariableDefinition(targ)) {
+ return true;
+ }
+ this->ErrorMessageUnknownDashDValue(targ);
+ return false;
+ };
+ auto const dashT = [this, &processSteps,
+ ctestExec](std::string const& action) -> bool {
+ if (!this->SetTest(action, false)) {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "CTest -T called with incorrect option: " << action << '\n');
+ /* clang-format off */
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Available options are:\n"
+ " " << ctestExec << " -T all\n"
+ " " << ctestExec << " -T start\n"
+ " " << ctestExec << " -T update\n"
+ " " << ctestExec << " -T configure\n"
+ " " << ctestExec << " -T build\n"
+ " " << ctestExec << " -T test\n"
+ " " << ctestExec << " -T coverage\n"
+ " " << ctestExec << " -T memcheck\n"
+ " " << ctestExec << " -T notes\n"
+ " " << ctestExec << " -T submit\n");
+ /* clang-format on */
+ return false;
+ }
+ processSteps = true;
+ return true;
+ };
+ auto const dashM = [this, &processSteps,
+ ctestExec](std::string const& model) -> bool {
+ if (cmSystemTools::LowerCase(model) == "nightly"_s) {
+ this->SetTestModel(cmCTest::NIGHTLY);
+ } else if (cmSystemTools::LowerCase(model) == "continuous"_s) {
+ this->SetTestModel(cmCTest::CONTINUOUS);
+ } else if (cmSystemTools::LowerCase(model) == "experimental"_s) {
+ this->SetTestModel(cmCTest::EXPERIMENTAL);
+ } else {
+ cmCTestLog(this, ERROR_MESSAGE,
+ "CTest -M called with incorrect option: " << model << '\n');
+ /* clang-format off */
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Available options are:\n"
+ " " << ctestExec << " -M Continuous\n"
+ " " << ctestExec << " -M Experimental\n"
+ " " << ctestExec << " -M Nightly\n");
+ /* clang-format on */
+ return false;
+ }
+ processSteps = true;
+ return true;
+ };
+ auto const dashSP =
+ [&runScripts, &SRArgumentSpecified](std::string const& script) -> bool {
+ // -SR is an internal argument, -SP should be ignored when it is passed
+ if (!SRArgumentSpecified) {
+ runScripts.emplace_back(cmSystemTools::ToNormalizedPathOnDisk(script),
+ false);
+ }
+ return true;
+ };
+ auto const dashSR =
+ [&runScripts, &SRArgumentSpecified](std::string const& script) -> bool {
+ SRArgumentSpecified = true;
+ runScripts.emplace_back(cmSystemTools::ToNormalizedPathOnDisk(script),
+ true);
+ return true;
+ };
+ auto const dash_S =
+ [&runScripts, &SRArgumentSpecified](std::string const& script) -> bool {
+ // -SR is an internal argument, -S should be ignored when it is passed
+ if (!SRArgumentSpecified) {
+ runScripts.emplace_back(cmSystemTools::ToNormalizedPathOnDisk(script),
+ true);
+ }
+ return true;
+ };
+ auto const dashJ = [this](cm::string_view arg,
+ std::string const& j) -> bool {
+ cm::optional<size_t> parallelLevel;
+ // No value or an empty value tells ctest to choose a default.
+ if (!j.empty()) {
+ // A non-empty value must be a non-negative integer.
+ unsigned long plevel = 0;
+ if (!cmStrToULong(j, &plevel)) {
+ cmSystemTools::Error(
+ cmStrCat('\'', arg, "' given invalid value '", j, '\''));
+ return false;
+ }
+ parallelLevel = plevel;
+ }
+ this->SetParallelLevel(parallelLevel);
+ this->Impl->ParallelLevelSetInCli = true;
+ return true;
+ };
+ auto const dashC = [this](std::string const& config) -> bool {
+ this->SetConfigType(config);
+ return true;
+ };
+ auto const dashGroup = [this](std::string const& group) -> bool {
+ this->Impl->SpecificGroup = group;
+ return true;
+ };
+ auto const dashQ = [this](std::string const&) -> bool {
+ this->Impl->Quiet = true;
+ return true;
+ };
+ auto const dashV = [this](std::string const&) -> bool {
+ this->Impl->Verbose = true;
+ return true;
+ };
+ auto const dashVV = [this](std::string const&) -> bool {
+ this->Impl->ExtraVerbose = true;
+ this->Impl->Verbose = true;
+ return true;
+ };
+ auto const dashO = [this](std::string const& log) -> bool {
+ this->SetOutputLogFileName(log);
+ return true;
+ };
+ auto const dashW = [this](std::string const& width) -> bool {
+ this->Impl->MaxTestNameWidth = atoi(width.c_str());
+ return true;
+ };
+ auto const dashA = [this, &processSteps](std::string const& notes) -> bool {
+ processSteps = true;
+ this->SetTest("Notes");
+ this->SetNotesFiles(notes);
+ return true;
+ };
+ auto const dashI = [this](std::string const& tests) -> bool {
+ this->Impl->TestOptions.TestsToRunInformation = tests;
+ return true;
+ };
+ auto const dashU = [this](std::string const&) -> bool {
+ this->Impl->TestOptions.UseUnion = true;
+ return true;
+ };
+ auto const dashR = [this](std::string const& expr) -> bool {
+ this->Impl->TestOptions.IncludeRegularExpression = expr;
+ return true;
+ };
+ auto const dashE = [this](std::string const& expr) -> bool {
+ this->Impl->TestOptions.ExcludeRegularExpression = expr;
+ return true;
+ };
+ auto const dashL = [this](std::string const& expr) -> bool {
+ this->Impl->TestOptions.LabelRegularExpression.push_back(expr);
+ return true;
+ };
+ auto const dashLE = [this](std::string const& expr) -> bool {
+ this->Impl->TestOptions.ExcludeLabelRegularExpression.push_back(expr);
+ return true;
+ };
+ auto const dashFA = [this](std::string const& expr) -> bool {
+ this->Impl->TestOptions.ExcludeFixtureRegularExpression = expr;
+ return true;
+ };
+ auto const dashFS = [this](std::string const& expr) -> bool {
+ this->Impl->TestOptions.ExcludeFixtureSetupRegularExpression = expr;
+ return true;
+ };
+ auto const dashFC = [this](std::string const& expr) -> bool {
+ this->Impl->TestOptions.ExcludeFixtureCleanupRegularExpression = expr;
+ return true;
+ };
+
+ using CommandArgument =
+ cmCommandLineArgument<bool(std::string const& value)>;
+
+ auto const arguments = std::vector<CommandArgument>{
+ CommandArgument{ "--dashboard", CommandArgument::Values::One, dashD },
+ CommandArgument{ "-D",
+ "-D must be followed by dashboard mode or VAR=VALUE.",
+ CommandArgument::Values::One, dashD },
+ CommandArgument{
+ "-D", "-D must be followed by dashboard mode or VAR=VALUE.",
+ CommandArgument::Values::One, CommandArgument::RequiresSeparator::No,
+ [this](std::string const& def) -> bool {
+ // Unsuccessful parsing of VAR=VALUE has historically
+ // been ignored.
+ this->AddVariableDefinition(def);
+ return true;
+ } },
+ CommandArgument{ "-T", CommandArgument::Values::One, dashT },
+ CommandArgument{ "--test-action", CommandArgument::Values::One, dashT },
+ CommandArgument{ "-M", CommandArgument::Values::One, dashM },
+ CommandArgument{ "--test-model", CommandArgument::Values::One, dashM },
+ CommandArgument{ "--extra-submit", CommandArgument::Values::One,
+ [this, &processSteps](std::string const& extra) -> bool {
+ processSteps = true;
+ this->SetTest("Submit");
+ return this->SubmitExtraFiles(extra);
+ } },
+ CommandArgument{
+ "--build-and-test", "--build-and-test must have source and binary dir",
+ CommandArgument::Values::Two,
+ [this, &cmakeAndTest](std::string const& dirs) -> bool {
+ cmakeAndTest = true;
+ cmList dirList{ dirs };
+ if (dirList.size() != 2) {
+ return false;
+ }
+ this->Impl->BuildAndTest.SourceDir =
+ cmSystemTools::ToNormalizedPathOnDisk(dirList[0]);
+ this->Impl->BuildAndTest.BinaryDir =
+ cmSystemTools::ToNormalizedPathOnDisk(dirList[1]);
+ cmSystemTools::MakeDirectory(this->Impl->BuildAndTest.BinaryDir);
+ return true;
+ } },
+ CommandArgument{ "--build-target", CommandArgument::Values::One,
+ [this](std::string const& t) -> bool {
+ this->Impl->BuildAndTest.BuildTargets.emplace_back(t);
+ return true;
+ } },
+ CommandArgument{ "--build-noclean", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->BuildAndTest.BuildNoClean = true;
+ return true;
+ } },
+ CommandArgument{ "--build-nocmake", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->BuildAndTest.BuildNoCMake = true;
+ return true;
+ } },
+ CommandArgument{ "--build-two-config", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->BuildAndTest.BuildTwoConfig = true;
+ return true;
+ } },
+ CommandArgument{ "--build-run-dir", CommandArgument::Values::One,
+ [this](std::string const& dir) -> bool {
+ this->Impl->BuildAndTest.BuildRunDir = dir;
+ return true;
+ } },
+ CommandArgument{ "--build-exe-dir", CommandArgument::Values::One,
+ [this](std::string const& dir) -> bool {
+ this->Impl->BuildAndTest.ExecutableDirectory = dir;
+ return true;
+ } },
+ CommandArgument{ "--test-timeout", CommandArgument::Values::One,
+ [this](std::string const& t) -> bool {
+ this->Impl->BuildAndTest.Timeout =
+ cmDuration(atof(t.c_str()));
+ return true;
+ } },
+ CommandArgument{ "--build-generator", CommandArgument::Values::One,
+ [this](std::string const& g) -> bool {
+ this->Impl->BuildAndTest.BuildGenerator = g;
+ return true;
+ } },
+ CommandArgument{ "--build-generator-platform",
+ CommandArgument::Values::One,
+ [this](std::string const& p) -> bool {
+ this->Impl->BuildAndTest.BuildGeneratorPlatform = p;
+ return true;
+ } },
+ CommandArgument{ "--build-generator-toolset", CommandArgument::Values::One,
+ [this](std::string const& t) -> bool {
+ this->Impl->BuildAndTest.BuildGeneratorToolset = t;
+ return true;
+ } },
+ CommandArgument{ "--build-project", CommandArgument::Values::One,
+ [this](std::string const& p) -> bool {
+ this->Impl->BuildAndTest.BuildProject = p;
+ return true;
+ } },
+ CommandArgument{ "--build-makeprogram", CommandArgument::Values::One,
+ [this](std::string const& p) -> bool {
+ this->Impl->BuildAndTest.BuildMakeProgram = p;
+ return true;
+ } },
+ CommandArgument{ "--build-config-sample", CommandArgument::Values::One,
+ [this](std::string const& s) -> bool {
+ this->Impl->BuildAndTest.ConfigSample = s;
+ return true;
+ } },
+ CommandArgument{ "-SP", CommandArgument::Values::One, dashSP },
+ CommandArgument{ "--script-new-process", CommandArgument::Values::One,
+ dashSP },
+ CommandArgument{ "-SR", CommandArgument::Values::One, dashSR },
+ CommandArgument{ "--script-run", CommandArgument::Values::One, dashSR },
+ CommandArgument{ "-S", CommandArgument::Values::One, dash_S },
+ CommandArgument{ "--script", CommandArgument::Values::One, dash_S },
+ CommandArgument{ "-F", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->Failover = true;
+ return true;
+ } },
+ CommandArgument{
+ "-j", CommandArgument::Values::ZeroOrOne,
+ [&dashJ](std::string const& j) -> bool { return dashJ("-j"_s, j); } },
+ CommandArgument{ "--parallel", CommandArgument::Values::ZeroOrOne,
+ [&dashJ](std::string const& j) -> bool {
+ return dashJ("--parallel"_s, j);
+ } },
+ CommandArgument{ "-j", CommandArgument::Values::One,
+ CommandArgument::RequiresSeparator::No,
+ [this](std::string const& j) -> bool {
+ // The value must be a non-negative integer.
+ unsigned long plevel = 0;
+ if (!cmStrToULong(j, &plevel)) {
+ cmSystemTools::Error(
+ cmStrCat("'-j' given invalid value '", j, '\''));
+ return false;
+ }
+ this->SetParallelLevel(plevel);
+ this->Impl->ParallelLevelSetInCli = true;
+ return true;
+ } },
+ CommandArgument{
+ "--repeat-until-fail", "'--repeat-until-fail' requires an argument",
+ CommandArgument::Values::One,
+ [this](std::string const& r) -> bool {
+ if (this->Impl->RepeatMode != cmCTest::Repeat::Never) {
+ cmSystemTools::Error("At most one '--repeat' option may be used.");
+ return false;
+ }
+ long repeat = 1;
+ if (!cmStrToLong(r, &repeat)) {
+ cmSystemTools::Error(cmStrCat(
+ "'--repeat-until-fail' given non-integer value '", r, '\''));
+ return false;
+ }
+ this->Impl->RepeatCount = static_cast<int>(repeat);
+ if (repeat > 1) {
+ this->Impl->RepeatMode = cmCTest::Repeat::UntilFail;
+ }
+ return true;
+ } },
+ CommandArgument{
+ "--repeat", CommandArgument::Values::One,
+ [this](std::string const& r) -> bool {
+ if (this->Impl->RepeatMode != cmCTest::Repeat::Never) {
+ cmSystemTools::Error("At most one '--repeat' option may be used.");
+ return false;
+ }
+ cmsys::RegularExpression repeatRegex(
+ "^(until-fail|until-pass|after-timeout):([0-9]+)$");
+ if (repeatRegex.find(r)) {
+ std::string const& count = repeatRegex.match(2);
+ unsigned long n = 1;
+ cmStrToULong(count, &n); // regex guarantees success
+ this->Impl->RepeatCount = static_cast<int>(n);
+ if (this->Impl->RepeatCount > 1) {
+ std::string const& mode = repeatRegex.match(1);
+ if (mode == "until-fail") {
+ this->Impl->RepeatMode = cmCTest::Repeat::UntilFail;
+ } else if (mode == "until-pass") {
+ this->Impl->RepeatMode = cmCTest::Repeat::UntilPass;
+ } else if (mode == "after-timeout") {
+ this->Impl->RepeatMode = cmCTest::Repeat::AfterTimeout;
+ }
+ }
+ } else {
+ cmSystemTools::Error(
+ cmStrCat("'--repeat' given invalid value '", r, '\''));
+ return false;
+ }
+ return true;
+ } },
+ CommandArgument{ "--test-load", CommandArgument::Values::One,
+ [this](std::string const& l) -> bool {
+ unsigned long load;
+ if (cmStrToULong(l, &load)) {
+ this->SetTestLoad(load);
+ } else {
+ cmCTestLog(
+ this, WARNING,
+ "Invalid value for 'Test Load' : " << l << '\n');
+ }
+ return true;
+ } },
+ CommandArgument{ "--no-compress-output", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->CompressTestOutput = false;
+ return true;
+ } },
+ CommandArgument{ "--print-labels", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->PrintLabels = true;
+ return true;
+ } },
+ CommandArgument{ "--http1.0", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->UseHTTP10 = true;
+ return true;
+ } },
+ CommandArgument{ "--timeout", CommandArgument::Values::One,
+ [this](std::string const& t) -> bool {
+ auto timeout = cmDuration(atof(t.c_str()));
+ this->Impl->GlobalTimeout = timeout;
+ return true;
+ } },
+ CommandArgument{ "--stop-time", CommandArgument::Values::One,
+ [this](std::string const& t) -> bool {
+ this->SetStopTime(t);
+ return true;
+ } },
+ CommandArgument{ "--stop-on-failure", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->StopOnFailure = true;
+ return true;
+ } },
+ CommandArgument{ "-C", CommandArgument::Values::One, dashC },
+ CommandArgument{ "--build-config", CommandArgument::Values::One, dashC },
+ CommandArgument{ "--debug", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->Debug = true;
+ return true;
+ } },
+ CommandArgument{ "--group", CommandArgument::Values::One, dashGroup },
+ // This is an undocumented / deprecated option.
+ // "Track" has been renamed to "Group".
+ CommandArgument{ "--track", CommandArgument::Values::One, dashGroup },
+ CommandArgument{ "--show-line-numbers", CommandArgument::Values::Zero,
+ [](std::string const&) -> bool {
+ // Silently ignore this never-documented and now-removed
+ // option.
+ return true;
+ } },
+ CommandArgument{ "--no-label-summary", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->LabelSummary = false;
+ return true;
+ } },
+ CommandArgument{ "--no-subproject-summary", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->SubprojectSummary = false;
+ return true;
+ } },
+ CommandArgument{ "--progress", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->TestProgressOutput = true;
+ return true;
+ } },
+ CommandArgument{ "-Q", CommandArgument::Values::Zero, dashQ },
+ CommandArgument{ "--quiet", CommandArgument::Values::Zero, dashQ },
+ CommandArgument{ "-V", CommandArgument::Values::Zero, dashV },
+ CommandArgument{ "--verbose", CommandArgument::Values::Zero, dashV },
+ CommandArgument{ "-VV", CommandArgument::Values::Zero, dashVV },
+ CommandArgument{ "--extra-verbose", CommandArgument::Values::Zero,
+ dashVV },
+ CommandArgument{ "--output-on-failure", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->OutputTestOutputOnTestFailure = true;
+ return true;
+ } },
+ CommandArgument{ "--test-output-size-passed", CommandArgument::Values::One,
+ [this](std::string const& sz) -> bool {
+ long outputSize;
+ if (cmStrToLong(sz, &outputSize)) {
+ this->Impl->TestOptions.OutputSizePassed =
+ static_cast<int>(outputSize);
+ } else {
+ cmCTestLog(
+ this, WARNING,
+ "Invalid value for '--test-output-size-passed': "
+ << sz << "\n");
+ }
+ return true;
+ } },
+ CommandArgument{ "--test-output-size-failed", CommandArgument::Values::One,
+ [this](std::string const& sz) -> bool {
+ long outputSize;
+ if (cmStrToLong(sz, &outputSize)) {
+ this->Impl->TestOptions.OutputSizeFailed =
+ static_cast<int>(outputSize);
+ } else {
+ cmCTestLog(
+ this, WARNING,
+ "Invalid value for '--test-output-size-failed': "
+ << sz << "\n");
+ }
+ return true;
+ } },
+ CommandArgument{
+ "--test-output-truncation", CommandArgument::Values::One,
+ [this](std::string const& mode) -> bool {
+ if (!SetTruncationMode(this->Impl->TestOptions.OutputTruncation,
+ mode)) {
+ cmSystemTools::Error(
+ cmStrCat("Invalid value for '--test-output-truncation': ", mode));
+ return false;
+ }
+ return true;
+ } },
+ CommandArgument{ "--show-only", CommandArgument::Values::ZeroOrOne,
+ [this](std::string const& format) -> bool {
+ this->Impl->ShowOnly = true;
+ // Check if a specific format is requested.
+ // Defaults to human readable text.
+ if (format == "json-v1") {
+ // Force quiet mode so the only output
+ // is the json object model.
+ this->Impl->Quiet = true;
+ this->Impl->OutputAsJson = true;
+ this->Impl->OutputAsJsonVersion = 1;
+ } else if (format == "human") {
+ } else if (!format.empty()) {
+ cmSystemTools::Error(
+ cmStrCat("'--show-only=' given unknown value '",
+ format, '\''));
+ return false;
+ }
+ return true;
+ } },
+ CommandArgument{ "-N", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->ShowOnly = true;
+ return true;
+ } },
+ CommandArgument{ "-O", CommandArgument::Values::One, dashO },
+ CommandArgument{ "--output-log", CommandArgument::Values::One, dashO },
+ CommandArgument{ "--tomorrow-tag", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->TomorrowTag = true;
+ return true;
+ } },
+ CommandArgument{ "--force-new-ctest-process",
+ CommandArgument::Values::Zero,
+ [](std::string const&) -> bool {
+ // Silently ignore now-removed option.
+ return true;
+ } },
+ CommandArgument{ "-W", CommandArgument::Values::One, dashW },
+ CommandArgument{ "--max-width", CommandArgument::Values::One, dashW },
+ CommandArgument{ "--interactive-debug-mode", CommandArgument::Values::One,
+ [this](std::string const& idm) -> bool {
+ this->Impl->InteractiveDebugMode = cmIsOn(idm);
+ return true;
+ } },
+ CommandArgument{ "--http-header", CommandArgument::Values::One,
+ [this](std::string const& h) -> bool {
+ this->Impl->CommandLineHttpHeaders.push_back(h);
+ return true;
+ } },
+ CommandArgument{ "--submit-index", CommandArgument::Values::One,
+ [this](std::string const& index) -> bool {
+ this->Impl->SubmitIndex = atoi(index.c_str());
+ if (this->Impl->SubmitIndex < 0) {
+ this->Impl->SubmitIndex = 0;
+ }
+ return true;
+ } },
+ CommandArgument{ "--overwrite", CommandArgument::Values::One,
+ [this](std::string const& opt) -> bool {
+ this->AddCTestConfigurationOverwrite(opt);
+ return true;
+ } },
+ CommandArgument{ "-A", CommandArgument::Values::One, dashA },
+ CommandArgument{ "--add-notes", CommandArgument::Values::One, dashA },
+ CommandArgument{ "--test-dir", "'--test-dir' requires an argument",
+ CommandArgument::Values::One,
+ [this](std::string const& dir) -> bool {
+ this->Impl->TestDir = dir;
+ return true;
+ } },
+ CommandArgument{ "--output-junit", CommandArgument::Values::One,
+ [this](std::string const& file) -> bool {
+ this->SetOutputJUnitFileName(file);
+ return true;
+ } },
+ CommandArgument{ "--no-tests", CommandArgument::Values::One,
+ [this](std::string const& action) -> bool {
+ if (action == "error"_s) {
+ this->Impl->NoTestsMode = cmCTest::NoTests::Error;
+ } else if (action == "ignore"_s) {
+ this->Impl->NoTestsMode = cmCTest::NoTests::Ignore;
+ } else {
+ cmSystemTools::Error(
+ cmStrCat("'--no-tests=' given unknown value '",
+ action, '\''));
+ return false;
+ }
+ this->Impl->NoTestsModeSetInCli = true;
+ return true;
+ } },
+ CommandArgument{ "-I", CommandArgument::Values::One, dashI },
+ CommandArgument{ "--tests-information", CommandArgument::Values::One,
+ dashI },
+ CommandArgument{ "-U", CommandArgument::Values::One, dashU },
+ CommandArgument{ "--union", CommandArgument::Values::One, dashU },
+ CommandArgument{ "-R", CommandArgument::Values::One, dashR },
+ CommandArgument{ "--tests-regex", CommandArgument::Values::One, dashR },
+ CommandArgument{ "-E", CommandArgument::Values::One, dashE },
+ CommandArgument{ "--exclude-regex", CommandArgument::Values::One, dashE },
+ CommandArgument{ "-L", CommandArgument::Values::One, dashL },
+ CommandArgument{ "--label-regex", CommandArgument::Values::One, dashL },
+ CommandArgument{ "-LE", CommandArgument::Values::One, dashLE },
+ CommandArgument{ "--label-exclude", CommandArgument::Values::One, dashLE },
+ CommandArgument{ "-FA", CommandArgument::Values::One, dashFA },
+ CommandArgument{ "--fixture-exclude-any", CommandArgument::Values::One,
+ dashFA },
+ CommandArgument{ "-FS", CommandArgument::Values::One, dashFS },
+ CommandArgument{ "--fixture-exclude-setup", CommandArgument::Values::One,
+ dashFS },
+ CommandArgument{ "-FC", CommandArgument::Values::One, dashFC },
+ CommandArgument{ "--fixture-exclude-cleanup", CommandArgument::Values::One,
+ dashFC },
+ CommandArgument{ "--resource-spec-file", CommandArgument::Values::One,
+ [this](std::string const& file) -> bool {
+ this->Impl->TestOptions.ResourceSpecFile = file;
+ return true;
+ } },
+ CommandArgument{ "--tests-from-file", CommandArgument::Values::One,
+ [this](std::string const& file) -> bool {
+ this->Impl->TestOptions.TestListFile = file;
+ return true;
+ } },
+ CommandArgument{ "--exclude-from-file", CommandArgument::Values::One,
+ [this](std::string const& file) -> bool {
+ this->Impl->TestOptions.ExcludeTestListFile = file;
+ return true;
+ } },
+ CommandArgument{ "--schedule-random", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->TestOptions.ScheduleRandom = true;
+ return true;
+ } },
+ CommandArgument{ "--rerun-failed", CommandArgument::Values::Zero,
+ [this](std::string const&) -> bool {
+ this->Impl->TestOptions.RerunFailed = true;
+ return true;
+ } },
+ };
+
// process the command line arguments
for (size_t i = 1; i < args.size(); ++i) {
- // handle the simple commandline arguments
- std::string errormsg;
- bool validArg = this->HandleCommandLineArguments(i, args, errormsg);
- if (!validArg && !errormsg.empty()) {
- cmSystemTools::Error(errormsg);
- return 1;
- }
- std::string arg = args[i];
-
- // handle the script arguments -S -SR -SP
- validArg =
- validArg || this->HandleScriptArguments(i, args, SRArgumentSpecified);
-
- // --dashboard: handle a request for a dashboard
- if (this->CheckArgument(arg, "-D"_s, "--dashboard") &&
- i < args.size() - 1) {
- this->Impl->ProduceXML = true;
- i++;
- std::string targ = args[i];
- // AddTestsForDashboard parses the dashboard type and converts it
- // into the separate stages
- if (!this->AddTestsForDashboardType(targ)) {
- if (!this->AddVariableDefinition(targ)) {
- this->ErrorMessageUnknownDashDValue(targ);
- executeTests = false;
+ std::string const& arg = args[i];
+ bool matched = false;
+ for (auto const& m : arguments) {
+ if (m.matches(arg)) {
+ matched = true;
+ if (!m.parse(arg, i, args)) {
+ return 1;
}
- }
- validArg = true;
- }
-
- // If it's not exactly -D, but it starts with -D, then try to parse out
- // a variable definition from it, same as CMake does. Unsuccessful
- // attempts are simply ignored since previous ctest versions ignore
- // this too. (As well as many other unknown command line args.)
- //
- if (arg != "-D" && cmHasLiteralPrefix(arg, "-D")) {
- std::string input = arg.substr(2);
- this->AddVariableDefinition(input);
- validArg = true;
- }
-
- // --test-action: calls SetTest(<stage>, /*report=*/ false) to enable
- // the corresponding stage
- if (!this->HandleTestActionArgument(ctestExec, i, args, validArg)) {
- executeTests = false;
- }
-
- // --test-model: what type of test model
- if (!this->HandleTestModelArgument(ctestExec, i, args, validArg)) {
- executeTests = false;
- }
-
- // --extra-submit
- if (this->CheckArgument(arg, "--extra-submit"_s) && i < args.size() - 1) {
- this->Impl->ProduceXML = true;
- this->SetTest("Submit");
- i++;
- if (!this->SubmitExtraFiles(args[i])) {
- return 0;
- }
- validArg = true;
- }
-
- // --build-and-test options
- if (this->CheckArgument(arg, "--build-and-test"_s) &&
- i < args.size() - 1) {
- cmakeAndTest = true;
- validArg = true;
- }
-
- // --schedule-random
- if (this->CheckArgument(arg, "--schedule-random"_s)) {
- this->Impl->ScheduleType = "Random";
- validArg = true;
- }
-
- // pass the argument to all the handlers as well, but it may no longer be
- // set to what it was originally so I'm not sure this is working as
- // intended
- for (auto& handler : this->Impl->GetTestingHandlers()) {
- if (!handler->ProcessCommandLineArguments(arg, i, args, validArg)) {
- cmCTestLog(
- this, ERROR_MESSAGE,
- "Problem parsing command line arguments within a handler\n");
- return 0;
+ break;
}
}
-
- if (!validArg && cmHasLiteralPrefix(arg, "-") &&
+ if (!matched && arg == "--build-options"_s) {
+ matched = true;
+ while (i + 1 < args.size() && args[i + 1] != "--build-target"_s &&
+ args[i + 1] != "--test-command"_s) {
+ ++i;
+ this->Impl->BuildAndTest.BuildOptions.emplace_back(args[i]);
+ }
+ }
+ if (!matched && arg == "--test-command"_s && i + 1 < args.size()) {
+ matched = true;
+ ++i;
+ this->Impl->BuildAndTest.TestCommand = args[i];
+ while (i + 1 < args.size()) {
+ ++i;
+ this->Impl->BuildAndTest.TestCommandArgs.emplace_back(args[i]);
+ }
+ }
+ if (!matched && cmHasLiteralPrefix(arg, "-") &&
!cmHasLiteralPrefix(arg, "--preset")) {
cmSystemTools::Error(cmStrCat("Unknown argument: ", arg));
cmSystemTools::Error("Run 'ctest --help' for all supported options.");
return 1;
}
- } // the close of the for argument loop
+ }
// handle CTEST_PARALLEL_LEVEL environment variable
if (!this->Impl->ParallelLevelSetInCli) {
@@ -2872,157 +2626,111 @@
// now what should cmake do? if --build-and-test was specified then
// we run the build and test handler and return
if (cmakeAndTest) {
- return this->RunCMakeAndTest(output);
+ return this->RunCMakeAndTest();
}
- if (executeTests) {
- return this->ExecuteTests();
+ // -S, -SP, and/or -SP was specified
+ if (!runScripts.empty()) {
+ return this->RunScripts(runScripts);
}
- return 1;
+ // -D, -T, and/or -M was specified
+ if (processSteps) {
+ return this->ProcessSteps();
+ }
+
+ return this->ExecuteTests();
}
-bool cmCTest::HandleTestActionArgument(const char* ctestExec, size_t& i,
- const std::vector<std::string>& args,
- bool& validArg)
+int cmCTest::RunScripts(
+ std::vector<std::pair<std::string, bool>> const& scripts)
{
- bool success = true;
- std::string const& arg = args[i];
- if (this->CheckArgument(arg, "-T"_s, "--test-action") &&
- (i < args.size() - 1)) {
- validArg = true;
- this->Impl->ProduceXML = true;
- i++;
- if (!this->SetTest(args[i], false)) {
- success = false;
- cmCTestLog(this, ERROR_MESSAGE,
- "CTest -T called with incorrect option: " << args[i] << '\n');
- /* clang-format off */
- cmCTestLog(this, ERROR_MESSAGE,
- "Available options are:\n"
- " " << ctestExec << " -T all\n"
- " " << ctestExec << " -T start\n"
- " " << ctestExec << " -T update\n"
- " " << ctestExec << " -T configure\n"
- " " << ctestExec << " -T build\n"
- " " << ctestExec << " -T test\n"
- " " << ctestExec << " -T coverage\n"
- " " << ctestExec << " -T memcheck\n"
- " " << ctestExec << " -T notes\n"
- " " << ctestExec << " -T submit\n");
- /* clang-format on */
- }
+ if (this->Impl->ExtraVerbose) {
+ cmCTestLog(this, OUTPUT, "* Extra verbosity turned on" << std::endl);
}
- return success;
-}
-bool cmCTest::HandleTestModelArgument(const char* ctestExec, size_t& i,
- const std::vector<std::string>& args,
- bool& validArg)
-{
- bool success = true;
- std::string const& arg = args[i];
- if (this->CheckArgument(arg, "-M"_s, "--test-model") &&
- (i < args.size() - 1)) {
- validArg = true;
- i++;
- std::string const& str = args[i];
- if (cmSystemTools::LowerCase(str) == "nightly"_s) {
- this->SetTestModel(cmCTest::NIGHTLY);
- } else if (cmSystemTools::LowerCase(str) == "continuous"_s) {
- this->SetTestModel(cmCTest::CONTINUOUS);
- } else if (cmSystemTools::LowerCase(str) == "experimental"_s) {
- this->SetTestModel(cmCTest::EXPERIMENTAL);
- } else {
- success = false;
- cmCTestLog(this, ERROR_MESSAGE,
- "CTest -M called with incorrect option: " << str << '\n');
- /* clang-format off */
- cmCTestLog(this, ERROR_MESSAGE,
- "Available options are:\n"
- " " << ctestExec << " -M Continuous\n"
- " " << ctestExec << " -M Experimental\n"
- " " << ctestExec << " -M Nightly\n");
- /* clang-format on */
- }
+ auto ch = cm::make_unique<cmCTestScriptHandler>(this);
+ for (auto const& script : scripts) {
+ ch->AddConfigurationScript(script.first, script.second);
}
- return success;
+
+ int res = ch->ProcessHandler();
+ if (res != 0) {
+ cmCTestLog(this, DEBUG,
+ "running script failing returning: " << res << std::endl);
+ }
+
+ return res;
}
int cmCTest::ExecuteTests()
{
- int res;
- // call process directory
- if (this->Impl->RunConfigurationScript) {
- if (this->Impl->ExtraVerbose) {
- cmCTestLog(this, OUTPUT, "* Extra verbosity turned on" << std::endl);
- }
- for (auto& handler : this->Impl->GetTestingHandlers()) {
- handler->SetVerbose(this->Impl->ExtraVerbose);
- handler->SetSubmitIndex(this->Impl->SubmitIndex);
- }
- this->GetScriptHandler()->SetVerbose(this->Impl->Verbose);
- res = this->GetScriptHandler()->ProcessHandler();
- if (res != 0) {
- cmCTestLog(this, DEBUG,
- "running script failing returning: " << res << std::endl);
- }
+ this->Impl->ExtraVerbose = this->Impl->Verbose;
+ this->Impl->Verbose = true;
+ const std::string currDir = cmSystemTools::GetLogicalWorkingDirectory();
+ std::string workDir = currDir;
+ if (!this->Impl->TestDir.empty()) {
+ workDir = cmSystemTools::ToNormalizedPathOnDisk(this->Impl->TestDir);
+ }
+
+ cmWorkingDirectory changeDir(workDir);
+ if (changeDir.Failed()) {
+ cmCTestLog(this, ERROR_MESSAGE, changeDir.GetError() << std::endl);
+ return 1;
+ }
+
+ cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
+ if (!this->Impl->InteractiveDebugMode) {
+ this->BlockTestErrorDiagnostics();
} else {
- // What is this? -V seems to be the same as -VV,
- // and Verbose is always on in this case
- this->Impl->ExtraVerbose = this->Impl->Verbose;
- this->Impl->Verbose = true;
- for (auto& handler : this->Impl->GetTestingHandlers()) {
- handler->SetVerbose(this->Impl->Verbose);
- handler->SetSubmitIndex(this->Impl->SubmitIndex);
- }
+ cmSystemTools::PutEnv("CTEST_INTERACTIVE_DEBUG_MODE=1");
+ }
- const std::string currDir = cmSystemTools::GetCurrentWorkingDirectory();
- std::string workDir = currDir;
- if (!this->Impl->TestDir.empty()) {
- workDir = cmSystemTools::CollapseFullPath(this->Impl->TestDir);
- }
+ this->Impl->BinaryDir = workDir;
+ cmSystemTools::ConvertToUnixSlashes(this->Impl->BinaryDir);
- if (currDir != workDir) {
- if (!this->TryToChangeDirectory(workDir)) {
- return 1;
- }
- }
+ this->UpdateCTestConfiguration();
- if (!this->Initialize(workDir, nullptr)) {
- res = 12;
+ cmCTestLog(this, DEBUG, "Here: " << __LINE__ << std::endl);
+
+ cmCTestTestHandler handler(this);
+
+ {
+ cmake cm(cmake::RoleScript, cmState::CTest);
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cmGlobalGenerator gg(&cm);
+ cmMakefile mf(&gg, cm.GetCurrentSnapshot());
+ this->ReadCustomConfigurationFileTree(this->Impl->BinaryDir, &mf);
+ handler.PopulateCustomVectors(&mf);
+ }
+
+ handler.SetVerbose(this->Impl->Verbose);
+ if (handler.ProcessHandler() < 0) {
+ cmCTestLog(this, ERROR_MESSAGE, "Errors while running CTest\n");
+ if (!this->Impl->OutputTestOutputOnTestFailure) {
+ const std::string lastTestLog =
+ this->GetBinaryDir() + "/Testing/Temporary/LastTest.log";
cmCTestLog(this, ERROR_MESSAGE,
- "Problem initializing the dashboard." << std::endl);
- } else {
- res = this->ProcessSteps();
+ "Output from these tests are in: " << lastTestLog << '\n');
+ cmCTestLog(this, ERROR_MESSAGE,
+ "Use \"--rerun-failed --output-on-failure\" to re-run the "
+ "failed cases verbosely.\n");
}
- this->Finalize();
+ return cmCTest::TEST_ERRORS;
+ }
- if (currDir != workDir) {
- cmSystemTools::ChangeDirectory(currDir);
- }
- }
- if (res != 0) {
- cmCTestLog(this, DEBUG,
- "Running a test(s) failed returning : " << res << std::endl);
- }
- return res;
+ return 0;
}
-int cmCTest::RunCMakeAndTest(std::string* output)
+int cmCTest::RunCMakeAndTest()
{
- this->Impl->Verbose = true;
- cmCTestBuildAndTestHandler* handler = this->GetBuildAndTestHandler();
- int retv = handler->ProcessHandler();
- *output = handler->GetOutput();
+ int retv = this->Impl->BuildAndTest.Run();
#ifndef CMAKE_BOOTSTRAP
cmDynamicLoader::FlushCache();
#endif
- if (retv != 0) {
- cmCTestLog(this, DEBUG,
- "build and test failing returning: " << retv << std::endl);
- }
return retv;
}
@@ -3094,17 +2802,25 @@
this->Impl->ScheduleType = type;
}
-int cmCTest::ReadCustomConfigurationFileTree(const std::string& dir,
- cmMakefile* mf)
+void cmCTest::ReadCustomConfigurationFileTree(const std::string& dir,
+ cmMakefile* mf)
{
- bool found = false;
cmCTestLog(this, DEBUG,
"* Read custom CTest configuration directory: " << dir
<< std::endl);
- std::string fname = cmStrCat(dir, "/CTestCustom.cmake");
- cmCTestLog(this, DEBUG, "* Check for file: " << fname << std::endl);
- if (cmSystemTools::FileExists(fname)) {
+ auto const fname = [this, &dir]() -> std::string {
+ for (char const* ext : { ".cmake", ".ctest" }) {
+ std::string path = cmStrCat(dir, "/CTestCustom", ext);
+ cmCTestLog(this, DEBUG, "* Check for file: " << path << std::endl);
+ if (cmSystemTools::FileExists(path)) {
+ return path;
+ }
+ }
+ return "";
+ }();
+
+ if (!fname.empty()) {
cmCTestLog(this, DEBUG,
"* Read custom CTest configuration file: " << fname
<< std::endl);
@@ -3116,43 +2832,10 @@
"Problem reading custom configuration: " << fname
<< std::endl);
}
- found = true;
if (erroroc) {
cmSystemTools::SetErrorOccurred();
}
}
-
- std::string rexpr = cmStrCat(dir, "/CTestCustom.ctest");
- cmCTestLog(this, DEBUG, "* Check for file: " << rexpr << std::endl);
- if (!found && cmSystemTools::FileExists(rexpr)) {
- cmsys::Glob gl;
- gl.RecurseOn();
- gl.FindFiles(rexpr);
- std::vector<std::string>& files = gl.GetFiles();
- for (const std::string& file : files) {
- cmCTestLog(this, DEBUG,
- "* Read custom CTest configuration file: " << file
- << std::endl);
- if (!mf->ReadListFile(file) || cmSystemTools::GetErrorOccurredFlag()) {
- cmCTestLog(this, ERROR_MESSAGE,
- "Problem reading custom configuration: " << file
- << std::endl);
- }
- }
- found = true;
- }
-
- if (found) {
- for (auto& handler : this->Impl->GetNamedTestingHandlers()) {
- cmCTestLog(this, DEBUG,
- "* Read custom CTest configuration vectors for handler: "
- << handler.first << " (" << handler.second << ")"
- << std::endl);
- handler.second->PopulateCustomVectors(mf);
- }
- }
-
- return 1;
}
void cmCTest::PopulateCustomVector(cmMakefile* mf, const std::string& def,
@@ -3183,10 +2866,9 @@
std::string cmCTest::GetShortPathToFile(const std::string& cfname)
{
- const std::string& sourceDir = cmSystemTools::CollapseFullPath(
- this->GetCTestConfiguration("SourceDirectory"));
- const std::string& buildDir = cmSystemTools::CollapseFullPath(
- this->GetCTestConfiguration("BuildDirectory"));
+ const std::string& sourceDir =
+ this->GetCTestConfiguration("SourceDirectory");
+ const std::string& buildDir = this->GetCTestConfiguration("BuildDirectory");
std::string fname = cmSystemTools::CollapseFullPath(cfname);
// Find relative paths to both directories
@@ -3409,10 +3091,14 @@
return this->Impl->ExtraVerbose;
}
-void cmCTest::SetStreams(std::ostream* out, std::ostream* err)
+int cmCTest::GetSubmitIndex() const
{
- this->Impl->StreamOut = out;
- this->Impl->StreamErr = err;
+ return this->Impl->SubmitIndex;
+}
+
+bool cmCTest::GetInteractiveDebugMode() const
+{
+ return this->Impl->InteractiveDebugMode;
}
bool cmCTest::GetLabelSummary() const
@@ -3460,6 +3146,16 @@
return this->Impl->BuildID;
}
+cmCTestTestOptions const& cmCTest::GetTestOptions() const
+{
+ return this->Impl->TestOptions;
+}
+
+std::vector<std::string> cmCTest::GetCommandLineHttpHeaders() const
+{
+ return this->Impl->CommandLineHttpHeaders;
+}
+
void cmCTest::AddSubmitFile(Part part, const std::string& name)
{
this->Impl->Parts[part].SubmitFiles.emplace_back(name);
@@ -3520,6 +3216,79 @@
return true;
}
+void cmCTest::SetCMakeVariables(cmMakefile& mf)
+{
+ auto set = [&](char const* cmake_var, char const* ctest_opt) {
+ std::string val = this->GetCTestConfiguration(ctest_opt);
+ if (!val.empty()) {
+ cmCTestOptionalLog(
+ this, HANDLER_VERBOSE_OUTPUT,
+ "SetCMakeVariable:" << cmake_var << ":" << val << std::endl, false);
+ mf.AddDefinition(cmake_var, val);
+ }
+ };
+
+ set("CTEST_SITE", "Site");
+ set("CTEST_BUILD_NAME", "BuildName");
+ set("CTEST_NIGHTLY_START_TIME", "NightlyStartTime");
+ set("CTEST_SOURCE_DIRECTORY", "SourceDirectory");
+ set("CTEST_BINARY_DIRECTORY", "BuildDirectory");
+
+ // CTest Update Step
+ set("CTEST_UPDATE_COMMAND", "UpdateCommand");
+ set("CTEST_UPDATE_OPTIONS", "UpdateOptions");
+ set("CTEST_CVS_COMMAND", "CVSCommand");
+ set("CTEST_CVS_UPDATE_OPTIONS", "CVSUpdateOptions");
+ set("CTEST_SVN_COMMAND", "SVNCommand");
+ set("CTEST_SVN_UPDATE_OPTIONS", "SVNUpdateOptions");
+ set("CTEST_SVN_OPTIONS", "SVNOptions");
+ set("CTEST_BZR_COMMAND", "BZRCommand");
+ set("CTEST_BZR_UPDATE_OPTIONS", "BZRUpdateOptions");
+ set("CTEST_GIT_COMMAND", "GITCommand");
+ set("CTEST_GIT_UPDATE_OPTIONS", "GITUpdateOptions");
+ set("CTEST_GIT_INIT_SUBMODULES", "GITInitSubmodules");
+ set("CTEST_GIT_UPDATE_CUSTOM", "GITUpdateCustom");
+ set("CTEST_UPDATE_VERSION_ONLY", "UpdateVersionOnly");
+ set("CTEST_UPDATE_VERSION_OVERRIDE", "UpdateVersionOverride");
+ set("CTEST_HG_COMMAND", "HGCommand");
+ set("CTEST_HG_UPDATE_OPTIONS", "HGUpdateOptions");
+ set("CTEST_P4_COMMAND", "P4Command");
+ set("CTEST_P4_UPDATE_OPTIONS", "P4UpdateOptions");
+ set("CTEST_P4_CLIENT", "P4Client");
+ set("CTEST_P4_OPTIONS", "P4Options");
+
+ // CTest Configure Step
+ set("CTEST_CONFIGURE_COMMAND", "ConfigureCommand");
+ set("CTEST_LABELS_FOR_SUBPROJECTS", "LabelsForSubprojects");
+
+ // CTest Build Step
+ set("CTEST_BUILD_COMMAND", "MakeCommand");
+ set("CTEST_USE_LAUNCHERS", "UseLaunchers");
+
+ // CTest Coverage Step
+ set("CTEST_COVERAGE_COMMAND", "CoverageCommand");
+ set("CTEST_COVERAGE_EXTRA_FLAGS", "CoverageExtraFlags");
+
+ // CTest MemCheck Step
+ set("CTEST_MEMORYCHECK_TYPE", "MemoryCheckType");
+ set("CTEST_MEMORYCHECK_SANITIZER_OPTIONS", "MemoryCheckSanitizerOptions");
+ set("CTEST_MEMORYCHECK_COMMAND", "MemoryCheckCommand");
+ set("CTEST_MEMORYCHECK_COMMAND_OPTIONS", "MemoryCheckCommandOptions");
+ set("CTEST_MEMORYCHECK_SUPPRESSIONS_FILE", "MemoryCheckSuppressionFile");
+
+ // CTest Submit Step
+ set("CTEST_SUBMIT_URL", "SubmitURL");
+ set("CTEST_DROP_METHOD", "DropMethod");
+ set("CTEST_DROP_SITE_USER", "DropSiteUser");
+ set("CTEST_DROP_SITE_PASSWORD", "DropSitePassword");
+ set("CTEST_DROP_SITE", "DropSite");
+ set("CTEST_DROP_LOCATION", "DropLocation");
+ set("CTEST_TLS_VERIFY", "TLSVerify");
+ set("CTEST_TLS_VERSION", "TLSVersion");
+ set("CTEST_CURL_OPTIONS", "CurlOptions");
+ set("CTEST_SUBMIT_INACTIVITY_TIMEOUT", "SubmitInactivityTimeout");
+}
+
bool cmCTest::RunCommand(std::vector<std::string> const& args,
std::string* stdOut, std::string* stdErr, int* retVal,
const char* dir, cmDuration timeout,
@@ -3649,7 +3418,7 @@
void cmCTest::SetOutputJUnitFileName(const std::string& name)
{
- this->Impl->TestHandler.SetJUnitXMLFileName(name);
+ this->Impl->TestOptions.JUnitXMLFileName = name;
// Turn test output compression off.
// This makes it easier to include test output in the resulting
// JUnit XML report.
@@ -3663,20 +3432,11 @@
"HANDLER_TEST_PROGRESS_OUTPUT",
"HANDLER_VERBOSE_OUTPUT",
"WARNING",
- "ERROR_MESSAGE",
- nullptr };
+ "ERROR_MESSAGE" };
-#define cmCTestLogOutputFileLine(stream) \
- do { \
- if (this->Impl->ShowLineNumbers) { \
- (stream) << std::endl << file << ":" << line << " "; \
- } \
- } while (false)
-
-void cmCTest::Log(int logType, const char* file, int line, const char* msg,
- bool suppress)
+void cmCTest::Log(LogType logType, std::string msg, bool suppress)
{
- if (!msg || !*msg) {
+ if (msg.empty()) {
return;
}
if (suppress && logType != cmCTest::ERROR_MESSAGE) {
@@ -3696,49 +3456,38 @@
display = false;
}
if (display) {
- cmCTestLogOutputFileLine(*this->Impl->OutputLogFile);
- if (logType != this->Impl->OutputLogFileLastTag) {
- *this->Impl->OutputLogFile << "[";
- if (logType >= OTHER || logType < 0) {
- *this->Impl->OutputLogFile << "OTHER";
- } else {
- *this->Impl->OutputLogFile << cmCTestStringLogType[logType];
- }
- *this->Impl->OutputLogFile << "] " << std::endl;
+ if (this->Impl->OutputLogFileLastTag &&
+ logType != *this->Impl->OutputLogFileLastTag) {
+ *this->Impl->OutputLogFile << "[" << cmCTestStringLogType[logType]
+ << "] " << std::endl;
}
*this->Impl->OutputLogFile << msg << std::flush;
- if (logType != this->Impl->OutputLogFileLastTag) {
+ if (this->Impl->OutputLogFileLastTag &&
+ logType != *this->Impl->OutputLogFileLastTag) {
*this->Impl->OutputLogFile << std::endl;
this->Impl->OutputLogFileLastTag = logType;
}
}
}
if (!this->Impl->Quiet) {
- std::ostream& out = *this->Impl->StreamOut;
- std::ostream& err = *this->Impl->StreamErr;
-
if (logType == HANDLER_TEST_PROGRESS_OUTPUT) {
if (this->Impl->TestProgressOutput) {
- cmCTestLogOutputFileLine(out);
if (this->Impl->FlushTestProgressLine) {
printf("\r");
this->Impl->FlushTestProgressLine = false;
- out.flush();
+ std::cout.flush();
}
- std::string msg_str{ msg };
- auto const lineBreakIt = msg_str.find('\n');
- if (lineBreakIt != std::string::npos) {
+ if (msg.find('\n') != std::string::npos) {
this->Impl->FlushTestProgressLine = true;
- msg_str.erase(std::remove(msg_str.begin(), msg_str.end(), '\n'),
- msg_str.end());
+ msg.erase(std::remove(msg.begin(), msg.end(), '\n'), msg.end());
}
- out << msg_str;
+ std::cout << msg;
#ifndef _WIN32
printf("\x1B[K"); // move caret to end
#endif
- out.flush();
+ std::cout.flush();
return;
}
logType = HANDLER_OUTPUT;
@@ -3747,41 +3496,29 @@
switch (logType) {
case DEBUG:
if (this->Impl->Debug) {
- cmCTestLogOutputFileLine(out);
- out << msg;
- out.flush();
+ std::cout << msg << std::flush;
}
break;
case OUTPUT:
case HANDLER_OUTPUT:
if (this->Impl->Debug || this->Impl->Verbose) {
- cmCTestLogOutputFileLine(out);
- out << msg;
- out.flush();
+ std::cout << msg << std::flush;
}
break;
case HANDLER_VERBOSE_OUTPUT:
if (this->Impl->Debug || this->Impl->ExtraVerbose) {
- cmCTestLogOutputFileLine(out);
- out << msg;
- out.flush();
+ std::cout << msg << std::flush;
}
break;
case WARNING:
- cmCTestLogOutputFileLine(err);
- err << msg;
- err.flush();
+ std::cerr << msg << std::flush;
break;
case ERROR_MESSAGE:
- cmCTestLogOutputFileLine(err);
- err << msg;
- err.flush();
+ std::cerr << msg << std::flush;
cmSystemTools::SetErrorOccurred();
break;
default:
- cmCTestLogOutputFileLine(out);
- out << msg;
- out.flush();
+ std::cout << msg << std::flush;
}
}
}
@@ -3795,9 +3532,21 @@
return "";
}
-cmDuration cmCTest::GetRemainingTimeAllowed()
+void cmCTest::SetTimeLimit(cmValue val)
{
- return this->GetScriptHandler()->GetRemainingTimeAllowed();
+ this->Impl->TimeLimit =
+ val ? cmDuration(atof(val->c_str())) : cmCTest::MaxDuration();
+}
+
+cmDuration cmCTest::GetElapsedTime() const
+{
+ return std::chrono::duration_cast<cmDuration>(
+ std::chrono::steady_clock::now() - this->Impl->StartTime);
+}
+
+cmDuration cmCTest::GetRemainingTimeAllowed() const
+{
+ return this->Impl->TimeLimit - this->GetElapsedTime();
}
cmDuration cmCTest::MaxDuration()
@@ -3805,20 +3554,6 @@
return cmDuration(1.0e7);
}
-void cmCTest::SetRunCurrentScript(bool value)
-{
- this->GetScriptHandler()->SetRunCurrentScript(value);
-}
-
-void cmCTest::OutputTestErrors(std::vector<char> const& process_output)
-{
- std::string test_outputs("\n*** Test Failed:\n");
- if (!process_output.empty()) {
- test_outputs.append(process_output.data(), process_output.size());
- }
- cmCTestLog(this, HANDLER_OUTPUT, test_outputs << std::endl);
-}
-
bool cmCTest::CompressString(std::string& str)
{
int ret;
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index 85f75fd..c8dc485 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -10,6 +10,7 @@
#include <memory>
#include <sstream>
#include <string>
+#include <utility>
#include <vector>
#include <cm/optional>
@@ -18,20 +19,12 @@
#include "cmDuration.h"
#include "cmProcessOutput.h"
-class cmCTestBuildHandler;
-class cmCTestBuildAndTestHandler;
-class cmCTestCoverageHandler;
-class cmCTestScriptHandler;
-class cmCTestTestHandler;
-class cmCTestUpdateHandler;
-class cmCTestConfigureHandler;
-class cmCTestMemCheckHandler;
-class cmCTestSubmitHandler;
-class cmCTestUploadHandler;
-class cmCTestStartCommand;
+class cmake;
class cmGeneratedFileStream;
class cmMakefile;
+class cmValue;
class cmXMLWriter;
+struct cmCTestTestOptions;
/** \class cmCTest
* \brief Represents a ctest invocation.
@@ -67,30 +60,16 @@
Part GetPartFromName(const std::string& name);
/** Process Command line arguments */
- int Run(std::vector<std::string>&, std::string* output = nullptr);
+ int Run(std::vector<std::string> const& args);
- /**
- * Initialize and finalize testing
- */
- bool InitializeFromCommand(cmCTestStartCommand* command);
- void Finalize();
+ /** Initialize a dashboard run in the given build tree. */
+ void Initialize(std::string const& binary_dir);
+
+ bool CreateNewTag(bool quiet);
+ bool ReadExistingTag(bool quiet);
/**
* Process the dashboard client steps.
- *
- * Steps are enabled using SetTest()
- *
- * The execution of the steps (or #Part) should look like this:
- *
- * /code
- * ctest foo;
- * foo.Initialize();
- * // Set some things on foo
- * foo.ProcessSteps();
- * foo.Finalize();
- * /endcode
- *
- * \sa Initialize(), Finalize(), Part, PartInfo, SetTest()
*/
int ProcessSteps();
@@ -140,7 +119,8 @@
void SetTestModel(int mode);
int GetTestModel() const;
- std::string GetTestModelString();
+ std::string GetTestModelString() const;
+ std::string GetTestGroupString() const;
static int GetTestModelFromString(const std::string& str);
static std::string CleanString(const std::string& str,
std::string::size_type spos = 0);
@@ -175,12 +155,15 @@
/** base64 encode a file */
std::string Base64EncodeFile(std::string const& file);
+ void SetTimeLimit(cmValue val);
+ cmDuration GetElapsedTime() const;
+
/**
* Return the time remaining that the script is allowed to run in
* seconds if the user has set the variable CTEST_TIME_LIMIT. If that has
* not been set it returns a very large duration.
*/
- cmDuration GetRemainingTimeAllowed();
+ cmDuration GetRemainingTimeAllowed() const;
static cmDuration MaxDuration();
@@ -246,7 +229,7 @@
static std::string SafeBuildIdField(const std::string& value);
/** Start CTest XML output file */
- void StartXML(cmXMLWriter& xml, bool append);
+ void StartXML(cmXMLWriter& xml, cmake* cm, bool append);
/** End CTest XML output file */
void EndXML(cmXMLWriter& xml);
@@ -299,31 +282,6 @@
void SetProduceXML(bool v);
/**
- * Run command specialized for tests. Returns process status and retVal is
- * return value or exception. If environment is non-null, it is used to set
- * environment variables prior to running the test. After running the test,
- * environment variables are restored to their previous values.
- */
- bool RunTest(const std::vector<std::string>& args, std::string* output,
- int* retVal, std::ostream* logfile, cmDuration testTimeOut,
- std::vector<std::string>* environment,
- Encoding encoding = cmProcessOutput::Auto);
-
- /**
- * Get the handler object
- */
- cmCTestBuildHandler* GetBuildHandler();
- cmCTestBuildAndTestHandler* GetBuildAndTestHandler();
- cmCTestCoverageHandler* GetCoverageHandler();
- cmCTestScriptHandler* GetScriptHandler();
- cmCTestTestHandler* GetTestHandler();
- cmCTestUpdateHandler* GetUpdateHandler();
- cmCTestConfigureHandler* GetConfigureHandler();
- cmCTestMemCheckHandler* GetMemCheckHandler();
- cmCTestSubmitHandler* GetSubmitHandler();
- cmCTestUploadHandler* GetUploadHandler();
-
- /**
* Set the CTest variable from CMake variable
*/
bool SetCTestConfigurationFromCMakeVariable(cmMakefile* mf,
@@ -331,6 +289,11 @@
const std::string& cmake_var,
bool suppress = false);
+ /**
+ * Set CMake variables from CTest Options
+ */
+ void SetCMakeVariables(cmMakefile& mf);
+
/** Decode a URL to the original string. */
static std::string DecodeURL(const std::string&);
@@ -348,7 +311,7 @@
void AddCTestConfigurationOverwrite(const std::string& encstr);
/** Create XML file that contains all the notes specified */
- int GenerateNotesFile(std::vector<std::string> const& files);
+ int GenerateNotesFile(cmake* cm, std::vector<std::string> const& files);
/** Create XML file to indicate that build is complete */
int GenerateDoneFile();
@@ -367,9 +330,9 @@
void SetConfigType(const std::string& ct);
/** Various log types */
- enum
+ enum LogType
{
- DEBUG = 0,
+ DEBUG,
OUTPUT,
HANDLER_OUTPUT,
HANDLER_PROGRESS_OUTPUT,
@@ -377,12 +340,10 @@
HANDLER_VERBOSE_OUTPUT,
WARNING,
ERROR_MESSAGE,
- OTHER
};
/** Add log to the output */
- void Log(int logType, const char* file, int line, const char* msg,
- bool suppress = false);
+ void Log(LogType logType, std::string msg, bool suppress = false);
/** Color values */
enum class Color
@@ -409,7 +370,7 @@
/**
* Read the custom configuration files and apply them to the current ctest
*/
- int ReadCustomConfigurationFileTree(const std::string& dir, cmMakefile* mf);
+ void ReadCustomConfigurationFileTree(const std::string& dir, cmMakefile* mf);
std::vector<std::string>& GetInitialCommandLineArguments();
@@ -424,11 +385,11 @@
bool GetVerbose() const;
bool GetExtraVerbose() const;
+ int GetSubmitIndex() const;
- /** Direct process output to given streams. */
- void SetStreams(std::ostream* out, std::ostream* err);
+ void AddSiteProperties(cmXMLWriter& xml, cmake* cm);
- void AddSiteProperties(cmXMLWriter& xml);
+ bool GetInteractiveDebugMode() const;
bool GetLabelSummary() const;
bool GetSubprojectSummary() const;
@@ -462,33 +423,22 @@
void GenerateSubprojectsOutput(cmXMLWriter& xml);
std::vector<std::string> GetLabelsForSubprojects();
- void SetRunCurrentScript(bool value);
+ /** Reread the configuration file */
+ bool UpdateCTestConfiguration();
+
+ cmCTestTestOptions const& GetTestOptions() const;
+ std::vector<std::string> GetCommandLineHttpHeaders() const;
private:
- void SetPersistentOptionIfNotEmpty(const std::string& value,
- const std::string& optionName);
- void AddPersistentMultiOptionIfNotEmpty(const std::string& value,
- const std::string& optionName);
-
- int GenerateNotesFile(const std::string& files);
+ int GenerateNotesFile(cmake* cm, const std::string& files);
void BlockTestErrorDiagnostics();
- /**
- * Initialize a dashboard run in the given build tree. The "command"
- * argument is non-NULL when running from a command-driven (ctest_start)
- * dashboard script, and NULL when running from the CTest command
- * line. Note that a declarative dashboard script does not actually
- * call this method because it sets CTEST_COMMAND to drive a build
- * through the ctest command line.
- */
- int Initialize(const std::string& binary_dir, cmCTestStartCommand* command);
-
/** parse the option after -D and convert it into the appropriate steps */
- bool AddTestsForDashboardType(std::string& targ);
+ bool AddTestsForDashboardType(std::string const& targ);
/** read as "emit an error message for an unknown -D value" */
- void ErrorMessageUnknownDashDValue(std::string& val);
+ void ErrorMessageUnknownDashDValue(std::string const& val);
/** add a variable definition from a command line -D value */
bool AddVariableDefinition(const std::string& arg);
@@ -496,10 +446,6 @@
/** set command line arguments read from a test preset */
bool SetArgsFromPreset(const std::string& presetName, bool listPresets);
- /** parse and process most common command line arguments */
- bool HandleCommandLineArguments(size_t& i, std::vector<std::string>& args,
- std::string& errormsg);
-
#if !defined(_WIN32)
/** returns true iff the console supports progress output */
static bool ConsoleIsNotDumb();
@@ -511,40 +457,18 @@
/** returns true iff the console supports colored output */
static bool ColoredOutputSupportedByConsole();
- /** handle the -S -SP and -SR arguments */
- bool HandleScriptArguments(size_t& i, std::vector<std::string>& args,
- bool& SRArgumentSpecified);
-
- /** Reread the configuration file */
- bool UpdateCTestConfiguration();
-
/** Create note from files. */
- int GenerateCTestNotesOutput(cmXMLWriter& xml,
+ int GenerateCTestNotesOutput(cmXMLWriter& xml, cmake* cm,
std::vector<std::string> const& files);
/** Check if the argument is the one specified */
static bool CheckArgument(const std::string& arg, cm::string_view varg1,
const char* varg2 = nullptr);
- /** Output errors from a test */
- void OutputTestErrors(std::vector<char> const& process_output);
-
- /** Handle the --test-action command line argument */
- bool HandleTestActionArgument(const char* ctestExec, size_t& i,
- const std::vector<std::string>& args,
- bool& validArg);
-
- /** Handle the --test-model command line argument */
- bool HandleTestModelArgument(const char* ctestExec, size_t& i,
- const std::vector<std::string>& args,
- bool& validArg);
-
- int RunCMakeAndTest(std::string* output);
+ int RunCMakeAndTest();
+ int RunScripts(std::vector<std::pair<std::string, bool>> const& scripts);
int ExecuteTests();
- /** return true iff change directory was successful */
- bool TryToChangeDirectory(std::string const& dir);
-
struct Private;
std::unique_ptr<Private> Impl;
};
@@ -553,14 +477,12 @@
do { \
std::ostringstream cmCTestLog_msg; \
cmCTestLog_msg << msg; \
- (ctSelf)->Log(cmCTest::logType, __FILE__, __LINE__, \
- cmCTestLog_msg.str().c_str()); \
+ (ctSelf)->Log(cmCTest::logType, cmCTestLog_msg.str()); \
} while (false)
#define cmCTestOptionalLog(ctSelf, logType, msg, suppress) \
do { \
std::ostringstream cmCTestLog_msg; \
cmCTestLog_msg << msg; \
- (ctSelf)->Log(cmCTest::logType, __FILE__, __LINE__, \
- cmCTestLog_msg.str().c_str(), suppress); \
+ (ctSelf)->Log(cmCTest::logType, cmCTestLog_msg.str(), suppress); \
} while (false)
diff --git a/Source/cmCommand.cxx b/Source/cmCommand.cxx
deleted file mode 100644
index 0c2734e..0000000
--- a/Source/cmCommand.cxx
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmCommand.h"
-
-#include <utility>
-
-#include "cmExecutionStatus.h"
-#include "cmMakefile.h"
-
-struct cmListFileArgument;
-
-void cmCommand::SetExecutionStatus(cmExecutionStatus* status)
-{
- this->Status = status;
- this->Makefile = &status->GetMakefile();
-}
-
-bool cmCommand::InvokeInitialPass(const std::vector<cmListFileArgument>& args,
- cmExecutionStatus& status)
-{
- std::vector<std::string> expandedArguments;
- if (!this->Makefile->ExpandArguments(args, expandedArguments)) {
- // There was an error expanding arguments. It was already
- // reported, so we can skip this command without error.
- return true;
- }
- return this->InitialPass(expandedArguments, status);
-}
-
-void cmCommand::SetError(const std::string& e)
-{
- this->Status->SetError(e);
-}
-
-cmLegacyCommandWrapper::cmLegacyCommandWrapper(std::unique_ptr<cmCommand> cmd)
- : Command(std::move(cmd))
-{
-}
-
-cmLegacyCommandWrapper::cmLegacyCommandWrapper(
- cmLegacyCommandWrapper const& other)
- : Command(other.Command->Clone())
-{
-}
-
-cmLegacyCommandWrapper& cmLegacyCommandWrapper::operator=(
- cmLegacyCommandWrapper const& other)
-{
- this->Command = other.Command->Clone();
- return *this;
-}
-
-bool cmLegacyCommandWrapper::operator()(
- std::vector<cmListFileArgument> const& args, cmExecutionStatus& status) const
-{
- auto cmd = this->Command->Clone();
- cmd->SetExecutionStatus(&status);
- return cmd->InvokeInitialPass(args, status);
-}
diff --git a/Source/cmCommand.h b/Source/cmCommand.h
deleted file mode 100644
index f5a5190..0000000
--- a/Source/cmCommand.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/* 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 <memory>
-#include <string>
-#include <vector>
-
-class cmExecutionStatus;
-class cmMakefile;
-struct cmListFileArgument;
-
-/** \class cmCommand
- * \brief Superclass for all commands in CMake.
- *
- * cmCommand is the base class for all commands in CMake. A command
- * manifests as an entry in CMakeLists.txt and produces one or
- * more makefile rules. Commands are associated with a particular
- * makefile. This base class cmCommand defines the API for commands
- * to support such features as enable/disable, inheritance,
- * documentation, and construction.
- */
-class cmCommand
-{
-public:
- /**
- * Construct the command. By default it has no makefile.
- */
- cmCommand() = default;
-
- /**
- * Need virtual destructor to destroy real command type.
- */
- virtual ~cmCommand() = default;
-
- cmCommand(cmCommand const&) = delete;
- cmCommand& operator=(cmCommand const&) = delete;
-
- /**
- * Specify the makefile.
- */
- cmMakefile* GetMakefile() { return this->Makefile; }
-
- void SetExecutionStatus(cmExecutionStatus* s);
- cmExecutionStatus* GetExecutionStatus() { return this->Status; }
-
- /**
- * This is called by the cmMakefile when the command is first
- * encountered in the CMakeLists.txt file. It expands the command's
- * arguments and then invokes the InitialPass.
- */
- bool InvokeInitialPass(const std::vector<cmListFileArgument>& args,
- cmExecutionStatus& status);
-
- /**
- * This is called when the command is first encountered in
- * the CMakeLists.txt file.
- */
- virtual bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus&) = 0;
-
- /**
- * This is a virtual constructor for the command.
- */
- virtual std::unique_ptr<cmCommand> Clone() = 0;
-
- /**
- * Set the error message
- */
- void SetError(const std::string& e);
-
-protected:
- cmMakefile* Makefile = nullptr;
-
-private:
- cmExecutionStatus* Status = nullptr;
-};
-
-class cmLegacyCommandWrapper
-{
-public:
- explicit cmLegacyCommandWrapper(std::unique_ptr<cmCommand> cmd);
-
- cmLegacyCommandWrapper(cmLegacyCommandWrapper const& other);
- cmLegacyCommandWrapper& operator=(cmLegacyCommandWrapper const& other);
-
- cmLegacyCommandWrapper(cmLegacyCommandWrapper&&) = default;
- cmLegacyCommandWrapper& operator=(cmLegacyCommandWrapper&&) = default;
-
- bool operator()(std::vector<cmListFileArgument> const& args,
- cmExecutionStatus& status) const;
-
-private:
- std::unique_ptr<cmCommand> Command;
-};
diff --git a/Source/cmCommandLineArgument.h b/Source/cmCommandLineArgument.h
index 003e972..15a1f70 100644
--- a/Source/cmCommandLineArgument.h
+++ b/Source/cmCommandLineArgument.h
@@ -2,7 +2,10 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
+#include <cctype>
+
#include <cm/optional>
+#include <cm/string_view>
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
@@ -126,7 +129,7 @@
if (input.size() == this->Name.size()) {
auto nextValueIndex = index + 1;
if (nextValueIndex >= allArgs.size() ||
- allArgs[nextValueIndex][0] == '-') {
+ IsFlag(allArgs[nextValueIndex])) {
if (this->Type == Values::ZeroOrOne) {
parseState =
this->StoreCall(std::string{}, std::forward<CallState>(state)...)
@@ -153,8 +156,8 @@
}
} else if (this->Type == Values::Two) {
if (input.size() == this->Name.size()) {
- if (index + 2 >= allArgs.size() || allArgs[index + 1][0] == '-' ||
- allArgs[index + 2][0] == '-') {
+ if (index + 2 >= allArgs.size() || IsFlag(allArgs[index + 1]) ||
+ IsFlag(allArgs[index + 2])) {
parseState = ParseMode::ValueError;
} else {
index += 2;
@@ -169,12 +172,12 @@
if (input.size() == this->Name.size()) {
auto nextValueIndex = index + 1;
if (nextValueIndex >= allArgs.size() ||
- allArgs[nextValueIndex][0] == '-') {
+ IsFlag(allArgs[nextValueIndex])) {
parseState = ParseMode::ValueError;
} else {
std::string buffer = allArgs[nextValueIndex++];
while (nextValueIndex < allArgs.size() &&
- allArgs[nextValueIndex][0] != '-') {
+ !IsFlag(allArgs[nextValueIndex])) {
buffer = cmStrCat(buffer, ";", allArgs[nextValueIndex++]);
}
parseState =
@@ -281,4 +284,10 @@
}
return std::string(possible_value);
}
+
+ static bool IsFlag(cm::string_view arg)
+ {
+ return !arg.empty() && arg[0] == '-' &&
+ !(arg.size() >= 2 && std::isdigit(arg[1]));
+ }
};
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index 551a45b..fde673a 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -257,7 +257,7 @@
if (processingOption.match(1) == "LIBRARY_TYPE") {
featureAttributes.LibraryTypes.clear();
for (auto const& value :
- cmTokenize(processingOption.match(2), ","_s)) {
+ cmTokenize(processingOption.match(2), ',')) {
if (value == "STATIC") {
featureAttributes.LibraryTypes.emplace(
cmStateEnums::STATIC_LIBRARY);
@@ -292,7 +292,8 @@
}
} else if (processingOption.match(1) == "OVERRIDE") {
featureAttributes.Override.clear();
- auto values = cmTokenize(processingOption.match(2), ","_s);
+ std::vector<std::string> values =
+ cmTokenize(processingOption.match(2), ',');
featureAttributes.Override.insert(values.begin(), values.end());
}
} else {
@@ -668,13 +669,14 @@
*linkLibraryOverride, target->GetLocalGenerator(), config, target, &dag,
target, linkLanguage);
- auto overrideList = cmTokenize(overrideValue, ","_s);
+ std::vector<std::string> overrideList =
+ cmTokenize(overrideValue, ',', cmTokenizerMode::New);
if (overrideList.size() >= 2) {
auto const& feature = overrideList.front();
- for_each(overrideList.cbegin() + 1, overrideList.cend(),
- [this, &feature](std::string const& item) {
- this->LinkLibraryOverride.emplace(item, feature);
- });
+ std::for_each(overrideList.cbegin() + 1, overrideList.cend(),
+ [this, &feature](std::string const& item) {
+ this->LinkLibraryOverride.emplace(item, feature);
+ });
}
}
}
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index c2c210b..5d3cbb4 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -1883,6 +1883,7 @@
// foo ==> -lfoo
// libfoo.a ==> -Wl,-Bstatic -lfoo
+ const cm::string_view LINKER{ "LINKER:" };
BT<std::string> const& item = entry.Item;
if (item.Value[0] == '-' || item.Value[0] == '$' || item.Value[0] == '`') {
@@ -1905,6 +1906,13 @@
this->Items.emplace_back(item, ItemIsPath::No);
return;
}
+ if (cmHasPrefix(item.Value, LINKER)) {
+ std::vector<BT<std::string>> linkerFlag{ 1, item };
+ this->Target->ResolveLinkerWrapper(linkerFlag, this->GetLinkLanguage(),
+ true);
+ this->Items.emplace_back(linkerFlag.front(), ItemIsPath::No);
+ return;
+ }
// Parse out the prefix, base, and suffix components of the
// library name. If the name matches that of a shared or static
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index 4d739ff..6ed3ad4 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -910,6 +910,14 @@
? "OLD"
: "NEW");
+ /* Set the appropriate policy information for the LINKER: prefix expansion
+ */
+ fprintf(fout, "cmake_policy(SET CMP0181 %s)\n",
+ this->Makefile->GetPolicyStatus(cmPolicies::CMP0181) ==
+ cmPolicies::NEW
+ ? "NEW"
+ : "OLD");
+
// Workaround for -Wl,-headerpad_max_install_names issue until we can avoid
// adding that flag in the platform and compiler language files
fprintf(fout,
diff --git a/Source/cmDebuggerAdapter.cxx b/Source/cmDebuggerAdapter.cxx
index c2e0d4f..c3587a1 100644
--- a/Source/cmDebuggerAdapter.cxx
+++ b/Source/cmDebuggerAdapter.cxx
@@ -70,7 +70,7 @@
{
}
- inline void Notify()
+ void Notify()
{
std::unique_lock<std::mutex> lock(Mutex);
Count++;
@@ -78,7 +78,7 @@
Cv.notify_one();
}
- inline void Wait()
+ void Wait()
{
std::unique_lock<std::mutex> lock(Mutex);
while (Count == 0) {
@@ -148,6 +148,7 @@
SupportsVariableType = req.supportsVariableType.value(false);
dap::CMakeInitializeResponse response;
response.supportsConfigurationDoneRequest = true;
+ response.supportsValueFormattingOptions = true;
response.cmakeVersion.major = CMake_VERSION_MAJOR;
response.cmakeVersion.minor = CMake_VERSION_MINOR;
response.cmakeVersion.patch = CMake_VERSION_PATCH;
@@ -186,7 +187,7 @@
std::unique_lock<std::mutex> lock(Mutex);
cm::optional<dap::StackTraceResponse> response =
- ThreadManager->GetThreadStackTraceResponse(request.threadId);
+ ThreadManager->GetThreadStackTraceResponse(request);
if (response.has_value()) {
return response.value();
}
diff --git a/Source/cmDebuggerStackFrame.cxx b/Source/cmDebuggerStackFrame.cxx
index 789b0a5..89cdbc6 100644
--- a/Source/cmDebuggerStackFrame.cxx
+++ b/Source/cmDebuggerStackFrame.cxx
@@ -25,4 +25,10 @@
return this->Function.Line();
}
+std::vector<cmListFileArgument> const& cmDebuggerStackFrame::GetArguments()
+ const noexcept
+{
+ return this->Function.Arguments();
+}
+
} // namespace cmDebugger
diff --git a/Source/cmDebuggerStackFrame.h b/Source/cmDebuggerStackFrame.h
index f4e6612..2133bcd 100644
--- a/Source/cmDebuggerStackFrame.h
+++ b/Source/cmDebuggerStackFrame.h
@@ -7,8 +7,10 @@
#include <atomic>
#include <cstdint>
#include <string>
+#include <vector>
class cmListFileFunction;
+struct cmListFileArgument;
class cmMakefile;
namespace cmDebugger {
@@ -32,6 +34,7 @@
{
return this->Function;
}
+ std::vector<cmListFileArgument> const& GetArguments() const noexcept;
};
} // namespace cmDebugger
diff --git a/Source/cmDebuggerThread.cxx b/Source/cmDebuggerThread.cxx
index f7a1778..047dd2d 100644
--- a/Source/cmDebuggerThread.cxx
+++ b/Source/cmDebuggerThread.cxx
@@ -14,6 +14,7 @@
#include "cmDebuggerVariablesHelper.h"
#include "cmDebuggerVariablesManager.h"
#include "cmListFileCache.h"
+#include "cmStringAlgorithms.h"
namespace cmDebugger {
@@ -117,8 +118,27 @@
}
dap::StackTraceResponse GetStackTraceResponse(
- std::shared_ptr<cmDebuggerThread> const& thread)
+ std::shared_ptr<cmDebuggerThread> const& thread,
+ dap::optional<dap::StackFrameFormat> format)
{
+ dap::boolean showParameters = false;
+ dap::boolean showParameterValues = false;
+ dap::boolean showLine = false;
+ if (format.has_value()) {
+ auto formatValue = format.value();
+ if (formatValue.parameters.has_value()) {
+ showParameters = formatValue.parameters.value();
+ }
+
+ if (formatValue.parameterValues.has_value()) {
+ showParameterValues = formatValue.parameterValues.value();
+ }
+
+ if (formatValue.line.has_value()) {
+ showLine = formatValue.line.value();
+ }
+ }
+
dap::StackTraceResponse response;
std::unique_lock<std::mutex> lock(thread->Mutex);
for (int i = static_cast<int>(thread->Frames.size()) - 1; i >= 0; --i) {
@@ -136,10 +156,29 @@
#endif
stackFrame.line = thread->Frames[i]->GetLine();
stackFrame.column = 1;
- stackFrame.name = thread->Frames[i]->GetFunction().OriginalName();
stackFrame.id = thread->Frames[i]->GetId();
stackFrame.source = source;
+ auto stackName = thread->Frames[i]->GetFunction().OriginalName();
+ if (showParameters) {
+ stackName.push_back('(');
+ if (showParameterValues && !thread->Frames[i]->GetArguments().empty()) {
+ for (auto const& arg : thread->Frames[i]->GetArguments()) {
+ stackName = cmStrCat(stackName, arg.Value, ", ");
+ }
+
+ stackName.erase(stackName.end() - 2, stackName.end());
+ }
+
+ stackName.push_back(')');
+ }
+
+ if (showLine) {
+ stackName =
+ cmStrCat(stackName, " Line: ", static_cast<int64_t>(stackFrame.line));
+ }
+
+ stackFrame.name = stackName;
response.stackFrames.push_back(stackFrame);
}
diff --git a/Source/cmDebuggerThread.h b/Source/cmDebuggerThread.h
index 65ee2cf..81664b5 100644
--- a/Source/cmDebuggerThread.h
+++ b/Source/cmDebuggerThread.h
@@ -23,6 +23,11 @@
class cmDebuggerVariablesManager;
}
+namespace dap {
+template <typename T>
+class optional;
+}
+
namespace cmDebugger {
class cmDebuggerThread
@@ -53,7 +58,8 @@
dap::VariablesResponse GetVariablesResponse(
dap::VariablesRequest const& request);
friend dap::StackTraceResponse GetStackTraceResponse(
- std::shared_ptr<cmDebuggerThread> const& thread);
+ std::shared_ptr<cmDebuggerThread> const& thread,
+ dap::optional<dap::StackFrameFormat> format);
};
} // namespace cmDebugger
diff --git a/Source/cmDebuggerThreadManager.cxx b/Source/cmDebuggerThreadManager.cxx
index 0eb443b..0f15b6b 100644
--- a/Source/cmDebuggerThreadManager.cxx
+++ b/Source/cmDebuggerThreadManager.cxx
@@ -6,6 +6,7 @@
#include <algorithm>
#include <cm3p/cppdap/protocol.h>
+#include <cm3p/cppdap/types.h>
#include "cmDebuggerThread.h"
@@ -30,18 +31,19 @@
}
cm::optional<dap::StackTraceResponse>
-cmDebuggerThreadManager::GetThreadStackTraceResponse(int64_t id)
+cmDebuggerThreadManager::GetThreadStackTraceResponse(
+ const dap::StackTraceRequest& request)
{
auto it = find_if(Threads.begin(), Threads.end(),
[&](const std::shared_ptr<cmDebuggerThread>& t) {
- return t->GetId() == id;
+ return t->GetId() == request.threadId;
});
if (it == Threads.end()) {
return {};
}
- return GetStackTraceResponse(*it);
+ return GetStackTraceResponse(*it, request.format);
}
} // namespace cmDebugger
diff --git a/Source/cmDebuggerThreadManager.h b/Source/cmDebuggerThreadManager.h
index 934cf85..6d27a5c 100644
--- a/Source/cmDebuggerThreadManager.h
+++ b/Source/cmDebuggerThreadManager.h
@@ -17,6 +17,7 @@
}
namespace dap {
+struct StackTraceRequest;
struct StackTraceResponse;
}
@@ -32,7 +33,7 @@
std::shared_ptr<cmDebuggerThread> StartThread(std::string const& name);
void EndThread(std::shared_ptr<cmDebuggerThread> const& thread);
cm::optional<dap::StackTraceResponse> GetThreadStackTraceResponse(
- std::int64_t id);
+ const dap::StackTraceRequest& request);
};
} // namespace cmDebugger
diff --git a/Source/cmDebuggerVariables.h b/Source/cmDebuggerVariables.h
index 753b811..0c4a416 100644
--- a/Source/cmDebuggerVariables.h
+++ b/Source/cmDebuggerVariables.h
@@ -102,22 +102,16 @@
std::shared_ptr<cmDebuggerVariablesManager> variablesManager,
std::string name, bool supportsVariableType,
std::function<std::vector<cmDebuggerVariableEntry>()> getKeyValuesFunc);
- inline int64_t GetId() const noexcept { return this->Id; }
- inline std::string GetName() const noexcept { return this->Name; }
- inline std::string GetValue() const noexcept { return this->Value; }
- inline void SetValue(std::string const& value) noexcept
- {
- this->Value = value;
- }
+ int64_t GetId() const noexcept { return this->Id; }
+ std::string GetName() const noexcept { return this->Name; }
+ std::string GetValue() const noexcept { return this->Value; }
+ void SetValue(std::string const& value) noexcept { this->Value = value; }
void AddSubVariables(std::shared_ptr<cmDebuggerVariables> const& variables);
- inline void SetIgnoreEmptyStringEntries(bool value) noexcept
+ void SetIgnoreEmptyStringEntries(bool value) noexcept
{
this->IgnoreEmptyStringEntries = value;
}
- inline void SetEnableSorting(bool value) noexcept
- {
- this->EnableSorting = value;
- }
+ void SetEnableSorting(bool value) noexcept { this->EnableSorting = value; }
virtual ~cmDebuggerVariables();
};
diff --git a/Source/cmDependsCompiler.cxx b/Source/cmDependsCompiler.cxx
index 17ec43b..408f19f 100644
--- a/Source/cmDependsCompiler.cxx
+++ b/Source/cmDependsCompiler.cxx
@@ -4,7 +4,6 @@
#include "cmDependsCompiler.h"
#include <algorithm>
-#include <iterator>
#include <map>
#include <string>
#include <unordered_set>
@@ -111,13 +110,9 @@
// copy depends for each target, except first one, which can be
// moved
for (auto index = entry.rules.size() - 1; index > 0; --index) {
- auto& rule_deps = dependencies[entry.rules[index]];
- rule_deps.insert(rule_deps.end(), depends.cbegin(),
- depends.cend());
+ dependencies[entry.rules[index]] = depends;
}
- auto& rule_deps = dependencies[entry.rules.front()];
- std::move(depends.cbegin(), depends.cend(),
- std::back_inserter(rule_deps));
+ dependencies[entry.rules.front()] = std::move(depends);
}
} else {
if (format == "msvc"_s) {
diff --git a/Source/cmDocumentationEntry.h b/Source/cmDocumentationEntry.h
index d971836..2a26ecd 100644
--- a/Source/cmDocumentationEntry.h
+++ b/Source/cmDocumentationEntry.h
@@ -17,7 +17,7 @@
}
#endif
- std::string Name = {};
- std::string Brief = {};
+ std::string Name;
+ std::string Brief;
char CustomNamePrefix = ' ';
};
diff --git a/Source/cmDocumentationFormatter.cxx b/Source/cmDocumentationFormatter.cxx
index b85b2f5..0c22259 100644
--- a/Source/cmDocumentationFormatter.cxx
+++ b/Source/cmDocumentationFormatter.cxx
@@ -5,175 +5,144 @@
#include <algorithm> // IWYU pragma: keep
#include <cassert>
#include <iomanip>
+#include <iterator>
#include <ostream>
#include <string>
#include <vector>
+#include <cm/string_view>
+#include <cmext/string_view>
+
#include "cmDocumentationEntry.h"
#include "cmDocumentationSection.h"
+#include "cmStringAlgorithms.h"
namespace {
-const char* skipSpaces(const char* ptr)
-{
- assert(ptr);
- for (; *ptr == ' '; ++ptr) {
- ;
- }
- return ptr;
-}
-const char* skipToSpace(const char* ptr)
-{
- assert(ptr);
- for (; *ptr && (*ptr != '\n') && (*ptr != ' '); ++ptr) {
- ;
- }
- return ptr;
-}
-}
+const auto EOL = "\n"_s;
+const auto SPACE = " "_s;
+const auto TWO_SPACES = " "_s;
+const auto MAX_WIDTH_PADDING =
+ std::string(cmDocumentationFormatter::TEXT_WIDTH, ' ');
-void cmDocumentationFormatter::PrintFormatted(std::ostream& os,
- std::string const& text) const
+void FormatLine(std::back_insert_iterator<std::vector<cm::string_view>> outIt,
+ const cm::string_view text, const cm::string_view padding)
{
- if (text.empty()) {
+ auto tokens = cmTokenizedView(text, ' ', cmTokenizerMode::New);
+ if (tokens.empty()) {
return;
}
- struct Buffer
- {
- // clang-format off
- using PrinterFn = void (cmDocumentationFormatter::*)(
- std::ostream&, std::string const&
- ) const;
- // clang-format on
- std::string collected;
- const PrinterFn printer;
- };
- // const auto NORMAL_IDX = 0u;
- const auto PREFORMATTED_IDX = 1u;
- const auto HANDLERS_SIZE = 2u;
- Buffer buffers[HANDLERS_SIZE] = {
- { {}, &cmDocumentationFormatter::PrintParagraph },
- { {}, &cmDocumentationFormatter::PrintPreformatted }
- };
-
- const auto padding = std::string(this->TextIndent, ' ');
-
- for (std::size_t pos = 0u, eol = 0u; pos < text.size(); pos = eol) {
- const auto current_idx = std::size_t(text[pos] == ' ');
- // size_t(!bool(current_idx))
- const auto other_idx = current_idx ^ 1u;
-
- // Flush the other buffer if anything has been collected
- if (!buffers[other_idx].collected.empty()) {
- // NOTE Whatever the other index is, the current buffered
- // string expected to be empty.
- assert(buffers[current_idx].collected.empty());
-
- (this->*buffers[other_idx].printer)(os, buffers[other_idx].collected);
- buffers[other_idx].collected.clear();
- }
-
- // ATTENTION The previous implementation had called `PrintParagraph()`
- // **for every processed (char by char) input line**.
- // The method unconditionally append the `\n' character after the
- // printed text. To keep the backward-compatible behavior it's needed to
- // add the '\n' character to the previously collected line...
- if (!buffers[current_idx].collected.empty() &&
- current_idx != PREFORMATTED_IDX) {
- buffers[current_idx].collected += '\n';
- }
-
- // Lookup EOL
- eol = text.find('\n', pos);
- if (current_idx == PREFORMATTED_IDX) {
- buffers[current_idx].collected.append(padding);
- }
- buffers[current_idx].collected.append(
- text, pos, eol == std::string::npos ? eol : ++eol - pos);
+ // Push padding in front of a first line
+ if (!padding.empty()) {
+ outIt = padding;
}
- for (auto& buf : buffers) {
- if (!buf.collected.empty()) {
- (this->*buf.printer)(os, buf.collected);
- }
- }
-}
+ auto currentWidth = padding.size();
+ auto newSentence = false;
-void cmDocumentationFormatter::PrintPreformatted(std::ostream& os,
- std::string const& text) const
-{
- os << text << '\n';
-}
-
-void cmDocumentationFormatter::PrintParagraph(std::ostream& os,
- std::string const& text) const
-{
- if (this->TextIndent) {
- os << std::string(this->TextIndent, ' ');
- }
- this->PrintColumn(os, text);
- os << '\n';
-}
-
-void cmDocumentationFormatter::PrintColumn(std::ostream& os,
- std::string const& text) const
-{
- // Print text arranged in an indented column of fixed width.
- bool newSentence = false;
- bool firstLine = true;
-
- assert(this->TextIndent < this->TextWidth);
- const std::ptrdiff_t width = this->TextWidth - this->TextIndent;
- std::ptrdiff_t column = 0;
-
- // Loop until the end of the text.
- for (const char *l = text.c_str(), *r = skipToSpace(text.c_str()); *l;
- l = skipSpaces(r), r = skipToSpace(l)) {
- // Does it fit on this line?
- if (r - l < width - column - std::ptrdiff_t(newSentence)) {
- // Word fits on this line.
- if (r > l) {
- if (column) {
- // Not first word on line. Separate from the previous word
- // by a space, or two if this is a new sentence.
- os << &(" "[std::size_t(!newSentence)]);
- column += 1u + std::ptrdiff_t(newSentence);
- } else if (!firstLine && this->TextIndent) {
- // First word on line. Print indentation unless this is the
- // first line.
- os << std::string(this->TextIndent, ' ');
- }
-
- // Print the word.
- os.write(l, r - l);
- newSentence = (*(r - 1) == '.');
+ for (auto token : tokens) {
+ // It's no need to add a space if this is a very first
+ // word on a line.
+ const auto needSpace = currentWidth > padding.size();
+ // Evaluate the size of a current token + possibly spaces before it.
+ const auto tokenWithSpaceSize = token.size() + std::size_t(needSpace) +
+ std::size_t(needSpace && newSentence);
+ // Check if a current word fits on a line.
+ // Also, take in account:
+ // - extra space if not a first word on a line
+ // - extra space if last token ends w/ a period
+ if (currentWidth + tokenWithSpaceSize <=
+ cmDocumentationFormatter::TEXT_WIDTH) {
+ // If not a first word on a line...
+ if (needSpace) {
+ // ... add a space after the last token +
+ // possibly one more space if the last token
+ // ends with a period (means, end of a sentence).
+ outIt = newSentence ? TWO_SPACES : SPACE;
}
-
- if (*r == '\n') {
- // Text provided a newline. Start a new line.
- os << '\n';
- ++r;
- column = 0;
- firstLine = false;
- } else {
- // No provided newline. Continue this line.
- column += r - l;
- }
+ outIt = token;
+ currentWidth += tokenWithSpaceSize;
} else {
- // Word does not fit on this line. Start a new line.
- os << '\n';
- firstLine = false;
- if (r > l) {
- os << std::string(this->TextIndent, ' ');
- os.write(l, r - l);
- column = r - l;
- newSentence = (*(r - 1) == '.');
- } else {
- column = 0;
+ // Start a new line!
+ outIt = EOL;
+ if (!padding.empty()) {
+ outIt = padding;
}
+ outIt = token;
+ currentWidth = padding.size() + token.size();
}
- // Move to beginning of next word. Skip over whitespace.
+
+ // Start a new sentence if the current word ends with period
+ newSentence = token.back() == '.';
}
+ // Always add EOL at the end of formatted text
+ outIt = EOL;
+}
+} // anonymous namespace
+
+std::string cmDocumentationFormatter::Format(std::string text) const
+{
+ // Exit early on empty text
+ if (text.empty()) {
+ return {};
+ }
+
+ assert(this->TextIndent < this->TEXT_WIDTH);
+
+ const auto padding =
+ cm::string_view(MAX_WIDTH_PADDING.c_str(), this->TextIndent);
+
+ std::vector<cm::string_view> tokens;
+ auto outIt = std::back_inserter(tokens);
+ auto prevWasPreFormatted = false;
+
+ // NOTE Can't use `cmTokenizedView()` cuz every sequential EOL does matter
+ // (and `cmTokenizedView()` will squeeze 'em)
+ for ( // clang-format off
+ std::string::size_type start = 0
+ , end = text.find('\n')
+ ; start < text.size()
+ ; start = end + ((end != std::string::npos) ? 1 : 0)
+ , end = text.find('\n', start)
+ ) // clang-format on
+ {
+ const auto isLastLine = end == std::string::npos;
+ const auto line = isLastLine
+ ? cm::string_view{ text.c_str() + start }
+ : cm::string_view{ text.c_str() + start, end - start };
+
+ if (!line.empty() && line.front() == ' ') {
+ // Preformatted lines go as is w/ a leading padding
+ if (!padding.empty()) {
+ outIt = padding;
+ }
+ outIt = line;
+ prevWasPreFormatted = true;
+ } else {
+ // Separate a normal paragraph from a pre-formatted
+ // w/ an extra EOL
+ if (prevWasPreFormatted) {
+ outIt = EOL;
+ }
+ if (line.empty()) {
+ if (!isLastLine) {
+ outIt = EOL;
+ }
+ } else {
+ FormatLine(outIt, line, padding);
+ }
+ prevWasPreFormatted = false;
+ }
+ if (!isLastLine) {
+ outIt = EOL;
+ }
+ }
+
+ if (prevWasPreFormatted) {
+ outIt = EOL;
+ }
+
+ return cmJoinStrings(tokens, {}, {});
}
void cmDocumentationFormatter::PrintSection(
@@ -202,13 +171,10 @@
if (entry.Name.size() > NAME_SIZE) {
os << '\n' << std::setw(int(this->TextIndent - PREFIX_SIZE)) << ' ';
}
- os << "= ";
- this->PrintColumn(os, entry.Brief);
- os << '\n';
+ os << "= " << this->Format(entry.Brief).substr(this->TextIndent);
} else {
- os << '\n';
this->TextIndent = 0u;
- this->PrintFormatted(os, entry.Brief);
+ os << '\n' << this->Format(entry.Brief);
}
}
diff --git a/Source/cmDocumentationFormatter.h b/Source/cmDocumentationFormatter.h
index 9d35e0a..77606cf 100644
--- a/Source/cmDocumentationFormatter.h
+++ b/Source/cmDocumentationFormatter.h
@@ -14,15 +14,20 @@
class cmDocumentationFormatter
{
public:
- void SetIndent(std::size_t indent) { this->TextIndent = indent; }
- void PrintFormatted(std::ostream& os, std::string const& text) const;
+ std::string Format(std::string text) const;
void PrintSection(std::ostream& os, cmDocumentationSection const& section);
+ void PrintFormatted(std::ostream& os, std::string const& text) const
+ {
+ os << this->Format(text);
+ }
+ void SetIndent(std::size_t indent) { this->TextIndent = indent; }
+
+ static constexpr std::size_t TEXT_WIDTH = 77u;
private:
void PrintPreformatted(std::ostream& os, std::string const&) const;
void PrintParagraph(std::ostream& os, std::string const&) const;
void PrintColumn(std::ostream& os, std::string const&) const;
- std::size_t TextWidth = 77u;
std::size_t TextIndent = 0u;
};
diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx
index 003f47b..99d0ba4 100644
--- a/Source/cmELF.cxx
+++ b/Source/cmELF.cxx
@@ -509,7 +509,7 @@
return 0;
}
ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
- return static_cast<unsigned long>(sec.sh_offset + sec.sh_entsize * j);
+ return sec.sh_offset + sec.sh_entsize * static_cast<unsigned long>(j);
}
template <class Types>
diff --git a/Source/cmExportCMakeConfigGenerator.cxx b/Source/cmExportCMakeConfigGenerator.cxx
index 4f4765c..522c1c8 100644
--- a/Source/cmExportCMakeConfigGenerator.cxx
+++ b/Source/cmExportCMakeConfigGenerator.cxx
@@ -185,7 +185,7 @@
// Isolate the file policy level.
// Support CMake versions as far back as the
// RequiredCMakeVersion{Major,Minor,Patch}, but also support using NEW
- // policy settings for up to CMake 3.29 (this upper limit may be reviewed
+ // policy settings for up to CMake 3.30 (this upper limit may be reviewed
// and increased from time to time). This reduces the opportunity for CMake
// warnings when an older export file is later used with newer CMake
// versions.
@@ -194,7 +194,7 @@
<< "cmake_policy(VERSION "
<< this->RequiredCMakeVersionMajor << '.'
<< this->RequiredCMakeVersionMinor << '.'
- << this->RequiredCMakeVersionPatch << "...3.29)\n";
+ << this->RequiredCMakeVersionPatch << "...3.30)\n";
/* clang-format on */
}
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 92e6b3e..e6fe94b 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -1409,8 +1409,7 @@
auto basePath = cmCMakePath{ *arguments.BaseDirectory };
path = basePath.Append(path);
}
- result = cmSystemTools::GetActualCaseForPath(
- cmSystemTools::GetRealPath(path.String()));
+ result = cmSystemTools::GetRealPath(path.String());
};
std::string realPath;
@@ -3846,14 +3845,13 @@
if (!cmSystemTools::FileIsFullPath(inFile)) {
inFile =
- cmStrCat(cmSystemTools::GetCurrentWorkingDirectory(), "/", inFile);
+ cmStrCat(cmSystemTools::GetLogicalWorkingDirectory(), "/", inFile);
}
}
cmWorkingDirectory workdir(destDir);
if (workdir.Failed()) {
- status.SetError(
- cmStrCat("failed to change working directory to: ", destDir));
+ status.SetError(workdir.GetError());
cmSystemTools::SetFatalErrorOccurred();
return false;
}
diff --git a/Source/cmFileCopier.cxx b/Source/cmFileCopier.cxx
index 686162b..47d3d51 100644
--- a/Source/cmFileCopier.cxx
+++ b/Source/cmFileCopier.cxx
@@ -713,7 +713,7 @@
if (!source.empty()) {
dir.Load(source);
}
- unsigned long numFiles = static_cast<unsigned long>(dir.GetNumberOfFiles());
+ unsigned long numFiles = dir.GetNumberOfFiles();
for (unsigned long fileNum = 0; fileNum < numFiles; ++fileNum) {
if (!(strcmp(dir.GetFile(fileNum), ".") == 0 ||
strcmp(dir.GetFile(fileNum), "..") == 0)) {
diff --git a/Source/cmFileLock.cxx b/Source/cmFileLock.cxx
index 548e327..64fbc1f 100644
--- a/Source/cmFileLock.cxx
+++ b/Source/cmFileLock.cxx
@@ -14,6 +14,9 @@
this->File = other.File;
other.File = (decltype(other.File))-1;
this->Filename = std::move(other.Filename);
+#if defined(_WIN32)
+ this->Overlapped = std::move(other.Overlapped);
+#endif
}
cmFileLock::~cmFileLock()
@@ -30,6 +33,9 @@
this->File = other.File;
other.File = (decltype(other.File))-1;
this->Filename = std::move(other.Filename);
+#if defined(_WIN32)
+ this->Overlapped = std::move(other.Overlapped);
+#endif
return *this;
}
diff --git a/Source/cmFileLock.h b/Source/cmFileLock.h
index 0f2e7d9..e17f8bc 100644
--- a/Source/cmFileLock.h
+++ b/Source/cmFileLock.h
@@ -7,6 +7,7 @@
#include <string>
#if defined(_WIN32)
+# include <memory>
using HANDLE = void*;
#endif
@@ -54,6 +55,7 @@
#if defined(_WIN32)
HANDLE File = (HANDLE)-1;
+ std::unique_ptr<struct _OVERLAPPED> Overlapped;
int LockFile(int flags);
#else
int File = -1;
diff --git a/Source/cmFileLockWin32.cxx b/Source/cmFileLockWin32.cxx
index 244ade2..8a4dadc 100644
--- a/Source/cmFileLockWin32.cxx
+++ b/Source/cmFileLockWin32.cxx
@@ -1,12 +1,18 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
-#include <windows.h> // CreateFileW
+#include <cm/memory>
+
+#include <windows.h>
#include "cmFileLock.h"
#include "cmSystemTools.h"
+static const unsigned long LOCK_LEN = static_cast<unsigned long>(-1);
+
cmFileLock::cmFileLock()
+ : Overlapped(cm::make_unique<OVERLAPPED>())
{
+ ZeroMemory(this->Overlapped.get(), sizeof(*this->Overlapped));
}
cmFileLockResult cmFileLock::Release()
@@ -14,15 +20,16 @@
if (this->Filename.empty()) {
return cmFileLockResult::MakeOk();
}
- const unsigned long len = static_cast<unsigned long>(-1);
- static OVERLAPPED overlapped;
const DWORD reserved = 0;
+ ZeroMemory(this->Overlapped.get(), sizeof(*this->Overlapped));
+
const BOOL unlockResult =
- UnlockFileEx(File, reserved, len, len, &overlapped);
+ UnlockFileEx(File, reserved, LOCK_LEN, LOCK_LEN, this->Overlapped.get());
this->Filename = "";
CloseHandle(this->File);
+
this->File = INVALID_HANDLE_VALUE;
if (unlockResult) {
@@ -51,37 +58,63 @@
cmFileLockResult cmFileLock::LockWithoutTimeout()
{
+ cmFileLockResult lock_result = cmFileLockResult::MakeOk();
if (!this->LockFile(LOCKFILE_EXCLUSIVE_LOCK)) {
- return cmFileLockResult::MakeSystem();
- } else {
- return cmFileLockResult::MakeOk();
+ lock_result = cmFileLockResult::MakeSystem();
}
+ CloseHandle(this->Overlapped->hEvent);
+ return lock_result;
}
cmFileLockResult cmFileLock::LockWithTimeout(unsigned long seconds)
{
+ cmFileLockResult lock_result = cmFileLockResult::MakeOk();
const DWORD flags = LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY;
- while (true) {
- const BOOL result = this->LockFile(flags);
- if (result) {
- return cmFileLockResult::MakeOk();
+ bool in_time = true;
+ while (in_time && !this->LockFile(flags)) {
+ switch (GetLastError()) {
+ case ERROR_INVALID_HANDLE:
+ lock_result = cmFileLockResult::MakeSystem();
+ break;
+ case ERROR_LOCK_VIOLATION:
+ if (seconds == 0) {
+ in_time = false;
+ lock_result = cmFileLockResult::MakeTimeout();
+ continue;
+ }
+ --seconds;
+ cmSystemTools::Delay(1000);
+ continue;
+ case ERROR_IO_PENDING:
+ switch (
+ WaitForSingleObject(this->Overlapped->hEvent, seconds * 1000)) {
+ case WAIT_OBJECT_0:
+ break;
+ case WAIT_TIMEOUT:
+ lock_result = cmFileLockResult::MakeTimeout();
+ break;
+ default:
+ lock_result = cmFileLockResult::MakeSystem();
+ break;
+ }
+ break;
+ default:
+ lock_result = cmFileLockResult::MakeSystem();
+ break;
}
- const DWORD error = GetLastError();
- if (error != ERROR_LOCK_VIOLATION) {
- return cmFileLockResult::MakeSystem();
- }
- if (seconds == 0) {
- return cmFileLockResult::MakeTimeout();
- }
- --seconds;
- cmSystemTools::Delay(1000);
}
+ CloseHandle(this->Overlapped->hEvent);
+ return lock_result;
}
int cmFileLock::LockFile(int flags)
{
const DWORD reserved = 0;
- const unsigned long len = static_cast<unsigned long>(-1);
- static OVERLAPPED overlapped;
- return LockFileEx(this->File, flags, reserved, len, len, &overlapped);
+
+ this->Overlapped->hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
+ if (this->Overlapped->hEvent == nullptr) {
+ return false;
+ }
+ return LockFileEx(this->File, flags, reserved, LOCK_LEN, LOCK_LEN,
+ this->Overlapped.get());
}
diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx
index 81e081c..ed29b82 100644
--- a/Source/cmFindBase.cxx
+++ b/Source/cmFindBase.cxx
@@ -56,7 +56,9 @@
} else if (argsIn[j] == "ENV") {
if (j + 1 < size) {
j++;
- cmSystemTools::GetPath(args, argsIn[j].c_str());
+ std::vector<std::string> p =
+ cmSystemTools::GetEnvPathNormalized(argsIn[j]);
+ std::move(p.begin(), p.end(), std::back_inserter(args));
}
} else {
args.push_back(argsIn[j]);
@@ -338,7 +340,6 @@
struct entry_to_remove
{
entry_to_remove(std::string const& name, cmMakefile* makefile)
- : value()
{
if (cmValue to_skip = makefile->GetDefinition(
cmStrCat("_CMAKE_SYSTEM_PREFIX_PATH_", name, "_PREFIX_COUNT"))) {
@@ -404,9 +405,11 @@
cmList expanded{ *prefix_paths };
install_entry.remove_self(expanded);
staging_entry.remove_self(expanded);
-
- paths.AddPrefixPaths(expanded,
- this->Makefile->GetCurrentSourceDirectory().c_str());
+ for (std::string& p : expanded) {
+ p = cmSystemTools::CollapseFullPath(
+ p, this->Makefile->GetCurrentSourceDirectory());
+ }
+ paths.AddPrefixPaths(expanded);
} else if (add_install_prefix && !install_prefix_in_list) {
paths.AddCMakePrefixPath("CMAKE_INSTALL_PREFIX");
paths.AddCMakePrefixPath("CMAKE_STAGING_PREFIX");
@@ -494,7 +497,6 @@
this->Makefile->GetCMakeInstance()->GetCMakeWorkingDirectory()))
.Normal()
.GenericString();
- // value = cmSystemTools::CollapseFullPath(*existingValue);
if (!cmSystemTools::FileExists(value, false)) {
value = *existingValue;
}
diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx
index 9df7665..c5a6038 100644
--- a/Source/cmFindLibraryCommand.cxx
+++ b/Source/cmFindLibraryCommand.cxx
@@ -220,9 +220,6 @@
};
std::vector<Name> Names;
- // Current full path under consideration.
- std::string TestPath;
-
void RegexFromLiteral(std::string& out, std::string const& in);
void RegexFromList(std::string& out, cmList const& in);
size_type GetPrefixIndex(std::string const& prefix)
@@ -423,20 +420,17 @@
// one cannot tell just from the library name whether it is a static
// library or an import library).
if (name.TryRaw) {
- this->TestPath = cmStrCat(path, name.Raw);
+ std::string testPath = cmStrCat(path, name.Raw);
- const bool exists = cmSystemTools::FileExists(this->TestPath, true);
- if (!exists) {
- this->DebugLibraryFailed(name.Raw, path);
- } else {
- auto testPath = cmSystemTools::CollapseFullPath(this->TestPath);
+ if (cmSystemTools::FileExists(testPath, true)) {
+ testPath = cmSystemTools::ToNormalizedPathOnDisk(testPath);
if (this->Validate(testPath)) {
this->DebugLibraryFound(name.Raw, path);
this->BestPath = testPath;
return true;
}
- this->DebugLibraryFailed(name.Raw, path);
}
+ this->DebugLibraryFailed(name.Raw, path);
}
// No library file has yet been found.
@@ -446,9 +440,7 @@
unsigned int bestMinor = 0;
// Search for a file matching the library name regex.
- std::string dir = path;
- cmSystemTools::ConvertToUnixSlashes(dir);
- std::set<std::string> const& files = this->GG->GetDirectoryContent(dir);
+ std::set<std::string> const& files = this->GG->GetDirectoryContent(path);
for (std::string const& origName : files) {
#if defined(_WIN32) || defined(__APPLE__)
std::string testName = cmSystemTools::LowerCase(origName);
@@ -456,14 +448,15 @@
std::string const& testName = origName;
#endif
if (name.Regex.find(testName)) {
- this->TestPath = cmStrCat(path, origName);
+ std::string testPath = cmStrCat(path, origName);
// Make sure the path is readable and is not a directory.
- if (cmSystemTools::FileExists(this->TestPath, true)) {
- if (!this->Validate(cmSystemTools::CollapseFullPath(this->TestPath))) {
+ if (cmSystemTools::FileExists(testPath, true)) {
+ testPath = cmSystemTools::ToNormalizedPathOnDisk(testPath);
+ if (!this->Validate(testPath)) {
continue;
}
- this->DebugLibraryFound(name.Raw, dir);
+ this->DebugLibraryFound(name.Raw, path);
// This is a matching file. Check if it is better than the
// best name found so far. Earlier prefixes are preferred,
// followed by earlier suffixes. For OpenBSD, shared library
@@ -480,7 +473,7 @@
(prefix == bestPrefix && suffix == bestSuffix &&
(major > bestMajor ||
(major == bestMajor && minor > bestMinor)))) {
- this->BestPath = this->TestPath;
+ this->BestPath = testPath;
bestPrefix = prefix;
bestSuffix = suffix;
bestMajor = major;
@@ -491,7 +484,7 @@
}
if (this->BestPath.empty()) {
- this->DebugLibraryFailed(name.Raw, dir);
+ this->DebugLibraryFailed(name.Raw, path);
} else {
this->DebugLibraryFound(name.Raw, this->BestPath);
}
@@ -560,7 +553,7 @@
for (std::string const& n : this->Names) {
fwPath = cmStrCat(d, n, ".xcframework");
if (cmSystemTools::FileIsDirectory(fwPath)) {
- auto finalPath = cmSystemTools::CollapseFullPath(fwPath);
+ auto finalPath = cmSystemTools::ToNormalizedPathOnDisk(fwPath);
if (this->Validate(finalPath)) {
return finalPath;
}
@@ -568,7 +561,7 @@
fwPath = cmStrCat(d, n, ".framework");
if (cmSystemTools::FileIsDirectory(fwPath)) {
- auto finalPath = cmSystemTools::CollapseFullPath(fwPath);
+ auto finalPath = cmSystemTools::ToNormalizedPathOnDisk(fwPath);
if (this->Validate(finalPath)) {
return finalPath;
}
@@ -588,7 +581,7 @@
for (std::string const& d : this->SearchPaths) {
fwPath = cmStrCat(d, n, ".xcframework");
if (cmSystemTools::FileIsDirectory(fwPath)) {
- auto finalPath = cmSystemTools::CollapseFullPath(fwPath);
+ auto finalPath = cmSystemTools::ToNormalizedPathOnDisk(fwPath);
if (this->Validate(finalPath)) {
return finalPath;
}
@@ -596,7 +589,7 @@
fwPath = cmStrCat(d, n, ".framework");
if (cmSystemTools::FileIsDirectory(fwPath)) {
- auto finalPath = cmSystemTools::CollapseFullPath(fwPath);
+ auto finalPath = cmSystemTools::ToNormalizedPathOnDisk(fwPath);
if (this->Validate(finalPath)) {
return finalPath;
}
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index cc150fd..4f97a18 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -12,11 +12,11 @@
#include <utility>
#include <cm/optional>
+#include <cmext/algorithm>
#include <cmext/string_view>
#include "cmsys/Directory.hxx"
#include "cmsys/FStream.hxx"
-#include "cmsys/Glob.hxx"
#include "cmsys/RegularExpression.hxx"
#include "cmsys/String.h"
@@ -164,8 +164,7 @@
{
public:
cmCaseInsensitiveDirectoryListGenerator(cm::string_view name)
- : DirectoryLister{}
- , DirName{ name }
+ : DirName{ name }
{
}
@@ -207,9 +206,10 @@
class cmDirectoryListGenerator
{
public:
- cmDirectoryListGenerator(std::vector<std::string> const& names)
+ cmDirectoryListGenerator(std::vector<std::string> const& names,
+ bool exactMatch)
: Names{ names }
- , Matches{}
+ , ExactMatch{ exactMatch }
, Current{ this->Matches.cbegin() }
{
}
@@ -233,20 +233,28 @@
// `isDirentryToIgnore(i)` condition to check.
for (auto i = 0ul; i < directoryLister.GetNumberOfFiles(); ++i) {
const char* const fname = directoryLister.GetFile(i);
- if (isDirentryToIgnore(fname)) {
+ // Skip entries to ignore or that aren't directories.
+ if (isDirentryToIgnore(fname) || !directoryLister.FileIsDirectory(i)) {
continue;
}
- for (const auto& n : this->Names.get()) {
- // NOTE Customization point for `cmMacProjectDirectoryListGenerator`
- const auto name = this->TransformNameBeforeCmp(n);
- // Skip entries that don't match and non-directories.
- // ATTENTION BTW, original code also didn't check if it's a symlink
- // to a directory!
- const auto equal =
- (cmsysString_strncasecmp(fname, name.c_str(), name.length()) == 0);
- if (equal && directoryLister.FileIsDirectory(i)) {
- this->Matches.emplace_back(fname);
+ if (!this->ExactMatch && this->Names.get().empty()) {
+ this->Matches.emplace_back(fname);
+ } else {
+ for (const auto& n : this->Names.get()) {
+ // NOTE Customization point for
+ // `cmMacProjectDirectoryListGenerator`
+ const auto name = this->TransformNameBeforeCmp(n);
+ // Skip entries that don't match.
+ const auto equal =
+ ((this->ExactMatch
+ ? cmsysString_strcasecmp(fname, name.c_str())
+ : cmsysString_strncasecmp(fname, name.c_str(),
+ name.length())) == 0);
+ if (equal) {
+ this->Matches.emplace_back(fname);
+ break;
+ }
}
}
}
@@ -275,6 +283,7 @@
virtual std::string TransformNameBeforeCmp(std::string same) { return same; }
std::reference_wrapper<const std::vector<std::string>> Names;
+ bool const ExactMatch;
std::vector<std::string> Matches;
std::vector<std::string>::const_iterator Current;
};
@@ -284,8 +293,9 @@
public:
cmProjectDirectoryListGenerator(std::vector<std::string> const& names,
cmFindPackageCommand::SortOrderType so,
- cmFindPackageCommand::SortDirectionType sd)
- : cmDirectoryListGenerator{ names }
+ cmFindPackageCommand::SortDirectionType sd,
+ bool exactMatch)
+ : cmDirectoryListGenerator{ names, exactMatch }
, SortOrder{ so }
, SortDirection{ sd }
{
@@ -312,7 +322,7 @@
public:
cmMacProjectDirectoryListGenerator(const std::vector<std::string>& names,
cm::string_view ext)
- : cmDirectoryListGenerator{ names }
+ : cmDirectoryListGenerator{ names, true }
, Extension{ ext }
{
}
@@ -327,49 +337,18 @@
const cm::string_view Extension;
};
-class cmFileListGeneratorGlob
+class cmAnyDirectoryListGenerator : public cmProjectDirectoryListGenerator
{
public:
- cmFileListGeneratorGlob(cm::string_view pattern)
- : Pattern(pattern)
- , Files{}
- , Current{}
+ cmAnyDirectoryListGenerator(cmFindPackageCommand::SortOrderType so,
+ cmFindPackageCommand::SortDirectionType sd)
+ : cmProjectDirectoryListGenerator(this->EmptyNamesList, so, sd, false)
{
}
- std::string GetNextCandidate(const std::string& parent)
- {
- if (this->Files.empty()) {
- // Glob the set of matching files.
- std::string expr = cmStrCat(parent, this->Pattern);
- cmsys::Glob g;
- if (!g.FindFiles(expr)) {
- return {};
- }
- this->Files = g.GetFiles();
- this->Current = this->Files.cbegin();
- }
-
- // Skip non-directories
- for (; this->Current != this->Files.cend() &&
- !cmSystemTools::FileIsDirectory(*this->Current);
- ++this->Current) {
- }
-
- return (this->Current != this->Files.cend()) ? *this->Current++
- : std::string{};
- }
-
- void Reset()
- {
- this->Files.clear();
- this->Current = this->Files.cbegin();
- }
-
private:
- cm::string_view Pattern;
- std::vector<std::string> Files;
- std::vector<std::string>::const_iterator Current;
+ // NOTE `cmDirectoryListGenerator` needs to hold a reference to this
+ std::vector<std::string> EmptyNamesList;
};
#if defined(__LCC__)
@@ -1965,11 +1944,13 @@
cmExpandList(*rootDEF, rootPaths);
}
if (rootEnv) {
- std::vector<std::string> p = cmSystemTools::SplitEnvPath(*rootEnv);
+ std::vector<std::string> p =
+ cmSystemTools::SplitEnvPathNormalized(*rootEnv);
std::move(p.begin(), p.end(), std::back_inserter(rootPaths));
}
if (rootENV) {
- std::vector<std::string> p = cmSystemTools::SplitEnvPath(*rootENV);
+ std::vector<std::string> p =
+ cmSystemTools::SplitEnvPathNormalized(*rootENV);
std::move(p.begin(), p.end(), std::back_inserter(rootPaths));
}
}
@@ -2120,9 +2101,9 @@
// Use the system search path to generate prefixes.
// Relative paths are interpreted with respect to the current
// working directory.
- std::vector<std::string> tmp;
- cmSystemTools::GetPath(tmp);
- for (std::string const& i : tmp) {
+ std::vector<std::string> envPATH =
+ cmSystemTools::GetEnvPathNormalized("PATH");
+ for (std::string const& i : envPATH) {
// If the path is a PREFIX/bin case then add its parent instead.
if ((cmHasLiteralSuffix(i, "/bin")) || (cmHasLiteralSuffix(i, "/sbin"))) {
paths.AddPath(cmSystemTools::GetFilenamePath(i));
@@ -2442,8 +2423,12 @@
{
assert(!dir.empty() && dir.back() == '/');
- // Look for the file in this directory.
std::string const d = dir.substr(0, dir.size() - 1);
+ if (cm::contains(this->IgnoredPaths, d)) {
+ return false;
+ }
+
+ // Look for the file in this directory.
if (this->FindConfigFile(d, this->FileFound)) {
// Remove duplicate slashes.
cmSystemTools::ConvertToUnixSlashes(this->FileFound);
@@ -2455,10 +2440,6 @@
bool cmFindPackageCommand::FindConfigFile(std::string const& dir,
std::string& file)
{
- if (this->IgnoredPaths.count(dir)) {
- return false;
- }
-
for (std::string const& c : this->Configs) {
file = cmStrCat(dir, '/', c);
if (this->DebugMode) {
@@ -2668,7 +2649,7 @@
auto iCMakeGen = cmCaseInsensitiveDirectoryListGenerator{ "cmake"_s };
auto firstPkgDirGen =
cmProjectDirectoryListGenerator{ this->Names, this->SortOrder,
- this->SortDirection };
+ this->SortDirection, false };
// PREFIX/(cmake|CMake)/ (useful on windows or in build trees)
if (TryGeneratedPaths(searchFn, prefix, iCMakeGen)) {
@@ -2687,7 +2668,7 @@
auto secondPkgDirGen =
cmProjectDirectoryListGenerator{ this->Names, this->SortOrder,
- this->SortDirection };
+ this->SortDirection, false };
// PREFIX/(Foo|foo|FOO).*/(cmake|CMake)/(Foo|foo|FOO).*/
if (TryGeneratedPaths(searchFn, prefix, firstPkgDirGen, iCMakeGen,
@@ -2766,7 +2747,8 @@
cmMacProjectDirectoryListGenerator{ this->Names, ".framework"_s };
auto rGen = cmAppendPathSegmentGenerator{ "Resources"_s };
auto vGen = cmAppendPathSegmentGenerator{ "Versions"_s };
- auto grGen = cmFileListGeneratorGlob{ "/*/Resources"_s };
+ auto anyGen =
+ cmAnyDirectoryListGenerator{ this->SortOrder, this->SortDirection };
// <prefix>/Foo.framework/Resources/
if (TryGeneratedPaths(searchFn, prefix, fwGen, rGen)) {
@@ -2779,12 +2761,13 @@
}
// <prefix>/Foo.framework/Versions/*/Resources/
- if (TryGeneratedPaths(searchFn, prefix, fwGen, vGen, grGen)) {
+ if (TryGeneratedPaths(searchFn, prefix, fwGen, vGen, anyGen, rGen)) {
return true;
}
// <prefix>/Foo.framework/Versions/*/Resources/CMake/
- return TryGeneratedPaths(searchFn, prefix, fwGen, vGen, grGen, iCMakeGen);
+ return TryGeneratedPaths(searchFn, prefix, fwGen, vGen, anyGen, rGen,
+ iCMakeGen);
}
bool cmFindPackageCommand::SearchAppBundlePrefix(std::string const& prefix_in)
diff --git a/Source/cmFindPathCommand.cxx b/Source/cmFindPathCommand.cxx
index 74a69d8..b6a7834 100644
--- a/Source/cmFindPathCommand.cxx
+++ b/Source/cmFindPathCommand.cxx
@@ -106,7 +106,7 @@
globIt.FindFiles(glob);
std::vector<std::string> files = globIt.GetFiles();
if (!files.empty()) {
- std::string fheader = cmSystemTools::CollapseFullPath(files[0]);
+ std::string fheader = cmSystemTools::ToNormalizedPathOnDisk(files[0]);
debug.FoundAt(fheader);
if (this->IncludeFileInPath) {
return fheader;
diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx
index dd22b41..51be6e0 100644
--- a/Source/cmFindProgramCommand.cxx
+++ b/Source/cmFindProgramCommand.cxx
@@ -48,12 +48,6 @@
// Current names under consideration.
std::vector<std::string> Names;
- // Current name with extension under consideration.
- std::string TestNameExt;
-
- // Current full path under consideration.
- std::string TestPath;
-
// Debug state
cmFindBaseDebugState DebugSearches;
cmMakefile* Makefile;
@@ -81,8 +75,6 @@
{
return std::any_of(this->Names.begin(), this->Names.end(),
[this, &path](std::string const& n) -> bool {
- // Only perform search relative to current directory
- // if the file name contains a directory separator.
return this->CheckDirectoryForName(path, n);
});
}
@@ -93,20 +85,23 @@
if (!ext.empty() && cmHasSuffix(name, ext)) {
return false;
}
- this->TestNameExt = cmStrCat(name, ext);
- this->TestPath = cmSystemTools::CollapseFullPath(
- this->TestNameExt, path);
- bool exists = this->FileIsValid(this->TestPath);
- exists ? this->DebugSearches.FoundAt(this->TestPath)
- : this->DebugSearches.FailedAt(this->TestPath);
- if (exists) {
- this->BestPath = this->TestPath;
- return true;
+ std::string testNameExt = cmStrCat(name, ext);
+ std::string testPath =
+ cmSystemTools::CollapseFullPath(testNameExt, path);
+ if (this->FileIsExecutable(testPath)) {
+ testPath =
+ cmSystemTools::ToNormalizedPathOnDisk(testPath);
+ if (this->FindBase->Validate(testPath)) {
+ this->BestPath = testPath;
+ this->DebugSearches.FoundAt(testPath);
+ return true;
+ }
}
+ this->DebugSearches.FailedAt(testPath);
return false;
});
}
- bool FileIsValid(std::string const& file) const
+ bool FileIsExecutable(std::string const& file) const
{
if (!this->FileIsExecutableCMP0109(file)) {
return false;
@@ -122,7 +117,7 @@
}
}
#endif
- return this->FindBase->Validate(file);
+ return true;
}
bool FileIsExecutableCMP0109(std::string const& file) const
{
diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h
index 1349308..8d21aa8 100644
--- a/Source/cmGeneratorExpression.h
+++ b/Source/cmGeneratorExpression.h
@@ -72,11 +72,11 @@
static std::string StripEmptyListElements(const std::string& input);
- static inline bool StartsWithGeneratorExpression(const std::string& input)
+ static bool StartsWithGeneratorExpression(const std::string& input)
{
return input.length() >= 2 && input[0] == '$' && input[1] == '<';
}
- static inline bool StartsWithGeneratorExpression(const char* input)
+ static bool StartsWithGeneratorExpression(const char* input)
{
return input && input[0] == '$' && input[1] == '<';
}
diff --git a/Source/cmGeneratorOptions.h b/Source/cmGeneratorOptions.h
new file mode 100644
index 0000000..0e17f56
--- /dev/null
+++ b/Source/cmGeneratorOptions.h
@@ -0,0 +1,35 @@
+/* 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
+
+/** Flag if byproducts shall also be considered. */
+enum class cmSourceOutputKind
+{
+ OutputOnly,
+ OutputOrByproduct
+};
+
+/** What scanner to use for dependencies lookup. */
+enum class cmDependencyScannerKind
+{
+ CMake,
+ Compiler
+};
+
+/** What to compute language flags for */
+enum class cmBuildStep
+{
+ Compile,
+ Link
+};
+
+/** What compilation mode the swift files are in */
+enum class cmSwiftCompileMode
+{
+ Wholemodule,
+ Incremental,
+ Singlefile,
+ Unknown,
+};
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index fb92771..a99cd20 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -30,6 +30,7 @@
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorExpressionDAGChecker.h"
+#include "cmGeneratorOptions.h"
#include "cmGlobalGenerator.h"
#include "cmList.h"
#include "cmLocalGenerator.h"
@@ -2516,8 +2517,8 @@
return;
}
- return this->AddCUDAArchitectureFlagsImpl(compileOrLink, config, "CUDA",
- std::move(arch), flags);
+ this->AddCUDAArchitectureFlagsImpl(compileOrLink, config, "CUDA",
+ std::move(arch), flags);
}
void cmGeneratorTarget::AddCUDAArchitectureFlagsImpl(cmBuildStep compileOrLink,
@@ -2695,8 +2696,9 @@
}
if (this->Makefile->GetSafeDefinition("CMAKE_HIP_PLATFORM") == "nvidia") {
- return this->AddCUDAArchitectureFlagsImpl(compileOrLink, config, "HIP",
- std::move(arch), flags);
+ this->AddCUDAArchitectureFlagsImpl(compileOrLink, config, "HIP",
+ std::move(arch), flags);
+ return;
}
cmList options(arch);
diff --git a/Source/cmGeneratorTarget_Options.cxx b/Source/cmGeneratorTarget_Options.cxx
index d8b3eb3..8b978c5 100644
--- a/Source/cmGeneratorTarget_Options.cxx
+++ b/Source/cmGeneratorTarget_Options.cxx
@@ -565,11 +565,11 @@
cmSystemTools::ParseUnixCommandLine(
value.c_str() + LINKER_SHELL.length(), linkerOptions);
} else {
- linkerOptions = cmTokenize(value.substr(LINKER.length()), ",");
+ linkerOptions =
+ cmTokenize(value.substr(LINKER.length()), ',', cmTokenizerMode::New);
}
- if (linkerOptions.empty() ||
- (linkerOptions.size() == 1 && linkerOptions.front().empty())) {
+ if (linkerOptions.empty()) {
continue;
}
diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx
index 1815c4d..6ca5930 100644
--- a/Source/cmGetFilenameComponentCommand.cxx
+++ b/Source/cmGetFilenameComponentCommand.cxx
@@ -113,6 +113,7 @@
// Resolve symlinks if possible
result = cmSystemTools::GetRealPath(result);
}
+ result = cmSystemTools::GetActualCaseForPath(result);
} else {
std::string err = "unknown component " + args[2];
status.SetError(err);
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index a92faef..888dfd3 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -15,6 +15,7 @@
#include "cmCustomCommand.h"
#include "cmCustomCommandGenerator.h"
#include "cmGeneratedFileStream.h"
+#include "cmGeneratorOptions.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGhsMultiGenerator.h"
#include "cmLinkLineComputer.h" // IWYU pragma: keep
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index e3a38b0..382b656 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -1503,12 +1503,14 @@
// This generator does not support duplicate custom targets.
std::ostringstream e;
+ // clang-format off
e << "This project has enabled the ALLOW_DUPLICATE_CUSTOM_TARGETS "
- << "global property. "
- << "The \"" << this->GetName() << "\" generator does not support "
- << "duplicate custom targets. "
- << "Consider using a Makefiles generator or fix the project to not "
- << "use duplicate target names.";
+ "global property. "
+ "The \"" << this->GetName() << "\" generator does not support "
+ "duplicate custom targets. "
+ "Consider using a Makefiles generator or fix the project to not "
+ "use duplicate target names.";
+ // clang-format on
cmSystemTools::Error(e.str());
return false;
}
@@ -1777,11 +1779,12 @@
if (!this->CMP0042WarnTargets.empty()) {
std::ostringstream w;
- w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0042) << "\n";
- w << "MACOSX_RPATH is not specified for"
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0042)
+ << "\n"
+ "MACOSX_RPATH is not specified for"
" the following targets:\n";
for (std::string const& t : this->CMP0042WarnTargets) {
- w << " " << t << "\n";
+ w << ' ' << t << '\n';
}
this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
w.str());
@@ -1798,7 +1801,7 @@
;
/* clang-format on */
for (std::string const& t : this->CMP0068WarnTargets) {
- w << " " << t << "\n";
+ w << ' ' << t << '\n';
}
this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
w.str());
@@ -2218,9 +2221,9 @@
cmBuildOptions defaultBuildOptions(false, fast, PackageResolveMode::Disable);
std::stringstream ostr;
- auto ret =
- this->Build(jobs, srcdir, bindir, projectName, newTarget, ostr, "", config,
- defaultBuildOptions, true, this->TryCompileTimeout);
+ auto ret = this->Build(jobs, srcdir, bindir, projectName, newTarget, ostr,
+ "", config, defaultBuildOptions, true,
+ this->TryCompileTimeout, cmSystemTools::OUTPUT_NONE);
output = ostr.str();
return ret;
}
@@ -2249,7 +2252,7 @@
const std::string& projectName, const std::vector<std::string>& targets,
std::ostream& ostr, const std::string& makeCommandCSTR,
const std::string& config, const cmBuildOptions& buildOptions, bool verbose,
- cmDuration timeout, cmSystemTools::OutputOption outputflag,
+ cmDuration timeout, cmSystemTools::OutputOption outputMode,
std::vector<std::string> const& nativeOptions)
{
bool hideconsole = cmSystemTools::GetRunCommandHideConsole();
@@ -2261,8 +2264,7 @@
ostr << "Change Dir: '" << bindir << '\'' << std::endl;
if (workdir.Failed()) {
cmSystemTools::SetRunCommandHideConsole(hideconsole);
- std::string err = cmStrCat("Failed to change directory: ",
- std::strerror(workdir.GetLastResult()));
+ std::string const& err = workdir.GetError();
cmSystemTools::Error(err);
ostr << err << std::endl;
return 1;
@@ -2274,17 +2276,18 @@
int retVal = 0;
cmSystemTools::SetRunCommandHideConsole(true);
- std::string outputBuffer;
- std::string* outputPtr = &outputBuffer;
+
+ // Capture build command output when outputMode == OUTPUT_NONE.
+ std::string outputBuf;
std::vector<GeneratedMakeCommand> makeCommand = this->GenerateBuildCommand(
makeCommandCSTR, projectName, bindir, targets, realConfig, jobs, verbose,
buildOptions, nativeOptions);
// Workaround to convince some commands to produce output.
- if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH &&
+ if (outputMode == cmSystemTools::OUTPUT_PASSTHROUGH &&
makeCommand.back().RequiresOutputForward) {
- outputflag = cmSystemTools::OUTPUT_FORWARD;
+ outputMode = cmSystemTools::OUTPUT_FORWARD;
}
// should we do a clean first?
@@ -2303,16 +2306,16 @@
return 1;
}
if (!cmSystemTools::RunSingleCommand(cleanCommand.front().PrimaryCommand,
- outputPtr, outputPtr, &retVal,
- nullptr, outputflag, timeout)) {
+ &outputBuf, &outputBuf, &retVal,
+ nullptr, outputMode, timeout)) {
cmSystemTools::SetRunCommandHideConsole(hideconsole);
cmSystemTools::Error("Generator: execution of make clean failed.");
- ostr << *outputPtr << "\nGenerator: execution of make clean failed."
+ ostr << outputBuf << "\nGenerator: execution of make clean failed."
<< std::endl;
return 1;
}
- ostr << *outputPtr;
+ ostr << outputBuf;
}
// now build
@@ -2334,22 +2337,22 @@
}
ostr << outputMakeCommandStr << std::endl;
- if (!cmSystemTools::RunSingleCommand(command->PrimaryCommand, outputPtr,
- outputPtr, &retVal, nullptr,
- outputflag, timeout)) {
+ if (!cmSystemTools::RunSingleCommand(command->PrimaryCommand, &outputBuf,
+ &outputBuf, &retVal, nullptr,
+ outputMode, timeout)) {
cmSystemTools::SetRunCommandHideConsole(hideconsole);
cmSystemTools::Error(
- cmStrCat("Generator: execution of make failed. Make command was: ",
+ cmStrCat("Generator: build tool execution failed, command was: ",
makeCommandStr));
- ostr << *outputPtr
- << "\nGenerator: execution of make failed. Make command was: "
+ ostr << outputBuf
+ << "\nGenerator: build tool execution failed, command was: "
<< outputMakeCommandStr << std::endl;
return 1;
}
- ostr << *outputPtr << std::flush;
+ ostr << outputBuf << std::flush;
if (needBuildOutput) {
- buildOutput += *outputPtr;
+ buildOutput += outputBuf;
}
}
ostr << std::endl;
@@ -2811,7 +2814,7 @@
bool issueMessage = false;
switch (tgt->GetPolicyStatusCMP0037()) {
case cmPolicies::WARN:
- e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n";
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << '\n';
issueMessage = true;
CM_FALLTHROUGH;
case cmPolicies::OLD:
@@ -2825,7 +2828,7 @@
}
if (issueMessage) {
e << "The target name \"" << targetNameAsWritten << "\" is reserved "
- << reason << ".";
+ << reason << '.';
if (messageType == MessageType::AUTHOR_WARNING) {
e << " It may result in undefined behavior.";
}
@@ -2984,7 +2987,6 @@
}
cmCustomCommandLine singleLine;
singleLine.push_back(cmSystemTools::GetCTestCommand());
- singleLine.push_back("--force-new-ctest-process");
cmList args(mf->GetDefinition("CMAKE_CTEST_ARGUMENTS"));
for (auto const& arg : args) {
singleLine.push_back(arg);
@@ -3020,7 +3022,7 @@
bool issueMessage = false;
switch (policyStatus) {
case cmPolicies::WARN:
- e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0171) << "\n";
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0171) << '\n';
issueMessage = true;
CM_FALLTHROUGH;
case cmPolicies::OLD:
@@ -3127,8 +3129,8 @@
std::set<std::string>* componentsSet = &this->InstallComponents;
std::ostringstream ostr;
if (!componentsSet->empty()) {
- ostr << "Available install components are: ";
- ostr << cmWrap('"', *componentsSet, '"', " ");
+ ostr << "Available install components are: "
+ << cmWrap('"', *componentsSet, '"', " ");
} else {
ostr << "Only default component available";
}
@@ -3743,7 +3745,7 @@
fout << "# Hashes of file build rules.\n";
for (auto const& rh : this->RuleHashes) {
fout.write(rh.second.Data, 32);
- fout << " " << rh.first << "\n";
+ fout << ' ' << rh.first << '\n';
}
}
}
@@ -3761,7 +3763,7 @@
continue;
}
this->WriteSummary(tgt.get());
- fout << tgt->GetSupportDirectory() << "\n";
+ fout << tgt->GetSupportDirectory() << '\n';
}
}
}
@@ -3799,7 +3801,7 @@
if (!labels.empty()) {
fout << "# Target labels\n";
for (std::string const& l : labels) {
- fout << " " << l << "\n";
+ fout << ' ' << l << '\n';
lj_target_labels.append(l);
}
}
@@ -3822,12 +3824,12 @@
}
for (auto const& li : directoryLabelsList) {
- fout << " " << li << "\n";
+ fout << ' ' << li << '\n';
lj_target_labels.append(li);
}
for (auto const& li : cmakeDirectoryLabelsList) {
- fout << " " << li << "\n";
+ fout << ' ' << li << '\n';
lj_target_labels.append(li);
}
@@ -3844,13 +3846,13 @@
for (cmSourceFile* sf : cmMakeRange(sources.cbegin(), sourcesEnd)) {
Json::Value& lj_source = lj_sources.append(Json::objectValue);
std::string const& sfp = sf->ResolveFullPath();
- fout << sfp << "\n";
+ fout << sfp << '\n';
lj_source["file"] = sfp;
if (cmValue svalue = sf->GetProperty("LABELS")) {
Json::Value& lj_source_labels = lj_source["labels"] = Json::arrayValue;
labels.assign(*svalue);
for (auto const& label : labels) {
- fout << " " << label << "\n";
+ fout << ' ' << label << '\n';
lj_source_labels.append(label);
}
}
@@ -4021,3 +4023,16 @@
{
this->InstallScripts.push_back(file);
}
+
+void cmGlobalGenerator::AddTestFile(std::string const& file)
+{
+ this->TestFiles.push_back(file);
+}
+
+void cmGlobalGenerator::AddCMakeFilesToRebuild(
+ std::vector<std::string>& files) const
+{
+ files.insert(files.end(), this->InstallScripts.begin(),
+ this->InstallScripts.end());
+ files.insert(files.end(), this->TestFiles.begin(), this->TestFiles.end());
+}
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index a865adb..92e974c 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -248,15 +248,14 @@
* empty then all is assumed. clean indicates if a "make clean" should be
* done first.
*/
- int Build(
- int jobs, const std::string& srcdir, const std::string& bindir,
- const std::string& projectName,
- std::vector<std::string> const& targetNames, std::ostream& ostr,
- const std::string& makeProgram, const std::string& config,
- const cmBuildOptions& buildOptions, bool verbose, cmDuration timeout,
- cmSystemTools::OutputOption outputflag = cmSystemTools::OUTPUT_NONE,
- std::vector<std::string> const& nativeOptions =
- std::vector<std::string>());
+ int Build(int jobs, const std::string& srcdir, const std::string& bindir,
+ const std::string& projectName,
+ std::vector<std::string> const& targetNames, std::ostream& ostr,
+ const std::string& makeProgram, const std::string& config,
+ const cmBuildOptions& buildOptions, bool verbose,
+ cmDuration timeout, cmSystemTools::OutputOption outputMode,
+ std::vector<std::string> const& nativeOptions =
+ std::vector<std::string>());
/**
* Open a generated IDE project given the following information.
@@ -676,6 +675,8 @@
bool CheckCMP0171() const;
void AddInstallScript(std::string const& file);
+ void AddTestFile(std::string const& file);
+ void AddCMakeFilesToRebuild(std::vector<std::string>& files) const;
protected:
// for a project collect all its targets by following depend
@@ -917,6 +918,7 @@
RuntimeDependencySetsByName;
std::vector<std::string> InstallScripts;
+ std::vector<std::string> TestFiles;
#if !defined(CMAKE_BOOTSTRAP)
// Pool of file locks
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 17e9c44..d46ec81 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -3293,6 +3293,7 @@
if (!this->DefaultFileConfig.empty()) {
outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE));
}
+ this->AddCMakeFilesToRebuild(outputs);
}
void cmGlobalNinjaMultiGenerator::GetQtAutoGenConfigs(
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 69b2361..7bd7206 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -382,6 +382,7 @@
virtual void AddRebuildManifestOutputs(cmNinjaDeps& outputs) const
{
outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE));
+ this->AddCMakeFilesToRebuild(outputs);
}
int GetRuleCmdLength(const std::string& name)
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index f9abe29..3d911bd 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -339,12 +339,13 @@
bool cmGlobalVisualStudio10Generator::ParseGeneratorToolset(
std::string const& ts, cmMakefile* mf)
{
- std::vector<std::string> const fields = cmTokenize(ts, ",");
- auto fi = fields.begin();
- if (fi == fields.end()) {
+ std::vector<std::string> const fields =
+ cmTokenize(ts, ',', cmTokenizerMode::New);
+ if (fields.empty()) {
return true;
}
+ auto fi = fields.begin();
// The first field may be the VS platform toolset.
if (fi->find('=') == fi->npos) {
this->GeneratorToolset = *fi;
diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx
index b1fba8f..d9accad 100644
--- a/Source/cmGlobalVisualStudio8Generator.cxx
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -128,12 +128,13 @@
{
this->GeneratorPlatform.clear();
- std::vector<std::string> const fields = cmTokenize(p, ",");
- auto fi = fields.begin();
- if (fi == fields.end()) {
+ std::vector<std::string> const fields =
+ cmTokenize(p, ',', cmTokenizerMode::New);
+ if (fields.empty()) {
return true;
}
+ auto fi = fields.begin();
// The first field may be the VS platform.
if (fi->find('=') == fi->npos) {
this->GeneratorPlatform = *fi;
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
index 14460fd..ba51e36 100644
--- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
@@ -584,12 +584,13 @@
this->GeneratorInstance.clear();
this->GeneratorInstanceVersion.clear();
- std::vector<std::string> const fields = cmTokenize(is, ",");
- auto fi = fields.begin();
- if (fi == fields.end()) {
+ std::vector<std::string> const fields =
+ cmTokenize(is, ',', cmTokenizerMode::New);
+ if (fields.empty()) {
return true;
}
+ auto fi = fields.begin();
// The first field may be the VS instance.
if (fi->find('=') == fi->npos) {
this->GeneratorInstance = *fi;
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 7fa21d0..a45e23f 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -27,6 +27,7 @@
#include "cmCustomCommandTypes.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
+#include "cmGeneratorOptions.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGeneratorFactory.h"
#include "cmLinkItem.h"
@@ -354,12 +355,13 @@
bool cmGlobalXCodeGenerator::ParseGeneratorToolset(std::string const& ts,
cmMakefile* mf)
{
- std::vector<std::string> const fields = cmTokenize(ts, ",");
- auto fi = fields.cbegin();
- if (fi == fields.cend()) {
+ std::vector<std::string> const fields =
+ cmTokenize(ts, ',', cmTokenizerMode::New);
+ if (fields.empty()) {
return true;
}
+ auto fi = fields.cbegin();
// The first field may be the Xcode GCC_VERSION.
if (fi->find('=') == fi->npos) {
this->GeneratorToolset = *fi;
@@ -1362,12 +1364,20 @@
{
std::string const& a = l->GetTarget()->GetName();
std::string const& b = r->GetTarget()->GetName();
+ if (a == b) {
+ return false;
+ }
if (a == "ALL_BUILD"_s) {
return true;
}
if (b == "ALL_BUILD"_s) {
return false;
}
+ std::string a_low = cmSystemTools::LowerCase(l->GetTarget()->GetName());
+ std::string b_low = cmSystemTools::LowerCase(r->GetTarget()->GetName());
+ if (a_low != b_low) {
+ return a_low < b_low;
+ }
return a < b;
}
};
@@ -2530,7 +2540,8 @@
}
if (!extraLinkOptionsVar.empty()) {
this->CurrentLocalGenerator->AddConfigVariableFlags(
- extraLinkOptions, extraLinkOptionsVar, configName);
+ extraLinkOptions, extraLinkOptionsVar, gtgt, cmBuildStep::Link, llang,
+ configName);
}
if (gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY ||
@@ -2685,7 +2696,7 @@
// in many ways as an application bundle, as far as
// link flags go
std::string createFlags = this->LookupFlags(
- "CMAKE_SHARED_MODULE_CREATE_", llang, "_FLAGS", "-bundle");
+ "CMAKE_SHARED_MODULE_CREATE_", llang, "_FLAGS", gtgt, "-bundle");
if (!createFlags.empty()) {
extraLinkOptions += ' ';
extraLinkOptions += createFlags;
@@ -2711,7 +2722,7 @@
this->CreateString("NO"));
// Add the flags to create an executable.
std::string createFlags =
- this->LookupFlags("CMAKE_", llang, "_LINK_FLAGS", "");
+ this->LookupFlags("CMAKE_", llang, "_LINK_FLAGS", gtgt, "");
if (!createFlags.empty()) {
extraLinkOptions += ' ';
extraLinkOptions += createFlags;
@@ -2740,8 +2751,9 @@
this->CreateString(plist));
} else {
// Add the flags to create a shared library.
- std::string createFlags = this->LookupFlags(
- "CMAKE_SHARED_LIBRARY_CREATE_", llang, "_FLAGS", "-dynamiclib");
+ std::string createFlags =
+ this->LookupFlags("CMAKE_SHARED_LIBRARY_CREATE_", llang, "_FLAGS",
+ gtgt, "-dynamiclib");
if (!createFlags.empty()) {
extraLinkOptions += ' ';
extraLinkOptions += createFlags;
@@ -2761,7 +2773,7 @@
case cmStateEnums::EXECUTABLE: {
// Add the flags to create an executable.
std::string createFlags =
- this->LookupFlags("CMAKE_", llang, "_LINK_FLAGS", "");
+ this->LookupFlags("CMAKE_", llang, "_LINK_FLAGS", gtgt, "");
if (!createFlags.empty()) {
extraLinkOptions += ' ';
extraLinkOptions += createFlags;
@@ -4446,7 +4458,7 @@
if (it != this->TargetGroup.end()) {
tgroup = it->second;
} else {
- std::vector<std::string> tgt_folders = cmTokenize(target, "/");
+ std::vector<std::string> const tgt_folders = cmTokenize(target, '/');
std::string curr_tgt_folder;
for (std::vector<std::string>::size_type i = 0; i < tgt_folders.size();
i++) {
@@ -4479,7 +4491,7 @@
// It's a recursive folder structure, let's find the real parent group
if (sg->GetFullName() != sg->GetName()) {
std::string curr_folder = cmStrCat(target, '/');
- for (auto const& folder : cmTokenize(sg->GetFullName(), "\\")) {
+ for (auto const& folder : cmTokenize(sg->GetFullName(), '\\')) {
curr_folder += folder;
auto const i_folder = this->GroupNameMap.find(curr_folder);
// Create new folder
@@ -5199,13 +5211,17 @@
std::string cmGlobalXCodeGenerator::LookupFlags(
const std::string& varNamePrefix, const std::string& varNameLang,
- const std::string& varNameSuffix, const std::string& default_flags)
+ const std::string& varNameSuffix, cmGeneratorTarget const* gt,
+ const std::string& default_flags)
{
if (!varNameLang.empty()) {
std::string varName = cmStrCat(varNamePrefix, varNameLang, varNameSuffix);
if (cmValue varValue = this->CurrentMakefile->GetDefinition(varName)) {
if (!varValue->empty()) {
- return *varValue;
+ std::string flags;
+ this->CurrentLocalGenerator->AppendFlags(
+ flags, *varValue, varName, gt, cmBuildStep::Link, varNameLang);
+ return flags;
}
}
}
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index 14e9308..22743e5 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -304,6 +304,7 @@
std::string LookupFlags(const std::string& varNamePrefix,
const std::string& varNameLang,
const std::string& varNameSuffix,
+ cmGeneratorTarget const* gt,
const std::string& default_flags);
class Factory;
diff --git a/Source/cmInstallScriptHandler.cxx b/Source/cmInstallScriptHandler.cxx
index 9a4e70f..a7dfb0c 100644
--- a/Source/cmInstallScriptHandler.cxx
+++ b/Source/cmInstallScriptHandler.cxx
@@ -133,7 +133,7 @@
InstallScript::InstallScript(const std::vector<std::string>& cmd)
{
this->name = cmSystemTools::RelativePath(
- cmSystemTools::GetCurrentWorkingDirectory(), cmd.back());
+ cmSystemTools::GetLogicalWorkingDirectory(), cmd.back());
this->command = cmd;
}
diff --git a/Source/cmLinkItem.cxx b/Source/cmLinkItem.cxx
index 3654176..6744bbb 100644
--- a/Source/cmLinkItem.cxx
+++ b/Source/cmLinkItem.cxx
@@ -13,8 +13,6 @@
const std::string cmLinkItem::DEFAULT = "DEFAULT";
-cmLinkItem::cmLinkItem() = default;
-
cmLinkItem::cmLinkItem(std::string n, bool c, cmListFileBacktrace bt,
std::string feature)
: String(std::move(n))
@@ -73,11 +71,6 @@
return os << item.AsStr();
}
-cmLinkImplItem::cmLinkImplItem()
- : cmLinkItem()
-{
-}
-
cmLinkImplItem::cmLinkImplItem(cmLinkItem item, bool checkCMP0027)
: cmLinkItem(std::move(item))
, CheckCMP0027(checkCMP0027)
diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h
index 4e356b7..70efb16 100644
--- a/Source/cmLinkItem.h
+++ b/Source/cmLinkItem.h
@@ -29,7 +29,7 @@
// default feature: link library without decoration
static const std::string DEFAULT;
- cmLinkItem();
+ cmLinkItem() = default;
cmLinkItem(std::string s, bool c, cmListFileBacktrace bt,
std::string feature = DEFAULT);
cmLinkItem(cmGeneratorTarget const* t, bool c, cmListFileBacktrace bt,
@@ -50,7 +50,7 @@
class cmLinkImplItem : public cmLinkItem
{
public:
- cmLinkImplItem();
+ cmLinkImplItem() = default;
cmLinkImplItem(cmLinkItem item, bool checkCMP0027);
bool CheckCMP0027 = false;
};
diff --git a/Source/cmList.h b/Source/cmList.h
index e107096..7771a0e 100644
--- a/Source/cmList.h
+++ b/Source/cmList.h
@@ -1135,11 +1135,11 @@
// Non-members
// ===========
- friend inline bool operator==(const cmList& lhs, const cmList& rhs) noexcept
+ friend 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
+ friend bool operator!=(const cmList& lhs, const cmList& rhs) noexcept
{
return lhs.Values != rhs.Values;
}
diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx
index 81edea5..44eb029 100644
--- a/Source/cmLoadCommandCommand.cxx
+++ b/Source/cmLoadCommandCommand.cxx
@@ -18,12 +18,10 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
-#include <utility>
#include <cm/memory>
#include "cmCPluginAPI.h"
-#include "cmCommand.h"
#include "cmDynamicLoader.h"
#include "cmExecutionStatus.h"
#include "cmListFileCache.h"
@@ -124,40 +122,32 @@
};
// a class for loadabple commands
-class cmLoadedCommand : public cmCommand
+class cmLoadedCommand
{
public:
- cmLoadedCommand() = default;
explicit cmLoadedCommand(CM_INIT_FUNCTION init)
: Impl(std::make_shared<LoadedCommandImpl>(init))
{
}
- /**
- * This is a virtual constructor for the command.
- */
- std::unique_ptr<cmCommand> Clone() override
- {
- auto newC = cm::make_unique<cmLoadedCommand>();
- // we must copy when we clone
- newC->Impl = this->Impl;
- return std::unique_ptr<cmCommand>(std::move(newC));
- }
-
- /**
- * This is called when the command is first encountered in
- * the CMakeLists.txt file.
- */
- bool InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus&) override;
+ bool operator()(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status) const;
private:
std::shared_ptr<LoadedCommandImpl> Impl;
};
-bool cmLoadedCommand::InitialPass(std::vector<std::string> const& args,
- cmExecutionStatus&)
+bool cmLoadedCommand::operator()(
+ std::vector<cmListFileArgument> const& arguments,
+ cmExecutionStatus& status) const
{
+ cmMakefile& mf = status.GetMakefile();
+
+ std::vector<std::string> args;
+ if (!mf.ExpandArguments(arguments, args)) {
+ return true;
+ }
+
if (!this->Impl->InitialPass) {
return true;
}
@@ -177,13 +167,13 @@
for (i = 0; i < argc; ++i) {
argv[i] = strdup(args[i].c_str());
}
- int result = this->Impl->DoInitialPass(this->Makefile, argc, argv);
+ int result = this->Impl->DoInitialPass(&mf, argc, argv);
cmFreeArguments(argc, argv);
if (result) {
if (this->Impl->FinalPass) {
auto impl = this->Impl;
- this->Makefile->AddGeneratorAction(
+ mf.AddGeneratorAction(
[impl](cmLocalGenerator& lg, const cmListFileBacktrace&) {
impl->DoFinalPass(lg.GetMakefile());
});
@@ -193,7 +183,7 @@
/* Initial Pass must have failed so set the error string */
if (this->Impl->Error) {
- this->SetError(this->Impl->Error);
+ status.SetError(this->Impl->Error);
}
return false;
}
@@ -270,9 +260,8 @@
if (initFunction) {
return status.GetMakefile().GetState()->AddScriptedCommand(
args[0],
- BT<cmState::Command>(
- cmLegacyCommandWrapper(cm::make_unique<cmLoadedCommand>(initFunction)),
- status.GetMakefile().GetBacktrace()),
+ BT<cmState::Command>(cmLoadedCommand(initFunction),
+ status.GetMakefile().GetBacktrace()),
status.GetMakefile());
}
status.SetError("Attempt to load command failed. "
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 42b517e..b011747 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -208,12 +208,62 @@
}
std::unique_ptr<cmRulePlaceholderExpander>
-cmLocalGenerator::CreateRulePlaceholderExpander() const
+cmLocalGenerator::CreateRulePlaceholderExpander(cmBuildStep buildStep) const
{
return cm::make_unique<cmRulePlaceholderExpander>(
- this->Compilers, this->VariableMappings, this->CompilerSysroot,
+ buildStep, this->Compilers, this->VariableMappings, this->CompilerSysroot,
this->LinkerSysroot);
}
+std::unique_ptr<cmRulePlaceholderExpander>
+cmLocalGenerator::CreateRulePlaceholderExpander(
+ cmBuildStep buildStep, cmGeneratorTarget const* target,
+ std::string const& language)
+{
+ auto targetType = target->GetType();
+ if (buildStep == cmBuildStep::Link &&
+ (targetType == cmStateEnums::EXECUTABLE ||
+ targetType == cmStateEnums::SHARED_LIBRARY ||
+ targetType == cmStateEnums::MODULE_LIBRARY)) {
+ auto mappings = this->VariableMappings;
+ auto updateMapping = [buildStep, target, &language, &mappings,
+ this](std::string const& variable) {
+ auto search = this->VariableMappings.find(variable);
+ if (search != this->VariableMappings.end()) {
+ std::string finalFlags;
+ this->AppendFlags(finalFlags, search->second, variable, target,
+ buildStep, language);
+ mappings[variable] = std::move(finalFlags);
+ }
+ };
+
+ switch (targetType) {
+ // FALLTHROUGH is used because, depending of the compiler and/or
+ // platform, the wrong variable is used. For example
+ // CMAKE_SHARED_LIBRARY_CREATE_<LANG>_FLAGS is used to generate a module,
+ // and the variable CMAKE_SHARED_MODULE_CREATE_<LANG>_FLAGS is ignored.
+ case cmStateEnums::MODULE_LIBRARY:
+ updateMapping(
+ cmStrCat("CMAKE_SHARED_MODULE_CREATE_", language, "_FLAGS"));
+ CM_FALLTHROUGH;
+ case cmStateEnums::SHARED_LIBRARY:
+ updateMapping(
+ cmStrCat("CMAKE_SHARED_LIBRARY_CREATE_", language, "_FLAGS"));
+ CM_FALLTHROUGH;
+ case cmStateEnums::EXECUTABLE:
+ updateMapping(cmStrCat("CMAKE_", language, "_LINK_FLAGS"));
+ break;
+ default:
+ // no action needed
+ ;
+ }
+
+ return cm::make_unique<cmRulePlaceholderExpander>(
+ buildStep, this->Compilers, std::move(mappings), this->CompilerSysroot,
+ this->LinkerSysroot);
+ }
+
+ return this->CreateRulePlaceholderExpander(buildStep);
+}
cmLocalGenerator::~cmLocalGenerator() = default;
@@ -316,9 +366,9 @@
std::string file =
cmStrCat(this->StateSnapshot.GetDirectory().GetCurrentBinary(),
"/CTestTestfile.cmake");
+ this->GlobalGenerator->AddTestFile(file);
cmGeneratedFileStream fout(file);
- fout.SetCopyIfDifferent(true);
fout << "# CMake generated Testfile for \n"
"# Source directory: "
@@ -502,7 +552,6 @@
file += "/cmake_install.cmake";
this->GetGlobalGenerator()->AddInstallScript(file);
cmGeneratedFileStream fout(file);
- fout.SetCopyIfDifferent(true);
// Write the header.
/* clang-format off */
@@ -1495,17 +1544,16 @@
libraryLinkVariable = "CMAKE_MODULE_LINKER_FLAGS";
CM_FALLTHROUGH;
case cmStateEnums::SHARED_LIBRARY: {
- std::string sharedLibFlags;
if (this->IsSplitSwiftBuild() || linkLanguage != "Swift") {
- sharedLibFlags = cmStrCat(
- this->Makefile->GetSafeDefinition(libraryLinkVariable), ' ');
- if (!configUpper.empty()) {
- std::string build = cmStrCat(libraryLinkVariable, '_', configUpper);
- sharedLibFlags += this->Makefile->GetSafeDefinition(build);
- sharedLibFlags += " ";
+ std::string libFlags;
+ this->AddConfigVariableFlags(libFlags, libraryLinkVariable, target,
+ cmBuildStep::Link, linkLanguage, config);
+ if (!libFlags.empty()) {
+ linkFlags.emplace_back(std::move(libFlags));
}
}
+ std::string sharedLibFlags;
cmValue targetLinkFlags = target->GetProperty("LINK_FLAGS");
if (targetLinkFlags) {
sharedLibFlags += *targetLinkFlags;
@@ -1538,7 +1586,6 @@
}
} break;
case cmStateEnums::EXECUTABLE: {
- std::string exeFlags;
if (linkLanguage.empty()) {
cmSystemTools::Error(
"CMake can not determine linker language for target: " +
@@ -1547,25 +1594,28 @@
}
if (linkLanguage != "Swift") {
- exeFlags = this->Makefile->GetSafeDefinition("CMAKE_EXE_LINKER_FLAGS");
- exeFlags += " ";
- if (!configUpper.empty()) {
- exeFlags += this->Makefile->GetSafeDefinition(
- cmStrCat("CMAKE_EXE_LINKER_FLAGS_", configUpper));
- exeFlags += " ";
+ std::string exeFlags;
+ this->AddConfigVariableFlags(exeFlags, "CMAKE_EXE_LINKER_FLAGS",
+ target, cmBuildStep::Link, linkLanguage,
+ config);
+ if (!exeFlags.empty()) {
+ linkFlags.emplace_back(std::move(exeFlags));
}
}
- if (target->IsWin32Executable(config)) {
- exeFlags += this->Makefile->GetSafeDefinition(
- cmStrCat("CMAKE_", linkLanguage, "_CREATE_WIN32_EXE"));
- exeFlags += " ";
- } else {
- exeFlags += this->Makefile->GetSafeDefinition(
- cmStrCat("CMAKE_", linkLanguage, "_CREATE_CONSOLE_EXE"));
- exeFlags += " ";
+ {
+ auto exeType = cmStrCat(
+ "CMAKE_", linkLanguage, "_CREATE_",
+ (target->IsWin32Executable(config) ? "WIN32" : "CONSOLE"), "_EXE");
+ std::string exeFlags;
+ this->AppendFlags(exeFlags, this->Makefile->GetDefinition(exeType),
+ exeType, target, cmBuildStep::Link, linkLanguage);
+ if (!exeFlags.empty()) {
+ linkFlags.emplace_back(std::move(exeFlags));
+ }
}
+ std::string exeFlags;
if (target->IsExecutableWithExports()) {
exeFlags += this->Makefile->GetSafeDefinition(
cmStrCat("CMAKE_EXE_EXPORTS_", linkLanguage, "_FLAG"));
@@ -2380,7 +2430,7 @@
dep = cmStrCat(this->GetCurrentBinaryDirectory(), '/', inName);
}
- dep = cmSystemTools::CollapseFullPath(dep, this->GetBinaryDirectory());
+ dep = cmSystemTools::CollapseFullPath(dep);
return true;
}
@@ -2621,6 +2671,19 @@
this->AppendFlags(flags, this->Makefile->GetSafeDefinition(flagsVar));
}
}
+void cmLocalGenerator::AddConfigVariableFlags(std::string& flags,
+ const std::string& var,
+ cmGeneratorTarget const* target,
+ cmBuildStep compileOrLink,
+ const std::string& lang,
+ const std::string& config)
+{
+ std::string newFlags;
+ this->AddConfigVariableFlags(newFlags, var, config);
+ if (!newFlags.empty()) {
+ this->AppendFlags(flags, newFlags, var, target, compileOrLink, lang);
+ }
+}
void cmLocalGenerator::AppendFlags(std::string& flags,
const std::string& newFlags) const
@@ -2651,6 +2714,59 @@
this->EscapeForShell(rawFlag, false, false, false, this->IsNinjaMulti()));
}
+void cmLocalGenerator::AppendFlags(std::string& flags,
+ std::string const& newFlags,
+ const std::string& name,
+ const cmGeneratorTarget* target,
+ cmBuildStep compileOrLink,
+ const std::string& language)
+{
+ switch (target->GetPolicyStatusCMP0181()) {
+ case cmPolicies::WARN:
+ if (!this->Makefile->GetCMakeInstance()->GetIsInTryCompile() &&
+ this->Makefile->PolicyOptionalWarningEnabled(
+ "CMAKE_POLICY_WARNING_CMP0181")) {
+ this->Makefile->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0181),
+ "\nSince the policy is not set, the contents of variable '",
+ name,
+ "' will "
+ "be used as is."),
+ target->GetBacktrace());
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ this->AppendFlags(flags, newFlags);
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ this->Makefile->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0181),
+ target->GetBacktrace());
+ CM_FALLTHROUGH;
+ case cmPolicies::NEW:
+ if (compileOrLink == cmBuildStep::Link) {
+ std::vector<std::string> options;
+ cmSystemTools::ParseUnixCommandLine(newFlags.c_str(), options);
+ this->SetLinkScriptShell(this->GlobalGenerator->GetUseLinkScript());
+ std::vector<BT<std::string>> optionsWithBT{ options.size() };
+ std::transform(options.cbegin(), options.cend(), optionsWithBT.begin(),
+ [](const std::string& item) -> BT<std::string> {
+ return BT<std::string>{ item };
+ });
+ target->ResolveLinkerWrapper(optionsWithBT, language);
+ for (const auto& item : optionsWithBT) {
+ this->AppendFlagEscape(flags, item.Value);
+ }
+ this->SetLinkScriptShell(false);
+ } else {
+ this->AppendFlags(flags, newFlags);
+ }
+ }
+}
+
void cmLocalGenerator::AddISPCDependencies(cmGeneratorTarget* target)
{
std::vector<std::string> enabledLanguages =
@@ -3087,7 +3203,8 @@
cmLocalGenerator::UnitySource cmLocalGenerator::WriteUnitySource(
cmGeneratorTarget* target, std::vector<std::string> const& configs,
cmRange<std::vector<UnityBatchedSource>::const_iterator> sources,
- cmValue beforeInclude, cmValue afterInclude, std::string filename) const
+ cmValue beforeInclude, cmValue afterInclude, std::string filename,
+ std::string const& unityFileDirectory, UnityPathMode pathMode) const
{
cmValue uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID");
cmGeneratedFileStream file(
@@ -3110,7 +3227,8 @@
}
RegisterUnitySources(target, ubs.Source, filename);
WriteUnitySourceInclude(file, cond, ubs.Source->ResolveFullPath(),
- beforeInclude, afterInclude, uniqueIdName);
+ beforeInclude, afterInclude, uniqueIdName,
+ pathMode, unityFileDirectory);
}
return UnitySource(std::move(filename), perConfig);
@@ -3119,28 +3237,35 @@
void cmLocalGenerator::WriteUnitySourceInclude(
std::ostream& unity_file, cm::optional<std::string> const& cond,
std::string const& sf_full_path, cmValue beforeInclude, cmValue afterInclude,
- cmValue uniqueIdName) const
+ cmValue uniqueIdName, UnityPathMode pathMode,
+ std::string const& unityFileDirectory) const
{
if (cond) {
unity_file << "#if " << *cond << "\n";
}
+ std::string pathToHash;
+ std::string relocatableIncludePath;
+ auto PathEqOrSubDir = [](std::string const& a, std::string const& b) {
+ return (cmSystemTools::ComparePath(a, b) ||
+ cmSystemTools::IsSubDirectory(a, b));
+ };
+ const auto path = cmSystemTools::GetFilenamePath(sf_full_path);
+ if (PathEqOrSubDir(path, this->GetBinaryDirectory())) {
+ relocatableIncludePath =
+ cmSystemTools::RelativePath(unityFileDirectory, sf_full_path);
+ pathToHash = "BLD_" +
+ cmSystemTools::RelativePath(this->GetBinaryDirectory(), sf_full_path);
+ } else if (PathEqOrSubDir(path, this->GetSourceDirectory())) {
+ relocatableIncludePath =
+ cmSystemTools::RelativePath(this->GetSourceDirectory(), sf_full_path);
+ pathToHash = "SRC_" + relocatableIncludePath;
+ } else {
+ relocatableIncludePath = sf_full_path;
+ pathToHash = "ABS_" + sf_full_path;
+ }
+
if (cmNonempty(uniqueIdName)) {
- std::string pathToHash;
- auto PathEqOrSubDir = [](std::string const& a, std::string const& b) {
- return (cmSystemTools::ComparePath(a, b) ||
- cmSystemTools::IsSubDirectory(a, b));
- };
- const auto path = cmSystemTools::GetFilenamePath(sf_full_path);
- if (PathEqOrSubDir(path, this->GetBinaryDirectory())) {
- pathToHash = "BLD_" +
- cmSystemTools::RelativePath(this->GetBinaryDirectory(), sf_full_path);
- } else if (PathEqOrSubDir(path, this->GetSourceDirectory())) {
- pathToHash = "SRC_" +
- cmSystemTools::RelativePath(this->GetSourceDirectory(), sf_full_path);
- } else {
- pathToHash = "ABS_" + sf_full_path;
- }
cmCryptoHash hasher(cmCryptoHash::AlgoMD5);
unity_file << "/* " << pathToHash << " */\n"
<< "#undef " << *uniqueIdName << "\n"
@@ -3156,7 +3281,11 @@
unity_file
<< "/* NOLINTNEXTLINE(bugprone-suspicious-include,misc-include-cleaner) "
"*/\n";
- unity_file << "#include \"" << sf_full_path << "\"\n";
+ if (pathMode == UnityPathMode::Relative) {
+ unity_file << "#include \"" << relocatableIncludePath << "\"\n";
+ } else {
+ unity_file << "#include \"" << sf_full_path << "\"\n";
+ }
if (afterInclude) {
unity_file << *afterInclude << "\n";
@@ -3192,7 +3321,7 @@
std::vector<std::string> const& configs,
std::vector<UnityBatchedSource> const& filtered_sources,
cmValue beforeInclude, cmValue afterInclude,
- std::string const& filename_base, size_t batchSize)
+ std::string const& filename_base, UnityPathMode pathMode, size_t batchSize)
{
if (batchSize == 0) {
batchSize = filtered_sources.size();
@@ -3210,7 +3339,7 @@
auto const end = begin + chunk;
unity_files.emplace_back(this->WriteUnitySource(
target, configs, cmMakeRange(begin, end), beforeInclude, afterInclude,
- std::move(filename)));
+ std::move(filename), filename_base, pathMode));
}
return unity_files;
}
@@ -3221,7 +3350,7 @@
std::vector<std::string> const& configs,
std::vector<UnityBatchedSource> const& filtered_sources,
cmValue beforeInclude, cmValue afterInclude,
- std::string const& filename_base)
+ std::string const& filename_base, UnityPathMode pathMode)
{
std::vector<UnitySource> unity_files;
@@ -3247,7 +3376,7 @@
cmStrCat(filename_base, "unity_", name, unity_file_extension(lang));
unity_files.emplace_back(this->WriteUnitySource(
target, configs, cmMakeRange(item.second), beforeInclude, afterInclude,
- std::move(filename)));
+ std::move(filename), filename_base, pathMode));
}
return unity_files;
@@ -3305,6 +3434,9 @@
target->GetProperty("UNITY_BUILD_CODE_BEFORE_INCLUDE");
cmValue afterInclude = target->GetProperty("UNITY_BUILD_CODE_AFTER_INCLUDE");
cmValue unityMode = target->GetProperty("UNITY_BUILD_MODE");
+ UnityPathMode pathMode = target->GetPropertyAsBool("UNITY_BUILD_RELOCATABLE")
+ ? UnityPathMode::Relative
+ : UnityPathMode::Absolute;
for (std::string lang : { "C", "CXX", "OBJC", "OBJCXX", "CUDA" }) {
std::vector<UnityBatchedSource> filtered_sources;
@@ -3325,11 +3457,11 @@
if (!unityMode || *unityMode == "BATCH") {
unity_files = AddUnityFilesModeAuto(
target, lang, configs, filtered_sources, beforeInclude, afterInclude,
- filename_base, unityBatchSize);
+ filename_base, pathMode, unityBatchSize);
} else if (unityMode && *unityMode == "GROUP") {
- unity_files =
- AddUnityFilesModeGroup(target, lang, configs, filtered_sources,
- beforeInclude, afterInclude, filename_base);
+ unity_files = AddUnityFilesModeGroup(
+ target, lang, configs, filtered_sources, beforeInclude, afterInclude,
+ filename_base, pathMode);
} else {
// unity mode is set to an unsupported value
std::string e("Invalid UNITY_BUILD_MODE value of " + *unityMode +
@@ -3348,6 +3480,11 @@
unity->SetProperty("COMPILE_DEFINITIONS",
"CMAKE_UNITY_CONFIG_$<UPPER_CASE:$<CONFIG>>");
}
+
+ if (pathMode == UnityPathMode::Relative) {
+ unity->AppendProperty("INCLUDE_DIRECTORIES",
+ this->GetSourceDirectory(), false);
+ }
}
}
}
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 3ec349b..0305947 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -19,6 +19,7 @@
#include <cm3p/kwiml/int.h>
#include "cmCustomCommandTypes.h"
+#include "cmGeneratorOptions.h"
#include "cmGeneratorTarget.h"
#include "cmListFileCache.h"
#include "cmMessageType.h" // IWYU pragma: keep
@@ -46,36 +47,6 @@
template <typename Iter>
class cmRange;
-/** Flag if byproducts shall also be considered. */
-enum class cmSourceOutputKind
-{
- OutputOnly,
- OutputOrByproduct
-};
-
-/** What scanner to use for dependencies lookup. */
-enum class cmDependencyScannerKind
-{
- CMake,
- Compiler
-};
-
-/** What to compute language flags for */
-enum class cmBuildStep
-{
- Compile,
- Link
-};
-
-/** What compilation mode the swift files are in */
-enum class cmSwiftCompileMode
-{
- Wholemodule,
- Incremental,
- Singlefile,
- Unknown,
-};
-
/** Target and source file which have a specific output. */
struct cmSourcesWithOutput
{
@@ -147,7 +118,12 @@
}
virtual std::unique_ptr<cmRulePlaceholderExpander>
- CreateRulePlaceholderExpander() const;
+ CreateRulePlaceholderExpander(
+ cmBuildStep buildStep = cmBuildStep::Compile) const;
+ virtual std::unique_ptr<cmRulePlaceholderExpander>
+ CreateRulePlaceholderExpander(cmBuildStep buildStep,
+ cmGeneratorTarget const* target,
+ std::string const& language);
std::string GetLinkLibsCMP0065(std::string const& linkLanguage,
cmGeneratorTarget& tgt) const;
@@ -174,6 +150,12 @@
const std::string& lang);
void AddConfigVariableFlags(std::string& flags, const std::string& var,
const std::string& config);
+ // Handle prefixes processing (like LINKER:)
+ void AddConfigVariableFlags(std::string& flags, const std::string& var,
+ cmGeneratorTarget const* target,
+ cmBuildStep compileOrLink,
+ const std::string& lang,
+ const std::string& config);
void AddColorDiagnosticsFlags(std::string& flags, const std::string& lang);
//! Append flags to a string.
virtual void AppendFlags(std::string& flags,
@@ -182,6 +164,13 @@
const std::vector<BT<std::string>>& newFlags) const;
virtual void AppendFlagEscape(std::string& flags,
const std::string& rawFlag) const;
+ /**
+ * Append flags after parsing, prefixes processing (like LINKER:) and
+ * escaping
+ */
+ void AppendFlags(std::string& flags, std::string const& newFlags,
+ const std::string& name, const cmGeneratorTarget* target,
+ cmBuildStep compileOrLink, const std::string& lang);
void AddISPCDependencies(cmGeneratorTarget* target);
void AddPchDependencies(cmGeneratorTarget* target);
void AddUnityBuild(cmGeneratorTarget* target);
@@ -699,28 +688,37 @@
{
}
};
+ /** Whether to insert relative or absolute paths into unity files */
+ enum class UnityPathMode
+ {
+ Absolute,
+ Relative
+ };
UnitySource WriteUnitySource(
cmGeneratorTarget* target, std::vector<std::string> const& configs,
cmRange<std::vector<UnityBatchedSource>::const_iterator> sources,
- cmValue beforeInclude, cmValue afterInclude, std::string filename) const;
+ cmValue beforeInclude, cmValue afterInclude, std::string filename,
+ std::string const& unityFileDirectory, UnityPathMode pathMode) const;
void WriteUnitySourceInclude(std::ostream& unity_file,
cm::optional<std::string> const& cond,
std::string const& sf_full_path,
cmValue beforeInclude, cmValue afterInclude,
- cmValue uniqueIdName) const;
+ cmValue uniqueIdName, UnityPathMode pathMode,
+ std::string const& unityFileDirectory) const;
std::vector<UnitySource> AddUnityFilesModeAuto(
cmGeneratorTarget* target, std::string const& lang,
std::vector<std::string> const& configs,
std::vector<UnityBatchedSource> const& filtered_sources,
cmValue beforeInclude, cmValue afterInclude,
- std::string const& filename_base, size_t batchSize);
+ std::string const& filename_base, UnityPathMode pathMode,
+ size_t batchSize);
std::vector<UnitySource> AddUnityFilesModeGroup(
cmGeneratorTarget* target, std::string const& lang,
std::vector<std::string> const& configs,
std::vector<UnityBatchedSource> const& filtered_sources,
cmValue beforeInclude, cmValue afterInclude,
- std::string const& filename_base);
+ std::string const& filename_base, UnityPathMode pathMode);
};
namespace detail {
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index 46a95af..a566a46 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -50,9 +50,20 @@
// Virtual public methods.
std::unique_ptr<cmRulePlaceholderExpander>
-cmLocalNinjaGenerator::CreateRulePlaceholderExpander() const
+cmLocalNinjaGenerator::CreateRulePlaceholderExpander(
+ cmBuildStep buildStep) const
{
- auto ret = this->cmLocalGenerator::CreateRulePlaceholderExpander();
+ auto ret = this->cmLocalGenerator::CreateRulePlaceholderExpander(buildStep);
+ ret->SetTargetImpLib("$TARGET_IMPLIB");
+ return std::unique_ptr<cmRulePlaceholderExpander>(std::move(ret));
+}
+std::unique_ptr<cmRulePlaceholderExpander>
+cmLocalNinjaGenerator::CreateRulePlaceholderExpander(
+ cmBuildStep buildStep, cmGeneratorTarget const* target,
+ std::string const& language)
+{
+ auto ret = this->cmLocalGenerator::CreateRulePlaceholderExpander(
+ buildStep, target, language);
ret->SetTargetImpLib("$TARGET_IMPLIB");
return std::unique_ptr<cmRulePlaceholderExpander>(std::move(ret));
}
diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h
index 74b8b3b..1abc410 100644
--- a/Source/cmLocalNinjaGenerator.h
+++ b/Source/cmLocalNinjaGenerator.h
@@ -11,6 +11,7 @@
#include <string>
#include <vector>
+#include "cmGeneratorOptions.h"
#include "cmLocalCommonGenerator.h"
#include "cmNinjaTypes.h"
#include "cmOutputConverter.h"
@@ -42,8 +43,11 @@
void Generate() override;
- std::unique_ptr<cmRulePlaceholderExpander> CreateRulePlaceholderExpander()
- const override;
+ std::unique_ptr<cmRulePlaceholderExpander> CreateRulePlaceholderExpander(
+ cmBuildStep buildStep = cmBuildStep::Compile) const override;
+ std::unique_ptr<cmRulePlaceholderExpander> CreateRulePlaceholderExpander(
+ cmBuildStep buildStep, cmGeneratorTarget const* target,
+ std::string const& language) override;
std::string GetTargetDirectory(
cmGeneratorTarget const* target) const override;
diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h
index 7d5a922..6db410b 100644
--- a/Source/cmLocalUnixMakefileGenerator3.h
+++ b/Source/cmLocalUnixMakefileGenerator3.h
@@ -12,8 +12,8 @@
#include <vector>
#include "cmDepends.h"
+#include "cmGeneratorOptions.h"
#include "cmLocalCommonGenerator.h"
-#include "cmLocalGenerator.h"
class cmCustomCommand;
class cmCustomCommandGenerator;
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 8be21c2..97df2a5 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -25,6 +25,7 @@
#include "cmCustomCommandLines.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
+#include "cmGeneratorOptions.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalVisualStudio7Generator.h"
@@ -664,16 +665,16 @@
}
std::string flags;
std::string langForClCompile;
+ const std::string& linkLanguage =
+ (this->FortranProject ? std::string("Fortran")
+ : target->GetLinkerLanguage(configName));
+ if (linkLanguage.empty()) {
+ cmSystemTools::Error(
+ cmStrCat("CMake can not determine linker language for target: ",
+ target->GetName()));
+ return;
+ }
if (target->GetType() <= cmStateEnums::OBJECT_LIBRARY) {
- const std::string& linkLanguage =
- (this->FortranProject ? std::string("Fortran")
- : target->GetLinkerLanguage(configName));
- if (linkLanguage.empty()) {
- cmSystemTools::Error(
- cmStrCat("CMake can not determine linker language for target: ",
- target->GetName()));
- return;
- }
langForClCompile = linkLanguage;
if (langForClCompile == "C" || langForClCompile == "CXX" ||
langForClCompile == "Fortran") {
@@ -957,26 +958,14 @@
}
this->OutputTargetRules(fout, configName, target, libName);
- this->OutputBuildTool(fout, configName, target, targetOptions);
+ this->OutputBuildTool(fout, linkLanguage, configName, target, targetOptions);
this->OutputDeploymentDebuggerTool(fout, configName, target);
fout << "\t\t</Configuration>\n";
}
-std::string cmLocalVisualStudio7Generator::GetBuildTypeLinkerFlags(
- std::string const& rootLinkerFlags, const std::string& configName)
-{
- std::string configTypeUpper = cmSystemTools::UpperCase(configName);
- std::string extraLinkOptionsBuildTypeDef =
- cmStrCat(rootLinkerFlags, '_', configTypeUpper);
-
- const std::string& extraLinkOptionsBuildType =
- this->Makefile->GetRequiredDefinition(extraLinkOptionsBuildTypeDef);
-
- return extraLinkOptionsBuildType;
-}
-
void cmLocalVisualStudio7Generator::OutputBuildTool(
- std::ostream& fout, const std::string& configName, cmGeneratorTarget* target,
+ std::ostream& fout, const std::string& linkLanguage,
+ const std::string& configName, cmGeneratorTarget* target,
const Options& targetOptions)
{
cmGlobalVisualStudio7Generator* gg =
@@ -984,19 +973,19 @@
std::string temp;
std::string extraLinkOptions;
if (target->GetType() == cmStateEnums::EXECUTABLE) {
- extraLinkOptions = cmStrCat(
- this->Makefile->GetRequiredDefinition("CMAKE_EXE_LINKER_FLAGS"), ' ',
- GetBuildTypeLinkerFlags("CMAKE_EXE_LINKER_FLAGS", configName));
+ this->AddConfigVariableFlags(extraLinkOptions, "CMAKE_EXE_LINKER_FLAGS",
+ target, cmBuildStep::Link, linkLanguage,
+ configName);
}
if (target->GetType() == cmStateEnums::SHARED_LIBRARY) {
- extraLinkOptions = cmStrCat(
- this->Makefile->GetRequiredDefinition("CMAKE_SHARED_LINKER_FLAGS"), ' ',
- GetBuildTypeLinkerFlags("CMAKE_SHARED_LINKER_FLAGS", configName));
+ this->AddConfigVariableFlags(extraLinkOptions, "CMAKE_SHARED_LINKER_FLAGS",
+ target, cmBuildStep::Link, linkLanguage,
+ configName);
}
if (target->GetType() == cmStateEnums::MODULE_LIBRARY) {
- extraLinkOptions = cmStrCat(
- this->Makefile->GetRequiredDefinition("CMAKE_MODULE_LINKER_FLAGS"), ' ',
- GetBuildTypeLinkerFlags("CMAKE_MODULE_LINKER_FLAGS", configName));
+ this->AddConfigVariableFlags(extraLinkOptions, "CMAKE_MODULE_LINKER_FLAGS",
+ target, cmBuildStep::Link, linkLanguage,
+ configName);
}
cmValue targetLinkFlags = target->GetProperty("LINK_FLAGS");
@@ -1089,7 +1078,6 @@
return;
}
cmComputeLinkInformation& cli = *pcli;
- std::string linkLanguage = cli.GetLinkLanguage();
if (!target->GetLinkerTypeProperty(linkLanguage, configName).empty()) {
// Visual Studio 10 or upper is required for this feature
@@ -1173,7 +1161,6 @@
return;
}
cmComputeLinkInformation& cli = *pcli;
- std::string linkLanguage = cli.GetLinkLanguage();
if (!target->GetLinkerTypeProperty(linkLanguage, configName).empty()) {
// Visual Studio 10 or upper is required for this feature
diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h
index 7c395d6..baf85fb 100644
--- a/Source/cmLocalVisualStudio7Generator.h
+++ b/Source/cmLocalVisualStudio7Generator.h
@@ -99,8 +99,6 @@
private:
using Options = cmVS7GeneratorOptions;
using FCInfo = cmLocalVisualStudio7GeneratorFCInfo;
- std::string GetBuildTypeLinkerFlags(std::string const& rootLinkerFlags,
- const std::string& configName);
void FixGlobalTargets();
void WriteVCProjHeader(std::ostream& fout, const std::string& libName,
cmGeneratorTarget* tgt,
@@ -119,8 +117,9 @@
void OutputTargetRules(std::ostream& fout, const std::string& configName,
cmGeneratorTarget* target,
const std::string& libName);
- void OutputBuildTool(std::ostream& fout, const std::string& configName,
- cmGeneratorTarget* t, const Options& targetOptions);
+ void OutputBuildTool(std::ostream& fout, const std::string& linkLanguage,
+ const std::string& configName, cmGeneratorTarget* t,
+ const Options& targetOptions);
void OutputDeploymentDebuggerTool(std::ostream& fout,
std::string const& config,
cmGeneratorTarget* target);
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 98da10d..c6a831b 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -486,10 +486,6 @@
return result;
}
- if (this->ExecuteCommandCallback) {
- this->ExecuteCommandCallback();
- }
-
// Place this call on the call stack.
cmMakefileCall stack_manager(this, lff, std::move(deferId), status);
static_cast<void>(stack_manager);
@@ -545,6 +541,10 @@
}
}
+ if (this->ExecuteCommandCallback) {
+ this->ExecuteCommandCallback();
+ }
+
return result;
}
@@ -2088,7 +2088,7 @@
cmList files(value);
for (auto& file : files) {
if (!cmIsOff(file)) {
- file = cmSystemTools::CollapseFullPath(file);
+ file = cmSystemTools::ToNormalizedPathOnDisk(file);
}
}
nvalue = files.to_string();
@@ -2387,13 +2387,9 @@
cmSourceGroup* cmMakefile::GetOrCreateSourceGroup(const std::string& name)
{
- std::string delimiters;
- if (cmValue p = this->GetDefinition("SOURCE_GROUP_DELIMITER")) {
- delimiters = *p;
- } else {
- delimiters = "/\\";
- }
- return this->GetOrCreateSourceGroup(cmTokenize(name, delimiters));
+ auto p = this->GetDefinition("SOURCE_GROUP_DELIMITER");
+ return this->GetOrCreateSourceGroup(
+ cmTokenize(name, p ? cm::string_view(*p) : R"(\/)"_s));
}
/**
@@ -3722,10 +3718,7 @@
// use the cmake object instead of calling cmake
cmWorkingDirectory workdir(bindir);
if (workdir.Failed()) {
- this->IssueMessage(MessageType::FATAL_ERROR,
- cmStrCat("Failed to set working directory to ", bindir,
- " : ",
- std::strerror(workdir.GetLastResult())));
+ this->IssueMessage(MessageType::FATAL_ERROR, workdir.GetError());
cmSystemTools::SetFatalErrorOccurred();
this->IsSourceFileTryCompile = false;
return 1;
@@ -4645,14 +4638,14 @@
}
// Deprecate old policies.
- if (status == cmPolicies::OLD && id <= cmPolicies::CMP0129 &&
+ if (status == cmPolicies::OLD && id <= cmPolicies::CMP0139 &&
!(this->GetCMakeInstance()->GetIsInTryCompile() &&
(
// Policies set by cmCoreTryCompile::TryCompileCode.
id == cmPolicies::CMP0065 || id == cmPolicies::CMP0083 ||
id == cmPolicies::CMP0091 || id == cmPolicies::CMP0104 ||
id == cmPolicies::CMP0123 || id == cmPolicies::CMP0126 ||
- id == cmPolicies::CMP0128)) &&
+ id == cmPolicies::CMP0128 || id == cmPolicies::CMP0136)) &&
(!this->IsSet("CMAKE_WARN_DEPRECATED") ||
this->IsOn("CMAKE_WARN_DEPRECATED"))) {
this->IssueMessage(MessageType::DEPRECATION_WARNING,
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index 96a0d5c..e24f2b7 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -12,6 +12,7 @@
#include <cmext/algorithm>
#include "cmGeneratedFileStream.h"
+#include "cmGeneratorOptions.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalUnixMakefileGenerator3.h"
#include "cmLinkLineComputer.h"
@@ -233,7 +234,8 @@
}
auto rulePlaceholderExpander =
- this->LocalGenerator->CreateRulePlaceholderExpander();
+ this->LocalGenerator->CreateRulePlaceholderExpander(
+ cmBuildStep::Link, this->GeneratorTarget, linkLanguage);
// Expand placeholders in the commands.
rulePlaceholderExpander->SetTargetImpLib(targetOutput);
@@ -370,19 +372,20 @@
// Add flags to create an executable.
this->LocalGenerator->AddConfigVariableFlags(
- linkFlags, "CMAKE_EXE_LINKER_FLAGS", this->GetConfigName());
+ linkFlags, "CMAKE_EXE_LINKER_FLAGS", this->GeneratorTarget,
+ cmBuildStep::Link, linkLanguage, this->GetConfigName());
- if (this->GeneratorTarget->IsWin32Executable(
- this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"))) {
+ {
+ auto exeType =
+ cmStrCat("CMAKE_", linkLanguage, "_CREATE_",
+ (this->GeneratorTarget->IsWin32Executable(
+ this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"))
+ ? "WIN32"
+ : "CONSOLE"),
+ "_EXE");
this->LocalGenerator->AppendFlags(
- linkFlags,
- this->Makefile->GetSafeDefinition(
- cmStrCat("CMAKE_", linkLanguage, "_CREATE_WIN32_EXE")));
- } else {
- this->LocalGenerator->AppendFlags(
- linkFlags,
- this->Makefile->GetSafeDefinition(
- cmStrCat("CMAKE_", linkLanguage, "_CREATE_CONSOLE_EXE")));
+ linkFlags, this->Makefile->GetDefinition(exeType), exeType,
+ this->GeneratorTarget, cmBuildStep::Link, linkLanguage);
}
// Add symbol export flags if necessary.
@@ -602,7 +605,8 @@
}
auto rulePlaceholderExpander =
- this->LocalGenerator->CreateRulePlaceholderExpander();
+ this->LocalGenerator->CreateRulePlaceholderExpander(
+ cmBuildStep::Link, this->GeneratorTarget, linkLanguage);
// Expand placeholders in the commands.
rulePlaceholderExpander->SetTargetImpLib(targetOutPathImport);
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index 225e63b..746ee50 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -12,6 +12,7 @@
#include <cmext/algorithm>
#include "cmGeneratedFileStream.h"
+#include "cmGeneratorOptions.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalUnixMakefileGenerator3.h"
#include "cmLinkLineComputer.h"
@@ -177,7 +178,8 @@
std::string extraFlags;
this->GetTargetLinkFlags(extraFlags, linkLanguage);
this->LocalGenerator->AddConfigVariableFlags(
- extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->GetConfigName());
+ extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->GeneratorTarget,
+ cmBuildStep::Link, linkLanguage, this->GetConfigName());
std::unique_ptr<cmLinkLineComputer> linkLineComputer =
this->CreateLinkLineComputer(
@@ -212,7 +214,8 @@
std::string extraFlags;
this->GetTargetLinkFlags(extraFlags, linkLanguage);
this->LocalGenerator->AddConfigVariableFlags(
- extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->GetConfigName());
+ extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->GeneratorTarget,
+ cmBuildStep::Link, linkLanguage, this->GetConfigName());
std::unique_ptr<cmLinkLineComputer> linkLineComputer =
this->CreateLinkLineComputer(
@@ -239,7 +242,8 @@
std::string extraFlags;
this->GetTargetLinkFlags(extraFlags, linkLanguage);
this->LocalGenerator->AddConfigVariableFlags(
- extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS", this->GetConfigName());
+ extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS", this->GeneratorTarget,
+ cmBuildStep::Link, linkLanguage, this->GetConfigName());
this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
}
@@ -382,7 +386,8 @@
}
auto rulePlaceholderExpander =
- this->LocalGenerator->CreateRulePlaceholderExpander();
+ this->LocalGenerator->CreateRulePlaceholderExpander(
+ cmBuildStep::Link, this->GeneratorTarget, linkLanguage);
// Construct the main link rule and expand placeholders.
rulePlaceholderExpander->SetTargetImpLib(targetOutput);
@@ -707,7 +712,8 @@
// Expand the rule variables.
auto rulePlaceholderExpander =
- this->LocalGenerator->CreateRulePlaceholderExpander();
+ this->LocalGenerator->CreateRulePlaceholderExpander(
+ cmBuildStep::Link, this->GeneratorTarget, linkLanguage);
bool useWatcomQuote =
this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE");
cmList real_link_commands;
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 9d0d466..e27e7fd 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -25,6 +25,7 @@
#include "cmFileSet.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
+#include "cmGeneratorOptions.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalUnixMakefileGenerator3.h"
#include "cmLinkLineComputer.h" // IWYU pragma: keep
@@ -683,9 +684,7 @@
// The object file should be checked for dependency integrity.
std::string objFullPath =
cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/', obj);
- objFullPath = cmSystemTools::CollapseFullPath(objFullPath);
- std::string const srcFullPath =
- cmSystemTools::CollapseFullPath(source.GetFullPath());
+ std::string const srcFullPath = source.GetFullPath();
this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, lang,
objFullPath, srcFullPath, scanner);
@@ -1560,8 +1559,7 @@
cmOutputConverter::SHELL)
<< " "
<< this->LocalGenerator->ConvertToOutputFormat(
- cmSystemTools::CollapseFullPath(this->InfoFileNameFull),
- cmOutputConverter::SHELL);
+ this->InfoFileNameFull, cmOutputConverter::SHELL);
if (this->LocalGenerator->GetColorMakefile()) {
depCmd << " \"--color=$(COLOR)\"";
}
@@ -1710,7 +1708,8 @@
vars.Flags = flags.c_str();
std::string compileCmd = this->GetLinkRule("CMAKE_CUDA_DEVICE_LINK_COMPILE");
- auto rulePlaceholderExpander = localGen->CreateRulePlaceholderExpander();
+ auto rulePlaceholderExpander = localGen->CreateRulePlaceholderExpander(
+ cmBuildStep::Link, this->GetGeneratorTarget(), "CUDA");
rulePlaceholderExpander->ExpandRuleVariables(localGen, compileCmd, vars);
commands.emplace_back(compileCmd);
diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
index a4b2538..3a40069 100644
--- a/Source/cmMessageCommand.cxx
+++ b/Source/cmMessageCommand.cxx
@@ -26,14 +26,6 @@
namespace {
-enum class CheckingType
-{
- UNDEFINED,
- CHECK_START,
- CHECK_PASS,
- CHECK_FAIL
-};
-
std::string IndentText(std::string text, cmMakefile& mf)
{
auto indent =
@@ -106,7 +98,7 @@
auto type = MessageType::MESSAGE;
auto fatal = false;
auto level = Message::LogLevel::LOG_UNDEFINED;
- auto checkingType = CheckingType::UNDEFINED;
+ auto checkingType = Message::CheckType::UNDEFINED;
if (*i == "SEND_ERROR") {
type = MessageType::FATAL_ERROR;
level = Message::LogLevel::LOG_ERROR;
@@ -135,15 +127,15 @@
++i;
} else if (*i == "CHECK_START") {
level = Message::LogLevel::LOG_STATUS;
- checkingType = CheckingType::CHECK_START;
+ checkingType = Message::CheckType::CHECK_START;
++i;
} else if (*i == "CHECK_PASS") {
level = Message::LogLevel::LOG_STATUS;
- checkingType = CheckingType::CHECK_PASS;
+ checkingType = Message::CheckType::CHECK_PASS;
++i;
} else if (*i == "CHECK_FAIL") {
level = Message::LogLevel::LOG_STATUS;
- checkingType = CheckingType::CHECK_FAIL;
+ checkingType = Message::CheckType::CHECK_FAIL;
++i;
} else if (*i == "CONFIGURE_LOG") {
#ifndef CMAKE_BOOTSTRAP
@@ -217,16 +209,16 @@
case Message::LogLevel::LOG_STATUS:
switch (checkingType) {
- case CheckingType::CHECK_START:
+ case Message::CheckType::CHECK_START:
mf.DisplayStatus(IndentText(message, mf), -1);
mf.GetCMakeInstance()->PushCheckInProgressMessage(message);
break;
- case CheckingType::CHECK_PASS:
+ case Message::CheckType::CHECK_PASS:
ReportCheckResult("CHECK_PASS"_s, message, mf);
break;
- case CheckingType::CHECK_FAIL:
+ case Message::CheckType::CHECK_FAIL:
ReportCheckResult("CHECK_FAIL"_s, message, mf);
break;
diff --git a/Source/cmMessageType.h b/Source/cmMessageType.h
index decb4b3..a877592 100644
--- a/Source/cmMessageType.h
+++ b/Source/cmMessageType.h
@@ -6,6 +6,7 @@
enum class MessageType
{
+ UNDEFINED,
AUTHOR_WARNING,
AUTHOR_ERROR,
FATAL_ERROR,
@@ -31,4 +32,13 @@
LOG_DEBUG,
LOG_TRACE
};
+
+enum class CheckType
+{
+ UNDEFINED,
+ CHECK_START,
+ CHECK_PASS,
+ CHECK_FAIL
+};
+
}
diff --git a/Source/cmMessenger.cxx b/Source/cmMessenger.cxx
index 01ff7f0..1583353 100644
--- a/Source/cmMessenger.cxx
+++ b/Source/cmMessenger.cxx
@@ -102,11 +102,10 @@
t == MessageType::DEPRECATION_ERROR || t == MessageType::AUTHOR_ERROR) {
cmSystemTools::SetErrorOccurred();
md.title = "Error";
- cmSystemTools::Message(msg.str(), md);
} else {
md.title = "Warning";
- cmSystemTools::Message(msg.str(), md);
}
+ cmSystemTools::Message(msg.str(), md);
}
void PrintCallStack(std::ostream& out, cmListFileBacktrace bt,
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index 891187a..ff514ff 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -18,6 +18,7 @@
#include "cmCustomCommand.h" // IWYU pragma: keep
#include "cmCustomCommandGenerator.h"
#include "cmGeneratedFileStream.h"
+#include "cmGeneratorOptions.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalNinjaGenerator.h"
#include "cmLinkLineComputer.h"
@@ -350,7 +351,9 @@
}
auto rulePlaceholderExpander =
- this->GetLocalGenerator()->CreateRulePlaceholderExpander();
+ this->GetLocalGenerator()->CreateRulePlaceholderExpander(
+ cmBuildStep::Link, this->GetGeneratorTarget(),
+ this->TargetLinkLanguage(config));
// Rule for linking library/executable.
std::vector<std::string> linkCmds = this->ComputeDeviceLinkCmd();
@@ -413,7 +416,9 @@
std::string compileCmd = this->GetMakefile()->GetRequiredDefinition(
"CMAKE_CUDA_DEVICE_LINK_COMPILE");
auto rulePlaceholderExpander =
- this->GetLocalGenerator()->CreateRulePlaceholderExpander();
+ this->GetLocalGenerator()->CreateRulePlaceholderExpander(
+ cmBuildStep::Link, this->GetGeneratorTarget(),
+ this->TargetLinkLanguage(config));
rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
compileCmd, vars);
@@ -566,7 +571,9 @@
}
auto rulePlaceholderExpander =
- this->GetLocalGenerator()->CreateRulePlaceholderExpander();
+ this->GetLocalGenerator()->CreateRulePlaceholderExpander(
+ cmBuildStep::Link, this->GetGeneratorTarget(),
+ this->TargetLinkLanguage(config));
// Rule for linking library/executable.
std::vector<std::string> linkCmds = this->ComputeLinkCmd(config);
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 720020d..144fa35 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -29,6 +29,7 @@
#include "cmFileSet.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
+#include "cmGeneratorOptions.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalCommonGenerator.h"
#include "cmGlobalNinjaGenerator.h"
@@ -1289,11 +1290,9 @@
if (cmValue name = target->GetProperty("Swift_DEPENDENCIES_FILE")) {
return *name;
}
- return this->GetLocalGenerator()->ConvertToOutputFormat(
- this->ConvertToNinjaPath(cmStrCat(target->GetSupportDirectory(), '/',
- config, '/', target->GetName(),
- ".swiftdeps")),
- cmOutputConverter::SHELL);
+ return this->ConvertToNinjaPath(cmStrCat(target->GetSupportDirectory(),
+ '/', config, '/',
+ target->GetName(), ".swiftdeps"));
}();
std::string mapFilePath =
@@ -1311,7 +1310,7 @@
// Add flag
this->LocalGenerator->AppendFlags(flags, "-output-file-map");
- this->LocalGenerator->AppendFlagEscape(
+ this->LocalGenerator->AppendFlags(
flags,
this->GetLocalGenerator()->ConvertToOutputFormat(
ConvertToNinjaPath(mapFilePath), cmOutputConverter::SHELL));
@@ -2014,7 +2013,10 @@
std::string const emitModuleFlag = "-emit-module";
std::string const modulePathFlag = "-emit-module-path";
this->LocalGenerator->AppendFlags(
- vars["FLAGS"], { emitModuleFlag, modulePathFlag, moduleFilepath });
+ vars["FLAGS"],
+ { emitModuleFlag, modulePathFlag,
+ this->LocalGenerator->ConvertToOutputFormat(
+ moduleFilepath, cmOutputConverter::SHELL) });
objBuild.Outputs.push_back(moduleFilepath);
}
this->LocalGenerator->AppendFlags(vars["FLAGS"],
@@ -2273,7 +2275,10 @@
}
compileObjectVars.Source = escapedSourceFileName.c_str();
- compileObjectVars.Object = objectFileName.c_str();
+ std::string escapedObjectFileName =
+ this->LocalGenerator->ConvertToOutputFormat(objectFileName,
+ cmOutputConverter::SHELL);
+ compileObjectVars.Object = escapedObjectFileName.c_str();
compileObjectVars.ObjectDir = objectDir.c_str();
compileObjectVars.ObjectFileDir = objectFileDir.c_str();
compileObjectVars.Flags = fullFlags.c_str();
diff --git a/Source/cmPathResolver.cxx b/Source/cmPathResolver.cxx
new file mode 100644
index 0000000..93457a5
--- /dev/null
+++ b/Source/cmPathResolver.cxx
@@ -0,0 +1,541 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmPathResolver.h"
+
+#include <algorithm>
+#include <cerrno>
+#include <cstddef>
+#include <string>
+#include <utility>
+
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#ifdef _WIN32
+# include <cctype>
+
+# include <windows.h>
+#endif
+
+#define MAX_SYMBOLIC_LINKS 32
+
+namespace cm {
+namespace PathResolver {
+
+namespace {
+
+namespace Options {
+
+enum class ActualCase
+{
+ No,
+ Yes,
+};
+
+enum class Symlinks
+{
+ None,
+ Lazy,
+ Eager,
+};
+
+enum class Existence
+{
+ Agnostic,
+ Required,
+};
+}
+
+enum class Root
+{
+ None,
+ POSIX,
+#ifdef _WIN32
+ Drive,
+ Network,
+#endif
+};
+
+struct Control
+{
+ enum class Tag
+ {
+ Continue,
+ Restart,
+ Error,
+ };
+ Tag tag;
+ union
+ {
+ std::string::size_type slash; // data for Continue
+ cmsys::Status error; // data for Error
+ };
+ static Control Continue(std::string::size_type s)
+ {
+ Control c{ Tag::Continue };
+ c.slash = s;
+ return c;
+ }
+ static Control Restart() { return Control{ Tag::Restart }; }
+ static Control Error(cmsys::Status e)
+ {
+ Control c{ Tag::Error };
+ c.error = e;
+ return c;
+ }
+
+private:
+ Control(Tag t)
+ : tag(t)
+ {
+ }
+};
+
+Root ClassifyRoot(cm::string_view p)
+{
+#ifdef _WIN32
+ if (p.size() >= 2 && std::isalpha(p[0]) && p[1] == ':') {
+ return Root::Drive;
+ }
+ if (p.size() >= 3 && p[0] == '/' && p[1] == '/' && p[2] != '/') {
+ return Root::Network;
+ }
+#endif
+ if (!p.empty() && p[0] == '/') {
+ return Root::POSIX;
+ }
+ return Root::None;
+}
+
+class ImplBase
+{
+protected:
+ ImplBase(System& os)
+ : OS(os)
+ {
+ }
+
+ System& OS;
+ std::string P;
+ std::size_t SymlinkDepth = 0;
+
+#ifdef _WIN32
+ std::string GetWorkingDirectoryOnDrive(char letter);
+ Control ResolveRootRelative();
+#endif
+ cm::optional<std::string> ReadSymlink(std::string const& path,
+ cmsys::Status& status);
+ Control ResolveSymlink(Root root, std::string::size_type slash,
+ std::string::size_type next_slash,
+ std::string symlink_target);
+};
+
+template <class Policy>
+class Impl : public ImplBase
+{
+ Control ResolveRelativePath();
+ Control ResolveRoot(Root root);
+ Control ResolveComponent(Root root, std::string::size_type root_slash,
+ std::string::size_type slash);
+ Control ResolvePath();
+
+public:
+ Impl(System& os)
+ : ImplBase(os)
+ {
+ }
+ cmsys::Status Resolve(std::string in, std::string& out);
+};
+
+template <class Policy>
+Control Impl<Policy>::ResolveRelativePath()
+{
+ // This is a relative path. Convert it to absolute and restart.
+ std::string p = this->OS.GetWorkingDirectory();
+ std::replace(p.begin(), p.end(), '\\', '/');
+ if (ClassifyRoot(p) == Root::None) {
+ p.insert(0, 1, '/');
+ }
+ if (p.back() != '/') {
+ p.push_back('/');
+ }
+ P.insert(0, p);
+ return Control::Restart();
+}
+
+#ifdef _WIN32
+std::string ImplBase::GetWorkingDirectoryOnDrive(char letter)
+{
+ // Use the drive's working directory, if any.
+ std::string d = this->OS.GetWorkingDirectoryOnDrive(letter);
+ std::replace(d.begin(), d.end(), '\\', '/');
+ if (d.size() >= 3 && std::toupper(d[0]) == std::toupper(letter) &&
+ d[1] == ':' && d[2] == '/') {
+ d[0] = letter;
+ d.push_back('/');
+ return d;
+ }
+
+ // Use the current working directory if the drive matches.
+ d = this->OS.GetWorkingDirectory();
+ if (d.size() >= 3 && std::toupper(d[0]) == std::toupper(letter) &&
+ d[1] == ':' && d[2] == '/') {
+ d[0] = letter;
+ d.push_back('/');
+ return d;
+ }
+
+ // Fall back to the root directory on the drive.
+ d = "_:/";
+ d[0] = letter;
+ return d;
+}
+
+Control ImplBase::ResolveRootRelative()
+{
+ // This is a root-relative path. Resolve the root drive and restart.
+ P.replace(0, 2, this->GetWorkingDirectoryOnDrive(P[0]));
+ return Control::Restart();
+}
+#endif
+
+cm::optional<std::string> ImplBase::ReadSymlink(std::string const& path,
+ cmsys::Status& status)
+{
+ cm::optional<std::string> result;
+ std::string target;
+ status = this->OS.ReadSymlink(path, target);
+ if (status && ++this->SymlinkDepth >= MAX_SYMBOLIC_LINKS) {
+ status = cmsys::Status::POSIX(ELOOP);
+ }
+ if (status) {
+ if (!target.empty()) {
+ result = std::move(target);
+ }
+ } else if (status.GetPOSIX() == EINVAL
+#ifdef _WIN32
+ || status.GetWindows() == ERROR_NOT_A_REPARSE_POINT
+#endif
+ ) {
+ // The path was not a symlink.
+ status = cmsys::Status::Success();
+ }
+ return result;
+}
+
+Control ImplBase::ResolveSymlink(Root root, std::string::size_type slash,
+ std::string::size_type next_slash,
+ std::string symlink_target)
+{
+ std::replace(symlink_target.begin(), symlink_target.end(), '\\', '/');
+ Root const symlink_target_root = ClassifyRoot(symlink_target);
+ if (symlink_target_root == Root::None) {
+ // This is a symlink to a relative path.
+ // Resolve the symlink, while preserving the leading and
+ // trailing (if any) slash:
+ // "*/link/" => "*/dest/"
+ // ^slash ^slash
+ P.replace(slash + 1, next_slash - slash - 1, symlink_target);
+ return Control::Continue(slash);
+ }
+
+#ifdef _WIN32
+ if (root == Root::Drive && symlink_target_root == Root::POSIX) {
+ // This is a symlink to a POSIX absolute path,
+ // but the current path is on a drive letter. Resolve the
+ // symlink while preserving the drive letter, and start over:
+ // "C:/*/link/" => "C:/dest/"
+ // ^slash (restart)
+ P.replace(2, next_slash - 2, symlink_target);
+ return Control::Restart();
+ }
+#else
+ static_cast<void>(root);
+#endif
+
+ // This is a symlink to an absolute path.
+ // Resolve it and start over:
+ // "*/link/" => "/dest/"
+ // ^slash (restart)
+ P.replace(0, next_slash, symlink_target);
+ return Control::Restart();
+}
+
+template <class Policy>
+Control Impl<Policy>::ResolveRoot(Root root)
+{
+ if (root == Root::None) {
+ return this->ResolveRelativePath();
+ }
+
+ // POSIX absolute paths always start with a '/'.
+ std::string::size_type root_slash = 0;
+
+#ifdef _WIN32
+ if (root == Root::Drive) {
+ if (P.size() == 2 || P[2] != '/') {
+ return this->ResolveRootRelative();
+ }
+
+ if (Policy::ActualCase == Options::ActualCase::Yes) {
+ // Normalize the drive letter to upper-case.
+ P[0] = static_cast<char>(std::toupper(P[0]));
+ }
+
+ // The root is a drive letter. The root '/' immediately follows.
+ root_slash = 2;
+ } else if (root == Root::Network) {
+ // The root is a network name. Find the root '/' after it.
+ root_slash = P.find('/', 2);
+ if (root_slash == std::string::npos) {
+ root_slash = P.size();
+ P.push_back('/');
+ }
+ }
+#endif
+
+ if (Policy::Existence == Options::Existence::Required
+#ifdef _WIN32
+ && root != Root::Network
+#endif
+ ) {
+ std::string path = P.substr(0, root_slash + 1);
+ if (!this->OS.PathExists(path)) {
+ P = std::move(path);
+ return Control::Error(cmsys::Status::POSIX(ENOENT));
+ }
+ }
+
+ return Control::Continue(root_slash);
+}
+
+template <class Policy>
+Control Impl<Policy>::ResolveComponent(Root root,
+ std::string::size_type root_slash,
+ std::string::size_type slash)
+{
+ // Look for the '/' or end-of-input that ends this component.
+ // The sample paths in comments below show the trailing slash
+ // even if it is actually beyond the end of the path.
+ std::string::size_type next_slash = P.find('/', slash + 1);
+ if (next_slash == std::string::npos) {
+ next_slash = P.size();
+ }
+ cm::string_view c =
+ cm::string_view(P).substr(slash + 1, next_slash - (slash + 1));
+
+ if (slash == root_slash) {
+ if (c.empty() || c == "."_s || c == ".."_s) {
+ // This is an empty, '.', or '..' component at the root.
+ // Drop the component and its trailing slash, if any,
+ // while preserving the root slash:
+ // "//" => "/"
+ // "/./" => "/"
+ // "/../" => "/"
+ // ^slash ^slash
+ P.erase(slash + 1, next_slash - slash);
+ return Control::Continue(slash);
+ }
+ } else {
+ if (c.empty() || c == "."_s) {
+ // This is an empty or '.' component not at the root.
+ // Drop the component and its leading slash:
+ // "*//" => "*/"
+ // "*/./" => "*/"
+ // ^slash ^slash
+ P.erase(slash, next_slash - slash);
+ return Control::Continue(slash);
+ }
+
+ if (c == ".."_s) {
+ // This is a '..' component not at the root.
+ // Rewind to the previous component:
+ // "*/prev/../" => "*/prev/../"
+ // ^slash ^slash
+ next_slash = slash;
+ slash = P.rfind('/', slash - 1);
+
+ if (Policy::Symlinks == Options::Symlinks::Lazy) {
+ cmsys::Status status;
+ std::string path = P.substr(0, next_slash);
+ if (cm::optional<std::string> maybe_symlink_target =
+ this->ReadSymlink(path, status)) {
+ return this->ResolveSymlink(root, slash, next_slash,
+ std::move(*maybe_symlink_target));
+ }
+ if (!status && Policy::Existence == Options::Existence::Required) {
+ P = std::move(path);
+ return Control::Error(status);
+ }
+ }
+
+ // This is not a symlink.
+ // Drop the component, the following '..', and its trailing slash,
+ // if any, while preserving the (possibly root) leading slash:
+ // "*/dir/../" => "*/"
+ // ^slash ^slash
+ P.erase(slash + 1, next_slash + 3 - slash);
+ return Control::Continue(slash);
+ }
+ }
+
+ // This is a named component.
+
+ if (Policy::Symlinks == Options::Symlinks::Eager) {
+ cmsys::Status status;
+ std::string path = P.substr(0, next_slash);
+ if (cm::optional<std::string> maybe_symlink_target =
+ this->ReadSymlink(path, status)) {
+ return this->ResolveSymlink(root, slash, next_slash,
+ std::move(*maybe_symlink_target));
+ }
+ if (!status && Policy::Existence == Options::Existence::Required) {
+ P = std::move(path);
+ return Control::Error(status);
+ }
+ }
+
+#ifdef _WIN32
+ bool exists = false;
+ if (Policy::ActualCase == Options::ActualCase::Yes) {
+ std::string name;
+ std::string path = P.substr(0, next_slash);
+ if (cmsys::Status status = this->OS.ReadName(path, name)) {
+ exists = true;
+ if (!name.empty()) {
+ // Rename this component:
+ // "*/name/" => "*/Name/"
+ // ^slash ^slash
+ P.replace(slash + 1, next_slash - slash - 1, name);
+ next_slash = slash + 1 + name.length();
+ }
+ } else if (Policy::Existence == Options::Existence::Required) {
+ P = std::move(path);
+ return Control::Error(status);
+ }
+ }
+#endif
+
+ if (Policy::Existence == Options::Existence::Required
+#ifdef _WIN32
+ && !exists
+#endif
+ ) {
+ std::string path = P.substr(0, next_slash);
+ if (!this->OS.PathExists(path)) {
+ P = std::move(path);
+ return Control::Error(cmsys::Status::POSIX(ENOENT));
+ }
+ }
+
+ // Keep this component:
+ // "*/name/" => "*/name/"
+ // ^slash ^slash
+ return Control::Continue(next_slash);
+}
+
+template <class Policy>
+Control Impl<Policy>::ResolvePath()
+{
+ Root const root = ClassifyRoot(P);
+
+ // Resolve the root component. It always ends in a slash.
+ Control control = this->ResolveRoot(root);
+ if (control.tag != Control::Tag::Continue) {
+ return control;
+ }
+ std::string::size_type const root_slash = control.slash;
+
+ // Resolve later components. Every iteration that finishes
+ // the loop body makes progress either by removing a component
+ // or advancing the slash past it.
+ for (std::string::size_type slash = root_slash;
+ P.size() > root_slash + 1 && slash < P.size();) {
+ control = this->ResolveComponent(root, root_slash, slash);
+ if (control.tag != Control::Tag::Continue) {
+ return control;
+ }
+ slash = control.slash;
+ }
+ return Control::Continue(P.size());
+}
+
+template <class Policy>
+cmsys::Status Impl<Policy>::Resolve(std::string in, std::string& out)
+{
+ P = std::move(in);
+ std::replace(P.begin(), P.end(), '\\', '/');
+ for (;;) {
+ Control control = this->ResolvePath();
+ switch (control.tag) {
+ case Control::Tag::Continue:
+ out = std::move(P);
+ return cmsys::Status::Success();
+ case Control::Tag::Restart:
+ continue;
+ case Control::Tag::Error:
+ out = std::move(P);
+ return control.error;
+ };
+ }
+}
+
+}
+
+namespace Policies {
+struct NaivePath
+{
+#ifdef _WIN32
+ static constexpr Options::ActualCase ActualCase = Options::ActualCase::No;
+#endif
+ static constexpr Options::Symlinks Symlinks = Options::Symlinks::None;
+ static constexpr Options::Existence Existence = Options::Existence::Agnostic;
+};
+struct RealPath
+{
+#ifdef _WIN32
+ static constexpr Options::ActualCase ActualCase = Options::ActualCase::Yes;
+#endif
+ static constexpr Options::Symlinks Symlinks = Options::Symlinks::Eager;
+ static constexpr Options::Existence Existence = Options::Existence::Required;
+};
+struct LogicalPath
+{
+#ifdef _WIN32
+ static constexpr Options::ActualCase ActualCase = Options::ActualCase::Yes;
+#endif
+ static constexpr Options::Symlinks Symlinks = Options::Symlinks::Lazy;
+ static constexpr Options::Existence Existence = Options::Existence::Agnostic;
+};
+
+#if defined(__SUNPRO_CC)
+constexpr Options::Symlinks NaivePath::Symlinks;
+constexpr Options::Existence NaivePath::Existence;
+constexpr Options::Symlinks RealPath::Symlinks;
+constexpr Options::Existence RealPath::Existence;
+constexpr Options::Symlinks LogicalPath::Symlinks;
+constexpr Options::Existence LogicalPath::Existence;
+#endif
+}
+
+template <class Policy>
+Resolver<Policy>::Resolver(System& os)
+ : OS(os)
+{
+}
+template <class Policy>
+cmsys::Status Resolver<Policy>::Resolve(std::string in, std::string& out) const
+{
+ return Impl<Policy>(OS).Resolve(std::move(in), out);
+}
+
+System::System() = default;
+System::~System() = default;
+
+template class Resolver<Policies::LogicalPath>;
+template class Resolver<Policies::RealPath>;
+template class Resolver<Policies::NaivePath>;
+
+}
+}
diff --git a/Source/cmPathResolver.h b/Source/cmPathResolver.h
new file mode 100644
index 0000000..0f8baf8
--- /dev/null
+++ b/Source/cmPathResolver.h
@@ -0,0 +1,98 @@
+/* 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 <string>
+
+#include "cmsys/Status.hxx"
+
+namespace cm {
+namespace PathResolver {
+
+class System;
+
+/** Normalize filesystem paths according to a Policy.
+ *
+ * Resolved paths are always absolute, have no '..', '.', or empty
+ * components, and have a trailing '/' if and only if the entire
+ * path is a root component.
+ *
+ * The Policy determines behavior w.r.t. symbolic links, existence,
+ * and matching the on-disk case (upper/lower) of existing paths.
+ */
+template <class Policy>
+class Resolver
+{
+ System& OS;
+
+public:
+ /** Construct with a concrete filesystem access implementation. */
+ Resolver(System& os);
+
+ /** Resolve the input path according to the Policy, if possible.
+ On success, the resolved path is stored in 'out'.
+ On failure, the non-existent path is stored in 'out'. */
+ cmsys::Status Resolve(std::string in, std::string& out) const;
+};
+
+/** Access the filesystem via runtime dispatch.
+ This allows unit tests to work without accessing a real filesystem,
+ which is particularly important on Windows where symbolic links
+ may not be something we can create without administrator privileges.
+ */
+class System
+{
+public:
+ System();
+ virtual ~System() = 0;
+
+ /** If the given path is a symbolic link, read its target.
+ If the path exists but is not a symbolic link, fail
+ with EINVAL or ERROR_NOT_A_REPARSE_POINT. */
+ virtual cmsys::Status ReadSymlink(std::string const& path,
+ std::string& symlink_target) = 0;
+
+ /** Return whether the given path exists on disk. */
+ virtual bool PathExists(std::string const& path) = 0;
+
+ /** Get the process's working directory. */
+ virtual std::string GetWorkingDirectory() = 0;
+
+#ifdef _WIN32
+ /** Get the process's working directory on a Windows drive letter.
+ This is a legacy DOS concept supported by 'cmd' shells. */
+ virtual std::string GetWorkingDirectoryOnDrive(char drive_letter) = 0;
+
+ /** Read the on-disk spelling of the last component of a file path. */
+ virtual cmsys::Status ReadName(std::string const& path,
+ std::string& name) = 0;
+#endif
+};
+
+namespace Policies {
+// IWYU pragma: begin_exports
+
+/** Normalizes paths while resolving symlinks only when followed
+ by '..' components. Does not require paths to exist, but
+ reads on-disk case of paths that do exist (on Windows). */
+struct LogicalPath;
+
+/** Normalizes paths while resolving all symlinks.
+ Requires paths to exist, and reads their on-disk case (on Windows). */
+struct RealPath;
+
+/** Normalizes paths in memory without disk access.
+ Assumes components followed by '..' components are not symlinks. */
+struct NaivePath;
+
+// IWYU pragma: end_exports
+}
+
+extern template class Resolver<Policies::LogicalPath>;
+extern template class Resolver<Policies::RealPath>;
+extern template class Resolver<Policies::NaivePath>;
+
+}
+}
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index dbd6ce8..bc2aace 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -552,7 +552,10 @@
3, 31, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0180, \
"project() always sets <PROJECT-NAME>_* as normal variables.", 3, \
- 31, 0, cmPolicies::WARN)
+ 31, 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0181, \
+ "Link command-line fragment variables are parsed and re-quoted.", 3, \
+ 32, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
@@ -597,7 +600,8 @@
F(CMP0157) \
F(CMP0160) \
F(CMP0162) \
- F(CMP0179)
+ F(CMP0179) \
+ F(CMP0181)
#define CM_FOR_EACH_CUSTOM_COMMAND_POLICY(F) \
F(CMP0116) \
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 1fd406c..720cfa2 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -360,11 +360,11 @@
if (genVars.ExecutableTarget) {
dependencies.push_back(genVars.ExecutableTarget->Target->GetName());
} else if (this->MultiConfig && this->UseBetterGraph) {
- cm::string_view const& configGenexWithCommandConfig =
+ cm::string_view const configGenexWithCommandConfig =
"$<COMMAND_CONFIG:$<$<CONFIG:";
- cm::string_view const& configGenex = "$<$<CONFIG:";
- cm::string_view const& configGenexEnd = ">";
- cm::string_view const& configGenexEndWithCommandConfig = ">>";
+ cm::string_view const configGenex = "$<$<CONFIG:";
+ cm::string_view const configGenexEnd = ">";
+ cm::string_view const configGenexEndWithCommandConfig = ">>";
auto genexBegin =
this->CrossConfig ? configGenexWithCommandConfig : configGenex;
auto genexEnd =
diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx
index 376ac2a..cbd5949 100644
--- a/Source/cmQtAutoGenerator.cxx
+++ b/Source/cmQtAutoGenerator.cxx
@@ -439,7 +439,6 @@
// Info file
this->InfoFile_ = std::string(infoFile);
- cmSystemTools::CollapseFullPath(this->InfoFile_);
this->InfoDir_ = cmSystemTools::GetFilenamePath(this->InfoFile_);
// Load info file time
diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx
index 251ef3a..8bedc11 100644
--- a/Source/cmQtAutoMocUic.cxx
+++ b/Source/cmQtAutoMocUic.cxx
@@ -7,7 +7,6 @@
#include <cstddef>
#include <limits>
#include <map>
-#include <mutex>
#include <set>
#include <string>
#include <unordered_map>
@@ -561,7 +560,6 @@
std::string AbsoluteIncludePath(cm::string_view relativePath) const;
template <class JOBTYPE>
void CreateParseJobs(SourceFileMapT const& sourceMap);
- std::string CollapseFullPathTS(std::string const& path) const;
private:
// -- Abstract processing interface
@@ -595,8 +593,6 @@
// -- Worker thread pool
std::atomic<bool> JobError_{ false };
cmWorkerPool WorkerPool_;
- // -- Concurrent processing
- mutable std::mutex CMakeLibMutex_;
};
cmQtAutoMocUicT::IncludeKeyT::IncludeKeyT(std::string const& key,
@@ -1494,8 +1490,9 @@
&headerHandle](std::string const& basePath) -> bool {
bool found = false;
for (std::string const& ext : this->BaseConst().HeaderExtensions) {
- std::string const testPath =
- this->Gen()->CollapseFullPathTS(cmStrCat(basePath, '.', ext));
+ std::string const testPath = cmSystemTools::CollapseFullPath(
+ cmStrCat(basePath, '.', ext),
+ this->Gen()->ProjectDirs().CurrentSource);
cmFileTime fileTime;
if (!fileTime.Load(testPath)) {
// File not found
@@ -1682,7 +1679,8 @@
this->SearchLocations.clear();
auto findUi = [this](std::string const& testPath) -> bool {
- std::string const fullPath = this->Gen()->CollapseFullPathTS(testPath);
+ std::string const fullPath = cmSystemTools::CollapseFullPath(
+ testPath, this->Gen()->ProjectDirs().CurrentSource);
cmFileTime fileTime;
if (!fileTime.Load(fullPath)) {
this->SearchLocations.emplace_back(cmQtAutoGen::ParentDir(fullPath));
@@ -2885,17 +2883,6 @@
}
}
-/** Concurrently callable implementation of cmSystemTools::CollapseFullPath */
-std::string cmQtAutoMocUicT::CollapseFullPathTS(std::string const& path) const
-{
- std::lock_guard<std::mutex> guard(this->CMakeLibMutex_);
-#if defined(__NVCOMPILER) || defined(__LCC__)
- static_cast<void>(guard); // convince compiler var is used
-#endif
- return cmSystemTools::CollapseFullPath(path,
- this->ProjectDirs().CurrentSource);
-}
-
void cmQtAutoMocUicT::InitJobs()
{
// Add moc_predefs.h job
@@ -3130,10 +3117,6 @@
std::vector<std::string> cmQtAutoMocUicT::dependenciesFromDepFile(
const char* filePath)
{
- std::lock_guard<std::mutex> guard(this->CMakeLibMutex_);
-#if defined(__NVCOMPILER) || defined(__LCC__)
- static_cast<void>(guard); // convince compiler var is used
-#endif
auto const content = cmReadGccDepfile(filePath);
if (!content || content->empty()) {
return {};
diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx
index a8c81d0..a2435a3 100644
--- a/Source/cmRulePlaceholderExpander.cxx
+++ b/Source/cmRulePlaceholderExpander.cxx
@@ -9,10 +9,11 @@
#include "cmSystemTools.h"
cmRulePlaceholderExpander::cmRulePlaceholderExpander(
- std::map<std::string, std::string> compilers,
+ cmBuildStep buildStep, std::map<std::string, std::string> compilers,
std::map<std::string, std::string> variableMappings,
std::string compilerSysroot, std::string linkerSysroot)
- : Compilers(std::move(compilers))
+ : BuildStep(buildStep)
+ , Compilers(std::move(compilers))
, VariableMappings(std::move(variableMappings))
, CompilerSysroot(std::move(compilerSysroot))
, LinkerSysroot(std::move(linkerSysroot))
@@ -320,9 +321,8 @@
}
std::string sysroot;
// Some platforms may use separate sysroots for compiling and linking.
- // If we detect link flags, then we pass the link sysroot instead.
- // FIXME: Use a more robust way to detect link line expansion.
- if (this->ReplaceValues->LinkFlags) {
+ // When the build step is link, pass the link sysroot instead.
+ if (this->BuildStep == cmBuildStep::Link) {
sysroot = this->LinkerSysroot;
} else {
sysroot = this->CompilerSysroot;
diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h
index 225abd4..4858b08 100644
--- a/Source/cmRulePlaceholderExpander.h
+++ b/Source/cmRulePlaceholderExpander.h
@@ -8,6 +8,7 @@
#include <map>
#include <string>
+#include "cmGeneratorOptions.h"
#include "cmPlaceholderExpander.h"
class cmOutputConverter;
@@ -16,7 +17,7 @@
{
public:
cmRulePlaceholderExpander(
- std::map<std::string, std::string> compilers,
+ cmBuildStep buildStep, std::map<std::string, std::string> compilers,
std::map<std::string, std::string> variableMappings,
std::string compilerSysroot, std::string linkerSysroot);
@@ -84,6 +85,7 @@
std::string TargetImpLib;
+ cmBuildStep BuildStep = cmBuildStep::Compile;
std::map<std::string, std::string> Compilers;
std::map<std::string, std::string> VariableMappings;
std::string CompilerSysroot;
diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx
index ec70c05..bf3480f 100644
--- a/Source/cmSearchPath.cxx
+++ b/Source/cmSearchPath.cxx
@@ -62,7 +62,9 @@
// Process them all from the current directory
for (std::string const& p : outPaths) {
this->AddPathInternal(
- p, "", this->FC->Makefile->GetCurrentSourceDirectory().c_str());
+ cmSystemTools::CollapseFullPath(
+ p, this->FC->Makefile->GetCurrentSourceDirectory()),
+ "");
}
}
@@ -76,15 +78,17 @@
for (std::string const& p : expanded) {
this->AddPathInternal(
- p, "", this->FC->Makefile->GetCurrentSourceDirectory().c_str());
+ cmSystemTools::CollapseFullPath(
+ p, this->FC->Makefile->GetCurrentSourceDirectory()),
+ "");
}
}
}
void cmSearchPath::AddEnvPath(const std::string& variable)
{
- std::vector<std::string> expanded;
- cmSystemTools::GetPath(expanded, variable.c_str());
+ std::vector<std::string> expanded =
+ cmSystemTools::GetEnvPathNormalized(variable);
for (std::string const& p : expanded) {
this->AddPathInternal(p, "");
}
@@ -97,9 +101,11 @@
// Get a path from a CMake variable.
if (cmValue value = this->FC->Makefile->GetDefinition(variable)) {
cmList expanded{ *value };
-
- this->AddPrefixPaths(
- expanded, this->FC->Makefile->GetCurrentSourceDirectory().c_str());
+ for (std::string& p : expanded) {
+ p = cmSystemTools::CollapseFullPath(
+ p, this->FC->Makefile->GetCurrentSourceDirectory());
+ }
+ this->AddPrefixPaths(expanded);
}
}
@@ -114,8 +120,8 @@
void cmSearchPath::AddEnvPrefixPath(const std::string& variable, bool stripBin)
{
- std::vector<std::string> expanded;
- cmSystemTools::GetPath(expanded, variable.c_str());
+ std::vector<std::string> expanded =
+ cmSystemTools::GetEnvPathNormalized(variable);
if (stripBin) {
std::transform(expanded.begin(), expanded.end(), expanded.begin(),
cmSearchPathStripBin);
@@ -151,8 +157,7 @@
}
}
-void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths,
- const char* base)
+void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths)
{
assert(this->FC);
@@ -192,52 +197,43 @@
"CMAKE_PREFIX_LIBRARY_ARCHITECTURE")) {
if (foundUnknown) {
this->AddPathInternal(cmStrCat('/', archNoUnknown, dir, subdir),
- cmStrCat('/', archNoUnknown, prefix), base);
+ cmStrCat('/', archNoUnknown, prefix));
}
this->AddPathInternal(cmStrCat('/', *arch, dir, subdir),
- cmStrCat('/', *arch, prefix), base);
+ cmStrCat('/', *arch, prefix));
} else {
if (foundUnknown) {
this->AddPathInternal(cmStrCat(dir, subdir, '/', archNoUnknown),
- prefix, base);
+ prefix);
}
- this->AddPathInternal(cmStrCat(dir, subdir, '/', *arch), prefix,
- base);
+ this->AddPathInternal(cmStrCat(dir, subdir, '/', *arch), prefix);
}
}
}
std::string add = dir + subdir;
if (add != "/") {
- this->AddPathInternal(add, prefix, base);
+ this->AddPathInternal(add, prefix);
}
if (subdir == "bin") {
- this->AddPathInternal(dir + "sbin", prefix, base);
+ this->AddPathInternal(dir + "sbin", prefix);
}
if (!subdir.empty() && path != "/") {
- this->AddPathInternal(path, prefix, base);
+ this->AddPathInternal(path, prefix);
}
}
}
void cmSearchPath::AddPathInternal(const std::string& path,
- const std::string& prefix, const char* base)
+ const std::string& prefix)
{
assert(this->FC);
- std::string collapsedPath = cmSystemTools::CollapseFullPath(path, base);
-
- if (collapsedPath.empty()) {
+ if (path.empty()) {
return;
}
- std::string collapsedPrefix;
- if (!prefix.empty()) {
- collapsedPrefix = cmSystemTools::CollapseFullPath(prefix, base);
- }
-
// Insert the path if has not already been emitted.
- PathWithPrefix pathWithPrefix{ std::move(collapsedPath),
- std::move(collapsedPrefix) };
+ PathWithPrefix pathWithPrefix{ path, prefix };
if (this->FC->SearchPathsEmitted.insert(pathWithPrefix).second) {
this->Paths.emplace_back(std::move(pathWithPrefix));
}
diff --git a/Source/cmSearchPath.h b/Source/cmSearchPath.h
index 4c0cabb..895f4a3 100644
--- a/Source/cmSearchPath.h
+++ b/Source/cmSearchPath.h
@@ -55,12 +55,10 @@
void AddCMakePrefixPath(const std::string& variable);
void AddEnvPrefixPath(const std::string& variable, bool stripBin = false);
void AddSuffixes(const std::vector<std::string>& suffixes);
- void AddPrefixPaths(const std::vector<std::string>& paths,
- const char* base = nullptr);
+ void AddPrefixPaths(const std::vector<std::string>& paths);
protected:
- void AddPathInternal(const std::string& path, const std::string& prefix,
- const char* base = nullptr);
+ void AddPathInternal(const std::string& path, const std::string& prefix);
cmFindCommon* FC;
std::vector<PathWithPrefix> Paths;
diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx
index bb92856..31f541e 100644
--- a/Source/cmSourceGroupCommand.cxx
+++ b/Source/cmSourceGroupCommand.cxx
@@ -29,11 +29,6 @@
const std::string kRegexOptionName = "REGULAR_EXPRESSION";
const std::string kSourceGroupOptionName = "<sg_name>";
-std::vector<std::string> tokenizePath(const std::string& path)
-{
- return cmTokenize(path, "\\/");
-}
-
std::set<std::string> getSourceGroupFilesPaths(
const std::string& root, const std::vector<std::string>& files)
{
@@ -95,31 +90,28 @@
cmSourceGroup* sg;
for (std::string const& sgFilesPath : sgFilesPaths) {
+ std::vector<std::string> tokenizedPath = cmTokenize(
+ prefix.empty() ? sgFilesPath : cmStrCat(prefix, '/', sgFilesPath),
+ R"(\/)", cmTokenizerMode::New);
- std::vector<std::string> tokenizedPath;
- if (!prefix.empty()) {
- tokenizedPath = tokenizePath(cmStrCat(prefix, '/', sgFilesPath));
- } else {
- tokenizedPath = tokenizePath(sgFilesPath);
+ if (tokenizedPath.empty()) {
+ continue;
+ }
+ tokenizedPath.pop_back();
+
+ if (tokenizedPath.empty()) {
+ tokenizedPath.emplace_back();
}
- if (!tokenizedPath.empty()) {
- tokenizedPath.pop_back();
+ sg = makefile.GetOrCreateSourceGroup(tokenizedPath);
- if (tokenizedPath.empty()) {
- tokenizedPath.emplace_back();
- }
-
- sg = makefile.GetOrCreateSourceGroup(tokenizedPath);
-
- if (!sg) {
- errorMsg = "Could not create source group for file: " + sgFilesPath;
- return false;
- }
- const std::string fullPath =
- cmSystemTools::CollapseFullPath(sgFilesPath, root);
- sg->AddGroupFile(fullPath);
+ if (!sg) {
+ errorMsg = "Could not create source group for file: " + sgFilesPath;
+ return false;
}
+ const std::string fullPath =
+ cmSystemTools::CollapseFullPath(sgFilesPath, root);
+ sg->AddGroupFile(fullPath);
}
return true;
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index b716dc7..706f4e6 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -13,7 +13,6 @@
#include "cmsys/RegularExpression.hxx"
#include "cmCacheManager.h"
-#include "cmCommand.h"
#include "cmDefinitions.h"
#include "cmExecutionStatus.h"
#include "cmGlobCacheEntry.h"
@@ -397,12 +396,6 @@
this->IsGeneratorMultiConfig = b;
}
-void cmState::AddBuiltinCommand(std::string const& name,
- std::unique_ptr<cmCommand> command)
-{
- this->AddBuiltinCommand(name, cmLegacyCommandWrapper(std::move(command)));
-}
-
void cmState::AddBuiltinCommand(std::string const& name, Command command)
{
assert(name == cmSystemTools::LowerCase(name));
diff --git a/Source/cmState.h b/Source/cmState.h
index 4dc982f..6239511 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -27,7 +27,6 @@
#include "cmValue.h"
class cmCacheManager;
-class cmCommand;
class cmGlobVerificationManager;
class cmMakefile;
class cmStateSnapshot;
@@ -177,8 +176,6 @@
// Returns a command from its name, or nullptr
Command GetCommandByExactName(std::string const& name) const;
- void AddBuiltinCommand(std::string const& name,
- std::unique_ptr<cmCommand> command);
void AddBuiltinCommand(std::string const& name, Command command);
void AddBuiltinCommand(std::string const& name, BuiltinCommand command);
void AddFlowControlCommand(std::string const& name, Command command);
diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx
index 343bee5..104e707 100644
--- a/Source/cmStateDirectory.cxx
+++ b/Source/cmStateDirectory.cxx
@@ -21,7 +21,6 @@
#include "cmState.h"
#include "cmStatePrivate.h"
#include "cmStateTypes.h"
-#include "cmSystemTools.h"
#include "cmValue.h"
static std::string const kBINARY_DIR = "BINARY_DIR";
@@ -36,11 +35,9 @@
void cmStateDirectory::SetCurrentSource(std::string const& dir)
{
- std::string& loc = this->DirectoryState->Location;
- loc = dir;
- cmSystemTools::ConvertToUnixSlashes(loc);
- loc = cmSystemTools::CollapseFullPath(loc);
- this->Snapshot_.SetDefinition("CMAKE_CURRENT_SOURCE_DIR", loc);
+ this->DirectoryState->Location = dir;
+ this->Snapshot_.SetDefinition("CMAKE_CURRENT_SOURCE_DIR",
+ this->DirectoryState->Location);
}
std::string const& cmStateDirectory::GetCurrentBinary() const
@@ -50,11 +47,9 @@
void cmStateDirectory::SetCurrentBinary(std::string const& dir)
{
- std::string& loc = this->DirectoryState->OutputLocation;
- loc = dir;
- cmSystemTools::ConvertToUnixSlashes(loc);
- loc = cmSystemTools::CollapseFullPath(loc);
- this->Snapshot_.SetDefinition("CMAKE_CURRENT_BINARY_DIR", loc);
+ this->DirectoryState->OutputLocation = dir;
+ this->Snapshot_.SetDefinition("CMAKE_CURRENT_BINARY_DIR",
+ this->DirectoryState->OutputLocation);
}
cmStateDirectory::cmStateDirectory(
diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx
index 332bd8d..724ca75 100644
--- a/Source/cmStringAlgorithms.cxx
+++ b/Source/cmStringAlgorithms.cxx
@@ -55,30 +55,6 @@
return result;
}
-std::vector<std::string> cmTokenize(cm::string_view str, cm::string_view sep)
-{
- std::vector<std::string> tokens;
- cm::string_view::size_type tokend = 0;
-
- do {
- cm::string_view::size_type tokstart = str.find_first_not_of(sep, tokend);
- if (tokstart == cm::string_view::npos) {
- break; // no more tokens
- }
- tokend = str.find_first_of(sep, tokstart);
- if (tokend == cm::string_view::npos) {
- tokens.emplace_back(str.substr(tokstart));
- } else {
- tokens.emplace_back(str.substr(tokstart, tokend - tokstart));
- }
- } while (tokend != cm::string_view::npos);
-
- if (tokens.empty()) {
- tokens.emplace_back();
- }
- return tokens;
-}
-
namespace {
template <std::size_t N, typename T>
inline void MakeDigits(cm::string_view& view, char (&digits)[N],
diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h
index 2bd615a..72557d5 100644
--- a/Source/cmStringAlgorithms.h
+++ b/Source/cmStringAlgorithms.h
@@ -24,7 +24,7 @@
/** Returns length of a literal string. */
template <size_t N>
-constexpr size_t cmStrLen(const char (&/*str*/)[N])
+constexpr size_t cmStrLen(const char (&)[N])
{
return N - 1;
}
@@ -91,12 +91,12 @@
}
std::string result;
- result.reserve(
- std::accumulate(std::begin(rng), std::end(rng),
- initial.size() + (rng.size() - 1) * separator.size(),
- [](std::size_t sum, const std::string& item) {
- return sum + item.size();
- }));
+ result.reserve(std::accumulate(
+ std::begin(rng), std::end(rng),
+ initial.size() + (rng.size() - 1) * separator.size(),
+ [](std::size_t sum, typename Range::value_type const& item) {
+ return sum + item.size();
+ }));
result.append(std::begin(initial), std::end(initial));
auto begin = std::begin(rng);
@@ -122,8 +122,81 @@
std::string cmJoin(cmStringRange const& rng, cm::string_view separator,
cm::string_view initial = {});
-/** Extract tokens that are separated by any of the characters in @a sep. */
-std::vector<std::string> cmTokenize(cm::string_view str, cm::string_view sep);
+enum class cmTokenizerMode
+{
+ /// A backward-compatible behavior when in the case of no
+ /// tokens have found in an input text it'll return one empty
+ /// token in the result container (vector).
+ Legacy,
+ /// The new behavior is to return an empty vector.
+ New
+};
+
+/**
+ * \brief A generic version of a tokenizer.
+ *
+ * Extract tokens from the input string separated by any
+ * of the characters in `sep` and assign them to the
+ * given output iterator.
+ *
+ * The `mode` parameter defines the behavior in the case when
+ * no tokens have found in the input text.
+ *
+ */
+template <typename StringT, typename OutIt, typename Sep = char>
+void cmTokenize(OutIt outIt, cm::string_view str, Sep sep,
+ cmTokenizerMode mode)
+{
+ auto hasTokens = false;
+ // clang-format off
+ for (auto start = str.find_first_not_of(sep)
+ , end = str.find_first_of(sep, start)
+ ; start != cm::string_view::npos
+ ; start = str.find_first_not_of(sep, end)
+ , end = str.find_first_of(sep, start)
+ , hasTokens = true
+ ) {
+ *outIt++ = StringT{ str.substr(start, end - start) };
+ }
+ // clang-format on
+ if (!hasTokens && mode == cmTokenizerMode::Legacy) {
+ *outIt = {};
+ }
+}
+
+/**
+ * \brief Extract tokens that are separated by any of the
+ * characters in `sep`.
+ *
+ * Backward compatible signature.
+ *
+ * \return A vector of strings.
+ */
+template <typename Sep = char>
+std::vector<std::string> cmTokenize(
+ cm::string_view str, Sep sep, cmTokenizerMode mode = cmTokenizerMode::Legacy)
+{
+ using StringType = std::string;
+ std::vector<StringType> tokens;
+ cmTokenize<StringType>(std::back_inserter(tokens), str, sep, mode);
+ return tokens;
+}
+
+/**
+ * \brief Extract tokens that are separated by any of the
+ * characters in `sep`.
+ *
+ * \return A vector of string views.
+ */
+template <typename Sep = char>
+std::vector<cm::string_view> cmTokenizedView(
+ cm::string_view str, Sep sep, cmTokenizerMode mode = cmTokenizerMode::Legacy)
+{
+ using StringType = cm::string_view;
+ std::vector<StringType> tokens;
+ cmTokenize<StringType>(std::back_inserter(tokens), str, sep, mode);
+ return tokens;
+}
/** Concatenate string pieces into a single string. */
std::string cmCatViews(
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 5ad0439..cdb661c 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -20,6 +20,12 @@
#include "cmSystemTools.h"
+#include <iterator>
+
+#ifdef _WIN32
+# include <unordered_map>
+#endif
+
#include <cm/optional>
#include <cmext/algorithm>
#include <cmext/string_view>
@@ -29,6 +35,7 @@
#include "cmDuration.h"
#include "cmELF.h"
#include "cmMessageMetadata.h"
+#include "cmPathResolver.h"
#include "cmProcessOutput.h"
#include "cmRange.h"
#include "cmStringAlgorithms.h"
@@ -126,6 +133,116 @@
cmSystemTools::OutputCallback s_StderrCallback;
cmSystemTools::OutputCallback s_StdoutCallback;
+#ifdef _WIN32
+std::string GetDosDriveWorkingDirectory(char letter)
+{
+ // The Windows command processor tracks a per-drive working
+ // directory for compatibility with MS-DOS by using special
+ // environment variables named "=C:".
+ // https://web.archive.org/web/20100522040616/
+ // https://blogs.msdn.com/oldnewthing/archive/2010/05/06/10008132.aspx
+ return cmSystemTools::GetEnvVar(cmStrCat('=', letter, ':'))
+ .value_or(std::string());
+}
+
+cmsys::Status ReadNameOnDisk(std::string const& path, std::string& name)
+{
+ std::wstring wp = cmsys::Encoding::ToWide(path);
+ HANDLE h = CreateFileW(
+ wp.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nullptr);
+ if (h == INVALID_HANDLE_VALUE) {
+ return cmsys::Status::Windows_GetLastError();
+ }
+
+ WCHAR local_fni[((sizeof(FILE_NAME_INFO) - 1) / sizeof(WCHAR)) + 1024];
+ size_t fni_size = sizeof(local_fni);
+ auto* fni = reinterpret_cast<FILE_NAME_INFO*>(local_fni);
+ if (!GetFileInformationByHandleEx(h, FileNameInfo, fni, fni_size)) {
+ DWORD e = GetLastError();
+ if (e != ERROR_MORE_DATA) {
+ CloseHandle(h);
+ return cmsys::Status::Windows(e);
+ }
+ fni_size = fni->FileNameLength;
+ fni = static_cast<FILE_NAME_INFO*>(malloc(fni_size));
+ if (!fni) {
+ e = ERROR_NOT_ENOUGH_MEMORY;
+ CloseHandle(h);
+ return cmsys::Status::Windows(e);
+ }
+ if (!GetFileInformationByHandleEx(h, FileNameInfo, fni, fni_size)) {
+ e = GetLastError();
+ free(fni);
+ CloseHandle(h);
+ return cmsys::Status::Windows(e);
+ }
+ }
+
+ std::wstring wn{ fni->FileName, fni->FileNameLength / sizeof(WCHAR) };
+ std::string nn = cmsys::Encoding::ToNarrow(wn);
+ std::string::size_type last_slash = nn.find_last_of("/\\");
+ if (last_slash != std::string::npos) {
+ name = nn.substr(last_slash + 1);
+ }
+ if (fni != reinterpret_cast<FILE_NAME_INFO*>(local_fni)) {
+ free(fni);
+ }
+ CloseHandle(h);
+ return cmsys::Status::Success();
+}
+#endif
+
+class RealSystem : public cm::PathResolver::System
+{
+public:
+ ~RealSystem() override = default;
+ cmsys::Status ReadSymlink(std::string const& path,
+ std::string& link) override
+ {
+ return cmSystemTools::ReadSymlink(path, link);
+ }
+ bool PathExists(std::string const& path) override
+ {
+ return cmSystemTools::PathExists(path);
+ }
+ std::string GetWorkingDirectory() override
+ {
+ return cmSystemTools::GetLogicalWorkingDirectory();
+ }
+#ifdef _WIN32
+ std::string GetWorkingDirectoryOnDrive(char letter) override
+ {
+ return GetDosDriveWorkingDirectory(letter);
+ }
+
+ struct NameOnDisk
+ {
+ cmsys::Status Status;
+ std::string Name;
+ };
+ using NameOnDiskMap = std::unordered_map<std::string, NameOnDisk>;
+ NameOnDiskMap CachedNameOnDisk;
+
+ cmsys::Status ReadName(std::string const& path, std::string& name) override
+ {
+ // Cache results to avoid repeated filesystem access.
+ // We assume any files created by our own process keep their case.
+ // Index the cache by lower-case paths to make it case-insensitive.
+ std::string path_lower = cmSystemTools::LowerCase(path);
+ auto i = this->CachedNameOnDisk.find(path_lower);
+ if (i == this->CachedNameOnDisk.end()) {
+ i = this->CachedNameOnDisk.emplace(path_lower, NameOnDisk()).first;
+ i->second.Status = ReadNameOnDisk(path, i->second.Name);
+ }
+ name = i->second.Name;
+ return i->second.Status;
+ }
+#endif
+};
+
+RealSystem RealOS;
+
} // namespace
#if !defined(HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE)
@@ -133,7 +250,7 @@
# if defined(_WIN32)
extern __declspec(dllimport) char** environ;
# else
-extern char** environ;
+extern char** environ; // NOLINT(readability-redundant-declaration)
# endif
#endif
@@ -984,36 +1101,22 @@
#endif
-std::string cmSystemTools::GetRealPathResolvingWindowsSubst(
- const std::string& path, std::string* errorMessage)
+std::string cmSystemTools::GetRealPath(const std::string& path,
+ std::string* errorMessage)
{
#ifdef _WIN32
- // uv_fs_realpath uses Windows Vista API so fallback to kwsys if not found
std::string resolved_path;
- uv_fs_t req;
- int err = uv_fs_realpath(nullptr, &req, path.c_str(), nullptr);
- if (!err) {
- resolved_path = std::string((char*)req.ptr);
- cmSystemTools::ConvertToUnixSlashes(resolved_path);
- // Normalize to upper-case drive letter as GetActualCaseForPath does.
- if (resolved_path.size() > 1 && resolved_path[1] == ':') {
- resolved_path[0] = toupper(resolved_path[0]);
+ using namespace cm::PathResolver;
+ // IWYU pragma: no_forward_declare cm::PathResolver::Policies::RealPath
+ static const Resolver<Policies::RealPath> resolver(RealOS);
+ cmsys::Status status = resolver.Resolve(path, resolved_path);
+ if (!status) {
+ if (errorMessage) {
+ *errorMessage = status.GetString();
+ resolved_path.clear();
+ } else {
+ resolved_path = path;
}
- } else if (err == UV_ENOSYS) {
- resolved_path = cmsys::SystemTools::GetRealPath(path, errorMessage);
- } else if (errorMessage) {
- LPSTR message = nullptr;
- DWORD size = FormatMessageA(
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&message,
- 0, nullptr);
- *errorMessage = std::string(message, size);
- LocalFree(message);
-
- resolved_path = "";
- } else {
- resolved_path = path;
}
return resolved_path;
#else
@@ -1614,20 +1717,59 @@
return result;
}
-std::vector<std::string> cmSystemTools::SplitEnvPath(std::string const& value)
+std::vector<std::string> cmSystemTools::GetEnvPathNormalized(
+ std::string const& var)
+{
+ std::vector<std::string> result;
+ if (cm::optional<std::string> env = cmSystemTools::GetEnvVar(var)) {
+ std::vector<std::string> p = cmSystemTools::SplitEnvPathNormalized(*env);
+ std::move(p.begin(), p.end(), std::back_inserter(result));
+ }
+ return result;
+}
+
+std::vector<std::string> cmSystemTools::SplitEnvPath(cm::string_view in)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
static cm::string_view sep = ";"_s;
#else
static cm::string_view sep = ":"_s;
#endif
- std::vector<std::string> paths = cmTokenize(value, sep);
- for (std::string& p : paths) {
- SystemTools::ConvertToUnixSlashes(p);
+ std::vector<std::string> paths;
+ cm::string_view::size_type e = 0;
+ for (;;) {
+ cm::string_view::size_type b = in.find_first_not_of(sep, e);
+ if (b == cm::string_view::npos) {
+ break;
+ }
+ e = in.find_first_of(sep, b);
+ if (e == cm::string_view::npos) {
+ paths.emplace_back(in.substr(b));
+ break;
+ }
+ paths.emplace_back(in.substr(b, e - b));
}
return paths;
}
+std::vector<std::string> cmSystemTools::SplitEnvPathNormalized(
+ cm::string_view in)
+{
+ std::vector<std::string> paths = cmSystemTools::SplitEnvPath(in);
+ std::transform(paths.begin(), paths.end(), paths.begin(),
+ cmSystemTools::ToNormalizedPathOnDisk);
+ return paths;
+}
+
+std::string cmSystemTools::ToNormalizedPathOnDisk(std::string p)
+{
+ using namespace cm::PathResolver;
+ // IWYU pragma: no_forward_declare cm::PathResolver::Policies::LogicalPath
+ static const Resolver<Policies::LogicalPath> resolver(RealOS);
+ resolver.Resolve(std::move(p), p);
+ return p;
+}
+
#ifndef CMAKE_BOOTSTRAP
bool cmSystemTools::UnsetEnv(const char* value)
{
@@ -1874,12 +2016,12 @@
std::string const& format, int compressionLevel)
{
#if !defined(CMAKE_BOOTSTRAP)
- cmWorkingDirectory workdir(cmSystemTools::GetCurrentWorkingDirectory());
+ cmWorkingDirectory workdir(cmSystemTools::GetLogicalWorkingDirectory());
if (!workingDirectory.empty()) {
workdir.SetDirectory(workingDirectory);
}
- const std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ const std::string cwd = cmSystemTools::GetLogicalWorkingDirectory();
cmsys::ofstream fout(outFileName.c_str(), std::ios::out | std::ios::binary);
if (!fout) {
std::string e = cmStrCat("Cannot open output file \"", outFileName,
@@ -2513,30 +2655,48 @@
#endif
}
-static std::string cmSystemToolsCMakeCommand;
-static std::string cmSystemToolsCTestCommand;
-static std::string cmSystemToolsCPackCommand;
-static std::string cmSystemToolsCMakeCursesCommand;
-static std::string cmSystemToolsCMakeGUICommand;
-static std::string cmSystemToolsCMClDepsCommand;
-static std::string cmSystemToolsCMakeRoot;
-static std::string cmSystemToolsHTMLDoc;
-void cmSystemTools::FindCMakeResources(const char* argv0)
+namespace {
+std::string InitLogicalWorkingDirectory()
{
- std::string exe_dir;
+ std::string cwd = cmsys::SystemTools::GetCurrentWorkingDirectory();
+ std::string pwd;
+ if (cmSystemTools::GetEnv("PWD", pwd)) {
+ std::string const pwd_real = cmSystemTools::GetRealPath(pwd);
+ if (pwd_real == cwd) {
+ cwd = std::move(pwd);
+ }
+ }
+ return cwd;
+}
+
+std::string cmSystemToolsLogicalWorkingDirectory =
+ InitLogicalWorkingDirectory();
+
+std::string cmSystemToolsCMakeCommand;
+std::string cmSystemToolsCTestCommand;
+std::string cmSystemToolsCPackCommand;
+std::string cmSystemToolsCMakeCursesCommand;
+std::string cmSystemToolsCMakeGUICommand;
+std::string cmSystemToolsCMClDepsCommand;
+std::string cmSystemToolsCMakeRoot;
+std::string cmSystemToolsHTMLDoc;
+
+#if defined(__APPLE__)
+bool IsCMakeAppBundleExe(std::string const& exe)
+{
+ return cmHasLiteralSuffix(cmSystemTools::LowerCase(exe), "/macos/cmake");
+}
+#endif
+
+std::string FindOwnExecutable(const char* argv0)
+{
#if defined(_WIN32) && !defined(__CYGWIN__)
- (void)argv0; // ignore this on windows
+ static_cast<void>(argv0);
wchar_t modulepath[_MAX_PATH];
::GetModuleFileNameW(nullptr, modulepath, sizeof(modulepath));
- std::string path = cmsys::Encoding::ToNarrow(modulepath);
- std::string realPath =
- cmSystemTools::GetRealPathResolvingWindowsSubst(path, nullptr);
- if (realPath.empty()) {
- realPath = path;
- }
- exe_dir = cmSystemTools::GetFilenamePath(realPath);
+ std::string exe = cmsys::Encoding::ToNarrow(modulepath);
#elif defined(__APPLE__)
- (void)argv0; // ignore this on OS X
+ static_cast<void>(argv0);
# define CM_EXE_PATH_LOCAL_SIZE 16384
char exe_path_local[CM_EXE_PATH_LOCAL_SIZE];
# if defined(MAC_OS_X_VERSION_10_3) && !defined(MAC_OS_X_VERSION_10_4)
@@ -2550,41 +2710,133 @@
exe_path = static_cast<char*>(malloc(exe_path_size));
_NSGetExecutablePath(exe_path, &exe_path_size);
}
- exe_dir =
- cmSystemTools::GetFilenamePath(cmSystemTools::GetRealPath(exe_path));
+ std::string exe = exe_path;
if (exe_path != exe_path_local) {
free(exe_path);
}
- if (cmSystemTools::GetFilenameName(exe_dir) == "MacOS") {
+ if (IsCMakeAppBundleExe(exe)) {
// The executable is inside an application bundle.
- // Look for ..<CMAKE_BIN_DIR> (install tree) and then fall back to
- // ../../../bin (build tree).
- exe_dir = cmSystemTools::GetFilenamePath(exe_dir);
- if (cmSystemTools::FileExists(exe_dir + CMAKE_BIN_DIR "/cmake")) {
- exe_dir += CMAKE_BIN_DIR;
- } else {
- exe_dir = cmSystemTools::GetFilenamePath(exe_dir);
- exe_dir = cmSystemTools::GetFilenamePath(exe_dir);
+ // The install tree has "..<CMAKE_BIN_DIR>/cmake-gui".
+ // The build tree has '../../../cmake-gui".
+ std::string dir = cmSystemTools::GetFilenamePath(exe);
+ dir = cmSystemTools::GetFilenamePath(dir);
+ exe = cmStrCat(dir, CMAKE_BIN_DIR "/cmake-gui");
+ if (!cmSystemTools::PathExists(exe)) {
+ dir = cmSystemTools::GetFilenamePath(dir);
+ dir = cmSystemTools::GetFilenamePath(dir);
+ exe = cmStrCat(dir, "/cmake-gui");
}
}
#else
std::string errorMsg;
std::string exe;
- if (cmSystemTools::FindProgramPath(argv0, exe, errorMsg)) {
- // remove symlinks
- exe = cmSystemTools::GetRealPath(exe);
- exe_dir = cmSystemTools::GetFilenamePath(exe);
- } else {
+ if (!cmSystemTools::FindProgramPath(argv0, exe, errorMsg)) {
// ???
}
#endif
- exe_dir = cmSystemTools::GetActualCaseForPath(exe_dir);
- cmSystemToolsCMakeCommand =
- cmStrCat(exe_dir, "/cmake", cmSystemTools::GetExecutableExtension());
+ exe = cmSystemTools::ToNormalizedPathOnDisk(std::move(exe));
+ return exe;
+}
+
+#ifndef CMAKE_BOOTSTRAP
+bool ResolveSymlinkToOwnExecutable(std::string& exe, std::string& exe_dir)
+{
+ std::string linked_exe;
+ if (!cmSystemTools::ReadSymlink(exe, linked_exe)) {
+ return false;
+ }
+# if defined(__APPLE__)
+ // Ignore "cmake-gui -> ../MacOS/CMake".
+ if (IsCMakeAppBundleExe(linked_exe)) {
+ return false;
+ }
+# endif
+ if (cmSystemTools::FileIsFullPath(linked_exe)) {
+ exe = std::move(linked_exe);
+ } else {
+ exe = cmStrCat(exe_dir, '/', std::move(linked_exe));
+ }
+ exe = cmSystemTools::ToNormalizedPathOnDisk(std::move(exe));
+ exe_dir = cmSystemTools::GetFilenamePath(exe);
+ return true;
+}
+
+bool FindCMakeResourcesInInstallTree(std::string const& exe_dir)
+{
+ // Install tree has
+ // - "<prefix><CMAKE_BIN_DIR>/cmake"
+ // - "<prefix><CMAKE_DATA_DIR>"
+ // - "<prefix><CMAKE_DOC_DIR>"
+ if (cmHasLiteralSuffix(exe_dir, CMAKE_BIN_DIR)) {
+ std::string const prefix =
+ exe_dir.substr(0, exe_dir.size() - cmStrLen(CMAKE_BIN_DIR));
+ // Set cmSystemToolsCMakeRoot set to the location expected in an
+ // install tree, even if it does not exist, so that
+ // cmake::AddCMakePaths can print the location in its error message.
+ cmSystemToolsCMakeRoot = cmStrCat(prefix, CMAKE_DATA_DIR);
+ if (cmSystemTools::FileExists(
+ cmStrCat(cmSystemToolsCMakeRoot, "/Modules/CMake.cmake"))) {
+ if (cmSystemTools::FileExists(
+ cmStrCat(prefix, CMAKE_DOC_DIR "/html/index.html"))) {
+ cmSystemToolsHTMLDoc = cmStrCat(prefix, CMAKE_DOC_DIR "/html");
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+void FindCMakeResourcesInBuildTree(std::string const& exe_dir)
+{
+ // Build tree has "<build>/bin[/<config>]/cmake" and
+ // "<build>/CMakeFiles/CMakeSourceDir.txt".
+ std::string dir = cmSystemTools::GetFilenamePath(exe_dir);
+ std::string src_dir_txt = cmStrCat(dir, "/CMakeFiles/CMakeSourceDir.txt");
+ cmsys::ifstream fin(src_dir_txt.c_str());
+ std::string src_dir;
+ if (fin && cmSystemTools::GetLineFromStream(fin, src_dir) &&
+ cmSystemTools::FileIsDirectory(src_dir)) {
+ cmSystemToolsCMakeRoot = src_dir;
+ } else {
+ dir = cmSystemTools::GetFilenamePath(dir);
+ src_dir_txt = cmStrCat(dir, "/CMakeFiles/CMakeSourceDir.txt");
+ cmsys::ifstream fin2(src_dir_txt.c_str());
+ if (fin2 && cmSystemTools::GetLineFromStream(fin2, src_dir) &&
+ cmSystemTools::FileIsDirectory(src_dir)) {
+ cmSystemToolsCMakeRoot = src_dir;
+ }
+ }
+ if (!cmSystemToolsCMakeRoot.empty() && cmSystemToolsHTMLDoc.empty() &&
+ cmSystemTools::FileExists(
+ cmStrCat(dir, "/Utilities/Sphinx/html/index.html"))) {
+ cmSystemToolsHTMLDoc = cmStrCat(dir, "/Utilities/Sphinx/html");
+ }
+}
+#endif
+}
+
+void cmSystemTools::FindCMakeResources(const char* argv0)
+{
+ std::string exe = FindOwnExecutable(argv0);
#ifdef CMAKE_BOOTSTRAP
+ // The bootstrap cmake knows its resource locations.
+ cmSystemToolsCMakeRoot = CMAKE_BOOTSTRAP_SOURCE_DIR;
+ cmSystemToolsCMakeCommand = exe;
// The bootstrap cmake does not provide the other tools,
// so use the directory where they are about to be built.
- exe_dir = CMAKE_BOOTSTRAP_BINARY_DIR "/bin";
+ std::string exe_dir = CMAKE_BOOTSTRAP_BINARY_DIR "/bin";
+#else
+ // Find resources relative to our own executable.
+ std::string exe_dir = cmSystemTools::GetFilenamePath(exe);
+ bool found = false;
+ do {
+ found = FindCMakeResourcesInInstallTree(exe_dir);
+ } while (!found && ResolveSymlinkToOwnExecutable(exe, exe_dir));
+ if (!found) {
+ FindCMakeResourcesInBuildTree(exe_dir);
+ }
+ cmSystemToolsCMakeCommand =
+ cmStrCat(exe_dir, "/cmake", cmSystemTools::GetExecutableExtension());
#endif
cmSystemToolsCTestCommand =
cmStrCat(exe_dir, "/ctest", cmSystemTools::GetExecutableExtension());
@@ -2605,52 +2857,6 @@
if (!cmSystemTools::FileExists(cmSystemToolsCMClDepsCommand)) {
cmSystemToolsCMClDepsCommand.clear();
}
-
-#ifndef CMAKE_BOOTSTRAP
- // Install tree has
- // - "<prefix><CMAKE_BIN_DIR>/cmake"
- // - "<prefix><CMAKE_DATA_DIR>"
- // - "<prefix><CMAKE_DOC_DIR>"
- if (cmHasLiteralSuffix(exe_dir, CMAKE_BIN_DIR)) {
- std::string const prefix =
- exe_dir.substr(0, exe_dir.size() - cmStrLen(CMAKE_BIN_DIR));
- cmSystemToolsCMakeRoot = cmStrCat(prefix, CMAKE_DATA_DIR);
- if (cmSystemTools::FileExists(
- cmStrCat(prefix, CMAKE_DOC_DIR "/html/index.html"))) {
- cmSystemToolsHTMLDoc = cmStrCat(prefix, CMAKE_DOC_DIR "/html");
- }
- }
- if (cmSystemToolsCMakeRoot.empty() ||
- !cmSystemTools::FileExists(
- cmStrCat(cmSystemToolsCMakeRoot, "/Modules/CMake.cmake"))) {
- // Build tree has "<build>/bin[/<config>]/cmake" and
- // "<build>/CMakeFiles/CMakeSourceDir.txt".
- std::string dir = cmSystemTools::GetFilenamePath(exe_dir);
- std::string src_dir_txt = cmStrCat(dir, "/CMakeFiles/CMakeSourceDir.txt");
- cmsys::ifstream fin(src_dir_txt.c_str());
- std::string src_dir;
- if (fin && cmSystemTools::GetLineFromStream(fin, src_dir) &&
- cmSystemTools::FileIsDirectory(src_dir)) {
- cmSystemToolsCMakeRoot = src_dir;
- } else {
- dir = cmSystemTools::GetFilenamePath(dir);
- src_dir_txt = cmStrCat(dir, "/CMakeFiles/CMakeSourceDir.txt");
- cmsys::ifstream fin2(src_dir_txt.c_str());
- if (fin2 && cmSystemTools::GetLineFromStream(fin2, src_dir) &&
- cmSystemTools::FileIsDirectory(src_dir)) {
- cmSystemToolsCMakeRoot = src_dir;
- }
- }
- if (!cmSystemToolsCMakeRoot.empty() && cmSystemToolsHTMLDoc.empty() &&
- cmSystemTools::FileExists(
- cmStrCat(dir, "/Utilities/Sphinx/html/index.html"))) {
- cmSystemToolsHTMLDoc = cmStrCat(dir, "/Utilities/Sphinx/html");
- }
- }
-#else
- // Bootstrap build knows its source.
- cmSystemToolsCMakeRoot = CMAKE_BOOTSTRAP_SOURCE_DIR;
-#endif
}
std::string const& cmSystemTools::GetCMakeCommand()
@@ -2737,10 +2943,18 @@
return config;
}
-std::string cmSystemTools::GetCurrentWorkingDirectory()
+std::string const& cmSystemTools::GetLogicalWorkingDirectory()
{
- return cmSystemTools::CollapseFullPath(
- cmsys::SystemTools::GetCurrentWorkingDirectory());
+ return cmSystemToolsLogicalWorkingDirectory;
+}
+
+cmsys::Status cmSystemTools::SetLogicalWorkingDirectory(std::string const& lwd)
+{
+ cmsys::Status status = cmSystemTools::ChangeDirectory(lwd);
+ if (status) {
+ cmSystemToolsLogicalWorkingDirectory = lwd;
+ }
+ return status;
}
void cmSystemTools::MakefileColorEcho(int color, const char* message,
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 0531f63..4f62aee 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -399,7 +399,18 @@
std::string const& in);
static cm::optional<std::string> GetEnvVar(std::string const& var);
- static std::vector<std::string> SplitEnvPath(std::string const& value);
+ static std::vector<std::string> GetEnvPathNormalized(std::string const& var);
+
+ static std::vector<std::string> SplitEnvPath(cm::string_view in);
+ static std::vector<std::string> SplitEnvPathNormalized(cm::string_view in);
+
+ /** Convert an input path to an absolute path with no '/..' components.
+ Backslashes in the input path are converted to forward slashes.
+ Relative paths are interpreted w.r.t. GetLogicalWorkingDirectory.
+ On Windows, the on-disk capitalization is loaded for existing paths.
+ This is similar to 'realpath', but preserves symlinks that are
+ not erased by '../' components. */
+ static std::string ToNormalizedPathOnDisk(std::string p);
#ifndef CMAKE_BOOTSTRAP
/** Remove an environment variable */
@@ -529,8 +540,11 @@
static cm::optional<std::string> GetSystemConfigDirectory();
static cm::optional<std::string> GetCMakeConfigDirectory();
- /** Get the CWD mapped through the KWSys translation map. */
- static std::string GetCurrentWorkingDirectory();
+ static std::string const& GetLogicalWorkingDirectory();
+
+ /** The logical working directory may contain symlinks but must not
+ contain any '../' path components. */
+ static cmsys::Status SetLogicalWorkingDirectory(std::string const& lwd);
/** Echo a message in color using KWSys's Terminal cprintf. */
static void MakefileColorEcho(int color, const char* message, bool newLine,
@@ -591,11 +605,9 @@
static std::string GetComspec();
#endif
- /** Get the real path for a given path, removing all symlinks.
- This variant of GetRealPath also works on Windows but will
- resolve subst drives too. */
- static std::string GetRealPathResolvingWindowsSubst(
- const std::string& path, std::string* errorMessage = nullptr);
+ /** Get the real path for a given path, removing all symlinks. */
+ static std::string GetRealPath(const std::string& path,
+ std::string* errorMessage = nullptr);
/** Perform one-time initialization of libuv. */
static void InitializeLibUV();
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index f220837..87678b1 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -250,7 +250,7 @@
void CopyFromEntries(cmBTStringRange entries)
{
- return cm::append(this->Entries, entries);
+ cm::append(this->Entries, entries);
}
enum class Action
@@ -354,6 +354,8 @@
}
cm::static_string_view const Name;
+ // Explicit initialization is needed for AppleClang in Xcode 8 and below
+ // NOLINTNEXTLINE(readability-redundant-member-init)
cm::optional<cm::static_string_view> const Default = {};
InitCondition const InitConditional = InitCondition::Always;
Repetition const Repeat = Repetition::Once;
@@ -551,6 +553,7 @@
{ "UNITY_BUILD_UNIQUE_ID"_s, IC::CanCompileSources },
{ "UNITY_BUILD_BATCH_SIZE"_s, "8"_s, IC::CanCompileSources },
{ "UNITY_BUILD_MODE"_s, "BATCH"_s, IC::CanCompileSources },
+ { "UNITY_BUILD_RELOCATABLE"_s, IC::CanCompileSources },
{ "OPTIMIZE_DEPENDENCIES"_s, IC::CanCompileSources },
{ "VERIFY_INTERFACE_HEADER_SETS"_s },
// -- Android
@@ -2047,10 +2050,13 @@
{
ReadOnlyProperty(ReadOnlyCondition cond)
: Condition{ cond }
- , Policy{} {};
+ {
+ }
ReadOnlyProperty(ReadOnlyCondition cond, cmPolicies::PolicyID id)
: Condition{ cond }
- , Policy{ id } {};
+ , Policy{ id }
+ {
+ }
ReadOnlyCondition Condition;
cm::optional<cmPolicies::PolicyID> Policy;
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index 51dce76..efa8f44 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -97,8 +97,8 @@
if (!target) {
MessageType t = MessageType::FATAL_ERROR; // fail by default
std::ostringstream e;
- e << "Cannot specify link libraries for target \"" << args[0] << "\" "
- << "which is not built by this project.";
+ e << "Cannot specify link libraries for target \"" << args[0]
+ << "\" which is not built by this project.";
// The bad target is the only argument. Check how policy CMP0016 is set,
// and accept, warn or fail respectively:
if (args.size() < 2) {
@@ -107,9 +107,9 @@
t = MessageType::AUTHOR_WARNING;
// Print the warning.
e << "\n"
- << "CMake does not support this but it used to work accidentally "
- << "and is being allowed for compatibility."
- << "\n"
+ "CMake does not support this but it used to work accidentally "
+ "and is being allowed for compatibility."
+ "\n"
<< cmPolicies::GetPolicyWarning(cmPolicies::CMP0016);
break;
case cmPolicies::OLD: // OLD behavior does not warn.
@@ -117,7 +117,7 @@
break;
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::REQUIRED_ALWAYS:
- e << "\n" << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0016);
+ e << '\n' << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0016);
break;
case cmPolicies::NEW: // NEW behavior prints the error.
break;
@@ -145,7 +145,7 @@
MessageType messageType = MessageType::AUTHOR_WARNING;
switch (mf.GetPolicyStatus(cmPolicies::CMP0039)) {
case cmPolicies::WARN:
- e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0039) << "\n";
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0039) << '\n';
modal = "should";
CM_FALLTHROUGH;
case cmPolicies::OLD:
@@ -456,7 +456,7 @@
MessageType messageType = MessageType::AUTHOR_WARNING;
switch (this->Makefile.GetPolicyStatus(cmPolicies::CMP0023)) {
case cmPolicies::WARN:
- e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0023) << "\n";
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0023) << '\n';
modal = "should";
CM_FALLTHROUGH;
case cmPolicies::OLD:
diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx
index 4d8bc02..cb6eb6f 100644
--- a/Source/cmTimestamp.cxx
+++ b/Source/cmTimestamp.cxx
@@ -62,8 +62,7 @@
const std::string& formatString,
bool utcFlag) const
{
- std::string real_path =
- cmSystemTools::GetRealPathResolvingWindowsSubst(path);
+ std::string real_path = cmSystemTools::GetRealPath(path);
if (!cmsys::SystemTools::FileExists(real_path)) {
return std::string();
diff --git a/Source/cmUVHandlePtr.h b/Source/cmUVHandlePtr.h
index b8b3491..ef88ef1 100644
--- a/Source/cmUVHandlePtr.h
+++ b/Source/cmUVHandlePtr.h
@@ -158,10 +158,10 @@
};
template <typename T>
-inline uv_handle_ptr_base_<T>::uv_handle_ptr_base_(
+uv_handle_ptr_base_<T>::uv_handle_ptr_base_(
uv_handle_ptr_base_<T>&&) noexcept = default;
template <typename T>
-inline uv_handle_ptr_base_<T>& uv_handle_ptr_base_<T>::operator=(
+uv_handle_ptr_base_<T>& uv_handle_ptr_base_<T>::operator=(
uv_handle_ptr_base_<T>&&) noexcept = default;
/**
diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx
index b787f19..4060a3d 100644
--- a/Source/cmUVProcessChain.cxx
+++ b/Source/cmUVProcessChain.cxx
@@ -342,6 +342,9 @@
!defined(CMAKE_USE_SYSTEM_LIBUV)
options.flags |= UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME;
#endif
+#if UV_VERSION_MAJOR > 1 || !defined(CMAKE_USE_SYSTEM_LIBUV)
+ options.flags |= UV_PROCESS_WINDOWS_USE_PARENT_ERROR_MODE;
+#endif
if (!this->Builder->WorkingDirectory.empty()) {
options.cwd = this->Builder->WorkingDirectory.c_str();
}
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 694976e..8d9946f 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -30,6 +30,7 @@
#include "cmFileSet.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorExpression.h"
+#include "cmGeneratorOptions.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmGlobalVisualStudio10Generator.h"
@@ -1870,7 +1871,9 @@
BuildInParallel buildInParallel = BuildInParallel::No;
if (command.GetCMP0147Status() == cmPolicies::NEW &&
!command.GetUsesTerminal() &&
- !(command.HasMainDependency() && source->GetIsGenerated())) {
+ !(command.HasMainDependency() && source->GetIsGenerated()) &&
+ !source->GetPropertyAsBool(
+ "VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD")) {
buildInParallel = BuildInParallel::Yes;
}
this->WriteCustomRuleCpp(*spe2, c, script, additional_inputs.str(),
@@ -4426,12 +4429,9 @@
linkType = "EXE";
}
std::string flags;
- std::string linkFlagVarBase = cmStrCat("CMAKE_", linkType, "_LINKER_FLAGS");
- flags += ' ';
- flags += this->Makefile->GetRequiredDefinition(linkFlagVarBase);
- std::string linkFlagVar = cmStrCat(linkFlagVarBase, '_', CONFIG);
- flags += ' ';
- flags += this->Makefile->GetRequiredDefinition(linkFlagVar);
+ this->LocalGenerator->AddConfigVariableFlags(
+ flags, cmStrCat("CMAKE_", linkType, "_LINKER_FLAGS"),
+ this->GeneratorTarget, cmBuildStep::Link, linkLanguage, config);
cmValue targetLinkFlags = this->GeneratorTarget->GetProperty("LINK_FLAGS");
if (targetLinkFlags) {
flags += ' ';
diff --git a/Source/cmWorkerPool.cxx b/Source/cmWorkerPool.cxx
index 2fbf657..69ebdab 100644
--- a/Source/cmWorkerPool.cxx
+++ b/Source/cmWorkerPool.cxx
@@ -250,6 +250,9 @@
this->UVOptions_.args = const_cast<char**>(this->CommandPtr_.data());
this->UVOptions_.cwd = this->Setup_.WorkingDirectory.c_str();
this->UVOptions_.flags = UV_PROCESS_WINDOWS_HIDE;
+#if UV_VERSION_MAJOR > 1 || !defined(CMAKE_USE_SYSTEM_LIBUV)
+ this->UVOptions_.flags |= UV_PROCESS_WINDOWS_USE_PARENT_ERROR_MODE;
+#endif
this->UVOptions_.stdio_count =
static_cast<int>(this->UVOptionsStdIO_.size());
this->UVOptions_.stdio = this->UVOptionsStdIO_.data();
diff --git a/Source/cmWorkingDirectory.cxx b/Source/cmWorkingDirectory.cxx
index 12fae12..ec10fb1 100644
--- a/Source/cmWorkingDirectory.cxx
+++ b/Source/cmWorkingDirectory.cxx
@@ -2,13 +2,12 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmWorkingDirectory.h"
-#include <cerrno>
-
+#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
cmWorkingDirectory::cmWorkingDirectory(std::string const& newdir)
{
- this->OldDir = cmSystemTools::GetCurrentWorkingDirectory();
+ this->OldDir = cmSystemTools::GetLogicalWorkingDirectory();
this->SetDirectory(newdir);
}
@@ -19,11 +18,13 @@
bool cmWorkingDirectory::SetDirectory(std::string const& newdir)
{
- if (cmSystemTools::ChangeDirectory(newdir)) {
- this->ResultCode = 0;
+ cmsys::Status status = cmSystemTools::SetLogicalWorkingDirectory(newdir);
+ if (status) {
+ this->Error.clear();
return true;
}
- this->ResultCode = errno;
+ this->Error = cmStrCat("Failed to change working directory to \"", newdir,
+ "\": ", status.GetString());
return false;
}
diff --git a/Source/cmWorkingDirectory.h b/Source/cmWorkingDirectory.h
index e593621..82f79bc 100644
--- a/Source/cmWorkingDirectory.h
+++ b/Source/cmWorkingDirectory.h
@@ -26,19 +26,11 @@
bool SetDirectory(std::string const& newdir);
void Pop();
- bool Failed() const { return this->ResultCode != 0; }
-
- /** \return 0 if the last attempt to set the working directory was
- * successful. If it failed, the value returned will be the
- * \c errno value associated with the failure. A description
- * of the error code can be obtained by passing the result
- * to \c std::strerror().
- */
- int GetLastResult() const { return this->ResultCode; }
-
+ bool Failed() const { return !this->Error.empty(); }
+ std::string const& GetError() const { return this->Error; }
std::string const& GetOldDirectory() const { return this->OldDir; }
private:
std::string OldDir;
- int ResultCode;
+ std::string Error;
};
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index fcee5e5..2817819 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -7,7 +7,6 @@
#include <chrono>
#include <cstdio>
#include <cstdlib>
-#include <cstring>
#include <initializer_list>
#include <iomanip>
#include <iostream>
@@ -287,7 +286,7 @@
};
cmake::cmake(Role role, cmState::Mode mode, cmState::ProjectKind projectKind)
- : CMakeWorkingDirectory(cmSystemTools::GetCurrentWorkingDirectory())
+ : CMakeWorkingDirectory(cmSystemTools::GetLogicalWorkingDirectory())
, FileTimeCache(cm::make_unique<cmFileTimeCache>())
#ifndef CMAKE_BOOTSTRAP
, VariableWatch(cm::make_unique<cmVariableWatch>())
@@ -638,8 +637,8 @@
// Documented behavior of CMAKE{,_CURRENT}_{SOURCE,BINARY}_DIR is to be
// set to $PWD for -P mode.
state->SetWorkingMode(SCRIPT_MODE);
- state->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
- state->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ state->SetHomeDirectory(cmSystemTools::GetLogicalWorkingDirectory());
+ state->SetHomeOutputDirectory(cmSystemTools::GetLogicalWorkingDirectory());
state->ReadListFile(args, path);
return true;
};
@@ -690,7 +689,7 @@
cmSystemTools::Stdout("loading initial cache file " + value + "\n");
// Resolve script path specified on command line
// relative to $PWD.
- auto path = cmSystemTools::CollapseFullPath(value);
+ auto path = cmSystemTools::ToNormalizedPathOnDisk(value);
state->ReadListFile(args, path);
return true;
} },
@@ -779,10 +778,7 @@
snapshot.SetDefaultDefinitions();
cmMakefile mf(gg, snapshot);
if (this->GetWorkingMode() != NORMAL_MODE) {
- std::string file(cmSystemTools::CollapseFullPath(path));
- cmSystemTools::ConvertToUnixSlashes(file);
- mf.SetScriptModeFile(file);
-
+ mf.SetScriptModeFile(cmSystemTools::ToNormalizedPathOnDisk(path));
mf.SetArgcArgv(args);
}
if (!cmSystemTools::FileExists(path, true)) {
@@ -796,16 +792,16 @@
bool cmake::FindPackage(const std::vector<std::string>& args)
{
- this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
- this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ this->SetHomeDirectory(cmSystemTools::GetLogicalWorkingDirectory());
+ this->SetHomeOutputDirectory(cmSystemTools::GetLogicalWorkingDirectory());
this->SetGlobalGenerator(cm::make_unique<cmGlobalGenerator>(this));
cmStateSnapshot snapshot = this->GetCurrentSnapshot();
snapshot.GetDirectory().SetCurrentBinary(
- cmSystemTools::GetCurrentWorkingDirectory());
+ cmSystemTools::GetLogicalWorkingDirectory());
snapshot.GetDirectory().SetCurrentSource(
- cmSystemTools::GetCurrentWorkingDirectory());
+ cmSystemTools::GetLogicalWorkingDirectory());
// read in the list file to fill the cache
snapshot.SetDefaultDefinitions();
auto mfu = cm::make_unique<cmMakefile>(this->GetGlobalGenerator(), snapshot);
@@ -956,10 +952,8 @@
cmSystemTools::Error("No source directory specified for -S");
return false;
}
- std::string path = cmSystemTools::CollapseFullPath(value);
- cmSystemTools::ConvertToUnixSlashes(path);
-
- state->SetHomeDirectoryViaCommandLine(path);
+ state->SetHomeDirectoryViaCommandLine(
+ cmSystemTools::ToNormalizedPathOnDisk(value));
return true;
};
@@ -968,9 +962,8 @@
cmSystemTools::Error("No build directory specified for -B");
return false;
}
- std::string path = cmSystemTools::CollapseFullPath(value);
- cmSystemTools::ConvertToUnixSlashes(path);
- state->SetHomeOutputDirectory(path);
+ state->SetHomeOutputDirectory(
+ cmSystemTools::ToNormalizedPathOnDisk(value));
haveBArg = true;
return true;
};
@@ -1074,7 +1067,8 @@
CommandArgument{ "--graphviz", "No file specified for --graphviz",
CommandArgument::Values::One,
[](std::string const& value, cmake* state) -> bool {
- state->SetGraphVizFile(value);
+ state->SetGraphVizFile(
+ cmSystemTools::ToNormalizedPathOnDisk(value));
return true;
} },
@@ -1137,7 +1131,7 @@
"--debug-find-pkg", "Provide a package argument for --debug-find-pkg",
CommandArgument::Values::One, CommandArgument::RequiresSeparator::Yes,
[](std::string const& value, cmake* state) -> bool {
- std::vector<std::string> find_pkgs(cmTokenize(value, ","));
+ std::vector<std::string> find_pkgs(cmTokenize(value, ','));
std::cout << "Running with debug output on for the 'find' commands "
"for package(s)";
for (auto const& v : find_pkgs) {
@@ -1151,7 +1145,7 @@
"--debug-find-var", CommandArgument::Values::One,
CommandArgument::RequiresSeparator::Yes,
[](std::string const& value, cmake* state) -> bool {
- std::vector<std::string> find_vars(cmTokenize(value, ","));
+ std::vector<std::string> find_vars(cmTokenize(value, ','));
std::cout << "Running with debug output on for the variable(s)";
for (auto const& v : find_vars) {
std::cout << ' ' << v;
@@ -1278,23 +1272,22 @@
return false;
#endif
} },
- CommandArgument{
- "--debugger-dap-log", "No file specified for --debugger-dap-log",
- CommandArgument::Values::One,
- [](std::string const& value, cmake* state) -> bool {
+ CommandArgument{ "--debugger-dap-log",
+ "No file specified for --debugger-dap-log",
+ CommandArgument::Values::One,
+ [](std::string const& value, cmake* state) -> bool {
#ifdef CMake_ENABLE_DEBUGGER
- std::string path = cmSystemTools::CollapseFullPath(value);
- cmSystemTools::ConvertToUnixSlashes(path);
- state->DebuggerDapLogFile = path;
- return true;
+ state->DebuggerDapLogFile =
+ cmSystemTools::ToNormalizedPathOnDisk(value);
+ return true;
#else
- static_cast<void>(value);
- static_cast<void>(state);
- cmSystemTools::Error(
- "CMake was not built with support for --debugger-dap-log");
- return false;
+ static_cast<void>(value);
+ static_cast<void>(state);
+ cmSystemTools::Error("CMake was not built with support "
+ "for --debugger-dap-log");
+ return false;
#endif
- } },
+ } },
};
#if defined(CMAKE_HAVE_VS_GENERATORS)
@@ -1316,9 +1309,8 @@
arguments.emplace_back(
"--profiling-output", "No path specified for --profiling-output",
CommandArgument::Values::One,
- [&](std::string const& value, cmake*) -> bool {
- profilingOutput = cmSystemTools::CollapseFullPath(value);
- cmSystemTools::ConvertToUnixSlashes(profilingOutput);
+ [&profilingOutput](std::string const& value, cmake*) -> bool {
+ profilingOutput = cmSystemTools::ToNormalizedPathOnDisk(value);
return true;
});
arguments.emplace_back("--preset", "No preset specified for --preset",
@@ -1479,10 +1471,10 @@
}
if (!haveSourceDir) {
- this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ this->SetHomeDirectory(cmSystemTools::GetLogicalWorkingDirectory());
}
if (!haveBinaryDir) {
- this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ this->SetHomeOutputDirectory(cmSystemTools::GetLogicalWorkingDirectory());
}
#if !defined(CMAKE_BOOTSTRAP)
@@ -1588,7 +1580,8 @@
if (!expandedPreset->GraphVizFile.empty()) {
if (this->GraphVizFile.empty()) {
- this->SetGraphVizFile(expandedPreset->GraphVizFile);
+ this->SetGraphVizFile(
+ cmSystemTools::CollapseFullPath(expandedPreset->GraphVizFile));
}
}
@@ -1779,8 +1772,7 @@
bool is_source_dir = false;
bool is_empty_directory = false;
if (cmSystemTools::FileIsDirectory(arg)) {
- std::string path = cmSystemTools::CollapseFullPath(arg);
- cmSystemTools::ConvertToUnixSlashes(path);
+ std::string path = cmSystemTools::ToNormalizedPathOnDisk(arg);
std::string cacheFile = cmStrCat(path, "/CMakeCache.txt");
std::string listFile = cmStrCat(path, "/CMakeLists.txt");
@@ -1795,7 +1787,7 @@
is_source_dir = true;
}
} else if (cmSystemTools::FileExists(arg)) {
- std::string fullPath = cmSystemTools::CollapseFullPath(arg);
+ std::string fullPath = cmSystemTools::ToNormalizedPathOnDisk(arg);
std::string name = cmSystemTools::GetFilenameName(fullPath);
name = cmSystemTools::LowerCase(name);
if (name == "cmakecache.txt"_s) {
@@ -1846,14 +1838,13 @@
if (is_source_dir) {
this->SetHomeDirectoryViaCommandLine(listPath);
if (no_build_tree) {
- std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
- this->SetHomeOutputDirectory(cwd);
+ this->SetHomeOutputDirectory(
+ cmSystemTools::GetLogicalWorkingDirectory());
}
} else if (no_source_tree && no_build_tree) {
this->SetHomeDirectory(listPath);
-
- std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
- this->SetHomeOutputDirectory(cwd);
+ this->SetHomeOutputDirectory(
+ cmSystemTools::GetLogicalWorkingDirectory());
} else if (no_build_tree) {
this->SetHomeOutputDirectory(listPath);
}
@@ -1861,18 +1852,16 @@
if (no_source_tree) {
// We didn't find a CMakeLists.txt and it wasn't specified
// with -S. Assume it is the path to the source tree
- std::string full = cmSystemTools::CollapseFullPath(arg);
- this->SetHomeDirectory(full);
+ this->SetHomeDirectory(cmSystemTools::ToNormalizedPathOnDisk(arg));
}
if (no_build_tree && !no_source_tree && is_empty_directory) {
// passed `-S <path> <build_dir> when build_dir is an empty directory
- std::string full = cmSystemTools::CollapseFullPath(arg);
- this->SetHomeOutputDirectory(full);
+ this->SetHomeOutputDirectory(cmSystemTools::ToNormalizedPathOnDisk(arg));
} else if (no_build_tree) {
// We didn't find a CMakeCache.txt and it wasn't specified
// with -B. Assume the current working directory as the build tree.
- std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
- this->SetHomeOutputDirectory(cwd);
+ this->SetHomeOutputDirectory(
+ cmSystemTools::GetLogicalWorkingDirectory());
used_provided_path = false;
}
}
@@ -2373,7 +2362,6 @@
int cmake::ActualConfigure()
{
// Construct right now our path conversion table before it's too late:
- this->UpdateConversionPathTable();
this->CleanupCommandsAndMacros();
cmSystemTools::RemoveADirectory(this->GetHomeOutputDirectory() +
@@ -3214,31 +3202,6 @@
#endif
}
-void cmake::UpdateConversionPathTable()
-{
- // Update the path conversion table with any specified file:
- cmValue tablepath =
- this->State->GetInitializedCacheValue("CMAKE_PATH_TRANSLATION_FILE");
-
- if (tablepath) {
- cmsys::ifstream table(tablepath->c_str());
- if (!table) {
- cmSystemTools::Error("CMAKE_PATH_TRANSLATION_FILE set to " + *tablepath +
- ". CMake can not open file.");
- cmSystemTools::ReportLastSystemError("CMake can not open file.");
- } else {
- std::string a;
- std::string b;
- while (!table.eof()) {
- // two entries per line
- table >> a;
- table >> b;
- cmSystemTools::AddTranslationPath(a, b);
- }
- }
- }
-}
-
int cmake::CheckBuildSystem()
{
// We do not need to rerun CMake. Check dependency integrity.
@@ -3479,7 +3442,7 @@
{
// so create the directory
std::string resultFile;
- std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ std::string cwd = cmSystemTools::GetLogicalWorkingDirectory();
std::string destPath = cwd + "/__cmake_systeminformation";
cmSystemTools::RemoveADirectory(destPath);
if (!cmSystemTools::MakeDirectory(destPath)) {
@@ -3548,8 +3511,7 @@
// file to it, so we wouldn't expect to get here unless the default
// permissions are questionable or some other process has deleted the
// directory
- std::cerr << "Failed to change to directory " << destPath << " : "
- << std::strerror(workdir.GetLastResult()) << '\n';
+ std::cerr << workdir.GetError() << '\n';
return 1;
}
std::vector<std::string> args2;
@@ -3618,8 +3580,8 @@
#if !defined(CMAKE_BOOTSTRAP)
if (!presetName.empty() || listPresets) {
- this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
- this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ this->SetHomeDirectory(cmSystemTools::GetLogicalWorkingDirectory());
+ this->SetHomeOutputDirectory(cmSystemTools::GetLogicalWorkingDirectory());
cmCMakePresetsGraph settingsFile;
auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory());
@@ -3964,8 +3926,8 @@
WorkflowListPresets listPresets, WorkflowFresh fresh)
{
#ifndef CMAKE_BOOTSTRAP
- this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory());
- this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory());
+ this->SetHomeDirectory(cmSystemTools::GetLogicalWorkingDirectory());
+ this->SetHomeOutputDirectory(cmSystemTools::GetLogicalWorkingDirectory());
cmCMakePresetsGraph settingsFile;
auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory());
diff --git a/Source/cmake.h b/Source/cmake.h
index cfe4edd..d5c8bbb 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -26,7 +26,6 @@
#include "cmState.h"
#include "cmStateSnapshot.h"
#include "cmStateTypes.h"
-#include "cmSystemTools.h"
#include "cmValue.h"
#if !defined(CMAKE_BOOTSTRAP)
@@ -300,12 +299,7 @@
}
//! Set the name of the graphviz file.
- void SetGraphVizFile(std::string const& ts)
- {
- std::string path = cmSystemTools::CollapseFullPath(ts);
- cmSystemTools::ConvertToUnixSlashes(path);
- this->GraphVizFile = path;
- }
+ void SetGraphVizFile(std::string const& ts) { this->GraphVizFile = ts; }
bool IsAKnownSourceExtension(cm::string_view ext) const
{
@@ -811,8 +805,6 @@
std::unique_ptr<cmGlobalGenerator> GlobalGenerator;
- void UpdateConversionPathTable();
-
//! Print a list of valid generators to stderr.
void PrintGeneratorList();
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index b57cdb3..985362a 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -219,7 +219,7 @@
int do_cmake(int ac, char const* const* av)
{
- if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
+ if (cmSystemTools::GetLogicalWorkingDirectory().empty()) {
std::cerr << "Current working directory cannot be established."
<< std::endl;
return 1;
@@ -601,7 +601,7 @@
}
}
if (!matched && i == 0) {
- dir = cmSystemTools::CollapseFullPath(arg);
+ dir = cmSystemTools::ToNormalizedPathOnDisk(arg);
matched = true;
parsed = true;
}
@@ -873,7 +873,7 @@
};
if (ac >= 3) {
- dir = cmSystemTools::CollapseFullPath(av[2]);
+ dir = cmSystemTools::ToNormalizedPathOnDisk(av[2]);
std::vector<std::string> inputArgs;
inputArgs.reserve(ac - 3);
@@ -1098,7 +1098,7 @@
for (int i = 2; i < ac; ++i) {
switch (doing) {
case DoingDir:
- dir = cmSystemTools::CollapseFullPath(av[i]);
+ dir = cmSystemTools::ToNormalizedPathOnDisk(av[i]);
doing = DoingNone;
break;
default:
diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx
index 5310166..aa4fd76 100644
--- a/Source/cmcldeps.cxx
+++ b/Source/cmcldeps.cxx
@@ -24,6 +24,7 @@
#include <windows.h>
#include "cmsys/Encoding.hxx"
+#include "cmsys/SystemTools.hxx"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
@@ -151,7 +152,7 @@
// FIXME should this be fatal or not? delete obj? delete d?
if (!out)
return;
- std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ std::string cwd = cmsys::SystemTools::GetCurrentWorkingDirectory();
replaceAll(cwd, "/", "\\");
cwd += "\\";
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index c82cb32..997c1a6 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -1347,10 +1347,10 @@
// Create a local generator configured for the directory in
// which dependencies will be scanned.
- homeDir = cmSystemTools::CollapseFullPath(homeDir);
- startDir = cmSystemTools::CollapseFullPath(startDir);
- homeOutDir = cmSystemTools::CollapseFullPath(homeOutDir);
- startOutDir = cmSystemTools::CollapseFullPath(startOutDir);
+ homeDir = cmSystemTools::ToNormalizedPathOnDisk(homeDir);
+ startDir = cmSystemTools::ToNormalizedPathOnDisk(startDir);
+ homeOutDir = cmSystemTools::ToNormalizedPathOnDisk(homeOutDir);
+ startOutDir = cmSystemTools::ToNormalizedPathOnDisk(startOutDir);
cm.SetHomeDirectory(homeDir);
cm.SetHomeOutputDirectory(homeOutDir);
cm.GetCurrentSnapshot().SetDefaultDefinitions();
@@ -1643,10 +1643,10 @@
std::string startDir;
std::string homeOutDir;
std::string startOutDir;
- homeDir = cmSystemTools::CollapseFullPath(args[4]);
- startDir = cmSystemTools::CollapseFullPath(args[5]);
- homeOutDir = cmSystemTools::CollapseFullPath(args[6]);
- startOutDir = cmSystemTools::CollapseFullPath(args[7]);
+ homeDir = cmSystemTools::ToNormalizedPathOnDisk(args[4]);
+ startDir = cmSystemTools::ToNormalizedPathOnDisk(args[5]);
+ homeOutDir = cmSystemTools::ToNormalizedPathOnDisk(args[6]);
+ startOutDir = cmSystemTools::ToNormalizedPathOnDisk(args[7]);
cm.SetHomeDirectory(homeDir);
cm.SetHomeOutputDirectory(homeOutDir);
cm.GetCurrentSnapshot().SetDefaultDefinitions();
@@ -2413,7 +2413,7 @@
// Create a resource file referencing the manifest.
std::string absManifestFile =
- cmSystemTools::CollapseFullPath(this->ManifestFile);
+ cmSystemTools::ToNormalizedPathOnDisk(this->ManifestFile);
if (this->Verbose) {
std::cout << "Create " << this->ManifestFileRC << '\n';
}
diff --git a/Source/ctest.cxx b/Source/ctest.cxx
index 68c36df..388e96b 100644
--- a/Source/ctest.cxx
+++ b/Source/ctest.cxx
@@ -15,7 +15,6 @@
#include "cmSystemTools.h"
#include "CTest/cmCTestLaunch.h"
-#include "CTest/cmCTestScriptHandler.h"
namespace {
const cmDocumentationEntry cmDocumentationName = {
@@ -147,8 +146,6 @@
{ "--overwrite", "Overwrite CTest configuration option." },
{ "--extra-submit <file>[;<file>]", "Submit extra files to the dashboard." },
{ "--http-header <header>", "Append HTTP header when submitting" },
- { "--force-new-ctest-process",
- "Run child CTest instances as new processes" },
{ "--schedule-random", "Use a random order for scheduling tests" },
{ "--submit-index",
"Submit individual dashboard tests with specific index" },
@@ -185,11 +182,8 @@
return cmCTestLaunch::Main(argc, argv);
}
- cmCTest inst;
-
- if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
- cmCTestLog(&inst, ERROR_MESSAGE,
- "Current working directory cannot be established.\n");
+ if (cmSystemTools::GetLogicalWorkingDirectory().empty()) {
+ std::cerr << "Current working directory cannot be established.\n";
return 1;
}
@@ -200,18 +194,13 @@
!(cmSystemTools::FileExists("CTestTestfile.cmake") ||
cmSystemTools::FileExists("DartTestfile.txt"))) {
if (argc == 1) {
- cmCTestLog(&inst, ERROR_MESSAGE,
- "*********************************\n"
- "No test configuration file found!\n"
- "*********************************\n");
+ std::cerr << "*********************************\n"
+ "No test configuration file found!\n"
+ "*********************************\n";
}
cmDocumentation doc;
doc.addCTestStandardDocSections();
if (doc.CheckOptions(argc, argv)) {
- // Construct and print requested documentation.
- cmCTestScriptHandler* ch = inst.GetScriptHandler();
- ch->CreateCMake();
-
doc.SetShowGenerators(false);
doc.SetName("ctest");
doc.SetSection("Name", cmDocumentationName);
@@ -222,15 +211,8 @@
}
// copy the args to a vector
- std::vector<std::string> args;
- args.reserve(argc);
- for (int i = 0; i < argc; ++i) {
- args.emplace_back(argv[i]);
- }
- // run ctest
- std::string output;
- int res = inst.Run(args, &output);
- cmCTestLog(&inst, OUTPUT, output);
+ auto args = std::vector<std::string>(argv, argv + argc);
- return res;
+ // run ctest
+ return cmCTest{}.Run(args);
}
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
index 562d5e6..be510b1 100644
--- a/Source/kwsys/CMakeLists.txt
+++ b/Source/kwsys/CMakeLists.txt
@@ -410,14 +410,6 @@
endif()
if(KWSYS_USE_SystemTools)
- if (NOT DEFINED KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP)
- set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1)
- endif ()
- if (KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP)
- set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1)
- else ()
- set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 0)
- endif ()
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_SETENV
"Checking whether CXX compiler has setenv" DIRECT)
KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UNSETENV
diff --git a/Source/kwsys/Configure.hxx.in b/Source/kwsys/Configure.hxx.in
index 8d47340..b4b0efa 100644
--- a/Source/kwsys/Configure.hxx.in
+++ b/Source/kwsys/Configure.hxx.in
@@ -11,9 +11,6 @@
/* Whether <ext/stdio_filebuf.h> is available. */
#define @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H \
@KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H@
-/* Whether the translation map is available or not. */
-#define @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP \
- @KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP@
#if defined(__SUNPRO_CC) && __SUNPRO_CC > 0x5130 && defined(__has_attribute)
# define @KWSYS_NAMESPACE@_has_cpp_attribute(x) __has_attribute(x)
@@ -58,8 +55,6 @@
# define KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H \
@KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H
# define KWSYS_FALLTHROUGH @KWSYS_NAMESPACE@_FALLTHROUGH
-# define KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP \
- @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP
#endif
#endif
diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c
index 0b43b4a..c1a566f 100644
--- a/Source/kwsys/ProcessWin32.c
+++ b/Source/kwsys/ProcessWin32.c
@@ -666,14 +666,14 @@
if (dir && dir[0]) {
wchar_t* wdir = kwsysEncoding_DupToWide(dir);
/* We must convert the working directory to a full path. */
- DWORD length = GetFullPathNameW(wdir, 0, 0, 0);
+ DWORD length = GetFullPathNameW(wdir, 0, NULL, NULL);
if (length > 0) {
wchar_t* work_dir = malloc(length * sizeof(wchar_t));
if (!work_dir) {
free(wdir);
return 0;
}
- if (!GetFullPathNameW(wdir, length, work_dir, 0)) {
+ if (!GetFullPathNameW(wdir, length, work_dir, NULL)) {
free(work_dir);
free(wdir);
return 0;
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 6cc103d..5b57900 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -59,9 +59,6 @@
#include <cctype>
#include <cerrno>
-#ifdef __QNX__
-# include <malloc.h> /* for malloc/free on QNX */
-#endif
#include <cstdio>
#include <cstdlib>
#include <cstring>
@@ -338,10 +335,9 @@
std::string* errorMessage = nullptr)
{
std::wstring tmp = KWSYS_NAMESPACE::Encoding::ToWide(path);
- wchar_t* ptemp;
wchar_t fullpath[MAX_PATH];
DWORD bufferLen = GetFullPathNameW(
- tmp.c_str(), sizeof(fullpath) / sizeof(fullpath[0]), fullpath, &ptemp);
+ tmp.c_str(), sizeof(fullpath) / sizeof(fullpath[0]), fullpath, nullptr);
if (bufferLen < sizeof(fullpath) / sizeof(fullpath[0])) {
resolved_path = KWSYS_NAMESPACE::Encoding::ToNarrow(fullpath);
KWSYS_NAMESPACE::SystemTools::ConvertToUnixSlashes(resolved_path);
@@ -494,75 +490,17 @@
}
};
-#ifdef _WIN32
-# if defined(_WIN64)
-static constexpr size_t FNV_OFFSET_BASIS = 14695981039346656037ULL;
-static constexpr size_t FNV_PRIME = 1099511628211ULL;
-# else
-static constexpr size_t FNV_OFFSET_BASIS = 2166136261U;
-static constexpr size_t FNV_PRIME = 16777619U;
-# endif
-
-// Case insensitive Fnv1a hash
-struct SystemToolsPathCaseHash
-{
- size_t operator()(std::string const& path) const
- {
- size_t hash = FNV_OFFSET_BASIS;
- for (auto c : path) {
- hash ^= static_cast<size_t>(std::tolower(c));
- hash *= FNV_PRIME;
- }
-
- return hash;
- }
-};
-
-struct SystemToolsPathCaseEqual
-{
- bool operator()(std::string const& l, std::string const& r) const
- {
-# ifdef _MSC_VER
- return _stricmp(l.c_str(), r.c_str()) == 0;
-# elif defined(__GNUC__)
- return strcasecmp(l.c_str(), r.c_str()) == 0;
-# else
- return SystemTools::Strucmp(l.c_str(), r.c_str()) == 0;
-# endif
- }
-};
-#endif
-
/**
* SystemTools static variables singleton class.
*/
class SystemToolsStatic
{
public:
- using StringMap = std::map<std::string, std::string>;
-#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
- /**
- * Path translation table from dir to refdir
- * Each time 'dir' will be found it will be replace by 'refdir'
- */
- StringMap TranslationMap;
-#endif
#ifdef _WIN32
- static std::string GetCasePathName(std::string const& pathIn,
- bool const cache);
- static std::string GetActualCaseForPathCached(std::string const& path);
+ static std::string GetCasePathName(std::string const& pathIn);
static const char* GetEnvBuffered(const char* key);
- std::unordered_map<std::string, std::string, SystemToolsPathCaseHash,
- SystemToolsPathCaseEqual>
- FindFileMap;
- std::unordered_map<std::string, std::string, SystemToolsPathCaseHash,
- SystemToolsPathCaseEqual>
- PathCaseMap;
std::map<std::string, std::string> EnvMap;
#endif
-#ifdef __CYGWIN__
- StringMap Cyg2Win32Map;
-#endif
/**
* Actual implementation of ReplaceString.
@@ -589,8 +527,7 @@
static SystemToolsStatic* SystemToolsStatics;
#ifdef _WIN32
-std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn,
- bool const cache)
+std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn)
{
std::string casePath;
@@ -643,30 +580,15 @@
std::string test_str = casePath;
test_str += path_components[idx];
- bool found_in_cache = false;
- if (cache) {
- auto const it = SystemToolsStatics->FindFileMap.find(test_str);
- if (it != SystemToolsStatics->FindFileMap.end()) {
- path_components[idx] = it->second;
- found_in_cache = true;
- }
- }
-
- if (!found_in_cache) {
- WIN32_FIND_DATAW findData;
- HANDLE hFind =
- ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData);
- if (INVALID_HANDLE_VALUE != hFind) {
- auto case_file_name = Encoding::ToNarrow(findData.cFileName);
- if (cache) {
- SystemToolsStatics->FindFileMap.emplace(test_str,
- case_file_name);
- }
- path_components[idx] = std::move(case_file_name);
- ::FindClose(hFind);
- } else {
- converting = false;
- }
+ WIN32_FIND_DATAW findData;
+ HANDLE hFind =
+ ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData);
+ if (INVALID_HANDLE_VALUE != hFind) {
+ auto case_file_name = Encoding::ToNarrow(findData.cFileName);
+ path_components[idx] = std::move(case_file_name);
+ ::FindClose(hFind);
+ } else {
+ converting = false;
}
}
}
@@ -675,21 +597,6 @@
}
return casePath;
}
-
-std::string SystemToolsStatic::GetActualCaseForPathCached(std::string const& p)
-{
- std::string casePath;
-
- auto it = SystemToolsStatics->PathCaseMap.find(p);
- if (it != SystemToolsStatics->PathCaseMap.end()) {
- casePath = it->second;
- } else {
- casePath = SystemToolsStatic::GetCasePathName(p, true);
- SystemToolsStatics->PathCaseMap.emplace(p, casePath);
- }
-
- return casePath;
-}
#endif
// adds the elements of the env variable path to the arg passed in
@@ -824,25 +731,14 @@
#elif defined(__CYGWIN__) || defined(__GLIBC__)
/* putenv("A") removes A from the environment. It must not put the
memory in the environment because it does not have any "=" syntax. */
+
static int kwsysUnPutEnv(const std::string& env)
{
int err = 0;
- size_t pos = env.find('=');
- size_t const len = pos == std::string::npos ? env.size() : pos;
- size_t const sz = len + 1;
- char local_buf[256];
- char* buf = sz > sizeof(local_buf) ? (char*)malloc(sz) : local_buf;
- if (!buf) {
- return -1;
- }
- strncpy(buf, env.c_str(), len);
- buf[len] = 0;
- if (putenv(buf) < 0 && errno != EINVAL) {
+ std::string buf = env.substr(0, env.find('='));
+ if (putenv(&buf[0]) < 0 && errno != EINVAL) {
err = errno;
}
- if (buf != local_buf) {
- free(buf);
- }
if (err) {
errno = err;
return -1;
@@ -3407,6 +3303,14 @@
}
std::wstring substituteName(substituteNameData, substituteNameLength);
origName = Encoding::ToNarrow(substituteName);
+ // Symbolic links to absolute paths may use a NT Object Path prefix.
+ // If the path begins with "\??\UNC\", replace it with "\\".
+ // Otherwise, if the path begins with "\??\", remove the prefix.
+ if (origName.compare(0, 8, "\\??\\UNC\\") == 0) {
+ origName.erase(1, 6);
+ } else if (origName.compare(0, 4, "\\??\\") == 0) {
+ origName.erase(0, 4);
+ }
#else
char buf[KWSYS_SYSTEMTOOLS_MAXPATH + 1];
int count = static_cast<int>(
@@ -3501,72 +3405,6 @@
return true;
}
-#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
-void SystemTools::AddTranslationPath(const std::string& a,
- const std::string& b)
-{
- std::string path_a = a;
- std::string path_b = b;
- SystemTools::ConvertToUnixSlashes(path_a);
- SystemTools::ConvertToUnixSlashes(path_b);
- // First check this is a directory path, since we don't want the table to
- // grow too fat
- if (SystemTools::FileIsDirectory(path_a)) {
- // Make sure the path is a full path and does not contain no '..'
- // Ken--the following code is incorrect. .. can be in a valid path
- // for example /home/martink/MyHubba...Hubba/Src
- if (SystemTools::FileIsFullPath(path_b) &&
- path_b.find("..") == std::string::npos) {
- // Before inserting make sure path ends with '/'
- if (!path_a.empty() && path_a.back() != '/') {
- path_a += '/';
- }
- if (!path_b.empty() && path_b.back() != '/') {
- path_b += '/';
- }
- if (!(path_a == path_b)) {
- SystemToolsStatics->TranslationMap.insert(
- SystemToolsStatic::StringMap::value_type(std::move(path_a),
- std::move(path_b)));
- }
- }
- }
-}
-
-void SystemTools::AddKeepPath(const std::string& dir)
-{
- std::string cdir;
- Realpath(SystemTools::CollapseFullPath(dir), cdir);
- SystemTools::AddTranslationPath(cdir, dir);
-}
-
-void SystemTools::CheckTranslationPath(std::string& path)
-{
- // Do not translate paths that are too short to have meaningful
- // translations.
- if (path.size() < 2) {
- return;
- }
-
- // Always add a trailing slash before translation. It does not
- // matter if this adds an extra slash, but we do not want to
- // translate part of a directory (like the foo part of foo-dir).
- path += '/';
-
- // In case a file was specified we still have to go through this:
- // Now convert any path found in the table back to the one desired:
- for (auto const& pair : SystemToolsStatics->TranslationMap) {
- // We need to check of the path is a substring of the other path
- if (path.compare(0, pair.first.size(), pair.first) == 0) {
- path = path.replace(0, pair.first.size(), pair.second);
- }
- }
-
- // Remove the trailing slash we added before.
- path.pop_back();
-}
-#endif
-
static void SystemToolsAppendComponents(
std::vector<std::string>& out_components,
std::vector<std::string>::iterator first,
@@ -3629,25 +3467,7 @@
// Transform the path back to a string.
std::string newPath = SystemTools::JoinPath(out_components);
-#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
- // Update the translation table with this potentially new path. I am not
- // sure why this line is here, it seems really questionable, but yet I
- // would put good money that if I remove it something will break, basically
- // from what I can see it created a mapping from the collapsed path, to be
- // replaced by the input path, which almost completely does the opposite of
- // this function, the only thing preventing this from happening a lot is
- // that if the in_path has a .. in it, then it is not added to the
- // translation table. So for most calls this either does nothing due to the
- // .. or it adds a translation between identical paths as nothing was
- // collapsed, so I am going to try to comment it out, and see what hits the
- // fan, hopefully quickly.
- // Commented out line below:
- // SystemTools::AddTranslationPath(newPath, in_path);
-
- SystemTools::CheckTranslationPath(newPath);
-#endif
#ifdef _WIN32
- newPath = SystemToolsStatics->GetActualCaseForPathCached(newPath);
SystemTools::ConvertToUnixSlashes(newPath);
#endif
// Return the reconstructed path.
@@ -3756,7 +3576,7 @@
std::string SystemTools::GetActualCaseForPath(const std::string& p)
{
#ifdef _WIN32
- return SystemToolsStatic::GetCasePathName(p, false);
+ return SystemToolsStatic::GetCasePathName(p);
#else
return p;
#endif
@@ -4968,51 +4788,6 @@
// Create statics singleton instance
SystemToolsStatics = new SystemToolsStatic;
-
-#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP
-// Add some special translation paths for unix. These are not added
-// for windows because drive letters need to be maintained. Also,
-// there are not sym-links and mount points on windows anyway.
-# if !defined(_WIN32) || defined(__CYGWIN__)
- // The tmp path is frequently a logical path so always keep it:
- SystemTools::AddKeepPath("/tmp/");
-
- // If the current working directory is a logical path then keep the
- // logical name.
- std::string pwd_str;
- if (SystemTools::GetEnv("PWD", pwd_str)) {
- char buf[2048];
- if (const char* cwd = Getcwd(buf, 2048)) {
- // The current working directory may be a logical path. Find
- // the shortest logical path that still produces the correct
- // physical path.
- std::string cwd_changed;
- std::string pwd_changed;
-
- // Test progressively shorter logical-to-physical mappings.
- std::string cwd_str = cwd;
- std::string pwd_path;
- Realpath(pwd_str, pwd_path);
- while (cwd_str == pwd_path && cwd_str != pwd_str) {
- // The current pair of paths is a working logical mapping.
- cwd_changed = cwd_str;
- pwd_changed = pwd_str;
-
- // Strip off one directory level and see if the logical
- // mapping still works.
- pwd_str = SystemTools::GetFilenamePath(pwd_str);
- cwd_str = SystemTools::GetFilenamePath(cwd_str);
- Realpath(pwd_str, pwd_path);
- }
-
- // Add the translation to keep the logical path name.
- if (!cwd_changed.empty() && !pwd_changed.empty()) {
- SystemTools::AddTranslationPath(cwd_changed, pwd_changed);
- }
- }
- }
-# endif
-#endif
}
void SystemTools::ClassFinalize()
diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in
index 294ffca..03fa3bc 100644
--- a/Source/kwsys/SystemTools.hxx.in
+++ b/Source/kwsys/SystemTools.hxx.in
@@ -984,25 +984,6 @@
*/
static int GetTerminalWidth();
-#if @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP
- /**
- * Add an entry in the path translation table.
- */
- static void AddTranslationPath(const std::string& dir,
- const std::string& refdir);
-
- /**
- * If dir is different after CollapseFullPath is called,
- * Then insert it into the path translation table
- */
- static void AddKeepPath(const std::string& dir);
-
- /**
- * Update path by going through the Path Translation table;
- */
- static void CheckTranslationPath(std::string& path);
-#endif
-
/**
* Delay the execution for a specified amount of time specified
* in milliseconds
@@ -1052,14 +1033,7 @@
static std::string DecodeURL(const std::string& url);
private:
- /**
- * Allocate the stl map that serve as the Path Translation table.
- */
static void ClassInitialize();
-
- /**
- * Deallocate the stl map that serve as the Path Translation table.
- */
static void ClassFinalize();
/**
diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt
index 5b189e7..de08d56 100644
--- a/Tests/CMakeLib/CMakeLists.txt
+++ b/Tests/CMakeLib/CMakeLists.txt
@@ -16,12 +16,14 @@
testCTestResourceSpec.cxx
testCTestResourceGroups.cxx
testDebug.cxx
+ testDocumentationFormatter.cxx
testGccDepfileReader.cxx
testGeneratedFileStream.cxx
testJSONHelpers.cxx
testRST.cxx
testRange.cxx
testOptional.cxx
+ testPathResolver.cxx
testString.cxx
testStringAlgorithms.cxx
testSystemTools.cxx
diff --git a/Tests/CMakeLib/testCommon.h b/Tests/CMakeLib/testCommon.h
index de4a689..56e5ef4 100644
--- a/Tests/CMakeLib/testCommon.h
+++ b/Tests/CMakeLib/testCommon.h
@@ -40,10 +40,9 @@
break;
}
}
- std::cout << '.';
}
- if (!result) {
- std::cout << " Passed\n";
+ if (result == 0) {
+ std::cout << "Passed\n";
}
return result;
}
diff --git a/Tests/CMakeLib/testDebuggerAdapter.cxx b/Tests/CMakeLib/testDebuggerAdapter.cxx
index a055cb7..b2c9458 100644
--- a/Tests/CMakeLib/testDebuggerAdapter.cxx
+++ b/Tests/CMakeLib/testDebuggerAdapter.cxx
@@ -132,6 +132,7 @@
ASSERT_TRUE(initializeResponse.response.supportsExceptionInfoRequest);
ASSERT_TRUE(
initializeResponse.response.exceptionBreakpointFilters.has_value());
+ ASSERT_TRUE(initializeResponse.response.supportsValueFormattingOptions);
dap::LaunchRequest launchRequest;
auto launchResponse = client->send(launchRequest).get();
diff --git a/Tests/CMakeLib/testDebuggerAdapterPipe.cxx b/Tests/CMakeLib/testDebuggerAdapterPipe.cxx
index 3647088..312b0e2 100644
--- a/Tests/CMakeLib/testDebuggerAdapterPipe.cxx
+++ b/Tests/CMakeLib/testDebuggerAdapterPipe.cxx
@@ -20,9 +20,10 @@
#include "cmVersionConfig.h"
#ifdef _WIN32
+# include "cmsys/SystemTools.hxx"
+
# include "cmCryptoHash.h"
# include "cmDebuggerWindowsPipeConnection.h"
-# include "cmSystemTools.h"
#else
# include "cmDebuggerPosixPipeConnection.h"
#endif
@@ -69,7 +70,7 @@
#ifdef _WIN32
std::string namedPipe = R"(\\.\pipe\LOCAL\CMakeDebuggerPipe2_)" +
cmCryptoHash(cmCryptoHash::AlgoSHA256)
- .HashString(cmSystemTools::GetCurrentWorkingDirectory());
+ .HashString(cmsys::SystemTools::GetCurrentWorkingDirectory());
#else
std::string namedPipe = "CMakeDebuggerPipe2";
#endif
diff --git a/Tests/CMakeLib/testDebuggerThread.cxx b/Tests/CMakeLib/testDebuggerThread.cxx
index 3b7fe6e..4eed247 100644
--- a/Tests/CMakeLib/testDebuggerThread.cxx
+++ b/Tests/CMakeLib/testDebuggerThread.cxx
@@ -2,6 +2,7 @@
#include <string>
#include <vector>
+#include <cm3p/cppdap/optional.h>
#include <cm3p/cppdap/protocol.h>
#include <cm3p/cppdap/types.h>
@@ -10,21 +11,52 @@
#include "testCommon.h"
-static bool testStackFrameFunctionName()
+static bool testStackFrameFunctionName(
+ dap::optional<dap::StackFrameFormat> format, const char* expectedName)
{
auto thread = std::make_shared<cmDebugger::cmDebuggerThread>(0, "name");
const auto* functionName = "function_name";
- auto arguments = std::vector<cmListFileArgument>{};
+ auto arguments = std::vector<cmListFileArgument>{ cmListFileArgument(
+ "arg", cmListFileArgument::Delimiter::Unquoted, 0) };
cmListFileFunction func(functionName, 10, 20, arguments);
thread->PushStackFrame(nullptr, "CMakeLists.txt", func);
- auto stackTrace = GetStackTraceResponse(thread);
+ auto stackTrace = GetStackTraceResponse(thread, format);
- ASSERT_TRUE(stackTrace.stackFrames[0].name == functionName);
+ ASSERT_TRUE(stackTrace.stackFrames[0].name == expectedName);
return true;
}
+bool testStackFrameNoFormatting()
+{
+ return testStackFrameFunctionName({}, "function_name");
+}
+
+bool testStackFrameFormatParameters()
+{
+ dap::StackFrameFormat format;
+ format.parameters = true;
+ return testStackFrameFunctionName(format, "function_name()");
+}
+
+bool testStackFrameFormatParameterValues()
+{
+ dap::StackFrameFormat format;
+ format.parameters = true;
+ format.parameterValues = true;
+ return testStackFrameFunctionName(format, "function_name(arg)");
+}
+
+bool testStackFrameFormatLine()
+{
+ dap::StackFrameFormat format;
+ format.line = true;
+ return testStackFrameFunctionName(format, "function_name Line: 10");
+}
+
int testDebuggerThread(int, char*[])
{
- return runTests({ testStackFrameFunctionName });
+ return runTests({ testStackFrameNoFormatting, testStackFrameFormatParameters,
+ testStackFrameFormatParameterValues,
+ testStackFrameFormatLine });
}
diff --git a/Tests/CMakeLib/testDocumentationFormatter.cxx b/Tests/CMakeLib/testDocumentationFormatter.cxx
new file mode 100644
index 0000000..e332535
--- /dev/null
+++ b/Tests/CMakeLib/testDocumentationFormatter.cxx
@@ -0,0 +1,184 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <sstream>
+#include <string>
+#include <utility>
+
+#include <cmDocumentationFormatter.h>
+
+#include "testCommon.h"
+
+namespace {
+using TestCases = std::initializer_list<std::pair<std::string, std::string>>;
+
+bool testPrintFormattedNoIndent()
+{
+ const TestCases testCases = {
+ { "", "" },
+ { "\n\n", "\n\n\n\n" },
+ { "\n \n\n", "\n\n \n\n\n\n" },
+ { "One line no EOL text", "One line no EOL text\n" },
+ { "One line with trailing spaces and no EOL ",
+ "One line with trailing spaces and no EOL\n" },
+ { "Short text. Two sentences.", "Short text. Two sentences.\n" },
+ { "Short text\non\nmultiple\nlines\n",
+ "Short text\n\non\n\nmultiple\n\nlines\n\n" },
+ { "Just one a very long word: "
+ "01234567890123456789012345678901234567890123456789012345"
+ "678901234567890123456789",
+ "Just one a very long "
+ "word:\n01234567890123456789012345678901234567890123456789012345"
+ "678901234567890123456789\n" },
+ { " Pre-formatted paragraph with the very long word stays the same: "
+ "0123456789012345678901234567890123456789012345678901234567890123456789",
+ " Pre-formatted paragraph with the very long word stays the same: "
+ "0123456789012345678901234567890123456789012345678901234567890123456789"
+ "\n" },
+ { " Two pre-formatted\n paragraphs w/o EOL",
+ " Two pre-formatted\n paragraphs w/o EOL\n" },
+ { " Two pre-formatted\n paragraphs w/ EOL\n",
+ " Two pre-formatted\n paragraphs w/ EOL\n\n" },
+ { "Extra spaces are removed. However, \n not in a "
+ "pre-formatted\n "
+ "paragraph",
+ "Extra spaces are removed. However,\n\n not in a pre-formatted\n "
+ "paragraph\n" },
+ { "This is the text paragraph longer than a pre-defined wrapping position "
+ "of the `cmDocumentationFormatter` class. And it's gonna be wrapped "
+ "over multiple lines!",
+ "This is the text paragraph longer than a pre-defined wrapping position "
+ "of the\n`cmDocumentationFormatter` class. And it's gonna be wrapped "
+ "over multiple\nlines!\n" },
+ { "A normal paragraph, followed by ... \n Pre-formatted\n paragraphs "
+ "with trailing whitespaces ",
+ "A normal paragraph, followed by ...\n\n Pre-formatted\n paragraphs "
+ "with trailing whitespaces \n" },
+ { "A normal paragraph, followed by ... \n Pre-formatted\n paragraphs "
+ "with trailing whitespaces \nAnd another paragraph w/o EOL",
+ "A normal paragraph, followed by ...\n\n Pre-formatted\n paragraphs "
+ "with trailing whitespaces \n\nAnd another paragraph w/o EOL\n" },
+ { "A normal paragraph, followed by ... \n Pre-formatted\n paragraphs "
+ "with trailing whitespaces \nAnd another paragraph w/ EOL\n",
+ "A normal paragraph, followed by ...\n\n Pre-formatted\n paragraphs "
+ "with trailing whitespaces \n\nAnd another paragraph w/ EOL\n\n" },
+ { "A normal paragraph, followed by ... \n Pre-formatted\n paragraphs "
+ "with trailing whitespaces \nAnd another two\nparagraphs w/ EOL\n",
+ "A normal paragraph, followed by ...\n\n Pre-formatted\n paragraphs "
+ "with trailing whitespaces \n\nAnd another two\n\nparagraphs w/ "
+ "EOL\n\n" }
+ };
+
+ cmDocumentationFormatter formatter;
+
+ for (auto& test : testCases) {
+ std::ostringstream out;
+ formatter.PrintFormatted(out, test.first);
+ auto actual = out.str();
+ ASSERT_EQUAL(actual, test.second);
+ }
+
+ return true;
+}
+
+bool testPrintFormattedIndent2()
+{
+ const TestCases testCases = {
+ { "", "" },
+ // BEGIN NOTE Empty lines are not indented.
+ { "\n\n", "\n\n\n\n" },
+ { "\n \n\n", "\n\n \n\n\n\n" },
+ // END NOTE
+ { "One line no EOL text", " One line no EOL text\n" },
+ { "Short text. Two sentences.", " Short text. Two sentences.\n" },
+ { "Short text\non\nmultiple\nlines\n",
+ " Short text\n\n on\n\n multiple\n\n lines\n\n" },
+ { "Just one a very long word: "
+ "01234567890123456789012345678901234567890123456789012345"
+ "678901234567890123456789",
+ " Just one a very long "
+ "word:\n 01234567890123456789012345678901234567890123456789012345"
+ "678901234567890123456789\n" },
+ { " Pre-formatted paragraph with the very long word stays the same: "
+ "0123456789012345678901234567890123456789012345678901234567890123456789",
+ " Pre-formatted paragraph with the very long word stays the same: "
+ "0123456789012345678901234567890123456789012345678901234567890123456789"
+ "\n" },
+ { "Extra spaces are removed. However, \n not in a "
+ "pre-formatted\n "
+ "paragraph",
+ " Extra spaces are removed. However,\n\n not in a "
+ "pre-formatted\n "
+ "paragraph\n" },
+ { "This is the text paragraph longer than a pre-defined wrapping position "
+ "of the `cmDocumentationFormatter` class. And it's gonna be wrapped "
+ "over multiple lines!",
+ " This is the text paragraph longer than a pre-defined wrapping "
+ "position of\n"
+ " the `cmDocumentationFormatter` class. And it's gonna be wrapped "
+ "over\n multiple lines!\n" },
+ { "A normal paragraph, followed by ... \n Pre-formatted\n paragraphs "
+ "with trailing whitespaces ",
+ " A normal paragraph, followed by ...\n\n Pre-formatted\n "
+ "paragraphs "
+ "with trailing whitespaces \n" },
+ { "A normal paragraph, followed by ... \n Pre-formatted\n paragraphs "
+ "with trailing whitespaces \nAnd another paragraph w/o EOL",
+ " A normal paragraph, followed by ...\n\n Pre-formatted\n "
+ "paragraphs with trailing whitespaces \n\n And another paragraph "
+ "w/o EOL\n" },
+ { "A normal paragraph, followed by ... \n Pre-formatted\n paragraphs "
+ "with trailing whitespaces \nAnd another paragraph w/ EOL\n",
+ " A normal paragraph, followed by ...\n\n Pre-formatted\n "
+ "paragraphs with trailing whitespaces \n\n And another paragraph "
+ "w/ EOL\n\n" }
+ };
+
+ cmDocumentationFormatter formatter;
+ formatter.SetIndent(2);
+
+ for (auto& test : testCases) {
+ std::ostringstream out;
+ formatter.PrintFormatted(out, test.first);
+ auto actual = out.str();
+ ASSERT_EQUAL(actual, test.second);
+ }
+
+ return true;
+}
+
+bool testPrintFormattedIndent10()
+{
+ const TestCases testCases = {
+ { "", "" },
+ { "One line no EOL text", " One line no EOL text\n" },
+ { "This is the text paragraph longer than a pre-defined wrapping position "
+ "of the `cmDocumentationFormatter` class. And it's gonna be wrapped "
+ "over multiple lines!",
+ " This is the text paragraph longer than a pre-defined "
+ "wrapping\n"
+ " position of the `cmDocumentationFormatter` class. "
+ "And it's gonna\n"
+ " be wrapped over multiple lines!\n" }
+ };
+
+ cmDocumentationFormatter formatter;
+ formatter.SetIndent(10);
+
+ for (auto& test : testCases) {
+ std::ostringstream out;
+ formatter.PrintFormatted(out, test.first);
+ auto actual = out.str();
+ ASSERT_EQUAL(actual, test.second);
+ }
+
+ return true;
+}
+}
+
+int testDocumentationFormatter(int /*unused*/, char* /*unused*/[])
+{
+ return runTests({ testPrintFormattedNoIndent, testPrintFormattedIndent2,
+ testPrintFormattedIndent10 },
+ false);
+}
diff --git a/Tests/CMakeLib/testPathResolver.cxx b/Tests/CMakeLib/testPathResolver.cxx
new file mode 100644
index 0000000..4c4ff87
--- /dev/null
+++ b/Tests/CMakeLib/testPathResolver.cxx
@@ -0,0 +1,476 @@
+/* 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 <cerrno>
+#include <map>
+#include <string>
+#include <utility>
+
+#include <cmsys/Status.hxx>
+
+#include "cmPathResolver.h"
+
+#ifdef _WIN32
+# include <cctype>
+
+# include "cmSystemTools.h"
+#endif
+
+#include "testCommon.h"
+
+// IWYU pragma: no_forward_declare cm::PathResolver::Policies::LogicalPath
+// IWYU pragma: no_forward_declare cm::PathResolver::Policies::NaivePath
+// IWYU pragma: no_forward_declare cm::PathResolver::Policies::RealPath
+
+namespace {
+
+class MockSystem : public cm::PathResolver::System
+{
+public:
+ ~MockSystem() override = default;
+
+ struct Path
+ {
+ std::string Name;
+ std::string Link;
+ };
+
+ std::map<std::string, Path> Paths;
+
+ void SetPaths(std::map<std::string, Path> paths)
+ {
+ this->Paths = std::move(paths);
+ }
+
+ static std::string AdjustCase(std::string const& path)
+ {
+#ifdef _WIN32
+ return cmSystemTools::LowerCase(path);
+#else
+ return path;
+#endif
+ }
+
+ cmsys::Status ReadSymlink(std::string const& path,
+ std::string& link) override
+ {
+ auto i = this->Paths.find(AdjustCase(path));
+ if (i == this->Paths.end()) {
+ return cmsys::Status::POSIX(ENOENT);
+ }
+ if (i->second.Link.empty()) {
+ return cmsys::Status::POSIX(EINVAL);
+ }
+ link = i->second.Link;
+ return cmsys::Status::Success();
+ }
+
+ bool PathExists(std::string const& path) override
+ {
+ return this->Paths.find(AdjustCase(path)) != this->Paths.end();
+ }
+
+ std::string WorkDir;
+
+ void SetWorkDir(std::string wd) { this->WorkDir = std::move(wd); }
+
+ std::string GetWorkingDirectory() override { return this->WorkDir; }
+
+#ifdef _WIN32
+ std::map<char, std::string> WorkDirOnDrive;
+
+ void SetWorkDirOnDrive(std::map<char, std::string> wd)
+ {
+ this->WorkDirOnDrive = std::move(wd);
+ }
+
+ std::string GetWorkingDirectoryOnDrive(char letter) override
+ {
+ std::string result;
+ auto i = this->WorkDirOnDrive.find(std::tolower(letter));
+ if (i != this->WorkDirOnDrive.end()) {
+ result = i->second;
+ }
+ return result;
+ }
+
+ cmsys::Status ReadName(std::string const& path, std::string& name) override
+ {
+ auto i = this->Paths.find(AdjustCase(path));
+ if (i == this->Paths.end()) {
+ return cmsys::Status::POSIX(ENOENT);
+ }
+ name = i->second.Name;
+ return cmsys::Status::Success();
+ }
+#endif
+};
+
+#define EXPECT_RESOLVE(_in, _expect) \
+ do { \
+ std::string out; \
+ ASSERT_TRUE(r.Resolve(_in, out)); \
+ ASSERT_EQUAL(out, _expect); \
+ } while (false)
+
+#define EXPECT_ENOENT(_in, _expect) \
+ do { \
+ std::string out; \
+ ASSERT_EQUAL(r.Resolve(_in, out).GetPOSIX(), ENOENT); \
+ ASSERT_EQUAL(out, _expect); \
+ } while (false)
+
+using namespace cm::PathResolver;
+
+bool posixRoot()
+{
+ std::cout << "posixRoot()\n";
+ MockSystem os;
+ os.SetPaths({
+ { "/", { {}, {} } },
+ });
+ Resolver<Policies::RealPath> const r(os);
+ EXPECT_RESOLVE("/", "/");
+ EXPECT_RESOLVE("//", "/");
+ EXPECT_RESOLVE("/.", "/");
+ EXPECT_RESOLVE("/./", "/");
+ EXPECT_RESOLVE("/..", "/");
+ EXPECT_RESOLVE("/../", "/");
+ return true;
+}
+
+bool posixAbsolutePath()
+{
+ std::cout << "posixAbsolutePath()\n";
+ MockSystem os;
+ os.SetPaths({
+ { "/", { {}, {} } },
+ { "/a", { {}, {} } },
+ });
+ Resolver<Policies::RealPath> const r(os);
+ EXPECT_RESOLVE("/a", "/a");
+ EXPECT_RESOLVE("/a/", "/a");
+ EXPECT_RESOLVE("/a//", "/a");
+ EXPECT_RESOLVE("/a/.", "/a");
+ EXPECT_RESOLVE("/a/./", "/a");
+ EXPECT_RESOLVE("/a/..", "/");
+ EXPECT_RESOLVE("/a/../", "/");
+ EXPECT_RESOLVE("/a/../..", "/");
+#ifndef _WIN32
+ EXPECT_RESOLVE("//a", "/a");
+#endif
+ return true;
+}
+
+bool posixWorkingDirectory()
+{
+ std::cout << "posixWorkingDirectory()\n";
+ MockSystem os;
+ os.SetPaths({
+ { "/", { {}, {} } },
+ { "/a", { {}, {} } },
+ { "/cwd", { {}, {} } },
+ { "/cwd/a", { {}, {} } },
+ });
+ Resolver<Policies::RealPath> const r(os);
+ EXPECT_RESOLVE("", "/");
+ EXPECT_RESOLVE(".", "/");
+ EXPECT_RESOLVE("..", "/");
+ EXPECT_RESOLVE("a", "/a");
+ os.SetWorkDir("/cwd");
+ EXPECT_RESOLVE("", "/cwd");
+ EXPECT_RESOLVE(".", "/cwd");
+ EXPECT_RESOLVE("..", "/");
+ EXPECT_RESOLVE("a", "/cwd/a");
+ return true;
+}
+
+bool posixSymlink()
+{
+ std::cout << "posixSymlink()\n";
+ MockSystem os;
+ os.SetPaths({
+ { "/", { {}, {} } },
+ { "/link-a", { {}, "a" } },
+ { "/link-a-excess", { {}, "a//." } },
+ { "/link-broken", { {}, "link-broken-dest" } },
+ { "/a", { {}, {} } },
+ { "/a/b", { {}, {} } },
+ { "/a/link-b", { {}, "b" } },
+ { "/a/b/link-c", { {}, "c" } },
+ { "/a/b/c", { {}, {} } },
+ { "/a/b/c/link-..|..", { {}, "../.." } },
+ { "/a/link-|1|2", { {}, "/1/2" } },
+ { "/1", { {}, {} } },
+ { "/1/2", { {}, {} } },
+ { "/1/2/3", { {}, {} } },
+ });
+
+ {
+ Resolver<Policies::LogicalPath> const r(os);
+ EXPECT_RESOLVE("/link-a", "/link-a");
+ EXPECT_RESOLVE("/link-a-excess", "/link-a-excess");
+ EXPECT_RESOLVE("/link-a-excess/b", "/link-a-excess/b");
+ EXPECT_RESOLVE("/link-broken", "/link-broken");
+ EXPECT_RESOLVE("/link-a/../missing", "/missing");
+ EXPECT_RESOLVE("/a/b/link-c", "/a/b/link-c");
+ EXPECT_RESOLVE("/a/link-b/c", "/a/link-b/c");
+ EXPECT_RESOLVE("/a/link-b/link-c/..", "/a/link-b");
+ EXPECT_RESOLVE("/a/b/c/link-..|..", "/a/b/c/link-..|..");
+ EXPECT_RESOLVE("/a/b/c/link-..|../link-b", "/a/b/c/link-..|../link-b");
+ EXPECT_RESOLVE("/a/link-|1|2/3", "/a/link-|1|2/3");
+ EXPECT_RESOLVE("/a/link-|1|2/../2/3", "/1/2/3");
+ }
+
+ {
+ Resolver<Policies::RealPath> const r(os);
+ EXPECT_RESOLVE("/link-a", "/a");
+ EXPECT_RESOLVE("/link-a-excess", "/a");
+ EXPECT_RESOLVE("/link-a-excess/b", "/a/b");
+ EXPECT_ENOENT("/link-broken", "/link-broken-dest");
+ EXPECT_ENOENT("/link-a/../missing", "/missing");
+ EXPECT_RESOLVE("/a/b/link-c", "/a/b/c");
+ EXPECT_RESOLVE("/a/link-b/c", "/a/b/c");
+ EXPECT_RESOLVE("/a/link-b/link-c/..", "/a/b");
+ EXPECT_RESOLVE("/a/b/c/link-..|..", "/a");
+ EXPECT_RESOLVE("/a/b/c/link-..|../link-b", "/a/b");
+ EXPECT_RESOLVE("/a/link-|1|2/3", "/1/2/3");
+ }
+
+ return true;
+}
+
+#ifdef _WIN32
+bool windowsRoot()
+{
+ std::cout << "windowsRoot()\n";
+ MockSystem os;
+ {
+ Resolver<Policies::NaivePath> const r(os);
+ EXPECT_RESOLVE("c:/", "c:/");
+ EXPECT_RESOLVE("C:/", "C:/");
+ EXPECT_RESOLVE("c://", "c:/");
+ EXPECT_RESOLVE("C:/.", "C:/");
+ EXPECT_RESOLVE("c:/./", "c:/");
+ EXPECT_RESOLVE("C:/..", "C:/");
+ EXPECT_RESOLVE("c:/../", "c:/");
+ }
+ os.SetPaths({
+ { "c:/", { {}, {} } },
+ { "//host/", { {}, {} } },
+ });
+ {
+ Resolver<Policies::RealPath> const r(os);
+ EXPECT_RESOLVE("c:/", "C:/");
+ EXPECT_RESOLVE("C:/", "C:/");
+ EXPECT_RESOLVE("c://", "C:/");
+ EXPECT_RESOLVE("C:/.", "C:/");
+ EXPECT_RESOLVE("c:/./", "C:/");
+ EXPECT_RESOLVE("C:/..", "C:/");
+ EXPECT_RESOLVE("c:/../", "C:/");
+ EXPECT_RESOLVE("//host", "//host/");
+ EXPECT_RESOLVE("//host/.", "//host/");
+ EXPECT_RESOLVE("//host/./", "//host/");
+ EXPECT_RESOLVE("//host/..", "//host/");
+ EXPECT_RESOLVE("//host/../", "//host/");
+ }
+ return true;
+}
+
+bool windowsAbsolutePath()
+{
+ std::cout << "windowsAbsolutePath()\n";
+ MockSystem os;
+ os.SetPaths({
+ { "c:/", { {}, {} } },
+ { "c:/a", { {}, {} } },
+ });
+ Resolver<Policies::RealPath> const r(os);
+ EXPECT_RESOLVE("c:/a", "C:/a");
+ EXPECT_RESOLVE("c:/a/", "C:/a");
+ EXPECT_RESOLVE("c:/a//", "C:/a");
+ EXPECT_RESOLVE("c:/a/.", "C:/a");
+ EXPECT_RESOLVE("c:/a/./", "C:/a");
+ EXPECT_RESOLVE("c:/a/..", "C:/");
+ EXPECT_RESOLVE("c:/a/../", "C:/");
+ EXPECT_RESOLVE("c:/a/../..", "C:/");
+ return true;
+}
+
+bool windowsActualCase()
+{
+ std::cout << "windowsActualCase()\n";
+ MockSystem os;
+ os.SetPaths({
+ { "c:/", { {}, {} } },
+ { "c:/mixed", { "MiXeD", {} } },
+ { "c:/mixed/link-mixed", { "LiNk-MiXeD", "mixed" } },
+ { "c:/mixed/mixed", { "MiXeD", {} } },
+ { "c:/mixed/link-c-mixed", { "LiNk-C-MiXeD", "C:/mIxEd" } },
+ { "c:/upper", { "UPPER", {} } },
+ { "c:/upper/link-upper", { "LINK-UPPER", "upper" } },
+ { "c:/upper/upper", { "UPPER", {} } },
+ { "c:/upper/link-c-upper", { "LINK-C-UPPER", "c:/upper" } },
+ });
+
+ {
+ Resolver<Policies::LogicalPath> const r(os);
+ EXPECT_RESOLVE("c:/mIxEd/MiSsInG", "C:/MiXeD/MiSsInG");
+ EXPECT_RESOLVE("c:/mIxEd/link-MiXeD", "C:/MiXeD/LiNk-MiXeD");
+ EXPECT_RESOLVE("c:/mIxEd/link-c-MiXeD", "C:/MiXeD/LiNk-C-MiXeD");
+ EXPECT_RESOLVE("c:/upper/mIsSiNg", "C:/UPPER/mIsSiNg");
+ EXPECT_RESOLVE("c:/upper/link-upper", "C:/UPPER/LINK-UPPER");
+ EXPECT_RESOLVE("c:/upper/link-c-upper", "C:/UPPER/LINK-C-UPPER");
+ }
+
+ {
+ Resolver<Policies::RealPath> const r(os);
+ EXPECT_ENOENT("c:/mIxEd/MiSsInG", "C:/MiXeD/MiSsInG");
+ EXPECT_RESOLVE("c:/mIxEd/link-MiXeD", "C:/MiXeD/MiXeD");
+ EXPECT_RESOLVE("c:/mIxEd/link-c-MiXeD", "C:/MiXeD");
+ EXPECT_ENOENT("c:/upper/mIsSiNg", "C:/UPPER/mIsSiNg");
+ EXPECT_RESOLVE("c:/upper/link-upper", "C:/UPPER/UPPER");
+ EXPECT_RESOLVE("c:/upper/link-c-upper", "C:/UPPER");
+ }
+
+ return true;
+}
+
+bool windowsWorkingDirectory()
+{
+ std::cout << "windowsWorkingDirectory()\n";
+ MockSystem os;
+ os.SetPaths({
+ { "c:/", { {}, {} } },
+ { "c:/a", { {}, {} } },
+ { "c:/cwd", { {}, {} } },
+ { "c:/cwd/a", { {}, {} } },
+ });
+ {
+ Resolver<Policies::LogicalPath> const r(os);
+ EXPECT_RESOLVE("", "/");
+ EXPECT_RESOLVE(".", "/");
+ EXPECT_RESOLVE("..", "/");
+ EXPECT_RESOLVE("a", "/a");
+ }
+ {
+ Resolver<Policies::RealPath> const r(os);
+ os.SetWorkDir("c:/cwd");
+ EXPECT_RESOLVE("", "C:/cwd");
+ EXPECT_RESOLVE(".", "C:/cwd");
+ EXPECT_RESOLVE("..", "C:/");
+ EXPECT_RESOLVE("a", "C:/cwd/a");
+ EXPECT_ENOENT("missing", "C:/cwd/missing");
+ }
+ return true;
+}
+
+bool windowsWorkingDirectoryOnDrive()
+{
+ std::cout << "windowsWorkingDirectoryOnDrive()\n";
+ MockSystem os;
+ os.SetWorkDir("c:/cwd");
+ os.SetWorkDirOnDrive({
+ { 'd', "d:/cwd-d" },
+ });
+ {
+ Resolver<Policies::NaivePath> const r(os);
+ EXPECT_RESOLVE("c:", "c:/cwd");
+ EXPECT_RESOLVE("c:.", "c:/cwd");
+ EXPECT_RESOLVE("c:..", "c:/");
+ EXPECT_RESOLVE("C:", "C:/cwd");
+ EXPECT_RESOLVE("C:.", "C:/cwd");
+ EXPECT_RESOLVE("C:..", "C:/");
+ EXPECT_RESOLVE("d:", "d:/cwd-d");
+ EXPECT_RESOLVE("d:.", "d:/cwd-d");
+ EXPECT_RESOLVE("d:..", "d:/");
+ EXPECT_RESOLVE("D:", "D:/cwd-d");
+ EXPECT_RESOLVE("D:.", "D:/cwd-d");
+ EXPECT_RESOLVE("D:..", "D:/");
+ EXPECT_RESOLVE("e:", "e:/");
+ EXPECT_RESOLVE("e:.", "e:/");
+ EXPECT_RESOLVE("e:..", "e:/");
+ EXPECT_RESOLVE("E:", "E:/");
+ EXPECT_RESOLVE("E:.", "E:/");
+ EXPECT_RESOLVE("E:..", "E:/");
+ }
+ os.SetPaths({
+ { "c:/", { {}, {} } },
+ { "c:/cwd", { {}, {} } },
+ { "c:/cwd/existing", { {}, {} } },
+ { "d:/", { {}, {} } },
+ { "d:/cwd-d", { {}, {} } },
+ { "d:/cwd-d/existing", { {}, {} } },
+ { "e:/", { {}, {} } },
+ });
+ {
+ Resolver<Policies::RealPath> const r(os);
+ EXPECT_RESOLVE("c:existing", "C:/cwd/existing");
+ EXPECT_ENOENT("c:missing", "C:/cwd/missing");
+ EXPECT_RESOLVE("C:existing", "C:/cwd/existing");
+ EXPECT_ENOENT("C:missing", "C:/cwd/missing");
+ EXPECT_RESOLVE("d:existing", "D:/cwd-d/existing");
+ EXPECT_ENOENT("d:missing", "D:/cwd-d/missing");
+ EXPECT_ENOENT("e:missing", "E:/missing");
+ EXPECT_ENOENT("f:", "F:/");
+ }
+ return true;
+}
+
+bool windowsNetworkShare()
+{
+ std::cout << "windowsNetworkShare()\n";
+ MockSystem os;
+ os.SetPaths({
+ { "c:/", { {}, {} } },
+ { "c:/cwd", { {}, {} } },
+ { "c:/cwd/link-to-host-share", { {}, "//host/share" } },
+ { "//host/", { {}, {} } },
+ { "//host/share", { {}, {} } },
+ });
+ os.SetWorkDir("c:/cwd");
+ {
+ Resolver<Policies::RealPath> const r(os);
+ EXPECT_RESOLVE("//host/share", "//host/share");
+ EXPECT_RESOLVE("//host/share/", "//host/share");
+ EXPECT_RESOLVE("//host/share/.", "//host/share");
+ EXPECT_RESOLVE("//host/share/./", "//host/share");
+ EXPECT_RESOLVE("//host/share/..", "//host/");
+ EXPECT_RESOLVE("//host/share/../", "//host/");
+ EXPECT_RESOLVE("//host/share/../..", "//host/");
+ EXPECT_RESOLVE("link-to-host-share", "//host/share");
+ EXPECT_RESOLVE("link-to-host-share/..", "//host/");
+ EXPECT_ENOENT("link-to-host-share/../missing", "//host/missing");
+ }
+
+ {
+ Resolver<Policies::LogicalPath> const r(os);
+ EXPECT_RESOLVE("link-to-host-share", "C:/cwd/link-to-host-share");
+ EXPECT_RESOLVE("link-to-host-share/..", "//host/");
+ EXPECT_RESOLVE("link-to-host-share/../missing", "//host/missing");
+ }
+ return true;
+}
+#endif
+
+}
+
+int testPathResolver(int /*unused*/, char* /*unused*/[])
+{
+ return runTests({
+ posixRoot,
+ posixAbsolutePath,
+ posixWorkingDirectory,
+ posixSymlink,
+#ifdef _WIN32
+ windowsRoot,
+ windowsAbsolutePath,
+ windowsActualCase,
+ windowsWorkingDirectory,
+ windowsWorkingDirectoryOnDrive,
+ windowsNetworkShare,
+#endif
+ });
+}
diff --git a/Tests/CMakeLib/testStringAlgorithms.cxx b/Tests/CMakeLib/testStringAlgorithms.cxx
index 78442ba..4d418b4 100644
--- a/Tests/CMakeLib/testStringAlgorithms.cxx
+++ b/Tests/CMakeLib/testStringAlgorithms.cxx
@@ -10,6 +10,7 @@
#include <vector>
#include <cm/string_view>
+#include <cmext/string_view>
#include "cmStringAlgorithms.h"
@@ -103,7 +104,9 @@
{
typedef std::vector<std::string> VT;
assert_ok(cmTokenize("", ";") == VT{ "" }, "cmTokenize empty");
- assert_ok(cmTokenize(";", ";") == VT{ "" }, "cmTokenize sep");
+ assert_ok(cmTokenize(";", ";") == VT{ "" }, "cmTokenize sep (char*)");
+ assert_ok(cmTokenize(";", ";"_s) == VT{ "" },
+ "cmTokenize sep (string_view)");
assert_ok(cmTokenize("abc", ";") == VT{ "abc" }, "cmTokenize item");
assert_ok(cmTokenize("abc;", ";") == VT{ "abc" }, "cmTokenize item sep");
assert_ok(cmTokenize(";abc", ";") == VT{ "abc" }, "cmTokenize sep item");
@@ -112,6 +115,22 @@
assert_ok(cmTokenize("a1;a2;a3;a4", ";") == VT{ "a1", "a2", "a3", "a4" },
"cmTokenize multiple items");
}
+ {
+ typedef std::vector<cm::string_view> VT;
+ assert_ok(cmTokenizedView("", ';') == VT{ "" }, "cmTokenizedView empty");
+ assert_ok(cmTokenizedView(";", ';') == VT{ "" }, "cmTokenizedView sep");
+ assert_ok(cmTokenizedView("abc", ';') == VT{ "abc" },
+ "cmTokenizedView item");
+ assert_ok(cmTokenizedView("abc;", ';') == VT{ "abc" },
+ "cmTokenizedView item sep");
+ assert_ok(cmTokenizedView(";abc", ';') == VT{ "abc" },
+ "cmTokenizedView sep item");
+ assert_ok(cmTokenizedView("abc;;efg", ';') == VT{ "abc", "efg" },
+ "cmTokenizedView item sep sep item");
+ assert_ok(cmTokenizedView("a1;a2;a3;a4", ';') ==
+ VT{ "a1", "a2", "a3", "a4" },
+ "cmTokenizedView multiple items");
+ }
// ----------------------------------------------------------------------
// Test cmStrCat
diff --git a/Tests/CMakeLib/testUVProcessChainHelper.cxx b/Tests/CMakeLib/testUVProcessChainHelper.cxx
index 1b4adb7..29ee765 100644
--- a/Tests/CMakeLib/testUVProcessChainHelper.cxx
+++ b/Tests/CMakeLib/testUVProcessChainHelper.cxx
@@ -7,7 +7,7 @@
#include <string>
#include <thread>
-#include "cmSystemTools.h"
+#include "cmsys/SystemTools.hxx"
#ifdef _WIN32
# include <windows.h>
@@ -73,7 +73,7 @@
#endif
}
if (command == "pwd") {
- std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+ std::string cwd = cmsys::SystemTools::GetCurrentWorkingDirectory();
std::cout << cwd << std::flush;
return 0;
}
diff --git a/Tests/CMakeLib/testUVStreambuf.cxx b/Tests/CMakeLib/testUVStreambuf.cxx
index af06a8e..1f42727 100644
--- a/Tests/CMakeLib/testUVStreambuf.cxx
+++ b/Tests/CMakeLib/testUVStreambuf.cxx
@@ -106,6 +106,9 @@
options.file = cmakeCommand;
options.args = const_cast<char**>(processArgs.data());
options.flags = UV_PROCESS_WINDOWS_HIDE;
+#if UV_VERSION_MAJOR > 1 || !defined(CMAKE_USE_SYSTEM_LIBUV)
+ options.flags |= UV_PROCESS_WINDOWS_USE_PARENT_ERROR_MODE;
+#endif
options.stdio = stdio.data();
options.stdio_count = static_cast<int>(stdio.size());
options.exit_cb = [](uv_process_t* handle, int64_t exitStatus,
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 428ec8b..7f642b3 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -663,7 +663,6 @@
${build_generator_args}
--build-project ExternalDataTest
--build-noclean
- --force-new-ctest-process
--build-options
-DMAKE_SUPPORTS_SPACES=${MAKE_SUPPORTS_SPACES}
--test-command ${CMAKE_CTEST_COMMAND} -C \${CTEST_CONFIGURATION_TYPE} -V
@@ -1383,7 +1382,6 @@
${build_generator_args}
--build-project EnvironmentProj
--build-exe-dir "${CMake_BINARY_DIR}/Tests/Environment"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Environment")
@@ -1422,7 +1420,6 @@
${build_generator_args}
--build-project Qt4Targets
--build-exe-dir "${CMake_BINARY_DIR}/Tests/Qt4Targets"
- --force-new-ctest-process
--build-options
-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}
--test-command ${CMAKE_CTEST_COMMAND} -V
@@ -1437,7 +1434,6 @@
${build_generator_args}
--build-project Qt4And5Automoc
--build-exe-dir "${CMake_BINARY_DIR}/Tests/Qt4And5AutomocForward"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Qt4And5AutomocForward")
@@ -1448,7 +1444,6 @@
${build_generator_args}
--build-project Qt4And5Automoc
--build-exe-dir "${CMake_BINARY_DIR}/Tests/Qt4And5AutomocReverse"
- --force-new-ctest-process
--build-options -DQT_REVERSE_FIND_ORDER=1
--test-command ${CMAKE_CTEST_COMMAND} -V
)
@@ -1645,7 +1640,6 @@
${build_generator_args}
--build-project ExternalProjectTest
--build-exe-dir "${CMake_BINARY_DIR}/Tests/ExternalProject"
- --force-new-ctest-process
--build-options ${ExternalProject_BUILD_OPTIONS}
--test-command ${CMAKE_CTEST_COMMAND} -V
)
@@ -1662,7 +1656,6 @@
"${CMake_BINARY_DIR}/Tests/ExternalProjectSubdir"
${build_generator_args}
--build-project ExternalProjectSubdir
- --force-new-ctest-process
)
list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectSubdir")
@@ -1673,7 +1666,6 @@
"${CMake_BINARY_DIR}/Tests/ExternalProjectSourceSubdir"
${build_generator_args}
--build-project ExternalProjectSourceSubdir
- --force-new-ctest-process
)
list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectSourceSubdir")
@@ -1684,7 +1676,6 @@
"${CMake_BINARY_DIR}/Tests/ExternalProjectSourceSubdirNotCMake"
${build_generator_args}
--build-project ExternalProjectSourceSubdirNotCMake
- --force-new-ctest-process
)
list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectSourceSubdirNotCMake")
@@ -1695,7 +1686,6 @@
${build_generator_args}
--build-project ExternalProjectLocalTest
--build-exe-dir "${CMake_BINARY_DIR}/Tests/ExternalProjectLocal"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectLocal")
@@ -1710,7 +1700,6 @@
${build_generator_args}
--build-project ExternalProjectUpdateTest
--build-exe-dir "${CMake_BINARY_DIR}/Tests/ExternalProjectUpdate"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/ExternalProjectUpdate")
@@ -1766,7 +1755,6 @@
${build_generator_args}
--build-project superpro
--build-exe-dir "${CMake_BINARY_DIR}/Tests/InstallMode-${_mode}"
- --force-new-ctest-process
--build-options
${_maybe_BUILD_OPTIONS}
"-DCMAKE_INSTALL_PREFIX:PATH=${CMake_BINARY_DIR}/Tests/InstallMode-${_mode}/install"
@@ -2363,7 +2351,6 @@
--build-generator "Green Hills MULTI"
--build-project test
--build-config $<CONFIGURATION>
- --force-new-ctest-process
--build-options ${ghs_target_arch} ${ghs_toolset_name} ${ghs_toolset_root} ${ghs_target_platform}
${ghs_os_root} ${ghs_os_dir} ${ghs_bsp_name} ${_ghs_build_opts} ${_ghs_toolset_extra}
${_ghs_test_command}
@@ -2577,7 +2564,6 @@
${build_generator_args}
--build-project TestsWorkingDirectoryProj
--build-exe-dir "${CMake_BINARY_DIR}/Tests/TestsWorkingDirectory"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V -C \${CTEST_CONFIGURATION_TYPE}
)
list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/TestsWorkingDirectory")
@@ -2589,9 +2575,9 @@
# A simple test for ctest in script mode
configure_file("${CMake_SOURCE_DIR}/Tests/CTestScriptMode/CTestTestScriptMode.cmake.in"
"${CMake_BINARY_DIR}/Tests/CTestScriptMode/CTestTestScriptMode.cmake" @ONLY)
-# add_test(CTest.ScriptMode ${CMAKE_CTEST_COMMAND}
-# -S "${CMake_BINARY_DIR}/Tests/CTestScriptMode/CTestTestScriptMode.cmake"
-# )
+ add_test(CTest.ScriptMode ${CMAKE_CTEST_COMMAND}
+ -S "${CMake_BINARY_DIR}/Tests/CTestScriptMode/CTestTestScriptMode.cmake"
+ )
# Test CTest Update with Subversion
if(NOT DEFINED CMake_TEST_CTestUpdate_SVN OR CMake_TEST_CTestUpdate_SVN)
@@ -3032,7 +3018,6 @@
)
if(NOT BORLAND)
- set(CTestLimitDashJ_CTEST_OPTIONS --force-new-ctest-process)
add_test_macro(CTestLimitDashJ ${CMAKE_CTEST_COMMAND} -j 4
--output-on-failure -C "\${CTestTest_CONFIG}")
endif()
diff --git a/Tests/CTestConfig/ScriptWithArgs.cmake b/Tests/CTestConfig/ScriptWithArgs.cmake
index 79896a7..4d63e22 100644
--- a/Tests/CTestConfig/ScriptWithArgs.cmake
+++ b/Tests/CTestConfig/ScriptWithArgs.cmake
@@ -1,5 +1,3 @@
-set(CTEST_RUN_CURRENT_SCRIPT 0)
-
macro(check_arg name expected_value)
message("${name}='${${name}}'")
if(NOT "${${name}}" STREQUAL "${expected_value}")
diff --git a/Tests/CTestLimitDashJ/CreateSleepDelete.cmake b/Tests/CTestLimitDashJ/CreateSleepDelete.cmake
index b09307f..f16deaa 100644
--- a/Tests/CTestLimitDashJ/CreateSleepDelete.cmake
+++ b/Tests/CTestLimitDashJ/CreateSleepDelete.cmake
@@ -1,5 +1,3 @@
-set(CTEST_RUN_CURRENT_SCRIPT 0)
-
if(NOT DEFINED basefilename)
message(FATAL_ERROR "pass -Dbasefilename=f1")
endif()
diff --git a/Tests/CTestScriptMode/CTestTestScriptMode.cmake.in b/Tests/CTestScriptMode/CTestTestScriptMode.cmake.in
index 45f0e37..5ff1bf2 100644
--- a/Tests/CTestScriptMode/CTestTestScriptMode.cmake.in
+++ b/Tests/CTestScriptMode/CTestTestScriptMode.cmake.in
@@ -6,9 +6,3 @@
if (NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "${CMAKE_CMAKE_SYSTEM_NAME}")
message(FATAL_ERROR "Error: CMAKE_SYSTEM_NAME is \"${CMAKE_SYSTEM_NAME}\", but should be \"@CMAKE_SYSTEM_NAME@\"")
endif()
-
-# this seems to be necessary, otherwise ctest complains that these
-# variables are not set:
-set(CTEST_COMMAND "\"@CMAKE_CTEST_COMMAND@\"")
-set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestScriptMode/")
-set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestScriptMode/")
diff --git a/Tests/CTestTest/test.cmake.in b/Tests/CTestTest/test.cmake.in
index 23166a7..61d30a6 100644
--- a/Tests/CTestTest/test.cmake.in
+++ b/Tests/CTestTest/test.cmake.in
@@ -43,12 +43,6 @@
CMAKE_GENERATOR:INTERNAL=@CMAKE_GENERATOR@
CMAKE_GENERATOR_PLATFORM:INTERNAL=@CMAKE_GENERATOR_PLATFORM@
CMAKE_GENERATOR_TOOLSET:INTERNAL=@CMAKE_GENERATOR_TOOLSET@
-CMAKE_CXX_FLAGS:STRING=@CMAKE_CXX_FLAGS@
-CMAKE_C_FLAGS:STRING=@CMAKE_C_FLAGS@
-CMAKE_C_COMPILER:STRING=@CMAKE_C_COMPILER@
-CMAKE_CXX_COMPILER:STRING=@CMAKE_CXX_COMPILER@
-CMAKE_C_COMPILER_ARG1:STRING=@CMAKE_C_COMPILER_ARG1@
-CMAKE_CXX_COMPILER_ARG1:STRING=@CMAKE_CXX_COMPILER_ARG1@
DART_ROOT:PATH=
MEMORYCHECK_COMMAND:STRING=@MEMORYCHECK_COMMAND@
MEMORYCHECK_SUPPRESSIONS_FILE:FILEPATH=@MEMORYCHECK_SUPPRESSIONS_FILE@
diff --git a/Tests/CTestTest2/test.cmake.in b/Tests/CTestTest2/test.cmake.in
index 6d833fe..48fd82a 100644
--- a/Tests/CTestTest2/test.cmake.in
+++ b/Tests/CTestTest2/test.cmake.in
@@ -28,12 +28,6 @@
#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
file(WRITE "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" "
-CMAKE_CXX_FLAGS:STRING=@CMAKE_CXX_FLAGS@
-CMAKE_C_FLAGS:STRING=@CMAKE_C_FLAGS@
-CMAKE_C_COMPILER:STRING=@CMAKE_C_COMPILER@
-CMAKE_CXX_COMPILER:STRING=@CMAKE_CXX_COMPILER@
-CMAKE_C_COMPILER_ARG1:STRING=@CMAKE_C_COMPILER_ARG1@
-CMAKE_CXX_COMPILER_ARG1:STRING=@CMAKE_CXX_COMPILER_ARG1@
KWSYS_ENCODING_DEFAULT_CODEPAGE:STRING=CP_UTF8
# This one is needed for testing advanced ctest features
diff --git a/Tests/CTestTestEmptyBinaryDirectory/test.cmake.in b/Tests/CTestTestEmptyBinaryDirectory/test.cmake.in
index 3f8437c..e71d514 100644
--- a/Tests/CTestTestEmptyBinaryDirectory/test.cmake.in
+++ b/Tests/CTestTestEmptyBinaryDirectory/test.cmake.in
@@ -1,7 +1,5 @@
cmake_minimum_required(VERSION 3.10)
-set(CTEST_RUN_CURRENT_SCRIPT 0)
-
set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestEmptyBinaryDirectory")
set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestEmptyBinaryDirectory")
diff --git a/Tests/CTestTestLaunchers/test.cmake.in b/Tests/CTestTestLaunchers/test.cmake.in
index 21a3ed4..3c99857 100644
--- a/Tests/CTestTestLaunchers/test.cmake.in
+++ b/Tests/CTestTestLaunchers/test.cmake.in
@@ -22,15 +22,6 @@
ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY})
- file(WRITE "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" "
- CMAKE_CXX_FLAGS:STRING=@CMAKE_CXX_FLAGS@
- CMAKE_C_FLAGS:STRING=@CMAKE_C_FLAGS@
- CMAKE_C_COMPILER:STRING=@CMAKE_C_COMPILER@
- CMAKE_CXX_COMPILER:STRING=@CMAKE_CXX_COMPILER@
- CMAKE_C_COMPILER_ARG1:STRING=@CMAKE_C_COMPILER_ARG1@
- CMAKE_CXX_COMPILER_ARG1:STRING=@CMAKE_CXX_COMPILER_ARG1@
- ")
-
ctest_start(Experimental)
ctest_configure(OPTIONS "-DCTEST_USE_LAUNCHERS=1")
ctest_build(NUMBER_ERRORS error_count)
diff --git a/Tests/CTestTestRunScript/hello.cmake.in b/Tests/CTestTestRunScript/hello.cmake.in
index 37905e3..4fa6446 100644
--- a/Tests/CTestTestRunScript/hello.cmake.in
+++ b/Tests/CTestTestRunScript/hello.cmake.in
@@ -1,2 +1 @@
-set(CTEST_RUN_CURRENT_SCRIPT 0)
message("hello world")
diff --git a/Tests/CTestTestRunScript/test.cmake.in b/Tests/CTestTestRunScript/test.cmake.in
index 3074a51..9e50f7f 100644
--- a/Tests/CTestTestRunScript/test.cmake.in
+++ b/Tests/CTestTestRunScript/test.cmake.in
@@ -1,2 +1 @@
-set(CTEST_RUN_CURRENT_SCRIPT 0)
CTEST_RUN_SCRIPT("CTestTestRunScript/hello.cmake" RETURN_VALUE res RETURN_VALUE)
diff --git a/Tests/CTestTestSerialInDepends/test.ctest b/Tests/CTestTestSerialInDepends/test.ctest
index cf0d314..71c6da2 100644
--- a/Tests/CTestTestSerialInDepends/test.ctest
+++ b/Tests/CTestTestSerialInDepends/test.ctest
@@ -1,5 +1,3 @@
-set(CTEST_RUN_CURRENT_SCRIPT 0)
-
set(LOCK_FILE "${TEST_NAME}.lock")
# Delete the old lock file in case it's lingering from a previous failed test run
diff --git a/Tests/CTestTestUpload/sleep.c b/Tests/CTestTestUpload/sleep.c
index b9b6e89..2d69f7f 100644
--- a/Tests/CTestTestUpload/sleep.c
+++ b/Tests/CTestTestUpload/sleep.c
@@ -1,3 +1,5 @@
+#include <stdlib.h>
+
#if defined(_WIN32)
# include <windows.h>
#else
diff --git a/Tests/FindGTK2/CMakeLists.txt b/Tests/FindGTK2/CMakeLists.txt
index 0105fae..15a7c29 100644
--- a/Tests/FindGTK2/CMakeLists.txt
+++ b/Tests/FindGTK2/CMakeLists.txt
@@ -11,7 +11,6 @@
--build-target gtk-all-libs
--build-project gtk
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Components/gtk"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -25,7 +24,6 @@
--build-target gtkmm-all-libs
--build-project gtkmm
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Components/gtkmm"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -40,7 +38,6 @@
${build_generator_args}
--build-project glib
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/glib"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -53,7 +50,6 @@
${build_generator_args}
--build-project gobject
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gobject"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -66,7 +62,6 @@
${build_generator_args}
--build-project gio
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gio"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -79,7 +74,6 @@
${build_generator_args}
--build-project gmodule
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gmodule"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -92,7 +86,6 @@
${build_generator_args}
--build-project gthread
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gthread"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -105,7 +98,6 @@
${build_generator_args}
--build-project atk
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/atk"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -118,7 +110,6 @@
${build_generator_args}
--build-project gdk_pixbuf
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gdk_pixbuf"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -131,7 +122,6 @@
${build_generator_args}
--build-project cairo
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/cairo"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -144,7 +134,6 @@
${build_generator_args}
--build-project pango
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/pango"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -157,7 +146,6 @@
${build_generator_args}
--build-project pangocairo
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/pangocairo"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -170,7 +158,6 @@
${build_generator_args}
--build-project pangoxft
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/pangoxft"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -183,7 +170,6 @@
${build_generator_args}
--build-project pangoft2
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/pangoft2"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -196,7 +182,6 @@
${build_generator_args}
--build-project gdk
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gdk"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -209,7 +194,6 @@
${build_generator_args}
--build-project gtk
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gtk"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -222,7 +206,6 @@
${build_generator_args}
--build-project sigc++
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/sigc++"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -235,7 +218,6 @@
${build_generator_args}
--build-project glibmm
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/glibmm"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -248,7 +230,6 @@
${build_generator_args}
--build-project giomm
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/giomm"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -261,7 +242,6 @@
${build_generator_args}
--build-project atkmm
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/atkmm"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -274,7 +254,6 @@
${build_generator_args}
--build-project cairomm
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/cairomm"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -287,7 +266,6 @@
${build_generator_args}
--build-project pangomm
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/pangomm"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -300,7 +278,6 @@
${build_generator_args}
--build-project gdkmm
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/GTK2Targets/gdkmm"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
@@ -314,7 +291,6 @@
--build-target gtkmm-target
--build-project gtkmm
--build-exe-dir "${CMake_BINARY_DIR}/Tests/FindGTK2/GTK2Targets/gtkmm"
- --force-new-ctest-process
--test-command ${CMAKE_CTEST_COMMAND} -V
)
endif()
diff --git a/Tests/FindPackageTest/CMakeLists.txt b/Tests/FindPackageTest/CMakeLists.txt
index 73d3fb4..46940a3 100644
--- a/Tests/FindPackageTest/CMakeLists.txt
+++ b/Tests/FindPackageTest/CMakeLists.txt
@@ -204,7 +204,7 @@
# The result must preserve the /symlink/ path.
set(SetFoundResolved_EXPECTED "${CMAKE_CURRENT_SOURCE_DIR}/symlink/cmake")
if(NOT "${SetFoundResolved_DIR}" STREQUAL "${SetFoundResolved_EXPECTED}")
- message(SEND_ERROR "SetFoundResolved_DIR set by find_package() is set to \"${SetFoundResolved_DIR}\" (expected \"${SetFoundResolved_EXPECTED}\")")
+ message(SEND_ERROR "SetFoundResolved_DIR set by find_package() is set to\n \"${SetFoundResolved_DIR}\"\nnot the expected\n \"${SetFoundResolved_EXPECTED}\"")
endif()
# This part of the test only works if there are no symlinks in our path.
@@ -217,7 +217,7 @@
# ./symlink points back here so it should be gone when resolved.
set(SetFoundResolved_EXPECTED "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
if(NOT "${SetFoundResolved_DIR}" STREQUAL "${SetFoundResolved_EXPECTED}")
- message(SEND_ERROR "SetFoundResolved_DIR set by find_package() is set to \"${SetFoundResolved_DIR}\" (expected \"${SetFoundResolved_EXPECTED}\")")
+ message(SEND_ERROR "SetFoundResolved_DIR set by find_package() is set to\n \"${SetFoundResolved_DIR}\"\nnot the expected\n \"${SetFoundResolved_EXPECTED}\"")
endif()
endif()
@@ -492,15 +492,15 @@
include("${CMAKE_CURRENT_BINARY_DIR}/RelocatableConfig.cmake")
if(NOT "${RELOC_INCLUDE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/include")
- message(SEND_ERROR "RELOC_INCLUDE_DIR set by configure_package_config_file() is set to \"${RELOC_INCLUDE_DIR}\" (expected \"${CMAKE_CURRENT_BINARY_DIR}/include\")")
+ message(SEND_ERROR "RELOC_INCLUDE_DIR set by configure_package_config_file() is set to\n \"${RELOC_INCLUDE_DIR}\"\nnot the expected\n \"${CMAKE_CURRENT_BINARY_DIR}/include\"")
endif()
if(NOT "${RELOC_SHARE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/share/")
- message(SEND_ERROR "RELOC_SHARE_DIR set by configure_package_config_file() is set to \"${RELOC_SHARE_DIR}\" (expected \"${CMAKE_CURRENT_BINARY_DIR}/share/\")")
+ message(SEND_ERROR "RELOC_SHARE_DIR set by configure_package_config_file() is set to\n \"${RELOC_SHARE_DIR}\"\nnot the expected\n \"${CMAKE_CURRENT_BINARY_DIR}/share/\"")
endif()
if(NOT "${RELOC_BUILD_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
- message(SEND_ERROR "RELOC_BUILD_DIR set by configure_package_config_file() is set to \"${RELOC_BUILD_DIR}\" (expected \"${CMAKE_CURRENT_BINARY_DIR}\")")
+ message(SEND_ERROR "RELOC_BUILD_DIR set by configure_package_config_file() is set to\n \"${RELOC_BUILD_DIR}\"\nnot the expected\n \"${CMAKE_CURRENT_BINARY_DIR}\"")
endif()
if(NOT DEFINED Relocatable_FOUND)
@@ -527,15 +527,15 @@
include("${CMAKE_CURRENT_BINARY_DIR}/RelocatableConfig.cmake")
if(NOT "${RELOC_INCLUDE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/include")
- message(SEND_ERROR "RELOC_INCLUDE_DIR set by configure_package_config_file() is set to \"${RELOC_INCLUDE_DIR}\" (expected \"${CMAKE_CURRENT_BINARY_DIR}/include\")")
+ message(SEND_ERROR "RELOC_INCLUDE_DIR set by configure_package_config_file() is set to\n \"${RELOC_INCLUDE_DIR}\"\nnot the expected\n \"${CMAKE_CURRENT_BINARY_DIR}/include\"")
endif()
if(NOT "${RELOC_SHARE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/share/")
- message(SEND_ERROR "RELOC_SHARE_DIR set by configure_package_config_file() is set to \"${RELOC_SHARE_DIR}\" (expected \"${CMAKE_CURRENT_BINARY_DIR}/share/\")")
+ message(SEND_ERROR "RELOC_SHARE_DIR set by configure_package_config_file() is set to\n \"${RELOC_SHARE_DIR}\"\nnot the expected\n \"${CMAKE_CURRENT_BINARY_DIR}/share/\"")
endif()
if(NOT "${RELOC_BUILD_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
- message(SEND_ERROR "RELOC_BUILD_DIR set by configure_package_config_file() is set to \"${RELOC_BUILD_DIR}\" (expected \"${CMAKE_CURRENT_BINARY_DIR}\")")
+ message(SEND_ERROR "RELOC_BUILD_DIR set by configure_package_config_file() is set to\n \"${RELOC_BUILD_DIR}\"\nnot the expected\n \"${CMAKE_CURRENT_BINARY_DIR}\"")
endif()
if(NOT DEFINED Relocatable_FOUND)
@@ -550,10 +550,10 @@
############################################################################
##Test FIND_PACKAGE using sorting
set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR})
-SET(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
-SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION ASC)
set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+SET(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
+SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION ASC)
FIND_PACKAGE(SortLib CONFIG)
IF (NOT "${SortLib_VERSION}" STREQUAL "3.1.1")
message(SEND_ERROR "FIND_PACKAGE_SORT_ORDER Name Asc! ${SortLib_VERSION}")
@@ -579,6 +579,28 @@
endif()
unset(SortLib_VERSION)
+
+set(SortFramework_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+SET(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
+SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION ASC)
+FIND_PACKAGE(SortFramework CONFIG)
+IF (NOT "${SortFramework_VERSION}" STREQUAL "3.1.1")
+ message(SEND_ERROR "FIND_PACKAGE_SORT_ORDER Framework Name Asc! ${SortFramework_VERSION}")
+endif()
+set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+unset(SortFramework_VERSION)
+
+
+set(SortFramework_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
+SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
+FIND_PACKAGE(SortFramework CONFIG)
+IF (NOT "${SortFramework_VERSION}" STREQUAL "3.10.1")
+ message(SEND_ERROR "FIND_PACKAGE_SORT_ORDER Framework Natural! Dec ${SortFramework_VERSION}")
+endif()
+set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+unset(SortFramework_VERSION)
+
unset(CMAKE_FIND_PACKAGE_SORT_ORDER)
unset(CMAKE_FIND_PACKAGE_SORT_DIRECTION)
set(CMAKE_PREFIX_PATH )
diff --git a/Tests/FindPackageTest/SortFramework.framework/Versions/3.1.1/Resources/CMake/SortFrameworkConfig.cmake b/Tests/FindPackageTest/SortFramework.framework/Versions/3.1.1/Resources/CMake/SortFrameworkConfig.cmake
new file mode 100644
index 0000000..f51edb2
--- /dev/null
+++ b/Tests/FindPackageTest/SortFramework.framework/Versions/3.1.1/Resources/CMake/SortFrameworkConfig.cmake
@@ -0,0 +1,2 @@
+set(SORT_FRAMEWORK_VERSION 3.1.1)
+message("SortFramework 3.1.1 config reached")
diff --git a/Tests/FindPackageTest/SortFramework.framework/Versions/3.1.1/Resources/CMake/SortFrameworkConfigVersion.cmake b/Tests/FindPackageTest/SortFramework.framework/Versions/3.1.1/Resources/CMake/SortFrameworkConfigVersion.cmake
new file mode 100644
index 0000000..fa927c7
--- /dev/null
+++ b/Tests/FindPackageTest/SortFramework.framework/Versions/3.1.1/Resources/CMake/SortFrameworkConfigVersion.cmake
@@ -0,0 +1,9 @@
+set(PACKAGE_VERSION 3.1.1)
+if(PACKAGE_FIND_VERSION_MAJOR EQUAL 3)
+ if(PACKAGE_FIND_VERSION_MINOR EQUAL 1)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if(PACKAGE_FIND_VERSION_PATCH EQUAL 1)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+ endif()
+endif()
diff --git a/Tests/FindPackageTest/SortFramework.framework/Versions/3.10.1/Resources/CMake/SortFrameworkConfig.cmake b/Tests/FindPackageTest/SortFramework.framework/Versions/3.10.1/Resources/CMake/SortFrameworkConfig.cmake
new file mode 100644
index 0000000..f7f05ef
--- /dev/null
+++ b/Tests/FindPackageTest/SortFramework.framework/Versions/3.10.1/Resources/CMake/SortFrameworkConfig.cmake
@@ -0,0 +1,2 @@
+set(SORT_FRAMEWORK_VERSION 3.10.1)
+message("SortFramework 3.10.1 config reached")
diff --git a/Tests/FindPackageTest/SortFramework.framework/Versions/3.10.1/Resources/CMake/SortFrameworkConfigVersion.cmake b/Tests/FindPackageTest/SortFramework.framework/Versions/3.10.1/Resources/CMake/SortFrameworkConfigVersion.cmake
new file mode 100644
index 0000000..6f44c2d
--- /dev/null
+++ b/Tests/FindPackageTest/SortFramework.framework/Versions/3.10.1/Resources/CMake/SortFrameworkConfigVersion.cmake
@@ -0,0 +1,9 @@
+set(PACKAGE_VERSION 3.10.1)
+if(PACKAGE_FIND_VERSION_MAJOR EQUAL 3)
+ if(PACKAGE_FIND_VERSION_MINOR EQUAL 10)
+ set(PACKAGE_VERSION_COMPATIBLE 1)
+ if(PACKAGE_FIND_VERSION_PATCH EQUAL 1)
+ set(PACKAGE_VERSION_EXACT 1)
+ endif()
+ endif()
+endif()
diff --git a/Tests/FindProtobuf/CMakeLists.txt b/Tests/FindProtobuf/CMakeLists.txt
index b4ca29b..8e46ff8 100644
--- a/Tests/FindProtobuf/CMakeLists.txt
+++ b/Tests/FindProtobuf/CMakeLists.txt
@@ -9,3 +9,4 @@
"-DCMake_TEST_FindProtobuf_gRPC=${CMake_TEST_FindProtobuf_gRPC}"
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
)
+set_property(TEST FindProtobuf.Test PROPERTY FAIL_REGULAR_EXPRESSION PROTOC_EXE)
diff --git a/Tests/FindProtobuf/Test/CMakeLists.txt b/Tests/FindProtobuf/Test/CMakeLists.txt
index 2859c48..1409bd9 100644
--- a/Tests/FindProtobuf/Test/CMakeLists.txt
+++ b/Tests/FindProtobuf/Test/CMakeLists.txt
@@ -70,7 +70,7 @@
# NOTE: with IMPORT_DIRS msgs/, generated files will be placed under ${CMAKE_CURRENT_BINARY_DIR}/grpc/
target_include_directories(msgs_grpc_IMPORT_DIRS PUBLIC ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/grpc/)
target_link_libraries(msgs_grpc_IMPORT_DIRS PUBLIC ${Protobuf_LIBRARIES})
- protobuf_generate(TARGET msgs_grpc_IMPORT_DIRS LANGUAGE cpp IMPORT_DIRS msgs/)
+ protobuf_generate(TARGET msgs_grpc_IMPORT_DIRS LANGUAGE cpp IMPORT_DIRS msgs/ PROTOC_EXE ${Protobuf_PROTOC_EXECUTABLE})
protobuf_generate(TARGET msgs_grpc_IMPORT_DIRS LANGUAGE grpc IMPORT_DIRS msgs/ GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc PLUGIN "protoc-gen-grpc=${gRPC_CPP_PLUGIN}")
add_executable(test_generate_grpc_IMPORT_DIRS main-generate-grpc.cxx)
target_link_libraries(test_generate_grpc_IMPORT_DIRS PRIVATE msgs_grpc_IMPORT_DIRS)
diff --git a/Tests/FortranC/Flags.cmake.in b/Tests/FortranC/Flags.cmake.in
index cf361a5..83ceef0 100644
--- a/Tests/FortranC/Flags.cmake.in
+++ b/Tests/FortranC/Flags.cmake.in
@@ -5,6 +5,9 @@
# flags, remove them, and invoke the real compiler.
set(ID "CC")
set(COMMAND "@CMAKE_C_COMPILER@")
+if("x${COMMAND}" MATCHES "xctoolchain(/usr/bin/cc)$")
+ set(COMMAND "${CMAKE_MATCH_1}")
+endif()
configure_file("${src}/test_opt.sh.in" "${bld}/cc.sh" @ONLY)
set(ID "FC")
set(COMMAND "@CMAKE_Fortran_COMPILER@")
diff --git a/Tests/QtAutogen/TestMacros.cmake b/Tests/QtAutogen/TestMacros.cmake
index 529592e..a2e0fca 100644
--- a/Tests/QtAutogen/TestMacros.cmake
+++ b/Tests/QtAutogen/TestMacros.cmake
@@ -48,7 +48,6 @@
--build-project ${NAME}
${Autogen_CTEST_OPTIONS}
--build-exe-dir "${_BuildDir}"
- --force-new-ctest-process
--build-options ${build_options} ${Autogen_BUILD_OPTIONS}
${_TestCommand}
)
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake
index c3725a4..331d21d 100644
--- a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake
@@ -77,5 +77,14 @@
\"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:subexe>\"
\"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:sublib>\"
)
+
+ if (RunCMake_GENERATOR MATCHES \"Make\")
+ file(STRINGS \"${CMAKE_BINARY_DIR}/CMakeFiles/topcc.dir/compiler_depend.internal\" deps REGEX \"^.*topccdep\\\\.txt$\")
+ list(LENGTH deps count)
+ if (NOT count EQUAL 1)
+ string(APPEND RunCMake_TEST_FAILED \"dependencies are duplicated\\n\")
+ set(RunCMake_TEST_FAILED \"\${RunCMake_TEST_FAILED}\" PARENT_SCOPE)
+ endif()
+ endif()
endif()
")
diff --git a/Tests/RunCMake/CMP0132/CMP0132-OLD-stderr.txt b/Tests/RunCMake/CMP0132/CMP0132-OLD-stderr.txt
new file mode 100644
index 0000000..025665d
--- /dev/null
+++ b/Tests/RunCMake/CMP0132/CMP0132-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0132-OLD\.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0132 will be removed from a future version
+ of CMake\.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances\. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0135/CMP0135-OLD-stderr.txt b/Tests/RunCMake/CMP0135/CMP0135-OLD-stderr.txt
new file mode 100644
index 0000000..59a7a58
--- /dev/null
+++ b/Tests/RunCMake/CMP0135/CMP0135-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0135-OLD\.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0135 will be removed from a future version
+ of CMake\.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances\. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMP0139/CMP0139-OLD-stderr.txt b/Tests/RunCMake/CMP0139/CMP0139-OLD-stderr.txt
index 1cfb319..b04cd1a 100644
--- a/Tests/RunCMake/CMP0139/CMP0139-OLD-stderr.txt
+++ b/Tests/RunCMake/CMP0139/CMP0139-OLD-stderr.txt
@@ -1,3 +1,14 @@
+^CMake Deprecation Warning at CMP0139-OLD\.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0139 will be removed from a future version
+ of CMake\.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances\. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)
++
CMake Error at CMP0139-OLD.cmake:[0-9]+ \(if\):
if given arguments:
@@ -5,4 +16,4 @@
Unknown arguments specified
Call Stack \(most recent call first\):
- CMakeLists.txt:[0-9]+ \(include\)
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 0a96aef..c118be1 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -875,6 +875,9 @@
-DCMAKE_IMPORT_LIBRARY_PREFIX=${CMAKE_IMPORT_LIBRARY_PREFIX}
-DCMAKE_IMPORT_LIBRARY_SUFFIX=${CMAKE_IMPORT_LIBRARY_SUFFIX}
-DCMAKE_LINK_LIBRARY_FLAG=${CMAKE_LINK_LIBRARY_FLAG})
+add_RunCMake_test(target_link_libraries-LINKER-prefix -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
+ -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
+ -DCMAKE_C_COMPILER_FRONTEND_VARIANT=${CMAKE_C_COMPILER_FRONTEND_VARIANT})
add_RunCMake_test(add_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
add_RunCMake_test(target_link_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
-DCMake_TEST_CUDA=${CMake_TEST_CUDA})
diff --git a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
index a92a4c4..b0833d3 100644
--- a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
@@ -76,11 +76,16 @@
set(_preset)
endif()
+ set(_make_program)
+ if(RunCMake_MAKE_PROGRAM)
+ set(_make_program -DCMAKE_MAKE_PROGRAM=${RunCMake_MAKE_PROGRAM})
+ endif()
+
set(RunCMake_TEST_COMMAND ${CMAKE_COMMAND}
${_source_args}
-DRunCMake_TEST=${name}
-DRunCMake_GENERATOR=${RunCMake_GENERATOR}
- -DCMAKE_MAKE_PROGRAM=${RunCMake_MAKE_PROGRAM}
+ ${_make_program}
${_unused_cli}
${_preset}
${ARGN}
diff --git a/Tests/RunCMake/CMakeRoleGlobalProperty/test.cmake.in b/Tests/RunCMake/CMakeRoleGlobalProperty/test.cmake.in
index 4e2c085..d8f2e7b 100644
--- a/Tests/RunCMake/CMakeRoleGlobalProperty/test.cmake.in
+++ b/Tests/RunCMake/CMakeRoleGlobalProperty/test.cmake.in
@@ -1,5 +1,4 @@
cmake_minimum_required(VERSION 3.12)
-set(CTEST_RUN_CURRENT_SCRIPT 0)
get_property(role GLOBAL PROPERTY CMAKE_ROLE)
if(NOT role STREQUAL "CTEST")
diff --git a/Tests/RunCMake/CTestCommandLine/EmptyDirCoverage-ctest-result.txt b/Tests/RunCMake/CTestCommandLine/EmptyDirCoverage-ctest-result.txt
new file mode 100644
index 0000000..f5c8955
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/EmptyDirCoverage-ctest-result.txt
@@ -0,0 +1 @@
+32
diff --git a/Tests/RunCMake/CTestCommandLine/EmptyDirCoverage-ctest-stderr.txt b/Tests/RunCMake/CTestCommandLine/EmptyDirCoverage-ctest-stderr.txt
index e6f9325..f6d28a1 100644
--- a/Tests/RunCMake/CTestCommandLine/EmptyDirCoverage-ctest-stderr.txt
+++ b/Tests/RunCMake/CTestCommandLine/EmptyDirCoverage-ctest-stderr.txt
@@ -1,3 +1,3 @@
Cannot find file: [^
]*/Tests/RunCMake/CTestCommandLine/EmptyDirCoverage-ctest-build/DartConfiguration.tcl
-Binary directory is not set. No coverage checking will be performed.$
+CTEST_BINARY_DIRECTORY not set
diff --git a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
index b2374ca..e5e385e 100644
--- a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
@@ -355,6 +355,9 @@
set(RunCMake_TEST_NO_CLEAN 1)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ file(WRITE "${RunCMake_TEST_BINARY_DIR}/DartConfiguration.tcl" "
+BuildDirectory: ${RunCMake_TEST_BINARY_DIR}
+")
file(WRITE "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake" "
add_test(PassingTest \"${CMAKE_COMMAND}\" -E echo PassingTestOutput)
add_test(FailingTest \"${CMAKE_COMMAND}\" -E no_such_command)
@@ -375,6 +378,9 @@
set(TRUNCATED_OUTPUT ${expected}) # used in TestOutputTruncation-check.cmake
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ file(WRITE "${RunCMake_TEST_BINARY_DIR}/DartConfiguration.tcl" "
+BuildDirectory: ${RunCMake_TEST_BINARY_DIR}
+")
file(WRITE "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake" "
add_test(Truncation_${mode} \"${CMAKE_COMMAND}\" -E echo 123456789)
")
diff --git a/Tests/RunCMake/CTestCommandLine/TestOutputSize-stderr.txt b/Tests/RunCMake/CTestCommandLine/TestOutputSize-stderr.txt
deleted file mode 100644
index 19310b8..0000000
--- a/Tests/RunCMake/CTestCommandLine/TestOutputSize-stderr.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-^Cannot find file: .*/Tests/RunCMake/CTestCommandLine/TestOutputSize/DartConfiguration.tcl
-Errors while running CTest
diff --git a/Tests/RunCMake/CTestCommandLine/TestOutputTruncation_head-stderr.txt b/Tests/RunCMake/CTestCommandLine/TestOutputTruncation_head-stderr.txt
deleted file mode 100644
index 30b46ce..0000000
--- a/Tests/RunCMake/CTestCommandLine/TestOutputTruncation_head-stderr.txt
+++ /dev/null
@@ -1 +0,0 @@
-^Cannot find file: .*/Tests/RunCMake/CTestCommandLine/TestOutputTruncation.*/DartConfiguration.tcl
diff --git a/Tests/RunCMake/CTestCommandLine/TestOutputTruncation_middle-stderr.txt b/Tests/RunCMake/CTestCommandLine/TestOutputTruncation_middle-stderr.txt
deleted file mode 100644
index 30b46ce..0000000
--- a/Tests/RunCMake/CTestCommandLine/TestOutputTruncation_middle-stderr.txt
+++ /dev/null
@@ -1 +0,0 @@
-^Cannot find file: .*/Tests/RunCMake/CTestCommandLine/TestOutputTruncation.*/DartConfiguration.tcl
diff --git a/Tests/RunCMake/CTestCommandLine/TestOutputTruncation_tail-stderr.txt b/Tests/RunCMake/CTestCommandLine/TestOutputTruncation_tail-stderr.txt
deleted file mode 100644
index 30b46ce..0000000
--- a/Tests/RunCMake/CTestCommandLine/TestOutputTruncation_tail-stderr.txt
+++ /dev/null
@@ -1 +0,0 @@
-^Cannot find file: .*/Tests/RunCMake/CTestCommandLine/TestOutputTruncation.*/DartConfiguration.tcl
diff --git a/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stderr.txt b/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stderr.txt
index 017ccb0..6b16868 100644
--- a/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stderr.txt
+++ b/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stderr.txt
@@ -1 +1 @@
-Failed to change working directory to ".*/non-existing-dir" : No such file or directory
+Failed to change working directory to ".*/non-existing-dir": No such file or directory
diff --git a/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stdout.txt b/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stdout.txt
deleted file mode 100644
index ddcd238..0000000
--- a/Tests/RunCMake/CTestCommandLine/test-dir-non-existing-dir-stdout.txt
+++ /dev/null
@@ -1 +0,0 @@
-Internal ctest changing into directory: .*/non-existing-dir
diff --git a/Tests/RunCMake/CTestResourceAllocation/test.cmake.in b/Tests/RunCMake/CTestResourceAllocation/test.cmake.in
index 319ebf1..3237ef0 100644
--- a/Tests/RunCMake/CTestResourceAllocation/test.cmake.in
+++ b/Tests/RunCMake/CTestResourceAllocation/test.cmake.in
@@ -31,10 +31,18 @@
list(APPEND config_options "-DCTEST_RESOURCE_SPEC_FILE=@RunCMake_SOURCE_DIR@/resspec.json")
endif()
+set(test_args)
+if(DEFINED CTEST_PARALLEL)
+ list(APPEND test_args PARALLEL_LEVEL ${CTEST_PARALLEL})
+endif()
+if(DEFINED CTEST_RANDOM)
+ list(APPEND test_args SCHEDULE_RANDOM ${CTEST_RANDOM})
+endif()
+
ctest_start(Experimental QUIET)
ctest_configure(OPTIONS "${config_options}")
ctest_build()
-ctest_test(${resspec} RETURN_VALUE retval PARALLEL_LEVEL ${CTEST_PARALLEL} SCHEDULE_RANDOM ${CTEST_RANDOM})
+ctest_test(${resspec} RETURN_VALUE retval ${test_args})
if(retval)
message(FATAL_ERROR "Tests did not pass")
endif()
diff --git a/Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake b/Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake
index 470bbd8..6b4b96a 100644
--- a/Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake
@@ -34,7 +34,7 @@
target_compile_definitions(TestTimeout PRIVATE SIGNAL)
set_tests_properties(TestTimeout PROPERTIES
TIMEOUT_SIGNAL_NAME SIGUSR1
- TIMEOUT_SIGNAL_GRACE_PERIOD 1.2
+ TIMEOUT_SIGNAL_GRACE_PERIOD 32.1
)
]])
run_ctest_timeout(Signal)
@@ -91,7 +91,7 @@
block()
set(TIMEOUT 4)
set(CASE_TEST_PREFIX_CODE "set(CTEST_TEST_TIMEOUT 2)")
- set(CASE_CMAKELISTS_SUFFIX_CODE "set_property(TEST TestTimeout PROPERTY TIMEOUT 10)\n")
+ set(CASE_CMAKELISTS_SUFFIX_CODE "set_property(TEST TestTimeout PROPERTY TIMEOUT 60)\n")
run_ctest_timeout(PropertyOverridesVar)
endblock()
diff --git a/Tests/RunCMake/CXXModules/check-json.cmake b/Tests/RunCMake/CXXModules/check-json.cmake
index 8d95973..ec15f14 100644
--- a/Tests/RunCMake/CXXModules/check-json.cmake
+++ b/Tests/RunCMake/CXXModules/check-json.cmake
@@ -50,8 +50,8 @@
function (check_json_value path actual_type expect_type actual_value expect_value)
if (NOT actual_type STREQUAL expect_type)
- list(APPEND RunCMake_TEST_FAILED
- "Type mismatch at ${path}: ${actual_type} vs. ${expect_type}")
+ string(APPEND RunCMake_TEST_FAILED
+ "Type mismatch at:\n ${path}\nexpected:\n ${expect_type}\nactual:\n ${actual_type}\n")
set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
return ()
endif ()
@@ -60,13 +60,13 @@
# Nothing to check
elseif (actual_type STREQUAL BOOLEAN)
if (NOT actual_value STREQUAL expect_value)
- list(APPEND RunCMake_TEST_FAILED
- "Boolean mismatch at ${path}: ${actual_value} vs. ${expect_value}")
+ string(APPEND RunCMake_TEST_FAILED
+ "Boolean mismatch at:\n ${path}\nexpected:\n ${expect_value}\nactual:\n ${actual_value}\n")
endif ()
elseif (actual_type STREQUAL NUMBER)
if (NOT actual_value EQUAL expect_value)
- list(APPEND RunCMake_TEST_FAILED
- "Number mismatch at ${path}: ${actual_value} vs. ${expect_value}")
+ string(APPEND RunCMake_TEST_FAILED
+ "Number mismatch at:\n ${path}\nexpected:\n ${expect_value}\nactual:\n ${actual_value}\n")
endif ()
elseif (actual_type STREQUAL STRING)
# Allow some values to be ignored.
@@ -79,24 +79,24 @@
string(REPLACE "\\" "/" actual_value_check "${actual_value}")
string(REGEX REPLACE "^\"(.*)\"$" "\\1" actual_value_check "${actual_value_check}")
if (NOT actual_value_check MATCHES "^${expect_value_expanded}$")
- list(APPEND RunCMake_TEST_FAILED
- "String mismatch (path regex) at ${path}: ${actual_value} vs. ^${expect_value_expanded}$")
+ string(APPEND RunCMake_TEST_FAILED
+ "String mismatch (path regex) at:\n ${path}\nexpected:\n ^${expect_value_expanded}$\nactual:\n ${actual_value}\n")
endif ()
elseif (expect_value MATCHES "^REGEX:")
if (NOT actual_value MATCHES "^${expect_value_expanded}$")
- list(APPEND RunCMake_TEST_FAILED
- "String mismatch (regex) at ${path}: ${actual_value} vs. ^${expect_value_expanded}$")
+ string(APPEND RunCMake_TEST_FAILED
+ "String mismatch (regex) at:\n ${path}\nexpected:\n ^${expect_value_expanded}$\nactual:\n ${actual_value}\n")
endif ()
elseif (expect_value MATCHES "^PATH:")
string(REPLACE "\\" "/" actual_value_check "${actual_value}")
string(REGEX REPLACE "^\"(.*)\"$" "\\1" actual_value_check "${actual_value_check}")
if (NOT actual_value_check STREQUAL "${expect_value_expanded}")
- list(APPEND RunCMake_TEST_FAILED
- "String mismatch (path) at ${path}: ${actual_value} vs. ^${expect_value_expanded}$")
+ string(APPEND RunCMake_TEST_FAILED
+ "String mismatch (path) at:\n ${path}\nexpected:\n ${expect_value_expanded}\nactual:\n ${actual_value}\n")
endif ()
elseif (NOT actual_value STREQUAL expect_value_expanded)
- list(APPEND RunCMake_TEST_FAILED
- "String mismatch at ${path}: ${actual_value} vs. ${expect_value_expanded}")
+ string(APPEND RunCMake_TEST_FAILED
+ "String mismatch at:\n ${path}\nexpected:\n ${expect_value_expanded}\nactual:\n ${actual_value}\n")
endif ()
elseif (actual_type STREQUAL ARRAY)
check_json_array("${path}" "${actual_value}" "${expect_value}")
@@ -130,11 +130,11 @@
set(iter_len "${actual_len}")
if (actual_len LESS expect_len)
- list(APPEND RunCMake_TEST_FAILED
- "Missing array items at ${path}")
+ string(APPEND RunCMake_TEST_FAILED
+ "Missing array items at:\n ${path}\n")
elseif (expect_len LESS actual_len)
- list(APPEND RunCMake_TEST_FAILED
- "Extra array items at ${path}")
+ string(APPEND RunCMake_TEST_FAILED
+ "Extra array items at:\n ${path}\n")
set(iter_len "${expect_len}")
endif ()
@@ -200,13 +200,13 @@
if (actual_keys_missed)
string(REPLACE ";" ", " actual_keys_missed_text "${actual_keys_missed}")
- list(APPEND RunCMake_TEST_FAILED
- "Extra unexpected members at ${path}: ${actual_keys_missed_text}")
+ string(APPEND RunCMake_TEST_FAILED
+ "Extra unexpected members at:\n ${path}\nactual:\n ${actual_keys_missed_text}\n")
endif ()
if (expect_keys_missed)
string(REPLACE ";" ", " expect_keys_missed_text "${expect_keys_missed}")
- list(APPEND RunCMake_TEST_FAILED
- "Missing expected members at ${path}: ${expect_keys_missed_text}")
+ string(APPEND RunCMake_TEST_FAILED
+ "Missing expected members at\n ${path}\nactual:\n ${expect_keys_missed_text}\n")
endif ()
foreach (key IN LISTS common_keys)
diff --git a/Tests/RunCMake/CheckIPOSupported/CMP0138-OLD-stderr.txt b/Tests/RunCMake/CheckIPOSupported/CMP0138-OLD-stderr.txt
new file mode 100644
index 0000000..375ab1d
--- /dev/null
+++ b/Tests/RunCMake/CheckIPOSupported/CMP0138-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0138-OLD\.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0138 will be removed from a future version
+ of CMake\.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances\. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CommandLine/C_basic-stdout.txt b/Tests/RunCMake/CommandLine/C_basic-stdout.txt
index 74a938e..1cb0322 100644
--- a/Tests/RunCMake/CommandLine/C_basic-stdout.txt
+++ b/Tests/RunCMake/CommandLine/C_basic-stdout.txt
@@ -1 +1 @@
-loading initial cache file ../C_basic_initial-cache.txt
+loading initial cache file \.\./C_basic_initial-cache.txt
diff --git a/Tests/RunCMake/CommandLine/C_basic_fullpath-stdout.txt b/Tests/RunCMake/CommandLine/C_basic_fullpath-stdout.txt
index 32724f5..700e449 100644
--- a/Tests/RunCMake/CommandLine/C_basic_fullpath-stdout.txt
+++ b/Tests/RunCMake/CommandLine/C_basic_fullpath-stdout.txt
@@ -1 +1,2 @@
-loading initial cache file .*/Tests/RunCMake/CommandLine/C_basic_initial-cache.txt
+loading initial cache file [^
+]*/Tests/RunCMake/CommandLine/C_basic_initial-cache.txt
diff --git a/Tests/RunCMake/CommandLine/ExplicitDirs-C_buildsrcdir-stdout.txt b/Tests/RunCMake/CommandLine/ExplicitDirs-C_buildsrcdir-stdout.txt
index 862cfeb..c73adbd 100644
--- a/Tests/RunCMake/CommandLine/ExplicitDirs-C_buildsrcdir-stdout.txt
+++ b/Tests/RunCMake/CommandLine/ExplicitDirs-C_buildsrcdir-stdout.txt
@@ -1,2 +1,2 @@
-loading initial cache file .*initial-cache.txt
-.*
+loading initial cache file [^
+]*initial-cache.txt
diff --git a/Tests/RunCMake/Configure/RerunCMake-build5-check.cmake b/Tests/RunCMake/Configure/RerunCMake-build5-check.cmake
new file mode 100644
index 0000000..d740671
--- /dev/null
+++ b/Tests/RunCMake/Configure/RerunCMake-build5-check.cmake
@@ -0,0 +1,4 @@
+file(READ ${stamp} content)
+if(NOT content STREQUAL 5)
+ set(RunCMake_TEST_FAILED "Expected stamp '5' but got: '${content}'")
+endif()
diff --git a/Tests/RunCMake/Configure/RunCMakeTest.cmake b/Tests/RunCMake/Configure/RunCMakeTest.cmake
index 00d3272..9b686e4 100644
--- a/Tests/RunCMake/Configure/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Configure/RunCMakeTest.cmake
@@ -37,6 +37,15 @@
set(RunCMake_TEST_OUTPUT_MERGE 0)
run_cmake_command(RerunCMake-build4 ${CMAKE_COMMAND} --build .)
endif()
+ if(RunCMake_GENERATOR MATCHES "^Ninja")
+ file(REMOVE "${error}")
+ run_cmake(RerunCMake)
+ execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1) # handle 1s resolution
+ # remove cmake_install.cmake to trigger rerun
+ file(REMOVE "${RunCMake_TEST_BINARY_DIR}/cmake_install.cmake")
+ file(WRITE "${input}" "5")
+ run_cmake_command(RerunCMake-build5 ${CMAKE_COMMAND} --build .)
+ endif()
endblock()
block()
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/apple_exe_framework.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/apple_exe_framework.json
index a4c13a8..dd49b39 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/apple_exe_framework.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/apple_exe_framework.json
@@ -26,7 +26,7 @@
"backtrace": null
}
],
- "compileCommandFragments": []
+ "compileCommandFragments": null
}
],
"link": {
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_cross_emulator.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_cross_emulator.json
index bbd973b..a1b15ca 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_cross_emulator.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_cross_emulator.json
@@ -87,13 +87,7 @@
"link": {
"language": "CXX",
"lto": null,
- "commandFragments": [
- {
- "fragment" : ".*",
- "role" : "flags",
- "backtrace": null
- }
- ]
+ "commandFragments": null
},
"archive": null,
"dependencies": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_cross_emulator_args.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_cross_emulator_args.json
index c1a8b0c..24a7550 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_cross_emulator_args.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_cross_emulator_args.json
@@ -91,13 +91,7 @@
"link": {
"language": "CXX",
"lto": null,
- "commandFragments": [
- {
- "fragment" : ".*",
- "role" : "flags",
- "backtrace": null
- }
- ]
+ "commandFragments": null
},
"archive": null,
"dependencies": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_test_launcher.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_test_launcher.json
index 9002368..f5e365c 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_test_launcher.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_test_launcher.json
@@ -87,13 +87,7 @@
"link": {
"language": "CXX",
"lto": null,
- "commandFragments": [
- {
- "fragment" : ".*",
- "role" : "flags",
- "backtrace": null
- }
- ]
+ "commandFragments": null
},
"archive": null,
"dependencies": [
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_test_launcher_and_cross_emulator.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_test_launcher_and_cross_emulator.json
index 06e7a7b..8facf86 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_test_launcher_and_cross_emulator.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe_test_launcher_and_cross_emulator.json
@@ -91,13 +91,7 @@
"link": {
"language": "CXX",
"lto": null,
- "commandFragments": [
- {
- "fragment" : ".*",
- "role" : "flags",
- "backtrace": null
- }
- ]
+ "commandFragments": null
},
"archive": null,
"dependencies": [
diff --git a/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-env-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-env-stderr.txt
index b664fa0..01d446c 100644
--- a/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-env-stderr.txt
+++ b/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-env-stderr.txt
@@ -19,7 +19,7 @@
.*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\)
.*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\)
.*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\)
- .*/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-env/test\.cmake:10 \(ctest_read_custom_files\)
+ .*/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-env/test\.cmake:5 \(ctest_read_custom_files\)
Problem reading custom configuration: .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake
diff --git a/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-var-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-var-stderr.txt
index bc89703..2e81bcb 100644
--- a/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-var-stderr.txt
+++ b/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-var-stderr.txt
@@ -19,7 +19,7 @@
.*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\)
.*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\)
.*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\)
- .*/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-var/test\.cmake:10 \(ctest_read_custom_files\)
+ .*/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-var/test\.cmake:5 \(ctest_read_custom_files\)
Problem reading custom configuration: .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake
diff --git a/Tests/RunCMake/MaxRecursionDepth/ctest_run_script-var-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/ctest_run_script-var-stderr.txt
index b10b26d..0586d4f 100644
--- a/Tests/RunCMake/MaxRecursionDepth/ctest_run_script-var-stderr.txt
+++ b/Tests/RunCMake/MaxRecursionDepth/ctest_run_script-var-stderr.txt
@@ -11,41 +11,41 @@
Maximum recursion depth of 10 exceeded
-CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_10\.cmake:13 \(message\):
+CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_10\.cmake:8 \(message\):
Nested script failed
-CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_9\.cmake:13 \(message\):
+CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_9\.cmake:8 \(message\):
Nested script failed
-CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_8\.cmake:13 \(message\):
+CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_8\.cmake:8 \(message\):
Nested script failed
-CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_7\.cmake:13 \(message\):
+CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_7\.cmake:8 \(message\):
Nested script failed
-CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_6\.cmake:13 \(message\):
+CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_6\.cmake:8 \(message\):
Nested script failed
-CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_5\.cmake:13 \(message\):
+CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_5\.cmake:8 \(message\):
Nested script failed
-CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_4\.cmake:13 \(message\):
+CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_4\.cmake:8 \(message\):
Nested script failed
-CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_3\.cmake:13 \(message\):
+CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_3\.cmake:8 \(message\):
Nested script failed
-CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_2\.cmake:13 \(message\):
+CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script_2\.cmake:8 \(message\):
Nested script failed
-CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script-var/test\.cmake:19 \(message\):
+CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/ctest_run_script-var/test\.cmake:14 \(message\):
Nested script failed$
diff --git a/Tests/RunCMake/MaxRecursionDepth/ctest_run_script.cmake.in b/Tests/RunCMake/MaxRecursionDepth/ctest_run_script.cmake.in
index d4f28c4..5646a00 100644
--- a/Tests/RunCMake/MaxRecursionDepth/ctest_run_script.cmake.in
+++ b/Tests/RunCMake/MaxRecursionDepth/ctest_run_script.cmake.in
@@ -1,12 +1,7 @@
cmake_minimum_required(VERSION 3.12)
-set(CTEST_RUN_CURRENT_SCRIPT 0)
message("@LEVEL_CURRENT@")
-set(CTEST_SOURCE_DIRECTORY "@CTEST_SOURCE_DIRECTORY@")
-set(CTEST_BINARY_DIRECTORY "@CTEST_BINARY_DIRECTORY@")
-set(CTEST_COMMAND "@CTEST_COMMAND@")
-
ctest_run_script("${CMAKE_CURRENT_LIST_DIR}/ctest_run_script_@LEVEL_NEXT@.cmake" RETURN_VALUE val)
if(NOT val EQUAL 0)
diff --git a/Tests/RunCMake/MaxRecursionDepth/test.cmake.in b/Tests/RunCMake/MaxRecursionDepth/test.cmake.in
index fd1fc10..62c8e41 100644
--- a/Tests/RunCMake/MaxRecursionDepth/test.cmake.in
+++ b/Tests/RunCMake/MaxRecursionDepth/test.cmake.in
@@ -1,9 +1,4 @@
cmake_minimum_required(VERSION 3.12)
-set(CTEST_RUN_CURRENT_SCRIPT 0)
-
-set(CTEST_SOURCE_DIRECTORY "@RunCMake_SOURCE_DIR@")
-set(CTEST_BINARY_DIRECTORY "@RunCMake_BINARY_DIR@")
-set(CTEST_COMMAND "${CMAKE_CTEST_COMMAND}")
if(TEST_NAME STREQUAL "ctest_read_custom_files")
set(x 2)
diff --git a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
index 4015ae8..4f65b85 100644
--- a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
+++ b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
@@ -44,6 +44,7 @@
\* CMP0160
\* CMP0162
\* CMP0179
+ \* CMP0181
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake b/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake
index 78996e4..423262b 100644
--- a/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake
+++ b/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake
@@ -8,10 +8,16 @@
endfunction()
run_cmake(unitybuild_c)
+run_cmake(unitybuild_c_absolute_path)
+run_cmake(unitybuild_c_relocatable_path)
run_cmake(unitybuild_c_batch)
run_cmake(unitybuild_c_group)
run_cmake(unitybuild_cxx)
+run_cmake(unitybuild_cxx_absolute_path)
+run_cmake(unitybuild_cxx_relocatable_path)
run_cmake(unitybuild_cxx_group)
+run_cmake(unitybuild_c_and_cxx_absolute_path)
+run_cmake(unitybuild_c_and_cxx_relocatable_path)
run_cmake(unitybuild_c_and_cxx)
run_cmake(unitybuild_c_and_cxx_group)
if(CMake_TEST_OBJC)
@@ -37,6 +43,7 @@
run_build(unitybuild_anon_ns)
run_build(unitybuild_anon_ns_no_unity_build)
run_build(unitybuild_anon_ns_group_mode)
+run_cmake(unitybuild_relocatable_locations)
function(run_per_config name)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build)
diff --git a/Tests/RunCMake/UnityBuild/relocatable/foo.c b/Tests/RunCMake/UnityBuild/relocatable/foo.c
new file mode 100644
index 0000000..de1160c
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/relocatable/foo.c
@@ -0,0 +1,5 @@
+int foo(int x)
+{
+ (void)x;
+ return 0;
+}
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_absolute_path-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_absolute_path-check.cmake
new file mode 100644
index 0000000..e716e93
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_absolute_path-check.cmake
@@ -0,0 +1,17 @@
+set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.c")
+if(NOT EXISTS "${unitybuild_c}")
+ set(RunCMake_TEST_FAILED "Generated unity source file ${unitybuild_c} does not exist.")
+ return()
+endif()
+
+string(JOIN ".*" EXPECTED_UNITY_FILE_CONTENT
+ [[#include "([A-Za-z]:)?/[^"]*/Tests/RunCMake/UnityBuild/unitybuild_c_absolute_path-build/s1\.c"]]
+ [[#include "([A-Za-z]:)?/[^"]*/Tests/RunCMake/UnityBuild/unitybuild_c_absolute_path-build/s2\.c"]]
+ [[#include "([A-Za-z]:)?/[^"]*/Tests/RunCMake/UnityBuild/unitybuild_c_absolute_path-build/s3\.c"]]
+)
+
+file(STRINGS ${unitybuild_c} unitybuild_c_strings)
+if(NOT unitybuild_c_strings MATCHES "${EXPECTED_UNITY_FILE_CONTENT}")
+ set(RunCMake_TEST_FAILED "Generated unity file ${unitybuild_c} doesn't contain absolute paths")
+ return()
+endif()
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_absolute_path.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_absolute_path.cmake
new file mode 100644
index 0000000..0fe6fbf
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_absolute_path.cmake
@@ -0,0 +1,13 @@
+project(unitybuild_c_absolute_path C)
+
+set(srcs "")
+foreach(s RANGE 1 3)
+ set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
+ file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
+ list(APPEND srcs "${src}")
+endforeach()
+
+add_library(tgt SHARED ${srcs})
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD ON
+ UNITY_BUILD_RELOCATABLE FALSE)
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path-check.cmake
new file mode 100644
index 0000000..aa41f78
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path-check.cmake
@@ -0,0 +1,35 @@
+set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.c")
+if(NOT EXISTS "${unitybuild_c}")
+ set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c} does not exist.")
+ return()
+endif()
+
+string(JOIN ".*" EXPECTED_UNITY_FILE_CONTENT
+ [[#include "([A-Za-z]:)?/[^"]*/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path-build/s1\.c"]]
+ [[#include "([A-Za-z]:)?/[^"]*/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path-build/s2\.c"]]
+ [[#include "([A-Za-z]:)?/[^"]*/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path-build/s3\.c"]]
+)
+
+file(STRINGS ${unitybuild_c} unitybuild_c_strings)
+if(NOT unitybuild_c_strings MATCHES "${EXPECTED_UNITY_FILE_CONTENT}")
+ set(RunCMake_TEST_FAILED "Generated unity file ${unitybuild_c} doesn't contain absolute paths")
+ return()
+endif()
+
+set(unitybuild_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_cxx.cxx")
+if(NOT EXISTS "${unitybuild_cxx}")
+ set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_cxx} does not exist.")
+ return()
+endif()
+
+string(JOIN ".*" EXPECTED_UNITY_FILE_CONTENT_CXX
+ [[#include "([A-Za-z]:)?/[^"]*/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path-build/s1\.cxx"]]
+ [[#include "([A-Za-z]:)?/[^"]*/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path-build/s2\.cxx"]]
+ [[#include "([A-Za-z]:)?/[^"]*/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path-build/s3\.cxx"]]
+)
+
+file(STRINGS ${unitybuild_cxx} unitybuild_cxx_strings)
+if(NOT unitybuild_cxx_strings MATCHES "${EXPECTED_UNITY_FILE_CONTENT_CXX}")
+ set(RunCMake_TEST_FAILED "Generated unity file ${unitybuild_cxx} doesn't contain absolute paths")
+ return()
+endif()
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path.cmake
new file mode 100644
index 0000000..9c6b0e4
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path.cmake
@@ -0,0 +1,18 @@
+project(unitybuild_c_and_cxx_absolute_path C CXX)
+
+set(srcs "")
+foreach(s RANGE 1 3)
+ set(src_c "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
+ file(WRITE "${src_c}" "int s${s}(void) { return 0; }\n")
+
+ set(src_cxx "${CMAKE_CURRENT_BINARY_DIR}/s${s}.cxx")
+ file(WRITE "${src_cxx}" "int s${s}(void) { return 0; }\n")
+
+ list(APPEND srcs "${src_c}")
+ list(APPEND srcs "${src_cxx}")
+endforeach()
+
+add_library(tgt SHARED ${srcs})
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD ON
+ UNITY_BUILD_RELOCATABLE FALSE)
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_relocatable_path-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_relocatable_path-check.cmake
new file mode 100644
index 0000000..e5fd4df
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_relocatable_path-check.cmake
@@ -0,0 +1,35 @@
+set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.c")
+if(NOT EXISTS "${unitybuild_c}")
+ set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c} does not exist.")
+ return()
+endif()
+
+string(JOIN ".*" EXPECTED_UNITY_FILE_CONTENT
+ [[#include "\.\./\.\./\.\./s1\.c"]]
+ [[#include "\.\./\.\./\.\./s2\.c"]]
+ [[#include "\.\./\.\./\.\./s3\.c"]]
+)
+
+file(STRINGS ${unitybuild_c} unitybuild_c_strings)
+if(NOT unitybuild_c_strings MATCHES "${EXPECTED_UNITY_FILE_CONTENT}")
+ set(RunCMake_TEST_FAILED "Generated unity file ${unitybuild_c} doesn't contain relative paths")
+ return()
+endif()
+
+set(unitybuild_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_cxx.cxx")
+if(NOT EXISTS "${unitybuild_cxx}")
+ set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_cxx} does not exist.")
+ return()
+endif()
+
+string(JOIN ".*" EXPECTED_UNITY_FILE_CONTENT_CXX
+ [[#include "\.\./\.\./\.\./s1\.cxx"]]
+ [[#include "\.\./\.\./\.\./s2\.cxx"]]
+ [[#include "\.\./\.\./\.\./s3\.cxx"]]
+)
+
+file(STRINGS ${unitybuild_cxx} unitybuild_cxx_strings)
+if(NOT unitybuild_cxx_strings MATCHES "${EXPECTED_UNITY_FILE_CONTENT_CXX}")
+ set(RunCMake_TEST_FAILED "Generated unity file ${unitybuild_cxx} doesn't contain relative paths")
+ return()
+endif()
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_relocatable_path.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_relocatable_path.cmake
new file mode 100644
index 0000000..21257f4
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_relocatable_path.cmake
@@ -0,0 +1,18 @@
+project(unitybuild_c_and_cxx_relocatable_path C CXX)
+
+set(srcs "")
+foreach(s RANGE 1 3)
+ set(src_c "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
+ file(WRITE "${src_c}" "int s${s}(void) { return 0; }\n")
+
+ set(src_cxx "${CMAKE_CURRENT_BINARY_DIR}/s${s}.cxx")
+ file(WRITE "${src_cxx}" "int s${s}(void) { return 0; }\n")
+
+ list(APPEND srcs "${src_c}")
+ list(APPEND srcs "${src_cxx}")
+endforeach()
+
+add_library(tgt SHARED ${srcs})
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD ON
+ UNITY_BUILD_RELOCATABLE TRUE)
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_relocatable_path-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_relocatable_path-check.cmake
new file mode 100644
index 0000000..f8e41ce
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_relocatable_path-check.cmake
@@ -0,0 +1,17 @@
+set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.c")
+if(NOT EXISTS "${unitybuild_c}")
+ set(RunCMake_TEST_FAILED "Generated unity source file ${unitybuild_c} does not exist.")
+ return()
+endif()
+
+string(JOIN ".*" EXPECTED_UNITY_FILE_CONTENT
+ [[#include "\.\./\.\./\.\./s1\.c"]]
+ [[#include "\.\./\.\./\.\./s2\.c"]]
+ [[#include "\.\./\.\./\.\./s3\.c"]]
+)
+
+file(STRINGS ${unitybuild_c} unitybuild_c_strings)
+if(NOT unitybuild_c_strings MATCHES "${EXPECTED_UNITY_FILE_CONTENT}")
+ set(RunCMake_TEST_FAILED "Generated unity file ${unitybuild_c} doesn't contain relative paths")
+ return()
+endif()
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_relocatable_path.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_relocatable_path.cmake
new file mode 100644
index 0000000..e6046e6
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_relocatable_path.cmake
@@ -0,0 +1,14 @@
+project(unitybuild_c_relocatable_path C)
+
+set(srcs "")
+foreach(s RANGE 1 3)
+ set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
+ file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
+ list(APPEND srcs "${src}")
+endforeach()
+
+add_library(tgt SHARED ${srcs})
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD ON
+ UNITY_BUILD_RELOCATABLE TRUE
+ UNITY_BUILD_UNIQUE_ID "anon")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_cxx_absolute_path-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_cxx_absolute_path-check.cmake
new file mode 100644
index 0000000..95d96ec
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_cxx_absolute_path-check.cmake
@@ -0,0 +1,17 @@
+set(unitybuild_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_cxx.cxx")
+if(NOT EXISTS "${unitybuild_cxx}")
+ set(RunCMake_TEST_FAILED "Generated unity source file ${unitybuild_cxx} does not exist.")
+ return()
+endif()
+
+string(JOIN ".*" EXPECTED_UNITY_FILE_CONTENT
+ [[#include "([A-Za-z]:)?/[^"]*/Tests/RunCMake/UnityBuild/unitybuild_cxx_absolute_path-build/s1\.cxx"]]
+ [[#include "([A-Za-z]:)?/[^"]*/Tests/RunCMake/UnityBuild/unitybuild_cxx_absolute_path-build/s2\.cxx"]]
+ [[#include "([A-Za-z]:)?/[^"]*/Tests/RunCMake/UnityBuild/unitybuild_cxx_absolute_path-build/s3\.cxx"]]
+)
+
+file(STRINGS ${unitybuild_cxx} unitybuild_cxx_strings)
+if(NOT unitybuild_cxx_strings MATCHES "${EXPECTED_UNITY_FILE_CONTENT}")
+ set(RunCMake_TEST_FAILED "Generated unity file ${unitybuild_cxx} doesn't contain absolute paths")
+ return()
+endif()
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_cxx_absolute_path.cmake b/Tests/RunCMake/UnityBuild/unitybuild_cxx_absolute_path.cmake
new file mode 100644
index 0000000..07543f4
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_cxx_absolute_path.cmake
@@ -0,0 +1,13 @@
+project(unitybuild_cxx_absolute_path CXX)
+
+set(srcs "")
+foreach(s RANGE 1 3)
+ set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.cxx")
+ file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
+ list(APPEND srcs "${src}")
+endforeach()
+
+add_library(tgt SHARED ${srcs})
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD ON
+ UNITY_BUILD_RELOCATABLE FALSE)
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_cxx_relocatable_path-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_cxx_relocatable_path-check.cmake
new file mode 100644
index 0000000..d06547d
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_cxx_relocatable_path-check.cmake
@@ -0,0 +1,17 @@
+set(unitybuild_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_cxx.cxx")
+if(NOT EXISTS "${unitybuild_cxx}")
+ set(RunCMake_TEST_FAILED "Generated unity source file ${unitybuild_cxx} does not exist.")
+ return()
+endif()
+
+string(JOIN ".*" EXPECTED_UNITY_FILE_CONTENT
+ [[#include "\.\./\.\./\.\./s1\.cxx"]]
+ [[#include "\.\./\.\./\.\./s2\.cxx"]]
+ [[#include "\.\./\.\./\.\./s3\.cxx"]]
+)
+
+file(STRINGS ${unitybuild_cxx} unitybuild_cxx_strings)
+if(NOT unitybuild_cxx_strings MATCHES "${EXPECTED_UNITY_FILE_CONTENT}")
+ set(RunCMake_TEST_FAILED "Generated unity file ${unitybuild_cxx} doesn't contain relative paths")
+ return()
+endif()
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_cxx_relocatable_path.cmake b/Tests/RunCMake/UnityBuild/unitybuild_cxx_relocatable_path.cmake
new file mode 100644
index 0000000..abf672d
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_cxx_relocatable_path.cmake
@@ -0,0 +1,13 @@
+project(unitybuild_cxx_relocatable_path CXX)
+
+set(srcs "")
+foreach(s RANGE 1 3)
+ set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.cxx")
+ file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
+ list(APPEND srcs "${src}")
+endforeach()
+
+add_library(tgt SHARED ${srcs})
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD ON
+ UNITY_BUILD_RELOCATABLE TRUE)
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_relocatable_locations-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_relocatable_locations-check.cmake
new file mode 100644
index 0000000..565920c
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_relocatable_locations-check.cmake
@@ -0,0 +1,22 @@
+set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.c")
+if(NOT EXISTS "${unitybuild_c}")
+ set(RunCMake_TEST_FAILED "Generated unity source file ${unitybuild_c} does not exist.")
+ return()
+endif()
+
+string(JOIN ".*" EXPECTED_UNITY_FILE_CONTENT
+ [[#include "\.\./\.\./\.\./s1\.c"]]
+ [[#include "\.\./\.\./\.\./s2\.c"]]
+ [[#include "\.\./\.\./\.\./s3\.c"]]
+ [[#include "\.\./\.\./\.\./subFolder/sub1\.c"]]
+ [[#include "\.\./\.\./\.\./subFolder/sub2\.c"]]
+ [[#include "\.\./\.\./\.\./subFolder/sub3\.c"]]
+ [[#include "f\.c"]]
+ [[#include "relocatable/foo\.c"]]
+)
+
+file(STRINGS ${unitybuild_c} unitybuild_c_strings)
+if(NOT unitybuild_c_strings MATCHES "${EXPECTED_UNITY_FILE_CONTENT}")
+ set(RunCMake_TEST_FAILED "Generated unity file ${unitybuild_c} doesn't contain relative paths")
+ return()
+endif()
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_relocatable_locations.cmake b/Tests/RunCMake/UnityBuild/unitybuild_relocatable_locations.cmake
new file mode 100644
index 0000000..a28d89e
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_relocatable_locations.cmake
@@ -0,0 +1,23 @@
+project(unitybuild_relocatable_locations C)
+
+# Binary path relative source file
+set(srcs "")
+foreach(s RANGE 1 3)
+ set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
+ file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
+ list(APPEND srcs "${src}")
+endforeach()
+foreach(s RANGE 1 3)
+ set(src "${CMAKE_CURRENT_BINARY_DIR}/subFolder/sub${s}.c")
+ file(WRITE "${src}" "int sub${s}(void) { return 0; }\n")
+ list(APPEND srcs "${src}")
+endforeach()
+
+# Source path relative source file
+list(APPEND srcs "${CMAKE_SOURCE_DIR}/f.c")
+list(APPEND srcs "${CMAKE_SOURCE_DIR}/relocatable/foo.c")
+
+add_library(tgt SHARED ${srcs})
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD ON
+ UNITY_BUILD_RELOCATABLE TRUE)
diff --git a/Tests/RunCMake/VS10Project/CSharpSourceGroup/images/empty.bmp b/Tests/RunCMake/VS10Project/CSharpSourceGroup/Images/empty.bmp
similarity index 100%
rename from Tests/RunCMake/VS10Project/CSharpSourceGroup/images/empty.bmp
rename to Tests/RunCMake/VS10Project/CSharpSourceGroup/Images/empty.bmp
diff --git a/Tests/RunCMake/VS10Project/CustomCommandParallelDisable-check.cmake b/Tests/RunCMake/VS10Project/CustomCommandParallelDisable-check.cmake
new file mode 100644
index 0000000..e0608f6
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/CustomCommandParallelDisable-check.cmake
@@ -0,0 +1,42 @@
+# Check whether the 'BuildInParallel' setting is set as expected for a specified project file.
+# Note: if the setting is not present in the project file then it is assumed to be implicitly 'false'.
+function(check_build_in_parallel_setting projectFile expectedEnabled)
+ set(SettingEnabledRegex "<BuildInParallel.*>true</BuildInParallel>")
+ set(SettingDisabledRegex "<BuildInParallel.*>false</BuildInParallel>")
+
+ if(NOT EXISTS "${projectFile}")
+ set(RunCMake_TEST_FAILED "Project file '${projectFile}' does not exist." PARENT_SCOPE)
+ return()
+ endif()
+
+ set(settingEnabled FALSE)
+ set(settingExplicitlyDisabled FALSE)
+
+ file(STRINGS "${projectFile}" lines)
+
+ foreach(line IN LISTS lines)
+ if(line MATCHES "${SettingEnabledRegex}")
+ set(settingEnabled TRUE)
+ elseif(line MATCHES "${SettingDisabledRegex}")
+ set(settingExplicitlyDisabled TRUE)
+ endif()
+ endforeach()
+
+ if(expectedEnabled)
+ if(NOT settingEnabled)
+ set(RunCMake_TEST_FAILED "Expected 'BuildInParallel' to be enabled for projectFile '${projectFile}' but it was not!" PARENT_SCOPE)
+ endif()
+ if(settingExplicitlyDisabled)
+ set(RunCMake_TEST_FAILED "Expected 'BuildInParallel' to be enabled for projectFile '${projectFile}' but instead found it explicitly disabled!" PARENT_SCOPE)
+ endif()
+ else()
+ if(settingEnabled)
+ set(RunCMake_TEST_FAILED "Expected 'BuildInParallel' to be disabled for projectFile '${projectFile}' but it was not!")
+ endif()
+ endif()
+endfunction()
+
+check_build_in_parallel_setting("${RunCMake_TEST_BINARY_DIR}/foo1.vcxproj" TRUE)
+check_build_in_parallel_setting("${RunCMake_TEST_BINARY_DIR}/bar1.vcxproj" FALSE)
+check_build_in_parallel_setting("${RunCMake_TEST_BINARY_DIR}/foo2.vcxproj" FALSE)
+check_build_in_parallel_setting("${RunCMake_TEST_BINARY_DIR}/bar2.vcxproj" FALSE)
diff --git a/Tests/RunCMake/VS10Project/CustomCommandParallelDisable.cmake b/Tests/RunCMake/VS10Project/CustomCommandParallelDisable.cmake
new file mode 100644
index 0000000..b9ea3ab
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/CustomCommandParallelDisable.cmake
@@ -0,0 +1,21 @@
+block()
+ cmake_policy(SET CMP0147 NEW) # Build custom commands in parallel by default
+
+ add_custom_command(OUTPUT "foo.out.txt" COMMAND echo Foo > foo.out.txt MAIN_DEPENDENCY "foo.txt")
+ add_custom_command(OUTPUT "bar.out.txt" COMMAND echo Bar > bar.out.txt MAIN_DEPENDENCY "bar.txt")
+ set_property(SOURCE "bar.txt" PROPERTY VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD TRUE)
+
+ add_custom_target(foo1 SOURCES foo.txt)
+ add_custom_target(bar1 SOURCES bar.txt)
+endblock()
+
+block()
+ cmake_policy(SET CMP0147 OLD) # Don't build custom commands in parallel by default
+
+ add_custom_command(OUTPUT "foo.out.cpp" COMMAND echo Foo > foo.out.txt MAIN_DEPENDENCY "foo.cpp")
+ add_custom_command(OUTPUT "bar.out.cpp" COMMAND echo Bar > bar.out.txt MAIN_DEPENDENCY "bar.cpp")
+ set_property(SOURCE "bar.cpp" PROPERTY VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD TRUE)
+
+ add_custom_target(foo2 SOURCES foo.cpp)
+ add_custom_target(bar2 SOURCES bar.cpp)
+endblock()
diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
index bbd8c8b..49c345c 100644
--- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
@@ -10,6 +10,7 @@
run_cmake(CustomCommandGenex)
if(NOT RunCMake_GENERATOR MATCHES "^Visual Studio 1[1-5] ")
run_cmake(CustomCommandParallel)
+ run_cmake(CustomCommandParallelDisable)
endif()
run_cmake_with_options(VsCharacterSet -DSET_CHARSET=MultiByte)
run_cmake_with_options(VsCharacterSet -DSET_CHARSET=Unicode)
diff --git a/Tests/RunCMake/VS10Project/VsCsharpSourceGroup-check.cmake b/Tests/RunCMake/VS10Project/VsCsharpSourceGroup-check.cmake
index 9c9409c..5d1ee3e 100644
--- a/Tests/RunCMake/VS10Project/VsCsharpSourceGroup-check.cmake
+++ b/Tests/RunCMake/VS10Project/VsCsharpSourceGroup-check.cmake
@@ -11,7 +11,7 @@
set(SOURCE_GROUPS_TO_FIND
"CSharpSourceGroup\\\\foo\\.cs"
"CSharpSourceGroup\\\\nested\\\\baz\\.cs"
- "CSharpSourceGroup\\\\images\\\\empty\\.bmp"
+ "Images\\\\empty\\.bmp"
"VsCsharpSourceGroup\\.png"
"AssemblyInfo\\.cs"
)
diff --git a/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-stdout.txt b/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-stdout.txt
index da89317..a0098e7 100644
--- a/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-stdout.txt
+++ b/Tests/RunCMake/WorkingDirectory/buildAndTestNoBuildDir-stdout.txt
@@ -1 +1 @@
-Failed to change working directory to .*[/\\]buildAndTestNoBuildDir[/\\]CMakeLists.txt :
+Failed to change working directory to ".*[/\\]buildAndTestNoBuildDir[/\\]CMakeLists.txt": (Not a directory|Invalid argument)
diff --git a/Tests/RunCMake/WorkingDirectory/dirNotExist-stderr.txt b/Tests/RunCMake/WorkingDirectory/dirNotExist-stderr.txt
index 3cea890..21d288e 100644
--- a/Tests/RunCMake/WorkingDirectory/dirNotExist-stderr.txt
+++ b/Tests/RunCMake/WorkingDirectory/dirNotExist-stderr.txt
@@ -1 +1 @@
-Failed to change working directory to .*[/\\]dirNotExist-build[/\\]thisDirWillNotExist :
+Failed to change working directory to ".*[/\\]dirNotExist-build[/\\]thisDirWillNotExist": No such file or directory
diff --git a/Tests/RunCMake/XcFramework/RunCMakeTest.cmake b/Tests/RunCMake/XcFramework/RunCMakeTest.cmake
index 64505ff..8c8d970 100644
--- a/Tests/RunCMake/XcFramework/RunCMakeTest.cmake
+++ b/Tests/RunCMake/XcFramework/RunCMakeTest.cmake
@@ -104,17 +104,17 @@
create_xcframework(incomplete framework "tvos;watchos")
create_executables(library library)
create_executables(framework framework)
-run_cmake_with_options(create-executable-incomplete -DCMAKE_SYSTEM_NAME=Darwin "-DCMAKE_OSX_ARCHITECTURES=${macos_archs_1}" -DMYLIB_LIBRARY=${RunCMake_BINARY_DIR}/create-xcframework-incomplete-build/mylib.xcframework)
+run_cmake_with_options(create-executable-incomplete -DCMAKE_SYSTEM_NAME=Darwin "-DCMAKE_OSX_ARCHITECTURES=${macos_archs_1}" -DCMAKE_OSX_SYSROOT=macosx -DMYLIB_LIBRARY=${RunCMake_BINARY_DIR}/create-xcframework-incomplete-build/mylib.xcframework)
create_executables(target-library library)
create_executables(target-framework framework)
-run_cmake_with_options(create-executable-target-incomplete -DCMAKE_SYSTEM_NAME=Darwin "-DCMAKE_OSX_ARCHITECTURES=${macos_archs_1}" -DMYLIB_LIBRARY=${RunCMake_BINARY_DIR}/create-xcframework-incomplete-build/mylib.xcframework)
+run_cmake_with_options(create-executable-target-incomplete -DCMAKE_SYSTEM_NAME=Darwin "-DCMAKE_OSX_ARCHITECTURES=${macos_archs_1}" -DCMAKE_OSX_SYSROOT=macosx -DMYLIB_LIBRARY=${RunCMake_BINARY_DIR}/create-xcframework-incomplete-build/mylib.xcframework)
if(RunCMake_GENERATOR STREQUAL "Xcode" AND CMake_TEST_XCODE_VERSION VERSION_GREATER_EQUAL 12)
create_executables(library-link-phase library)
create_executables(framework-link-phase framework)
- run_cmake_with_options(create-executable-incomplete-link-phase -DCMAKE_SYSTEM_NAME=Darwin "-DCMAKE_OSX_ARCHITECTURES=${macos_archs_1}" -DMYLIB_LIBRARY=${RunCMake_BINARY_DIR}/create-xcframework-incomplete-build/mylib.xcframework)
+ run_cmake_with_options(create-executable-incomplete-link-phase -DCMAKE_SYSTEM_NAME=Darwin "-DCMAKE_OSX_ARCHITECTURES=${macos_archs_1}" -DCMAKE_OSX_SYSROOT=macosx -DMYLIB_LIBRARY=${RunCMake_BINARY_DIR}/create-xcframework-incomplete-build/mylib.xcframework)
create_executables(target-library-link-phase library)
create_executables(target-framework-link-phase framework)
- run_cmake_with_options(create-executable-target-incomplete-link-phase -DCMAKE_SYSTEM_NAME=Darwin "-DCMAKE_OSX_ARCHITECTURES=${macos_archs_1}" -DMYLIB_LIBRARY=${RunCMake_BINARY_DIR}/create-xcframework-incomplete-build/mylib.xcframework)
+ run_cmake_with_options(create-executable-target-incomplete-link-phase -DCMAKE_SYSTEM_NAME=Darwin "-DCMAKE_OSX_ARCHITECTURES=${macos_archs_1}" -DCMAKE_OSX_SYSROOT=macosx -DMYLIB_LIBRARY=${RunCMake_BINARY_DIR}/create-xcframework-incomplete-build/mylib.xcframework)
endif()
# Ensure that .xcframework is found before .framework
diff --git a/Tests/RunCMake/block/Scope-POLICIES-stderr.txt b/Tests/RunCMake/block/Scope-POLICIES-stderr.txt
new file mode 100644
index 0000000..84b99aa
--- /dev/null
+++ b/Tests/RunCMake/block/Scope-POLICIES-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at Scope-POLICIES\.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0139 will be removed from a future version
+ of CMake\.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances\. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/block/Scope-VARIABLES-stderr.txt b/Tests/RunCMake/block/Scope-VARIABLES-stderr.txt
new file mode 100644
index 0000000..458daa7
--- /dev/null
+++ b/Tests/RunCMake/block/Scope-VARIABLES-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at Scope-VARIABLES\.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0139 will be removed from a future version
+ of CMake\.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances\. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/block/Scope-stderr.txt b/Tests/RunCMake/block/Scope-stderr.txt
new file mode 100644
index 0000000..af84e88
--- /dev/null
+++ b/Tests/RunCMake/block/Scope-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at Scope\.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0139 will be removed from a future version
+ of CMake\.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances\. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/ctest_submit/CDashUploadNone-stderr.txt b/Tests/RunCMake/ctest_submit/CDashUploadNone-stderr.txt
index af95b5c..9e27918 100644
--- a/Tests/RunCMake/ctest_submit/CDashUploadNone-stderr.txt
+++ b/Tests/RunCMake/ctest_submit/CDashUploadNone-stderr.txt
@@ -1 +1,4 @@
-Upload file not specified
+^CMake Error at .*Tests/RunCMake/ctest_submit/CDashUploadNone/test.cmake:[0-9]+ \(ctest_submit\):
+ Error after keyword "CDASH_UPLOAD":
+
+ missing required value
diff --git a/Tests/RunCMake/ctest_submit/RepeatRETURN_VALUE-stderr.txt b/Tests/RunCMake/ctest_submit/RepeatRETURN_VALUE-stderr.txt
index 6e17c75..3951524 100644
--- a/Tests/RunCMake/ctest_submit/RepeatRETURN_VALUE-stderr.txt
+++ b/Tests/RunCMake/ctest_submit/RepeatRETURN_VALUE-stderr.txt
@@ -1,2 +1,2 @@
CMake Error at .*/Tests/RunCMake/ctest_submit/RepeatRETURN_VALUE/test.cmake:[0-9]+ \(ctest_submit\):
- Called with more than one value for RETURN_VALUE
+ ctest_submit called with more than one value for RETURN_VALUE
diff --git a/Tests/RunCMake/find_file/Registry-query-stderr.txt b/Tests/RunCMake/find_file/Registry-query-stderr.txt
new file mode 100644
index 0000000..0532022
--- /dev/null
+++ b/Tests/RunCMake/find_file/Registry-query-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at Registry-query\.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0134 will be removed from a future version
+ of CMake\.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances\. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/find_library/Registry-query-stderr.txt b/Tests/RunCMake/find_library/Registry-query-stderr.txt
new file mode 100644
index 0000000..0532022
--- /dev/null
+++ b/Tests/RunCMake/find_library/Registry-query-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at Registry-query\.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0134 will be removed from a future version
+ of CMake\.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances\. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/find_package/Registry-query-stderr.txt b/Tests/RunCMake/find_package/Registry-query-stderr.txt
new file mode 100644
index 0000000..0532022
--- /dev/null
+++ b/Tests/RunCMake/find_package/Registry-query-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at Registry-query\.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0134 will be removed from a future version
+ of CMake\.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances\. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/find_path/Registry-query-stderr.txt b/Tests/RunCMake/find_path/Registry-query-stderr.txt
new file mode 100644
index 0000000..0532022
--- /dev/null
+++ b/Tests/RunCMake/find_path/Registry-query-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at Registry-query\.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0134 will be removed from a future version
+ of CMake\.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances\. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/find_program/Registry-query-stderr.txt b/Tests/RunCMake/find_program/Registry-query-stderr.txt
new file mode 100644
index 0000000..0532022
--- /dev/null
+++ b/Tests/RunCMake/find_program/Registry-query-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at Registry-query\.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0134 will be removed from a future version
+ of CMake\.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances\. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/get_filename_component/KnownComponents.cmake b/Tests/RunCMake/get_filename_component/KnownComponents.cmake
index c2762ad..34af12e 100644
--- a/Tests/RunCMake/get_filename_component/KnownComponents.cmake
+++ b/Tests/RunCMake/get_filename_component/KnownComponents.cmake
@@ -1,7 +1,7 @@
# Assertion macro
macro(check desc actual expect)
if(NOT "x${actual}" STREQUAL "x${expect}")
- message(SEND_ERROR "${desc}: got \"${actual}\", not \"${expect}\"")
+ message(SEND_ERROR "${desc}: got\n \"${actual}\"\nnot\n \"${expect}\"")
endif()
endmacro()
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/CMakeLists.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/CMakeLists.txt
new file mode 100644
index 0000000..a8cb6d1
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.30...3.32)
+
+project(${RunCMake_TEST} LANGUAGES NONE)
+
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-CMP0181-OLD-validation.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-CMP0181-OLD-validation.cmake
new file mode 100644
index 0000000..45855bc
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-CMP0181-OLD-validation.cmake
@@ -0,0 +1,5 @@
+
+if (NOT actual_stdout MATCHES "LINKER:-foo,bar")
+ set (RunCMake_TEST_FAILED "LINKER: prefix was expanded.")
+ return()
+endif()
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER-check.cmake
new file mode 100644
index 0000000..99f5aa3
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER-check.cmake
@@ -0,0 +1,3 @@
+
+set(reference_file "LINKER.txt")
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER_CONSUMER-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER_CONSUMER-check.cmake
new file mode 100644
index 0000000..99f5aa3
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER_CONSUMER-check.cmake
@@ -0,0 +1,3 @@
+
+set(reference_file "LINKER.txt")
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER_SHELL-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER_SHELL-check.cmake
new file mode 100644
index 0000000..99f5aa3
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-LINKER_SHELL-check.cmake
@@ -0,0 +1,3 @@
+
+set(reference_file "LINKER.txt")
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-validation.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-validation.cmake
new file mode 100644
index 0000000..27adde6
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion-validation.cmake
@@ -0,0 +1,15 @@
+
+if (actual_stdout MATCHES "LINKER:" AND NOT linker_prefix_expected)
+ set (RunCMake_TEST_FAILED "LINKER: prefix was not expanded.")
+ return()
+endif()
+
+if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/${reference_file}")
+ set (RunCMake_TEST_FAILED "${RunCMake_TEST_BINARY_DIR}/${reference_file}: Reference file not found.")
+ return()
+endif()
+file(READ "${RunCMake_TEST_BINARY_DIR}/${reference_file}" linker_flag)
+
+if (NOT actual_stdout MATCHES "${linker_flag}")
+ set (RunCMake_TEST_FAILED "LINKER: was not expanded correctly.")
+endif()
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion.cmake
new file mode 100644
index 0000000..f71efbd
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion.cmake
@@ -0,0 +1,63 @@
+
+enable_language(C)
+
+set(cfg_dir)
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ set(cfg_dir /Debug)
+endif()
+set(DUMP_EXE "${CMAKE_CURRENT_BINARY_DIR}${cfg_dir}/dump${CMAKE_EXECUTABLE_SUFFIX}")
+
+add_executable(dump dump.c)
+
+# ensure no temp file nor response file will be used
+set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES 0)
+string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}")
+string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}")
+
+function (add_test_library target_name)
+ add_library(${target_name} SHARED LinkOptionsLib.c)
+
+ # use LAUNCH facility to dump linker command
+ set_property(TARGET ${target_name} PROPERTY RULE_LAUNCH_LINK "\"${DUMP_EXE}\"")
+
+ add_dependencies(${target_name} dump)
+endfunction()
+
+# Use LINKER alone
+add_test_library(linker)
+target_link_libraries(linker PRIVATE "LINKER:-foo,bar")
+
+# Use LINKER with SHELL
+add_test_library(linker_shell)
+target_link_libraries(linker_shell PRIVATE "LINKER:SHELL:-foo bar")
+
+# Propagate LINKER
+add_library(linker_interface INTERFACE)
+target_link_libraries(linker_interface INTERFACE "LINKER:-foo,bar")
+add_test_library(linker_consumer)
+target_link_libraries(linker_consumer PRIVATE linker_interface)
+
+# generate reference for LINKER flag
+if (CMAKE_C_LINKER_WRAPPER_FLAG)
+ set(linker_flag ${CMAKE_C_LINKER_WRAPPER_FLAG})
+ list(GET linker_flag -1 linker_space)
+ if (linker_space STREQUAL " ")
+ list(REMOVE_AT linker_flag -1)
+ else()
+ set(linker_space)
+ endif()
+ list (JOIN linker_flag " " linker_flag)
+ if (CMAKE_C_LINKER_WRAPPER_FLAG_SEP)
+ set(linker_sep "${CMAKE_C_LINKER_WRAPPER_FLAG_SEP}")
+
+ string (APPEND linker_flag "${linker_space}" "-foo${linker_sep}bar")
+ else()
+ set(linker_prefix "${linker_flag}${linker_space}")
+
+ set (linker_flag "${linker_prefix}-foo ${linker_prefix}bar")
+ endif()
+else()
+ set(linker_flag "-foo bar")
+endif()
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/LINKER.txt" "${linker_flag}")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-EXE_LINKER_FLAGS-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-EXE_LINKER_FLAGS-check.cmake
new file mode 100644
index 0000000..99f5aa3
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-EXE_LINKER_FLAGS-check.cmake
@@ -0,0 +1,3 @@
+
+set(reference_file "LINKER.txt")
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-EXE_LINKER_FLAGS-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-EXE_LINKER_FLAGS-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-EXE_LINKER_FLAGS-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-MODULE_LINKER_FLAGS-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-MODULE_LINKER_FLAGS-check.cmake
new file mode 100644
index 0000000..99f5aa3
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-MODULE_LINKER_FLAGS-check.cmake
@@ -0,0 +1,3 @@
+
+set(reference_file "LINKER.txt")
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-MODULE_LINKER_FLAGS-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-MODULE_LINKER_FLAGS-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-MODULE_LINKER_FLAGS-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-SHARED_LINKER_FLAGS-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-SHARED_LINKER_FLAGS-check.cmake
new file mode 100644
index 0000000..99f5aa3
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-SHARED_LINKER_FLAGS-check.cmake
@@ -0,0 +1,3 @@
+
+set(reference_file "LINKER.txt")
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-SHARED_LINKER_FLAGS-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-SHARED_LINKER_FLAGS-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-NEW-SHARED_LINKER_FLAGS-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-EXE_LINKER_FLAGS-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-EXE_LINKER_FLAGS-check.cmake
new file mode 100644
index 0000000..e0d406f
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-EXE_LINKER_FLAGS-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-CMP0181-OLD-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-EXE_LINKER_FLAGS-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-EXE_LINKER_FLAGS-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-EXE_LINKER_FLAGS-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-MODULE_LINKER_FLAGS-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-MODULE_LINKER_FLAGS-check.cmake
new file mode 100644
index 0000000..e0d406f
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-MODULE_LINKER_FLAGS-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-CMP0181-OLD-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-MODULE_LINKER_FLAGS-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-MODULE_LINKER_FLAGS-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-MODULE_LINKER_FLAGS-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-SHARED_LINKER_FLAGS-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-SHARED_LINKER_FLAGS-check.cmake
new file mode 100644
index 0000000..e0d406f
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-SHARED_LINKER_FLAGS-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-CMP0181-OLD-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-SHARED_LINKER_FLAGS-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-SHARED_LINKER_FLAGS-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2-CMP0181-OLD-SHARED_LINKER_FLAGS-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2.cmake
new file mode 100644
index 0000000..7cf333a
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion2.cmake
@@ -0,0 +1,56 @@
+
+enable_language(C)
+
+cmake_policy(SET CMP0181 ${CMP0181})
+
+# ensure command line is always displayed and do not use any response file
+set(CMAKE_VERBOSE_MAKEFILE TRUE)
+
+if (CMAKE_GENERATOR MATCHES "Borland|NMake")
+ string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE}")
+ string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE}")
+
+ string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}")
+ string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}")
+
+ string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_MODULE "${CMAKE_C_CREATE_SHARED_MODULE}")
+ string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_MODULE "${CMAKE_C_CREATE_SHARED_MODULE}")
+endif()
+
+
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} LINKER:-foo,bar")
+add_executable(exe_linker_flags main.c)
+
+set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} LINKER:-foo,bar")
+add_library(shared_linker_flags SHARED LinkOptionsLib.c)
+
+set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} LINKER:-foo,bar")
+add_library(module_linker_flags MODULE LinkOptionsLib.c)
+
+
+# generate reference for LINKER flag
+if (CMP0181 STREQUAL "NEW")
+ if (CMAKE_C_LINKER_WRAPPER_FLAG)
+ set(linker_flag ${CMAKE_C_LINKER_WRAPPER_FLAG})
+ list(GET linker_flag -1 linker_space)
+ if (linker_space STREQUAL " ")
+ list(REMOVE_AT linker_flag -1)
+ else()
+ set(linker_space)
+ endif()
+ list (JOIN linker_flag " " linker_flag)
+ if (CMAKE_C_LINKER_WRAPPER_FLAG_SEP)
+ set(linker_sep "${CMAKE_C_LINKER_WRAPPER_FLAG_SEP}")
+
+ string (APPEND linker_flag "${linker_space}" "-foo${linker_sep}bar")
+ else()
+ set(linker_prefix "${linker_flag}${linker_space}")
+
+ set (linker_flag "${linker_prefix}-foo ${linker_prefix}bar")
+ endif()
+ else()
+ set(linker_flag "-foo bar")
+ endif()
+
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/LINKER.txt" "${linker_flag}")
+endif()
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_EXE_CREATE_LINK_FLAGS-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_EXE_CREATE_LINK_FLAGS-check.cmake
new file mode 100644
index 0000000..99f5aa3
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_EXE_CREATE_LINK_FLAGS-check.cmake
@@ -0,0 +1,3 @@
+
+set(reference_file "LINKER.txt")
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_EXE_CREATE_LINK_FLAGS-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_EXE_CREATE_LINK_FLAGS-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_EXE_CREATE_LINK_FLAGS-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_MODULE_CREATE_LINK_FLAGS-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_MODULE_CREATE_LINK_FLAGS-check.cmake
new file mode 100644
index 0000000..99f5aa3
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_MODULE_CREATE_LINK_FLAGS-check.cmake
@@ -0,0 +1,3 @@
+
+set(reference_file "LINKER.txt")
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_MODULE_CREATE_LINK_FLAGS-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_MODULE_CREATE_LINK_FLAGS-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_MODULE_CREATE_LINK_FLAGS-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_SHARED_CREATE_LINK_FLAGS-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_SHARED_CREATE_LINK_FLAGS-check.cmake
new file mode 100644
index 0000000..99f5aa3
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_SHARED_CREATE_LINK_FLAGS-check.cmake
@@ -0,0 +1,3 @@
+
+set(reference_file "LINKER.txt")
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_SHARED_CREATE_LINK_FLAGS-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_SHARED_CREATE_LINK_FLAGS-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-NEW-C_SHARED_CREATE_LINK_FLAGS-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_EXE_CREATE_LINK_FLAGS-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_EXE_CREATE_LINK_FLAGS-check.cmake
new file mode 100644
index 0000000..e0d406f
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_EXE_CREATE_LINK_FLAGS-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-CMP0181-OLD-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_EXE_CREATE_LINK_FLAGS-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_EXE_CREATE_LINK_FLAGS-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_EXE_CREATE_LINK_FLAGS-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_MODULE_CREATE_LINK_FLAGS-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_MODULE_CREATE_LINK_FLAGS-check.cmake
new file mode 100644
index 0000000..e0d406f
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_MODULE_CREATE_LINK_FLAGS-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-CMP0181-OLD-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_MODULE_CREATE_LINK_FLAGS-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_MODULE_CREATE_LINK_FLAGS-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_MODULE_CREATE_LINK_FLAGS-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_SHARED_CREATE_LINK_FLAGS-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_SHARED_CREATE_LINK_FLAGS-check.cmake
new file mode 100644
index 0000000..e0d406f
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_SHARED_CREATE_LINK_FLAGS-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-CMP0181-OLD-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_SHARED_CREATE_LINK_FLAGS-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_SHARED_CREATE_LINK_FLAGS-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3-CMP0181-OLD-C_SHARED_CREATE_LINK_FLAGS-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3.cmake
new file mode 100644
index 0000000..301570b
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion3.cmake
@@ -0,0 +1,55 @@
+
+enable_language(C)
+
+cmake_policy(SET CMP0181 ${CMP0181})
+
+# ensure command line is always displayed and do not use any response file
+set(CMAKE_VERBOSE_MAKEFILE TRUE)
+
+if (CMAKE_GENERATOR MATCHES "Borland|NMake")
+ string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE}")
+ string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE}")
+
+ string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}")
+ string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}")
+
+ string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_MODULE "${CMAKE_C_CREATE_SHARED_MODULE}")
+ string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_CREATE_SHARED_MODULE "${CMAKE_C_CREATE_SHARED_MODULE}")
+endif()
+
+
+set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} LINKER:-foo,bar")
+add_executable(c_exe_create_link_flags main.c)
+
+set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS} LINKER:-foo,bar")
+add_library(c_shared_create_link_flags SHARED LinkOptionsLib.c)
+
+set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS "${CMAKE_SHARED_MODULE_CREATE_C_FLAGS} LINKER:-foo,bar")
+add_library(c_module_create_link_flags MODULE LinkOptionsLib.c)
+
+# generate reference for LINKER flag
+if (CMP0181 STREQUAL "NEW")
+ if (CMAKE_C_LINKER_WRAPPER_FLAG)
+ set(linker_flag ${CMAKE_C_LINKER_WRAPPER_FLAG})
+ list(GET linker_flag -1 linker_space)
+ if (linker_space STREQUAL " ")
+ list(REMOVE_AT linker_flag -1)
+ else()
+ set(linker_space)
+ endif()
+ list (JOIN linker_flag " " linker_flag)
+ if (CMAKE_C_LINKER_WRAPPER_FLAG_SEP)
+ set(linker_sep "${CMAKE_C_LINKER_WRAPPER_FLAG_SEP}")
+
+ string (APPEND linker_flag "${linker_space}" "-foo${linker_sep}bar")
+ else()
+ set(linker_prefix "${linker_flag}${linker_space}")
+
+ set (linker_flag "${linker_prefix}-foo ${linker_prefix}bar")
+ endif()
+ else()
+ set(linker_flag "-foo bar")
+ endif()
+
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/LINKER.txt" "${linker_flag}")
+endif()
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-NEW-C_CREATE_CONSOLE_EXE-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-NEW-C_CREATE_CONSOLE_EXE-check.cmake
new file mode 100644
index 0000000..99f5aa3
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-NEW-C_CREATE_CONSOLE_EXE-check.cmake
@@ -0,0 +1,3 @@
+
+set(reference_file "LINKER.txt")
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-NEW-C_CREATE_CONSOLE_EXE-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-NEW-C_CREATE_CONSOLE_EXE-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-NEW-C_CREATE_CONSOLE_EXE-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-NEW-C_CREATE_WIN32_EXE-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-NEW-C_CREATE_WIN32_EXE-check.cmake
new file mode 100644
index 0000000..99f5aa3
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-NEW-C_CREATE_WIN32_EXE-check.cmake
@@ -0,0 +1,3 @@
+
+set(reference_file "LINKER.txt")
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-NEW-C_CREATE_WIN32_EXE-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-NEW-C_CREATE_WIN32_EXE-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-NEW-C_CREATE_WIN32_EXE-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-OLD-C_CREATE_CONSOLE_EXE-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-OLD-C_CREATE_CONSOLE_EXE-check.cmake
new file mode 100644
index 0000000..e0d406f
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-OLD-C_CREATE_CONSOLE_EXE-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-CMP0181-OLD-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-OLD-C_CREATE_CONSOLE_EXE-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-OLD-C_CREATE_CONSOLE_EXE-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-OLD-C_CREATE_CONSOLE_EXE-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-OLD-C_CREATE_WIN32_EXE-check.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-OLD-C_CREATE_WIN32_EXE-check.cmake
new file mode 100644
index 0000000..e0d406f
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-OLD-C_CREATE_WIN32_EXE-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${CMAKE_CURRENT_LIST_DIR}/LINKER_expansion-CMP0181-OLD-validation.cmake")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-OLD-C_CREATE_WIN32_EXE-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-OLD-C_CREATE_WIN32_EXE-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4-CMP0181-OLD-C_CREATE_WIN32_EXE-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4.cmake
new file mode 100644
index 0000000..4e88e91
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LINKER_expansion4.cmake
@@ -0,0 +1,47 @@
+
+enable_language(C)
+
+cmake_policy(SET CMP0181 ${CMP0181})
+
+# ensure command line is always displayed and do not use any response file
+set(CMAKE_VERBOSE_MAKEFILE TRUE)
+
+if (CMAKE_GENERATOR MATCHES "Borland|NMake")
+ string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE}")
+ string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE}")
+endif()
+
+
+set(CMAKE_C_CREATE_WIN32_EXE "${CMAKE_C_CREATE_WIN32_EXE} LINKER:-foo,bar")
+add_executable (c_create_win32_exe WIN32 main.c)
+
+set(CMAKE_C_CREATE_CONSOLE_EXE "${CMAKE_C_CREATE_CONSOLE_EXE} LINKER:-foo,bar")
+add_executable(c_create_console_exe main.c)
+
+
+# generate reference for LINKER flag
+if (CMP0181 STREQUAL "NEW")
+ if (CMAKE_C_LINKER_WRAPPER_FLAG)
+ set(linker_flag ${CMAKE_C_LINKER_WRAPPER_FLAG})
+ list(GET linker_flag -1 linker_space)
+ if (linker_space STREQUAL " ")
+ list(REMOVE_AT linker_flag -1)
+ else()
+ set(linker_space)
+ endif()
+ list (JOIN linker_flag " " linker_flag)
+ if (CMAKE_C_LINKER_WRAPPER_FLAG_SEP)
+ set(linker_sep "${CMAKE_C_LINKER_WRAPPER_FLAG_SEP}")
+
+ string (APPEND linker_flag "${linker_space}" "-foo${linker_sep}bar")
+ else()
+ set(linker_prefix "${linker_flag}${linker_space}")
+
+ set (linker_flag "${linker_prefix}-foo ${linker_prefix}bar")
+ endif()
+ else()
+ set(linker_flag "-foo bar")
+ endif()
+
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/LINKER.txt" "${linker_flag}")
+endif()
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/LinkOptionsLib.c b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LinkOptionsLib.c
new file mode 100644
index 0000000..9bbd24c
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/LinkOptionsLib.c
@@ -0,0 +1,7 @@
+#if defined(_WIN32)
+__declspec(dllexport)
+#endif
+ int flags_lib(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/RunCMakeTest.cmake
new file mode 100644
index 0000000..5cfd519
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/RunCMakeTest.cmake
@@ -0,0 +1,59 @@
+
+include(RunCMake)
+
+macro(run_cmake_target test subtest target)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(${test}-${subtest} ${CMAKE_COMMAND} --build . --target ${target} ${ARGN})
+
+ unset(RunCMake_TEST_BINARY_DIR)
+ unset(RunCMake_TEST_NO_CLEAN)
+endmacro()
+
+
+run_cmake(bad_SHELL_usage)
+
+if(RunCMake_GENERATOR MATCHES "(Ninja|Makefile)")
+ run_cmake(LINKER_expansion)
+
+ run_cmake_target(LINKER_expansion LINKER linker)
+ run_cmake_target(LINKER_expansion LINKER_SHELL linker_shell)
+ run_cmake_target(LINKER_expansion LINKER_CONSUMER linker_consumer)
+endif()
+
+# Some environments are excluded because they are not able to honor verbose mode
+if (RunCMake_GENERATOR MATCHES "Makefiles|Ninja|Xcode|Visual Studio"
+ AND NOT CMAKE_C_COMPILER_ID STREQUAL "Intel")
+ set(RunCMake_TEST_OUTPUT_MERGE TRUE)
+
+ foreach(policy IN ITEMS OLD NEW)
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/LINKER_expansion2-CMP0181-${policy}-build)
+ run_cmake_with_options(LINKER_expansion2 -DCMP0181=${policy})
+
+ run_cmake_target(LINKER_expansion2-CMP0181-${policy} EXE_LINKER_FLAGS exe_linker_flags --verbose)
+ run_cmake_target(LINKER_expansion2-CMP0181-${policy} SHARED_LINKER_FLAGS shared_linker_flags --verbose)
+ run_cmake_target(LINKER_expansion2-CMP0181-${policy} MODULE_LINKER_FLAGS module_linker_flags --verbose)
+
+
+ if (NOT (RunCMake_GENERATOR MATCHES "Visual Studio" OR CMAKE_C_COMPILER_ID MATCHES "Borland|Embarcadero"))
+ # Visual Studio generator and Borland, Embarcadero compilers do not use these variables
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/LINKER_expansion3-CMP0181-${policy}-build)
+ run_cmake_with_options(LINKER_expansion3 -DCMP0181=${policy})
+
+ run_cmake_target(LINKER_expansion3-CMP0181-${policy} C_EXE_CREATE_LINK_FLAGS c_exe_create_link_flags --verbose)
+ if (NOT (CMAKE_C_COMPILER_ID STREQUAL "MSVC" OR CMAKE_C_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC"))
+ # MSVC compiler does not use these variables
+ run_cmake_target(LINKER_expansion3-CMP0181-${policy} C_SHARED_CREATE_LINK_FLAGS c_shared_create_link_flags --verbose)
+ run_cmake_target(LINKER_expansion3-CMP0181-${policy} C_MODULE_CREATE_LINK_FLAGS c_module_create_link_flags --verbose)
+ endif()
+
+ if (CMAKE_SYSTEM_NAME MATCHES "Windows")
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/LINKER_expansion4-CMP0181-${policy}-build)
+ run_cmake_with_options(LINKER_expansion4 -DCMP0181=${policy})
+
+ run_cmake_target(LINKER_expansion4-CMP0181-${policy} C_CREATE_WIN32_EXE c_create_win32_exe --verbose)
+ run_cmake_target(LINKER_expansion4-CMP0181-${policy} C_CREATE_CONSOLE_EXE c_create_console_exe --verbose)
+ endif()
+ endif()
+ endforeach()
+endif()
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage-result.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage-stderr.txt b/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage-stderr.txt
new file mode 100644
index 0000000..d6a298d
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at bad_SHELL_usage.cmake:[0-9]+ \(add_library\):
+ 'SHELL:' prefix is not supported as part of 'LINKER:' arguments.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage.cmake b/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage.cmake
new file mode 100644
index 0000000..e25bef6
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/bad_SHELL_usage.cmake
@@ -0,0 +1,5 @@
+
+enable_language(C)
+
+add_library(example SHARED LinkOptionsLib.c)
+target_link_libraries(example PRIVATE "LINKER:-foo,SHELL:-bar")
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/dump.c b/Tests/RunCMake/target_link_libraries-LINKER-prefix/dump.c
new file mode 100644
index 0000000..8baa313
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/dump.c
@@ -0,0 +1,13 @@
+
+#include "stdio.h"
+
+int main(int argc, char* argv[])
+{
+ int i;
+
+ for (i = 1; i < argc; i++)
+ printf("%s ", argv[i]);
+ printf("\n");
+
+ return 0;
+}
diff --git a/Tests/RunCMake/target_link_libraries-LINKER-prefix/main.c b/Tests/RunCMake/target_link_libraries-LINKER-prefix/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-LINKER-prefix/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/while/CMP0130-OLD-stderr.txt b/Tests/RunCMake/while/CMP0130-OLD-stderr.txt
new file mode 100644
index 0000000..e673966
--- /dev/null
+++ b/Tests/RunCMake/while/CMP0130-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0130-OLD\.cmake:[0-9]+ \(cmake_policy\):
+ The OLD behavior for policy CMP0130 will be removed from a future version
+ of CMake\.
+
+ The cmake-policies\(7\) manual explains that the OLD behaviors of all
+ policies are deprecated and that a policy should be set to OLD only under
+ specific short-term circumstances\. Projects should be ported to the NEW
+ behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/SwiftOnly/CMakeLists.txt b/Tests/SwiftOnly/CMakeLists.txt
index ba36c10..26f75f3 100644
--- a/Tests/SwiftOnly/CMakeLists.txt
+++ b/Tests/SwiftOnly/CMakeLists.txt
@@ -32,6 +32,8 @@
add_subdirectory(SubD)
add_subdirectory(SubE)
+add_subdirectory("Sub Space")
+
set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift)
add_executable(SwiftOnly main.swift)
diff --git a/Tests/SwiftOnly/Sub Space/CMakeLists.txt b/Tests/SwiftOnly/Sub Space/CMakeLists.txt
new file mode 100644
index 0000000..ac4cd18
--- /dev/null
+++ b/Tests/SwiftOnly/Sub Space/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(SubSpace SubSpace.swift)
diff --git a/Tests/SwiftOnly/Sub Space/SubSpace.swift b/Tests/SwiftOnly/Sub Space/SubSpace.swift
new file mode 100644
index 0000000..d17aa41
--- /dev/null
+++ b/Tests/SwiftOnly/Sub Space/SubSpace.swift
@@ -0,0 +1 @@
+public func space() { print("space") }
diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt
index 111bd6f..64f9a3f 100644
--- a/Utilities/Doxygen/CMakeLists.txt
+++ b/Utilities/Doxygen/CMakeLists.txt
@@ -3,7 +3,7 @@
if(NOT CMake_SOURCE_DIR)
set(CMakeDeveloperReference_STANDALONE 1)
- cmake_minimum_required(VERSION 3.13...3.29 FATAL_ERROR)
+ cmake_minimum_required(VERSION 3.13...3.30 FATAL_ERROR)
get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt
index ed7b631..a919b91 100644
--- a/Utilities/Sphinx/CMakeLists.txt
+++ b/Utilities/Sphinx/CMakeLists.txt
@@ -3,7 +3,7 @@
if(NOT CMake_SOURCE_DIR)
set(CMakeHelp_STANDALONE 1)
- cmake_minimum_required(VERSION 3.13...3.29 FATAL_ERROR)
+ cmake_minimum_required(VERSION 3.13...3.30 FATAL_ERROR)
get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
diff --git a/Utilities/Sphinx/conf.py.in b/Utilities/Sphinx/conf.py.in
index dca6794..8ff9b0e 100644
--- a/Utilities/Sphinx/conf.py.in
+++ b/Utilities/Sphinx/conf.py.in
@@ -91,7 +91,8 @@
linkcheck_ignore = [
r'about:',
r'https://gitlab\.kitware\.com/cmake/community/-/wikis/doc/cpack',
- r'https://www.intel.com/',
+ r'https://www\.intel\.com/',
+ r'https://www\.tasking\.com($|/)',
]
linkcheck_allowed_redirects = {
diff --git a/Utilities/cmlibuv/include/uv.h b/Utilities/cmlibuv/include/uv.h
index 42e3446..94113d1 100644
--- a/Utilities/cmlibuv/include/uv.h
+++ b/Utilities/cmlibuv/include/uv.h
@@ -1087,7 +1087,13 @@
* search for the exact file name before trying variants with
* extensions like '.exe' or '.cmd'.
*/
- UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME = (1 << 7)
+ UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME = (1 << 7),
+ /*
+ * Spawn the child process with the error mode of its parent.
+ * This option is only meaningful on Windows systems. On Unix
+ * it is silently ignored.
+ */
+ UV_PROCESS_WINDOWS_USE_PARENT_ERROR_MODE = (1 << 8)
};
/*
diff --git a/Utilities/cmlibuv/src/unix/process.c b/Utilities/cmlibuv/src/unix/process.c
index ebe185d..729a44b 100644
--- a/Utilities/cmlibuv/src/unix/process.c
+++ b/Utilities/cmlibuv/src/unix/process.c
@@ -1033,7 +1033,8 @@
UV_PROCESS_WINDOWS_HIDE |
UV_PROCESS_WINDOWS_HIDE_CONSOLE |
UV_PROCESS_WINDOWS_HIDE_GUI |
- UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS |
+ UV_PROCESS_WINDOWS_USE_PARENT_ERROR_MODE)));
uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
QUEUE_INIT(&process->queue);
diff --git a/Utilities/cmlibuv/src/win/process.c b/Utilities/cmlibuv/src/win/process.c
index 5cf9fb8..59db8f8 100644
--- a/Utilities/cmlibuv/src/win/process.c
+++ b/Utilities/cmlibuv/src/win/process.c
@@ -90,7 +90,6 @@
info.BasicLimitInformation.LimitFlags =
JOB_OBJECT_LIMIT_BREAKAWAY_OK |
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK |
- JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION |
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
uv_global_job_handle_ = CreateJobObjectW(&attr, NULL);
@@ -993,7 +992,8 @@
UV_PROCESS_WINDOWS_HIDE |
UV_PROCESS_WINDOWS_HIDE_CONSOLE |
UV_PROCESS_WINDOWS_HIDE_GUI |
- UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS |
+ UV_PROCESS_WINDOWS_USE_PARENT_ERROR_MODE)));
err = uv__utf8_to_utf16_alloc(options->file, &application);
if (err)
@@ -1097,7 +1097,10 @@
startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);
- process_flags = CREATE_UNICODE_ENVIRONMENT;
+ process_flags = CREATE_UNICODE_ENVIRONMENT | CREATE_DEFAULT_ERROR_MODE;
+ if (options->flags & UV_PROCESS_WINDOWS_USE_PARENT_ERROR_MODE) {
+ process_flags &= ~(CREATE_DEFAULT_ERROR_MODE);
+ }
if ((options->flags & UV_PROCESS_WINDOWS_HIDE_CONSOLE) ||
(options->flags & UV_PROCESS_WINDOWS_HIDE)) {
diff --git a/bootstrap b/bootstrap
index 53358d5..b41197f 100755
--- a/bootstrap
+++ b/bootstrap
@@ -315,7 +315,6 @@
cmCMakePolicyCommand \
cmCPackPropertiesGenerator \
cmCacheManager \
- cmCommand \
cmCommandArgumentParserHelper \
cmCommands \
cmCommonTargetGenerator \
@@ -459,6 +458,7 @@
cmOutputConverter \
cmParseArgumentsCommand \
cmPathLabel \
+ cmPathResolver \
cmPolicies \
cmProcessOutput \
cmProjectCommand \
@@ -843,7 +843,6 @@
s/@KWSYS_NAME_IS_KWSYS@/${KWSYS_NAME_IS_KWSYS}/g;
s/@KWSYS_STL_HAS_WSTRING@/${KWSYS_STL_HAS_WSTRING}/g;
s/@KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H@/${KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H}/g;
- s/@KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP@/${KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP}/g;
}" "${INFILE}" >> "${OUTFILE}${_tmp}"
if test -f "${OUTFILE}${_tmp}"; then
if "${_diff}" "${OUTFILE}" "${OUTFILE}${_tmp}" > /dev/null 2> /dev/null ; then
@@ -1563,7 +1562,6 @@
KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H=0
KWSYS_CXX_HAS_UTIMENSAT=0
KWSYS_CXX_HAS_UTIMES=0
-KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP=1
if cmake_try_run "${cmake_cxx_compiler}" \
"${cmake_cxx_flags} ${cmake_ld_flags} -DTEST_KWSYS_CXX_HAS_SETENV" \