New upstream version 3.28.2
This commit is contained in:
		
							parent
							
								
									a9633ce77d
								
							
						
					
					
						commit
						da192a20c6
					
				@ -5,11 +5,11 @@ Get a global property of the CMake instance.
 | 
			
		||||
 | 
			
		||||
.. code-block:: cmake
 | 
			
		||||
 | 
			
		||||
  get_cmake_property(<var> <property>)
 | 
			
		||||
  get_cmake_property(<variable> <property>)
 | 
			
		||||
 | 
			
		||||
Gets a global property from the CMake instance.  The value of
 | 
			
		||||
the ``<property>`` is stored in the variable ``<var>``.
 | 
			
		||||
If the property is not found, ``<var>`` will be set to ``NOTFOUND``.
 | 
			
		||||
the ``<property>`` is stored in the specified ``<variable>``.
 | 
			
		||||
If the property is not found, ``<variable>`` will be set to ``NOTFOUND``.
 | 
			
		||||
See the :manual:`cmake-properties(7)` manual for available properties.
 | 
			
		||||
 | 
			
		||||
In addition to global properties, this command (for historical reasons)
 | 
			
		||||
 | 
			
		||||
@ -9,14 +9,12 @@ Get a property for a source file.
 | 
			
		||||
                           [DIRECTORY <dir> | TARGET_DIRECTORY <target>]
 | 
			
		||||
                           <property>)
 | 
			
		||||
 | 
			
		||||
Gets a property from a source file.  The value of the property is
 | 
			
		||||
stored in the specified ``<variable>``.  If the source property is not found,
 | 
			
		||||
the behavior depends on whether it has been defined to be an ``INHERITED``
 | 
			
		||||
property or not (see :command:`define_property`).  Non-inherited properties
 | 
			
		||||
will set ``variable`` to ``NOTFOUND``, whereas inherited properties will search
 | 
			
		||||
the relevant parent scope as described for the :command:`define_property`
 | 
			
		||||
command and if still unable to find the property, ``variable`` will be set to
 | 
			
		||||
an empty string.
 | 
			
		||||
Gets a property from a source file.  The value of the property is stored in
 | 
			
		||||
the specified ``<variable>``.  If the ``<file>`` is not a source file, or the
 | 
			
		||||
source property is not found, ``<variable>`` will be set to ``NOTFOUND``.
 | 
			
		||||
If the source property was defined to be an ``INHERITED`` property (see
 | 
			
		||||
:command:`define_property`), the search will include the relevant parent
 | 
			
		||||
scopes, as described for the :command:`define_property` command.
 | 
			
		||||
 | 
			
		||||
By default, the source file's property will be read from the current source
 | 
			
		||||
directory's scope.
 | 
			
		||||
 | 
			
		||||
@ -5,16 +5,14 @@ Get a property from a target.
 | 
			
		||||
 | 
			
		||||
.. code-block:: cmake
 | 
			
		||||
 | 
			
		||||
  get_target_property(<VAR> target property)
 | 
			
		||||
  get_target_property(<variable> <target> <property>)
 | 
			
		||||
 | 
			
		||||
Get a property from a target.  The value of the property is stored in
 | 
			
		||||
the variable ``<VAR>``.  If the target property is not found, the behavior
 | 
			
		||||
depends on whether it has been defined to be an ``INHERITED`` property
 | 
			
		||||
or not (see :command:`define_property`).  Non-inherited properties will
 | 
			
		||||
set ``<VAR>`` to ``<VAR>-NOTFOUND``, whereas inherited properties will search
 | 
			
		||||
the relevant parent scope as described for the :command:`define_property`
 | 
			
		||||
command and if still unable to find the property, ``<VAR>`` will be set to
 | 
			
		||||
an empty string.
 | 
			
		||||
Get a property from a target.  The value of the property is stored in the
 | 
			
		||||
specified ``<variable>``.  If the target property is not found, ``<variable>``
 | 
			
		||||
will be set to ``<variable>-NOTFOUND``.  If the target property was defined to
 | 
			
		||||
be an ``INHERITED`` property (see :command:`define_property`), the search will
 | 
			
		||||
include the relevant parent scopes, as described for the
 | 
			
		||||
:command:`define_property` command.
 | 
			
		||||
 | 
			
		||||
Use :command:`set_target_properties` to set target property values.
 | 
			
		||||
Properties are usually used to control how a target is built, but some
 | 
			
		||||
 | 
			
		||||
@ -5,16 +5,14 @@ Get a property of the test.
 | 
			
		||||
 | 
			
		||||
.. code-block:: cmake
 | 
			
		||||
 | 
			
		||||
  get_test_property(test property [DIRECTORY <dir>] VAR)
 | 
			
		||||
  get_test_property(<test> <property> [DIRECTORY <dir>] <variable>)
 | 
			
		||||
 | 
			
		||||
Get a property from the test.  The value of the property is stored in
 | 
			
		||||
the variable ``VAR``.  If the test property is not found, the behavior
 | 
			
		||||
depends on whether it has been defined to be an ``INHERITED`` property
 | 
			
		||||
or not (see :command:`define_property`).  Non-inherited properties will
 | 
			
		||||
set ``VAR`` to "NOTFOUND", whereas inherited properties will search the
 | 
			
		||||
relevant parent scope as described for the :command:`define_property`
 | 
			
		||||
command and if still unable to find the property, ``VAR`` will be set to
 | 
			
		||||
an empty string.
 | 
			
		||||
the specified ``<variable>``.  If the ``<test>`` is not defined, or the
 | 
			
		||||
test property is not found, ``<variable>`` will be set to ``NOTFOUND``.
 | 
			
		||||
If the test property was defined to be an ``INHERITED`` property (see
 | 
			
		||||
:command:`define_property`), the search will include the relevant parent
 | 
			
		||||
scopes, as described for the :command:`define_property` command.
 | 
			
		||||
 | 
			
		||||
For a list of standard properties you can type
 | 
			
		||||
:option:`cmake --help-property-list`.
 | 
			
		||||
 | 
			
		||||
@ -5,9 +5,10 @@ Set properties of the current directory and subdirectories.
 | 
			
		||||
 | 
			
		||||
.. code-block:: cmake
 | 
			
		||||
 | 
			
		||||
  set_directory_properties(PROPERTIES prop1 value1 [prop2 value2] ...)
 | 
			
		||||
  set_directory_properties(PROPERTIES <prop1> <value1> [<prop2> <value2>] ...)
 | 
			
		||||
 | 
			
		||||
Sets properties of the current directory and its subdirectories in key-value pairs.
 | 
			
		||||
Sets properties of the current directory and its subdirectories in key-value
 | 
			
		||||
pairs.
 | 
			
		||||
 | 
			
		||||
See also the :command:`set_property(DIRECTORY)` command.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -5,9 +5,9 @@ Targets can have properties that affect how they are built.
 | 
			
		||||
 | 
			
		||||
.. code-block:: cmake
 | 
			
		||||
 | 
			
		||||
  set_target_properties(target1 target2 ...
 | 
			
		||||
                        PROPERTIES prop1 value1
 | 
			
		||||
                        prop2 value2 ...)
 | 
			
		||||
  set_target_properties(<targets> ...
 | 
			
		||||
                        PROPERTIES <prop1> <value1>
 | 
			
		||||
                        [<prop2> <value2>] ...)
 | 
			
		||||
 | 
			
		||||
Sets properties on targets.  The syntax for the command is to list all
 | 
			
		||||
the targets you want to change, and then provide the values you want to
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,10 @@ Set a property of the tests.
 | 
			
		||||
 | 
			
		||||
.. code-block:: cmake
 | 
			
		||||
 | 
			
		||||
  set_tests_properties(test1 [test2...] PROPERTIES prop1 value1 prop2 value2)
 | 
			
		||||
  set_tests_properties(<tests>...
 | 
			
		||||
                       [DIRECTORY <dir>]
 | 
			
		||||
                       PROPERTIES <prop1> <value1>
 | 
			
		||||
                       [<prop2> <value2>]...)
 | 
			
		||||
 | 
			
		||||
Sets a property for the tests.  If the test is not found, CMake
 | 
			
		||||
will report an error.
 | 
			
		||||
 | 
			
		||||
@ -22,7 +22,7 @@ Synopsis
 | 
			
		||||
    string(`JOIN`_ <glue> <out-var> [<input>...])
 | 
			
		||||
    string(`TOLOWER`_ <string> <out-var>)
 | 
			
		||||
    string(`TOUPPER`_ <string> <out-var>)
 | 
			
		||||
    string(`LENGTH`_ <string> <out-var>)
 | 
			
		||||
    string(`LENGTH <LENGTH_>`_ <string> <out-var>)
 | 
			
		||||
    string(`SUBSTRING`_ <string> <begin> <length> <out-var>)
 | 
			
		||||
    string(`STRIP`_ <string> <out-var>)
 | 
			
		||||
    string(`GENEX_STRIP`_ <string> <out-var>)
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,10 @@ following queries. The first query that provides a yes/no answer is used.
 | 
			
		||||
- Otherwise, the source file will be scanned if the compiler and generator
 | 
			
		||||
  support scanning.  See policy :policy:`CMP0155`.
 | 
			
		||||
 | 
			
		||||
Note that any scanned source will be excluded from any unity build (see
 | 
			
		||||
:prop_tgt:`UNITY_BUILD`) because module-related statements can only happen at
 | 
			
		||||
one place within a C++ translation unit.
 | 
			
		||||
 | 
			
		||||
Compiler Support
 | 
			
		||||
================
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -224,7 +224,7 @@ For example::
 | 
			
		||||
 They interpret the opening bracket as the start of an
 | 
			
		||||
 `Unquoted Argument`_.
 | 
			
		||||
 | 
			
		||||
.. _`Lua`: http://www.lua.org/
 | 
			
		||||
.. _`Lua`: https://www.lua.org/
 | 
			
		||||
 | 
			
		||||
.. _`Quoted Argument`:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -583,7 +583,7 @@ generator is recommended.  The :generator:`Unix Makefiles` or
 | 
			
		||||
:generator:`Ninja` generators can also be used, but they require the
 | 
			
		||||
project to handle more areas like target CPU selection and code signing.
 | 
			
		||||
 | 
			
		||||
Any of the three systems can be targeted by setting the
 | 
			
		||||
Any of the Apple device platforms can be targeted by setting the
 | 
			
		||||
:variable:`CMAKE_SYSTEM_NAME` variable to a value from the table below.
 | 
			
		||||
By default, the latest Device SDK is chosen.  As for all Apple platforms,
 | 
			
		||||
a different SDK (e.g. a simulator) can be selected by setting the
 | 
			
		||||
@ -611,9 +611,11 @@ Variable :variable:`CMAKE_OSX_ARCHITECTURES` can be used to set architectures
 | 
			
		||||
for both device and simulator. Variable :variable:`CMAKE_OSX_DEPLOYMENT_TARGET`
 | 
			
		||||
can be used to set an iOS/tvOS/visionOS/watchOS deployment target.
 | 
			
		||||
 | 
			
		||||
Next configuration will install fat 5 architectures iOS library
 | 
			
		||||
and add the ``-miphoneos-version-min=9.3``/``-mios-simulator-version-min=9.3``
 | 
			
		||||
flags to the compiler:
 | 
			
		||||
The next example installs five architectures in a universal binary for an iOS
 | 
			
		||||
library.  It adds the relevant ``-miphoneos-version-min=9.3`` or
 | 
			
		||||
``-mios-simulator-version-min=9.3`` compiler flag where appropriate.
 | 
			
		||||
Note that the :variable:`CMAKE_IOS_INSTALL_COMBINED` variable used in the
 | 
			
		||||
example is now deprecated, so this approach is no longer recommended.
 | 
			
		||||
 | 
			
		||||
.. code-block:: console
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1592,17 +1592,20 @@ that running several of these tests at once does not exhaust the GPU's memory
 | 
			
		||||
pool.
 | 
			
		||||
 | 
			
		||||
Please note that CTest has no concept of what a GPU is or how much memory it
 | 
			
		||||
has, nor does it have any way of communicating with a GPU to retrieve this
 | 
			
		||||
information or perform any memory management. CTest simply keeps track of a
 | 
			
		||||
list of abstract resource types, each of which has a certain number of slots
 | 
			
		||||
available for tests to use. Each test specifies the number of slots that it
 | 
			
		||||
requires from a certain resource, and CTest then schedules them in a way that
 | 
			
		||||
prevents the total number of slots in use from exceeding the listed capacity.
 | 
			
		||||
When a test is executed, and slots from a resource are allocated to that test,
 | 
			
		||||
tests may assume that they have exclusive use of those slots for the duration
 | 
			
		||||
of the test's process.
 | 
			
		||||
has. It does not have any way of communicating with a GPU to retrieve this
 | 
			
		||||
information or perform any memory management, although the project can define
 | 
			
		||||
a test that provides details about the test machine (see
 | 
			
		||||
:ref:`ctest-resource-dynamically-generated-spec-file`).
 | 
			
		||||
 | 
			
		||||
The CTest resource allocation feature consists of two inputs:
 | 
			
		||||
CTest keeps track of a list of abstract resource types, each of which has a
 | 
			
		||||
certain number of slots available for tests to use. Each test specifies the
 | 
			
		||||
number of slots that it requires from a certain resource, and CTest then
 | 
			
		||||
schedules them in a way that prevents the total number of slots in use from
 | 
			
		||||
exceeding the listed capacity. When a test is executed, and slots from a
 | 
			
		||||
resource are allocated to that test, tests may assume that they have exclusive
 | 
			
		||||
use of those slots for the duration of the test's process.
 | 
			
		||||
 | 
			
		||||
The CTest resource allocation feature consists of at least two inputs:
 | 
			
		||||
 | 
			
		||||
* The :ref:`resource specification file <ctest-resource-specification-file>`,
 | 
			
		||||
  described below, which describes the resources available on the system.
 | 
			
		||||
@ -1643,15 +1646,20 @@ properties to indicate a skipped test.
 | 
			
		||||
Resource Specification File
 | 
			
		||||
---------------------------
 | 
			
		||||
 | 
			
		||||
The resource specification file is a JSON file which is passed to CTest, either
 | 
			
		||||
on the command line as :option:`ctest --resource-spec-file`, or as the
 | 
			
		||||
``RESOURCE_SPEC_FILE`` argument of :command:`ctest_test`. If a dashboard script
 | 
			
		||||
is used and ``RESOURCE_SPEC_FILE`` is not specified, the value of
 | 
			
		||||
:variable:`CTEST_RESOURCE_SPEC_FILE` in the dashboard script is used instead.
 | 
			
		||||
If :option:`--resource-spec-file <ctest --resource-spec-file>`, ``RESOURCE_SPEC_FILE``,
 | 
			
		||||
and :variable:`CTEST_RESOURCE_SPEC_FILE` in the dashboard script are not specified,
 | 
			
		||||
the value of :variable:`CTEST_RESOURCE_SPEC_FILE` in the CMake build is used
 | 
			
		||||
instead. If none of these are specified, no resource spec file is used.
 | 
			
		||||
The resource specification file is a JSON file which is passed to CTest in one
 | 
			
		||||
of a number of ways. It can be specified on the command line with the
 | 
			
		||||
:option:`ctest --resource-spec-file` option, it can be given using the
 | 
			
		||||
``RESOURCE_SPEC_FILE`` argument of :command:`ctest_test`, or it can be
 | 
			
		||||
generated dynamically as part of test execution (see
 | 
			
		||||
:ref:`ctest-resource-dynamically-generated-spec-file`).
 | 
			
		||||
 | 
			
		||||
If a dashboard script is used and ``RESOURCE_SPEC_FILE`` is not specified, the
 | 
			
		||||
value of :variable:`CTEST_RESOURCE_SPEC_FILE` in the dashboard script is used
 | 
			
		||||
instead.  If :option:`--resource-spec-file <ctest --resource-spec-file>`,
 | 
			
		||||
``RESOURCE_SPEC_FILE``, and :variable:`CTEST_RESOURCE_SPEC_FILE` in the
 | 
			
		||||
dashboard script are not specified, the value of
 | 
			
		||||
:variable:`CTEST_RESOURCE_SPEC_FILE` in the CMake build is used instead.
 | 
			
		||||
If none of these are specified, no resource spec file is used.
 | 
			
		||||
 | 
			
		||||
The resource specification file must be a JSON object. All examples in this
 | 
			
		||||
document assume the following resource specification file:
 | 
			
		||||
 | 
			
		||||
@ -11,3 +11,7 @@ in the same way as it would with unity builds disabled.
 | 
			
		||||
This property helps with "ODR (One definition rule)" problems where combining
 | 
			
		||||
a particular source file with others might lead to build errors or other
 | 
			
		||||
unintended side effects.
 | 
			
		||||
 | 
			
		||||
Note that sources which are scanned for C++ modules (see
 | 
			
		||||
:manual:`cmake-cxxmodules(7)`) are not eligible for unity build inclusion and
 | 
			
		||||
will automatically be excluded.
 | 
			
		||||
 | 
			
		||||
@ -64,6 +64,11 @@ a number of measures to help address such problems:
 | 
			
		||||
  :prop_sf:`INCLUDE_DIRECTORIES` source property will not be combined
 | 
			
		||||
  into a unity source.
 | 
			
		||||
 | 
			
		||||
* Any source file which is scanned for C++ module sources via
 | 
			
		||||
  :prop_tgt:`CXX_SCAN_FOR_MODULES`, :prop_sf:`CXX_SCAN_FOR_MODULES`, or
 | 
			
		||||
  membership of a ``CXX_MODULES`` file set will not be combined into a unity
 | 
			
		||||
  source.  See :manual:`cmake-cxxmodules(7)` for details.
 | 
			
		||||
 | 
			
		||||
* Projects can prevent an individual source file from being combined into
 | 
			
		||||
  a unity source by setting its :prop_sf:`SKIP_UNITY_BUILD_INCLUSION`
 | 
			
		||||
  source property to true.  This can be a more effective way to prevent
 | 
			
		||||
 | 
			
		||||
@ -116,12 +116,6 @@ Modules
 | 
			
		||||
  Additionally, the :command:`ExternalProject_Add_Step` command
 | 
			
		||||
  has been updated to support the new ``JOB_SERVER_AWARE`` option.
 | 
			
		||||
 | 
			
		||||
* The :module:`ExternalProject` module now declares ``BYPRODUCTS`` for the
 | 
			
		||||
  downloaded file for generated ``download`` steps. Previously, if multiple
 | 
			
		||||
  external projects downloaded to the same file, hash verification could fail.
 | 
			
		||||
  Now, when using the :ref:`Ninja Generators`, this scenario is detected and
 | 
			
		||||
  Ninja will raise an error stating that multiple rules generate the same file.
 | 
			
		||||
 | 
			
		||||
* The :module:`FetchContent` module's :command:`FetchContent_Declare` command
 | 
			
		||||
  gained an ``EXCLUDE_FROM_ALL`` option, which propagates through to the
 | 
			
		||||
  :command:`add_subdirectory` call made by
 | 
			
		||||
@ -207,9 +201,9 @@ Updates
 | 
			
		||||
 | 
			
		||||
Changes made since CMake 3.28.0 include the following.
 | 
			
		||||
 | 
			
		||||
3.28.1
 | 
			
		||||
------
 | 
			
		||||
3.28.1, 3.28.2
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
* This version made no changes to documented features or interfaces.
 | 
			
		||||
* These versions made no changes to documented features or interfaces.
 | 
			
		||||
  Some implementation updates were made to support ecosystem changes
 | 
			
		||||
  and/or fix regressions.
 | 
			
		||||
 | 
			
		||||
@ -41,6 +41,12 @@ or :command:`project` commands:
 | 
			
		||||
    not be set without also setting
 | 
			
		||||
    :variable:`CMAKE_<LANG>_COMPILER` to a NVCC compiler.
 | 
			
		||||
 | 
			
		||||
  :variable:`CMAKE_<LANG>_PLATFORM <CMAKE_HIP_PLATFORM>`
 | 
			
		||||
    This variable is set to the detected GPU platform when ``<lang>`` is ``HIP``.
 | 
			
		||||
 | 
			
		||||
    If the variable is already set its value is always preserved. Only compatible values
 | 
			
		||||
    will be considered for :variable:`CMAKE_<LANG>_COMPILER`.
 | 
			
		||||
 | 
			
		||||
For example:
 | 
			
		||||
 | 
			
		||||
.. code-block:: cmake
 | 
			
		||||
@ -66,15 +72,23 @@ macro(check_language lang)
 | 
			
		||||
 | 
			
		||||
    set(extra_compiler_variables)
 | 
			
		||||
    if("${lang}" MATCHES "^(CUDA|HIP)$" AND NOT CMAKE_GENERATOR MATCHES "Visual Studio")
 | 
			
		||||
      set(extra_compiler_variables "set(CMAKE_CUDA_HOST_COMPILER \\\"\${CMAKE_CUDA_HOST_COMPILER}\\\")")
 | 
			
		||||
      set(extra_compiler_variables "set(CMAKE_${lang}_HOST_COMPILER \\\"\${CMAKE_${lang}_HOST_COMPILER}\\\")")
 | 
			
		||||
    endif()
 | 
			
		||||
 | 
			
		||||
    if("${lang}" STREQUAL "HIP")
 | 
			
		||||
      list(APPEND extra_compiler_variables "set(CMAKE_${lang}_PLATFORM \\\"\${CMAKE_${lang}_PLATFORM}\\\")")
 | 
			
		||||
    endif()
 | 
			
		||||
 | 
			
		||||
    list(TRANSFORM extra_compiler_variables PREPEND "\"")
 | 
			
		||||
    list(TRANSFORM extra_compiler_variables APPEND "\\n\"")
 | 
			
		||||
    list(JOIN extra_compiler_variables "\n  " extra_compiler_variables)
 | 
			
		||||
 | 
			
		||||
    set(_cl_content
 | 
			
		||||
      "cmake_minimum_required(VERSION ${CMAKE_VERSION})
 | 
			
		||||
project(Check${lang} ${lang})
 | 
			
		||||
file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
 | 
			
		||||
  \"set(CMAKE_${lang}_COMPILER \\\"\${CMAKE_${lang}_COMPILER}\\\")\\n\"
 | 
			
		||||
  \"${extra_compiler_variables}\\n\"
 | 
			
		||||
  ${extra_compiler_variables}
 | 
			
		||||
  )"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
@ -95,6 +109,11 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
 | 
			
		||||
    else()
 | 
			
		||||
      set(_D_CMAKE_TOOLCHAIN_FILE "")
 | 
			
		||||
    endif()
 | 
			
		||||
    if(CMAKE_${lang}_PLATFORM)
 | 
			
		||||
      set(_D_CMAKE_LANG_PLATFORM "-DCMAKE_${lang}_PLATFORM:STRING=${CMAKE_${lang}_PLATFORM}")
 | 
			
		||||
    else()
 | 
			
		||||
      set(_D_CMAKE_LANG_PLATFORM "")
 | 
			
		||||
    endif()
 | 
			
		||||
    execute_process(
 | 
			
		||||
      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}
 | 
			
		||||
      COMMAND ${CMAKE_COMMAND} . -G ${CMAKE_GENERATOR}
 | 
			
		||||
@ -103,6 +122,7 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
 | 
			
		||||
                                 ${_D_CMAKE_GENERATOR_INSTANCE}
 | 
			
		||||
                                 ${_D_CMAKE_MAKE_PROGRAM}
 | 
			
		||||
                                 ${_D_CMAKE_TOOLCHAIN_FILE}
 | 
			
		||||
                                 ${_D_CMAKE_LANG_PLATFORM}
 | 
			
		||||
      OUTPUT_VARIABLE _cl_output
 | 
			
		||||
      ERROR_VARIABLE _cl_output
 | 
			
		||||
      RESULT_VARIABLE _cl_result
 | 
			
		||||
@ -130,6 +150,10 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
 | 
			
		||||
      mark_as_advanced(CMAKE_${lang}_HOST_COMPILER)
 | 
			
		||||
    endif()
 | 
			
		||||
 | 
			
		||||
    if(CMAKE_${lang}_PLATFORM)
 | 
			
		||||
      set(CMAKE_${lang}_PLATFORM "${CMAKE_${lang}_PLATFORM}" CACHE STRING "${lang} platform")
 | 
			
		||||
      mark_as_advanced(CMAKE_${lang}_PLATFORM)
 | 
			
		||||
    endif()
 | 
			
		||||
  endif()
 | 
			
		||||
endmacro()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2825,7 +2825,6 @@ function(_ep_add_download_command name)
 | 
			
		||||
  set(comment)
 | 
			
		||||
  set(work_dir)
 | 
			
		||||
  set(extra_repo_info)
 | 
			
		||||
  set(byproduct_file)
 | 
			
		||||
 | 
			
		||||
  if(cmd_set)
 | 
			
		||||
    set(work_dir ${download_dir})
 | 
			
		||||
@ -3106,16 +3105,14 @@ hash=${hash}
 | 
			
		||||
          get_filename_component(fname "${fname}" NAME)
 | 
			
		||||
        else()
 | 
			
		||||
          # Fall back to a default file name.  The actual file name does not
 | 
			
		||||
          # matter as long as it doesn't conflict with other projects because
 | 
			
		||||
          # it is used only internally and our extraction tool inspects the
 | 
			
		||||
          # file content directly.  If it turns out the wrong URL was given
 | 
			
		||||
          # that will be revealed during the build which is an easier place for
 | 
			
		||||
          # users to diagnose than an error here anyway.
 | 
			
		||||
          set(fname "${name}-archive.tar")
 | 
			
		||||
          # matter because it is used only internally and our extraction tool
 | 
			
		||||
          # inspects the file content directly.  If it turns out the wrong URL
 | 
			
		||||
          # was given that will be revealed during the build which is an easier
 | 
			
		||||
          # place for users to diagnose than an error here anyway.
 | 
			
		||||
          set(fname "archive.tar")
 | 
			
		||||
        endif()
 | 
			
		||||
        string(REPLACE ";" "-" fname "${fname}")
 | 
			
		||||
        set(file ${download_dir}/${fname})
 | 
			
		||||
        set(byproduct_file "${download_dir}/${fname}")
 | 
			
		||||
        get_property(timeout TARGET ${name} PROPERTY _EP_TIMEOUT)
 | 
			
		||||
        get_property(inactivity_timeout
 | 
			
		||||
          TARGET ${name}
 | 
			
		||||
@ -3292,7 +3289,6 @@ hash=${hash}
 | 
			
		||||
      COMMAND ${__cmdQuoted}
 | 
			
		||||
      WORKING_DIRECTORY \${work_dir}
 | 
			
		||||
      DEPENDS \${depends}
 | 
			
		||||
      BYPRODUCTS \${byproduct_file}
 | 
			
		||||
      DEPENDEES mkdir
 | 
			
		||||
      ${log}
 | 
			
		||||
      ${uses_terminal}
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ packages and/or feature for a build tree such as::
 | 
			
		||||
    PNG, A PNG image library., <http://www.libpng.org/pub/png/>
 | 
			
		||||
       * Enables saving screenshots
 | 
			
		||||
    -- The following OPTIONAL packages have not been found:
 | 
			
		||||
    Lua51, The Lua scripting language., <http://www.lua.org>
 | 
			
		||||
    Lua51, The Lua scripting language., <https://www.lua.org>
 | 
			
		||||
       * Enables macros in MyWordProcessor
 | 
			
		||||
    Foo, Foo provides cool stuff.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1394,7 +1394,7 @@ function(_Boost_COMPONENT_DEPENDENCIES component _ret)
 | 
			
		||||
      set(_Boost_THREAD_DEPENDENCIES chrono atomic)
 | 
			
		||||
      set(_Boost_WAVE_DEPENDENCIES filesystem serialization thread chrono atomic)
 | 
			
		||||
      set(_Boost_WSERIALIZATION_DEPENDENCIES serialization)
 | 
			
		||||
      if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.84.0 AND NOT Boost_NO_WARN_NEW_VERSIONS)
 | 
			
		||||
      if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.85.0 AND NOT Boost_NO_WARN_NEW_VERSIONS)
 | 
			
		||||
        message(WARNING "New Boost version may have incorrect or missing dependencies and imported targets")
 | 
			
		||||
      endif()
 | 
			
		||||
    endif()
 | 
			
		||||
@ -1669,6 +1669,7 @@ else()
 | 
			
		||||
  # _Boost_COMPONENT_HEADERS.  See the instructions at the top of
 | 
			
		||||
  # _Boost_COMPONENT_DEPENDENCIES.
 | 
			
		||||
  set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS}
 | 
			
		||||
    "1.84.0" "1.84"
 | 
			
		||||
    "1.83.0" "1.83" "1.82.0" "1.82" "1.81.0" "1.81" "1.80.0" "1.80" "1.79.0" "1.79"
 | 
			
		||||
    "1.78.0" "1.78" "1.77.0" "1.77" "1.76.0" "1.76" "1.75.0" "1.75" "1.74.0" "1.74"
 | 
			
		||||
    "1.73.0" "1.73" "1.72.0" "1.72" "1.71.0" "1.71" "1.70.0" "1.70" "1.69.0" "1.69"
 | 
			
		||||
 | 
			
		||||
@ -960,7 +960,7 @@ endif()
 | 
			
		||||
# the version of the CUDA toolchain
 | 
			
		||||
# Create a separate variable so this directory can be selectively added to math targets.
 | 
			
		||||
find_path(CUDAToolkit_CUBLAS_INCLUDE_DIR cublas_v2.h PATHS
 | 
			
		||||
  "${CUDAToolkit_INCLUDE_DIRECTORIES}"
 | 
			
		||||
  ${CUDAToolkit_INCLUDE_DIRECTORIES}
 | 
			
		||||
  NO_DEFAULT_PATH)
 | 
			
		||||
 | 
			
		||||
if(NOT CUDAToolkit_CUBLAS_INCLUDE_DIR)
 | 
			
		||||
@ -973,7 +973,7 @@ if(NOT CUDAToolkit_CUBLAS_INCLUDE_DIR)
 | 
			
		||||
  cmake_path(NORMAL_PATH CUDAToolkit_MATH_INCLUDE_DIR)
 | 
			
		||||
 | 
			
		||||
  find_path(CUDAToolkit_CUBLAS_INCLUDE_DIR cublas_v2.h PATHS
 | 
			
		||||
    "${CUDAToolkit_INCLUDE_DIRECTORIES}"
 | 
			
		||||
    ${CUDAToolkit_INCLUDE_DIRECTORIES}
 | 
			
		||||
    )
 | 
			
		||||
  if(CUDAToolkit_CUBLAS_INCLUDE_DIR)
 | 
			
		||||
    list(APPEND CUDAToolkit_INCLUDE_DIRECTORIES "${CUDAToolkit_CUBLAS_INCLUDE_DIR}")
 | 
			
		||||
@ -1246,7 +1246,7 @@ if(CUDAToolkit_FOUND)
 | 
			
		||||
 | 
			
		||||
  find_path(CUDAToolkit_CUPTI_INCLUDE_DIR cupti.h PATHS
 | 
			
		||||
      "${CUDAToolkit_ROOT_DIR}/extras/CUPTI/include"
 | 
			
		||||
      "${CUDAToolkit_INCLUDE_DIRS}"
 | 
			
		||||
      ${CUDAToolkit_INCLUDE_DIRS}
 | 
			
		||||
      PATH_SUFFIXES "../extras/CUPTI/include"
 | 
			
		||||
                    "../../../extras/CUPTI/include"
 | 
			
		||||
      NO_DEFAULT_PATH)
 | 
			
		||||
 | 
			
		||||
@ -65,104 +65,6 @@ directory of a Freetype installation.
 | 
			
		||||
# I'm going to attempt to cut out the middleman and hope
 | 
			
		||||
# everything still works.
 | 
			
		||||
 | 
			
		||||
set(_Freetype_args)
 | 
			
		||||
if (Freetype_FIND_VERSION)
 | 
			
		||||
  list(APPEND _Freetype_args
 | 
			
		||||
    "${Freetype_FIND_VERSION}")
 | 
			
		||||
  if (Freetype_FIND_VERSION_EXACT)
 | 
			
		||||
    list(APPEND _Freetype_args
 | 
			
		||||
      EXACT)
 | 
			
		||||
  endif ()
 | 
			
		||||
endif ()
 | 
			
		||||
set(_Freetype_component_req)
 | 
			
		||||
set(_Freetype_component_opt)
 | 
			
		||||
foreach (_Freetype_component IN LISTS Freetype_FIND_COMPONENTS)
 | 
			
		||||
  if (Freetype_FIND_REQUIRE_${_Freetype_component})
 | 
			
		||||
    list(APPEND _Freetype_component_req
 | 
			
		||||
      "${_Freetype_component}")
 | 
			
		||||
  else ()
 | 
			
		||||
    list(APPEND _Freetype_component_opt
 | 
			
		||||
      "${_Freetype_component}")
 | 
			
		||||
  endif ()
 | 
			
		||||
endforeach ()
 | 
			
		||||
unset(_Freetype_component)
 | 
			
		||||
if (_Freetype_component_req)
 | 
			
		||||
  list(APPEND _Freetype_args
 | 
			
		||||
    COMPONENTS "${_Freetype_component_req}")
 | 
			
		||||
endif ()
 | 
			
		||||
unset(_Freetype_component_req)
 | 
			
		||||
if (_Freetype_component_opt)
 | 
			
		||||
  list(APPEND _Freetype_args
 | 
			
		||||
    OPTIONAL_COMPONENTS "${_Freetype_component_opt}")
 | 
			
		||||
endif ()
 | 
			
		||||
unset(_Freetype_component_opt)
 | 
			
		||||
# Always find with QUIET to avoid noise when it is not found.
 | 
			
		||||
find_package(freetype CONFIG QUIET ${_Freetype_args})
 | 
			
		||||
unset(_Freetype_args)
 | 
			
		||||
if (freetype_FOUND)
 | 
			
		||||
  if (NOT TARGET Freetype::Freetype)
 | 
			
		||||
    add_library(Freetype::Freetype IMPORTED INTERFACE)
 | 
			
		||||
    set_target_properties(Freetype::Freetype PROPERTIES
 | 
			
		||||
      INTERFACE_LINK_LIBRARIES freetype)
 | 
			
		||||
  endif ()
 | 
			
		||||
  get_property(FREETYPE_INCLUDE_DIRS TARGET freetype PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
 | 
			
		||||
  get_property(FREETYPE_LIBRARIES TARGET freetype PROPERTY INTERFACE_LINK_LIBRARIES)
 | 
			
		||||
  get_property(_Freetype_location TARGET freetype PROPERTY IMPORTED_IMPLIB)
 | 
			
		||||
  if (NOT _Freetype_location)
 | 
			
		||||
    get_property(_Freetype_location_release TARGET freetype PROPERTY IMPORTED_IMPLIB_RELEASE)
 | 
			
		||||
    if (NOT _Freetype_location_release)
 | 
			
		||||
      get_property(_Freetype_location_release TARGET freetype PROPERTY IMPORTED_IMPLIB_RELWITHDEBINFO)
 | 
			
		||||
    endif ()
 | 
			
		||||
    get_property(_Freetype_location_debug TARGET freetype PROPERTY IMPORTED_IMPLIB_DEBUG)
 | 
			
		||||
    if (_Freetype_location_release AND _Freetype_location_debug)
 | 
			
		||||
      set(_Freetype_location
 | 
			
		||||
        optimized "${_Freetype_location_release}"
 | 
			
		||||
        debug "${_Freetype_location_debug}")
 | 
			
		||||
    elseif (_Freetype_location_release)
 | 
			
		||||
      set(_Freetype_location "${_Freetype_location_release}")
 | 
			
		||||
    elseif (_Freetype_location_debug)
 | 
			
		||||
      set(_Freetype_location "${_Freetype_location_debug}")
 | 
			
		||||
    else ()
 | 
			
		||||
      get_property(_Freetype_location_release TARGET freetype PROPERTY LOCATION_RELEASE)
 | 
			
		||||
      if (NOT _Freetype_location_release)
 | 
			
		||||
        get_property(_Freetype_location_release TARGET freetype PROPERTY LOCATION_RELWITHDEBINFO)
 | 
			
		||||
      endif ()
 | 
			
		||||
      get_property(_Freetype_location_debug TARGET freetype PROPERTY LOCATION_DEBUG)
 | 
			
		||||
      if (_Freetype_location_release AND _Freetype_location_debug)
 | 
			
		||||
        set(_Freetype_location
 | 
			
		||||
          optimized "${_Freetype_location_release}"
 | 
			
		||||
          debug "${_Freetype_location_debug}")
 | 
			
		||||
      elseif (_Freetype_location_release)
 | 
			
		||||
        set(_Freetype_location "${_Freetype_location_release}")
 | 
			
		||||
      elseif (_Freetype_location_debug)
 | 
			
		||||
        set(_Freetype_location "${_Freetype_location_debug}")
 | 
			
		||||
      else ()
 | 
			
		||||
        get_property(_Freetype_location TARGET freetype PROPERTY LOCATION)
 | 
			
		||||
      endif ()
 | 
			
		||||
    endif ()
 | 
			
		||||
    unset(_Freetype_location_release)
 | 
			
		||||
    unset(_Freetype_location_debug)
 | 
			
		||||
  endif ()
 | 
			
		||||
  list(INSERT FREETYPE_LIBRARIES 0
 | 
			
		||||
    "${_Freetype_location}")
 | 
			
		||||
  unset(_Freetype_location)
 | 
			
		||||
  set(Freetype_FOUND 1)
 | 
			
		||||
  set(FREETYPE_FOUND 1)
 | 
			
		||||
  set(FREETYPE_VERSION_STRING "${freetype_VERSION}")
 | 
			
		||||
  foreach (_Freetype_component IN LISTS Freetype_FIND_COMPONENTS)
 | 
			
		||||
    set(Freetype_${_Freetype_component}_FOUND "${freetype_${_Freetype_component}_FOUND}")
 | 
			
		||||
  endforeach ()
 | 
			
		||||
  unset(_Freetype_component)
 | 
			
		||||
 | 
			
		||||
  include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 | 
			
		||||
  find_package_handle_standard_args(Freetype
 | 
			
		||||
    HANDLE_COMPONENTS
 | 
			
		||||
    VERSION_VAR FREETYPE_VERSION_STRING
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  return ()
 | 
			
		||||
endif ()
 | 
			
		||||
 | 
			
		||||
set(FREETYPE_FIND_ARGS
 | 
			
		||||
  HINTS
 | 
			
		||||
    ENV FREETYPE_DIR
 | 
			
		||||
 | 
			
		||||
@ -189,17 +189,13 @@ Cached variables
 | 
			
		||||
  the location of the root of the Matlab installation found. If this value
 | 
			
		||||
  is changed by the user, the result variables are recomputed.
 | 
			
		||||
 | 
			
		||||
Provided macros
 | 
			
		||||
^^^^^^^^^^^^^^^
 | 
			
		||||
Provided commands
 | 
			
		||||
^^^^^^^^^^^^^^^^^
 | 
			
		||||
 | 
			
		||||
:command:`matlab_get_version_from_release_name`
 | 
			
		||||
  returns the version from the release name
 | 
			
		||||
  returns the version from the Matlab release name
 | 
			
		||||
:command:`matlab_get_release_name_from_version`
 | 
			
		||||
  returns the release name from the Matlab version
 | 
			
		||||
 | 
			
		||||
Provided functions
 | 
			
		||||
^^^^^^^^^^^^^^^^^^
 | 
			
		||||
 | 
			
		||||
:command:`matlab_add_mex`
 | 
			
		||||
  adds a target compiling a MEX file.
 | 
			
		||||
:command:`matlab_add_unit_test`
 | 
			
		||||
@ -350,6 +346,11 @@ file(MAKE_DIRECTORY "${_matlab_temporary_folder}")
 | 
			
		||||
  * Output: ``version`` is the version of Matlab (e.g. 23.2.0)
 | 
			
		||||
 | 
			
		||||
  Returns the version of Matlab from a release name
 | 
			
		||||
 | 
			
		||||
  .. note::
 | 
			
		||||
 | 
			
		||||
    This command provides correct versions mappings for Matlab but not MCR.
 | 
			
		||||
 | 
			
		||||
#]=======================================================================]
 | 
			
		||||
macro(matlab_get_version_from_release_name release_name version_name)
 | 
			
		||||
 | 
			
		||||
@ -377,33 +378,27 @@ endmacro()
 | 
			
		||||
  * Output: ``release_name`` is the release name (R2023b)
 | 
			
		||||
 | 
			
		||||
  Returns the release name from the version of Matlab
 | 
			
		||||
 | 
			
		||||
  .. note::
 | 
			
		||||
 | 
			
		||||
    This command provides correct version mappings for Matlab but not MCR.
 | 
			
		||||
 | 
			
		||||
#]=======================================================================]
 | 
			
		||||
macro(matlab_get_release_name_from_version version release_name)
 | 
			
		||||
function(matlab_get_release_name_from_version version release_name)
 | 
			
		||||
 | 
			
		||||
  # only the major.minor version is used
 | 
			
		||||
  string(REGEX MATCH "([0-9]+\\.[0-9]+)" _match ${version})
 | 
			
		||||
  if(CMAKE_MATCH_1)
 | 
			
		||||
    set(short_version ${CMAKE_MATCH_1})
 | 
			
		||||
  else()
 | 
			
		||||
    set(short_version ${version})
 | 
			
		||||
  endif()
 | 
			
		||||
  string(REGEX REPLACE "^([0-9]+\\.[0-9]+).*" "\\1" version "${version}")
 | 
			
		||||
 | 
			
		||||
  set(${release_name} "")
 | 
			
		||||
  foreach(_var IN LISTS MATLAB_VERSIONS_MAPPING)
 | 
			
		||||
    string(REGEX MATCHALL "(.+)=${short_version}" _matched ${_var})
 | 
			
		||||
    if(NOT _matched STREQUAL "")
 | 
			
		||||
      set(${release_name} ${CMAKE_MATCH_1})
 | 
			
		||||
      break()
 | 
			
		||||
    if(_var MATCHES "(.+)=${version}")
 | 
			
		||||
      set(${release_name} ${CMAKE_MATCH_1} PARENT_SCOPE)
 | 
			
		||||
      return()
 | 
			
		||||
    endif()
 | 
			
		||||
  endforeach()
 | 
			
		||||
 | 
			
		||||
  unset(_var)
 | 
			
		||||
  unset(_matched)
 | 
			
		||||
  if(${release_name} STREQUAL "")
 | 
			
		||||
    message(WARNING "[MATLAB] The version ${short_version} is not registered")
 | 
			
		||||
  endif()
 | 
			
		||||
  message(WARNING "[MATLAB] The version ${version} is not registered")
 | 
			
		||||
 | 
			
		||||
endmacro()
 | 
			
		||||
endfunction()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# extracts all the supported release names (R2022b...) of Matlab
 | 
			
		||||
@ -453,9 +448,10 @@ endmacro()
 | 
			
		||||
  are installed. The found versions are returned in `matlab_versions`.
 | 
			
		||||
  Set `win64` to `TRUE` if the 64 bit version of Matlab should be looked for
 | 
			
		||||
  The returned list contains all versions under
 | 
			
		||||
  ``HKLM\\SOFTWARE\\Mathworks\\MATLAB`` and
 | 
			
		||||
  ``HKLM\\SOFTWARE\\Mathworks\\MATLAB Runtime`` or an empty list in case an
 | 
			
		||||
  error occurred (or nothing found).
 | 
			
		||||
  ``HKLM\\SOFTWARE\\Mathworks\\MATLAB``,
 | 
			
		||||
  ``HKLM\\SOFTWARE\\Mathworks\\MATLAB Runtime`` and
 | 
			
		||||
  ``HKLM\\SOFTWARE\\Mathworks\\MATLAB Compiler Runtime`` or an empty list in
 | 
			
		||||
  case an error occurred (or nothing found).
 | 
			
		||||
 | 
			
		||||
  .. note::
 | 
			
		||||
 | 
			
		||||
@ -466,7 +462,7 @@ endmacro()
 | 
			
		||||
function(matlab_extract_all_installed_versions_from_registry win64 matlab_versions)
 | 
			
		||||
 | 
			
		||||
  if(NOT CMAKE_HOST_WIN32)
 | 
			
		||||
    message(FATAL_ERROR "[MATLAB] This macro can only be called by a Windows host")
 | 
			
		||||
    message(FATAL_ERROR "[MATLAB] This function can only be called by a Windows host")
 | 
			
		||||
  endif()
 | 
			
		||||
 | 
			
		||||
  if(${win64} AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "64")
 | 
			
		||||
@ -485,24 +481,22 @@ function(matlab_extract_all_installed_versions_from_registry win64 matlab_versio
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    if(_reg)
 | 
			
		||||
      string(REGEX MATCHALL "([0-9]+(\\.[0-9]+)+)" _versions_regex "${_reg}")
 | 
			
		||||
 | 
			
		||||
      string(REGEX MATCHALL "([0-9]+\\.[0-9]+)" _versions_regex "${_reg}")
 | 
			
		||||
      foreach(_match IN LISTS _versions_regex)
 | 
			
		||||
        if(_match MATCHES "([0-9]+(\\.[0-9]+)+)")
 | 
			
		||||
          cmake_host_system_information(RESULT _reg
 | 
			
		||||
            QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Mathworks/${_installation_type}/${CMAKE_MATCH_1}"
 | 
			
		||||
            VALUE "MATLABROOT"
 | 
			
		||||
            VIEW ${_view}
 | 
			
		||||
          )
 | 
			
		||||
 | 
			
		||||
      foreach(match IN LISTS _versions_regex)
 | 
			
		||||
        string(REGEX MATCH "([0-9]+\\.[0-9]+)" current_match "${match}")
 | 
			
		||||
 | 
			
		||||
        if(NOT CMAKE_MATCH_1)
 | 
			
		||||
          continue()
 | 
			
		||||
        endif()
 | 
			
		||||
 | 
			
		||||
        cmake_host_system_information(RESULT _reg
 | 
			
		||||
          QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Mathworks/${_installation_type}/${CMAKE_MATCH_1}"
 | 
			
		||||
          VALUE "MATLABROOT"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        _Matlab_VersionInfoXML("${_reg}" _matlab_version_tmp)
 | 
			
		||||
        if(NOT "${_matlab_version_tmp}" STREQUAL "unknown")
 | 
			
		||||
          list(APPEND matlabs_from_registry ${_matlab_version_tmp})
 | 
			
		||||
          _Matlab_VersionInfoXML("${_reg}" _matlab_version_tmp)
 | 
			
		||||
          if("${_matlab_version_tmp}" STREQUAL "unknown")
 | 
			
		||||
            list(APPEND matlabs_from_registry ${_match})
 | 
			
		||||
          else()
 | 
			
		||||
            list(APPEND matlabs_from_registry ${_matlab_version_tmp})
 | 
			
		||||
          endif()
 | 
			
		||||
        endif()
 | 
			
		||||
      endforeach()
 | 
			
		||||
 | 
			
		||||
@ -558,42 +552,59 @@ function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_
 | 
			
		||||
  # extract_matlab_versions_from_registry_brute_force or
 | 
			
		||||
  # matlab_extract_all_installed_versions_from_registry.
 | 
			
		||||
 | 
			
		||||
  # Mostly the major.minor version is used in Mathworks Windows Registry keys.
 | 
			
		||||
  # If the patch is not zero, major.minor.patch is used.
 | 
			
		||||
  list(TRANSFORM matlab_versions REPLACE "^([0-9]+\\.[0-9]+(\\.[1-9][0-9]*)?).*" "\\1")
 | 
			
		||||
 | 
			
		||||
  set(_matlab_roots_list )
 | 
			
		||||
  # check for Matlab installations
 | 
			
		||||
  foreach(_matlab_current_version IN LISTS matlab_versions)
 | 
			
		||||
    get_filename_component(
 | 
			
		||||
      current_MATLAB_ROOT
 | 
			
		||||
      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${_matlab_current_version};MATLABROOT]"
 | 
			
		||||
      ABSOLUTE)
 | 
			
		||||
    cmake_host_system_information(RESULT current_MATLAB_ROOT
 | 
			
		||||
      QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Mathworks/MATLAB/${_matlab_current_version}"
 | 
			
		||||
      VALUE "MATLABROOT"
 | 
			
		||||
    )
 | 
			
		||||
    cmake_path(CONVERT "${current_MATLAB_ROOT}" TO_CMAKE_PATH_LIST current_MATLAB_ROOT)
 | 
			
		||||
 | 
			
		||||
    if(IS_DIRECTORY "${current_MATLAB_ROOT}")
 | 
			
		||||
      list(APPEND _matlab_roots_list "MATLAB" ${_matlab_current_version} ${current_MATLAB_ROOT})
 | 
			
		||||
      _Matlab_VersionInfoXML("${current_MATLAB_ROOT}" _matlab_version_tmp)
 | 
			
		||||
      if("${_matlab_version_tmp}" STREQUAL "unknown")
 | 
			
		||||
        list(APPEND _matlab_roots_list "MATLAB" ${_matlab_current_version} ${current_MATLAB_ROOT})
 | 
			
		||||
      else()
 | 
			
		||||
        list(APPEND _matlab_roots_list "MATLAB" ${_matlab_version_tmp} ${current_MATLAB_ROOT})
 | 
			
		||||
      endif()
 | 
			
		||||
    endif()
 | 
			
		||||
 | 
			
		||||
  endforeach()
 | 
			
		||||
 | 
			
		||||
  # Check for MCR installations
 | 
			
		||||
  foreach(_matlab_current_version IN LISTS matlab_versions)
 | 
			
		||||
    get_filename_component(
 | 
			
		||||
      current_MATLAB_ROOT
 | 
			
		||||
      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB Runtime\\${_matlab_current_version};MATLABROOT]"
 | 
			
		||||
      ABSOLUTE)
 | 
			
		||||
    cmake_host_system_information(RESULT current_MATLAB_ROOT
 | 
			
		||||
      QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Mathworks/MATLAB Runtime/${_matlab_current_version}"
 | 
			
		||||
      VALUE "MATLABROOT"
 | 
			
		||||
    )
 | 
			
		||||
    cmake_path(CONVERT "${current_MATLAB_ROOT}" TO_CMAKE_PATH_LIST current_MATLAB_ROOT)
 | 
			
		||||
 | 
			
		||||
    # remove the dot
 | 
			
		||||
    string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}")
 | 
			
		||||
 | 
			
		||||
    if(IS_DIRECTORY "${current_MATLAB_ROOT}")
 | 
			
		||||
      list(APPEND _matlab_roots_list "MCR" ${_matlab_current_version} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}")
 | 
			
		||||
      _Matlab_VersionInfoXML("${current_MATLAB_ROOT}" _matlab_version_tmp)
 | 
			
		||||
      if("${_matlab_version_tmp}" STREQUAL "unknown")
 | 
			
		||||
        list(APPEND _matlab_roots_list "MCR" ${_matlab_current_version} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}")
 | 
			
		||||
      else()
 | 
			
		||||
        list(APPEND _matlab_roots_list "MCR" ${_matlab_version_tmp} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}")
 | 
			
		||||
      endif()
 | 
			
		||||
    endif()
 | 
			
		||||
 | 
			
		||||
  endforeach()
 | 
			
		||||
 | 
			
		||||
  # Check for old MCR installations
 | 
			
		||||
  foreach(_matlab_current_version IN LISTS matlab_versions)
 | 
			
		||||
    get_filename_component(
 | 
			
		||||
      current_MATLAB_ROOT
 | 
			
		||||
      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB Compiler Runtime\\${_matlab_current_version};MATLABROOT]"
 | 
			
		||||
      ABSOLUTE)
 | 
			
		||||
    cmake_host_system_information(RESULT current_MATLAB_ROOT
 | 
			
		||||
      QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Mathworks/MATLAB Compiler Runtime/${_matlab_current_version}"
 | 
			
		||||
      VALUE "MATLABROOT"
 | 
			
		||||
    )
 | 
			
		||||
    cmake_path(CONVERT "${current_MATLAB_ROOT}" TO_CMAKE_PATH_LIST current_MATLAB_ROOT)
 | 
			
		||||
 | 
			
		||||
    # remove the dot
 | 
			
		||||
    string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}")
 | 
			
		||||
@ -1409,20 +1420,11 @@ function(_Matlab_VersionInfoXML matlab_root _version)
 | 
			
		||||
  set(_ver "unknown")
 | 
			
		||||
 | 
			
		||||
  set(_XMLfile ${matlab_root}/VersionInfo.xml)
 | 
			
		||||
  if(NOT EXISTS ${_XMLfile})
 | 
			
		||||
    return()
 | 
			
		||||
  endif()
 | 
			
		||||
  if(EXISTS ${_XMLfile})
 | 
			
		||||
    file(READ ${_XMLfile} versioninfo_string)
 | 
			
		||||
 | 
			
		||||
  file(READ ${_XMLfile} versioninfo_string)
 | 
			
		||||
 | 
			
		||||
  if(versioninfo_string)
 | 
			
		||||
    # parses "<version>23.2.0.2365128</version>"
 | 
			
		||||
    string(REGEX MATCH "<version>([0-9]+(\\.[0-9]+)+)</version>"
 | 
			
		||||
      version_reg_match
 | 
			
		||||
      ${versioninfo_string}
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
    if(CMAKE_MATCH_1)
 | 
			
		||||
    if(versioninfo_string MATCHES "<version>([0-9]+(\\.[0-9]+)+)</version>")
 | 
			
		||||
      set(_ver "${CMAKE_MATCH_1}")
 | 
			
		||||
    endif()
 | 
			
		||||
  endif()
 | 
			
		||||
@ -1634,7 +1636,17 @@ set(Matlab_VERSION_STRING "NOTFOUND")
 | 
			
		||||
set(Matlab_Or_MCR "UNKNOWN")
 | 
			
		||||
if(_numbers_of_matlab_roots GREATER 0)
 | 
			
		||||
  if(Matlab_FIND_VERSION_EXACT)
 | 
			
		||||
    list(FIND _matlab_possible_roots ${Matlab_FIND_VERSION} _list_index)
 | 
			
		||||
    set(_list_index -1)
 | 
			
		||||
    foreach(_matlab_root_index RANGE 1 ${_numbers_of_matlab_roots} 3)
 | 
			
		||||
      list(GET _matlab_possible_roots ${_matlab_root_index} _matlab_root_version)
 | 
			
		||||
      # only the major.minor version is used
 | 
			
		||||
      string(REGEX REPLACE "^([0-9]+\\.[0-9]+).*" "\\1" _matlab_root_version "${_matlab_root_version}")
 | 
			
		||||
      if(_matlab_root_version VERSION_EQUAL Matlab_FIND_VERSION)
 | 
			
		||||
        set(_list_index ${_matlab_root_index})
 | 
			
		||||
        break()
 | 
			
		||||
      endif()
 | 
			
		||||
    endforeach()
 | 
			
		||||
 | 
			
		||||
    if(_list_index LESS 0)
 | 
			
		||||
      set(_list_index 1)
 | 
			
		||||
    endif()
 | 
			
		||||
 | 
			
		||||
@ -55,23 +55,25 @@ function(cmake_cuda_architectures_all lang lang_var_)
 | 
			
		||||
  endif()
 | 
			
		||||
 | 
			
		||||
  if(${lang_var_}TOOLKIT_VERSION VERSION_GREATER_EQUAL 11.4)
 | 
			
		||||
    if(CMAKE_${lang}_COMPILER_ID STREQUAL "NVIDIA")
 | 
			
		||||
    if(CMAKE_${lang}_COMPILER_ID STREQUAL "NVIDIA"
 | 
			
		||||
        OR (CMAKE_${lang}_COMPILER_ID STREQUAL "Clang" AND CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)
 | 
			
		||||
        )
 | 
			
		||||
      list(APPEND CMAKE_CUDA_ARCHITECTURES_ALL 87)
 | 
			
		||||
    endif()
 | 
			
		||||
  endif()
 | 
			
		||||
 | 
			
		||||
  if(${lang_var_}TOOLKIT_VERSION VERSION_GREATER_EQUAL 11.8)
 | 
			
		||||
    if(CMAKE_${lang}_COMPILER_ID STREQUAL "NVIDIA")
 | 
			
		||||
    if(CMAKE_${lang}_COMPILER_ID STREQUAL "NVIDIA"
 | 
			
		||||
        OR (CMAKE_${lang}_COMPILER_ID STREQUAL "Clang" AND CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)
 | 
			
		||||
        )
 | 
			
		||||
      list(APPEND CMAKE_CUDA_ARCHITECTURES_ALL 89 90)
 | 
			
		||||
      list(APPEND CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR 90)
 | 
			
		||||
    endif()
 | 
			
		||||
  endif()
 | 
			
		||||
 | 
			
		||||
  if(${lang_var_}TOOLKIT_VERSION VERSION_GREATER_EQUAL 12.0)
 | 
			
		||||
    if(CMAKE_${lang}_COMPILER_ID STREQUAL "NVIDIA")
 | 
			
		||||
      list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL 35 37)
 | 
			
		||||
      list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR 35)
 | 
			
		||||
    endif()
 | 
			
		||||
    list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL 35 37)
 | 
			
		||||
    list(REMOVE_ITEM CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR 35)
 | 
			
		||||
  endif()
 | 
			
		||||
 | 
			
		||||
  # only generate jit code for the newest arch for all/all-major
 | 
			
		||||
 | 
			
		||||
@ -41,20 +41,19 @@ macro(PKGCONFIG _package _include_DIR _link_DIR _link_FLAGS _cflags)
 | 
			
		||||
    if(NOT _return_VALUE)
 | 
			
		||||
 | 
			
		||||
      execute_process(COMMAND ${PKGCONFIG_EXECUTABLE} ${_package} --variable=includedir
 | 
			
		||||
        OUTPUT_VARIABLE ${_include_DIR} )
 | 
			
		||||
        OUTPUT_VARIABLE ${_include_DIR} OUTPUT_STRIP_TRAILING_WHITESPACE )
 | 
			
		||||
      string(REGEX REPLACE "[\r\n]" " " ${_include_DIR} "${${_include_DIR}}")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
      execute_process(COMMAND ${PKGCONFIG_EXECUTABLE} ${_package} --variable=libdir
 | 
			
		||||
        OUTPUT_VARIABLE ${_link_DIR} )
 | 
			
		||||
        OUTPUT_VARIABLE ${_link_DIR} OUTPUT_STRIP_TRAILING_WHITESPACE )
 | 
			
		||||
      string(REGEX REPLACE "[\r\n]" " " ${_link_DIR} "${${_link_DIR}}")
 | 
			
		||||
 | 
			
		||||
      execute_process(COMMAND ${PKGCONFIG_EXECUTABLE} ${_package} --libs
 | 
			
		||||
        OUTPUT_VARIABLE ${_link_FLAGS} )
 | 
			
		||||
        OUTPUT_VARIABLE ${_link_FLAGS} OUTPUT_STRIP_TRAILING_WHITESPACE )
 | 
			
		||||
      string(REGEX REPLACE "[\r\n]" " " ${_link_FLAGS} "${${_link_FLAGS}}")
 | 
			
		||||
 | 
			
		||||
      execute_process(COMMAND ${PKGCONFIG_EXECUTABLE} ${_package} --cflags
 | 
			
		||||
        OUTPUT_VARIABLE ${_cflags} )
 | 
			
		||||
        OUTPUT_VARIABLE ${_cflags} OUTPUT_STRIP_TRAILING_WHITESPACE )
 | 
			
		||||
      string(REGEX REPLACE "[\r\n]" " " ${_cflags} "${${_cflags}}")
 | 
			
		||||
 | 
			
		||||
    else()
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
# CMake version number components.
 | 
			
		||||
set(CMake_VERSION_MAJOR 3)
 | 
			
		||||
set(CMake_VERSION_MINOR 28)
 | 
			
		||||
set(CMake_VERSION_PATCH 1)
 | 
			
		||||
set(CMake_VERSION_PATCH 2)
 | 
			
		||||
#set(CMake_VERSION_RC 0)
 | 
			
		||||
set(CMake_VERSION_IS_DIRTY 0)
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@ endif()
 | 
			
		||||
 | 
			
		||||
if(NOT CMake_VERSION_NO_GIT)
 | 
			
		||||
  # If this source was exported by 'git archive', use its commit info.
 | 
			
		||||
  set(git_info [==[1eed682d7c CMake 3.28.1]==])
 | 
			
		||||
  set(git_info [==[1f25aa1a0a CMake 3.28.2]==])
 | 
			
		||||
 | 
			
		||||
  # Otherwise, try to identify the current development source version.
 | 
			
		||||
  if(NOT git_info MATCHES "^([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]?[0-9a-f]?)[0-9a-f]* "
 | 
			
		||||
 | 
			
		||||
@ -7,8 +7,6 @@
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
#include "cmsys/FStream.hxx"
 | 
			
		||||
 | 
			
		||||
#include "cm_sys_stat.h"
 | 
			
		||||
 | 
			
		||||
@ -135,14 +135,14 @@ private:
 | 
			
		||||
std::string cmCTestBZR::LoadInfo()
 | 
			
		||||
{
 | 
			
		||||
  // Run "bzr info" to get the repository info from the work tree.
 | 
			
		||||
  std::string bzr = this->CommandLineTool;
 | 
			
		||||
  std::vector<std::string> bzr_info = { bzr, "info" };
 | 
			
		||||
  const char* bzr = this->CommandLineTool.c_str();
 | 
			
		||||
  const char* bzr_info[] = { bzr, "info", nullptr };
 | 
			
		||||
  InfoParser iout(this, "info-out> ");
 | 
			
		||||
  OutputLogger ierr(this->Log, "info-err> ");
 | 
			
		||||
  this->RunChild(bzr_info, &iout, &ierr);
 | 
			
		||||
 | 
			
		||||
  // Run "bzr revno" to get the repository revision number from the work tree.
 | 
			
		||||
  std::vector<std::string> bzr_revno = { bzr, "revno" };
 | 
			
		||||
  const char* bzr_revno[] = { bzr, "revno", nullptr };
 | 
			
		||||
  std::string rev;
 | 
			
		||||
  RevnoParser rout(this, "revno-out> ", rev);
 | 
			
		||||
  OutputLogger rerr(this->Log, "revno-err> ");
 | 
			
		||||
@ -372,18 +372,22 @@ bool cmCTestBZR::UpdateImpl()
 | 
			
		||||
  // TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
 | 
			
		||||
 | 
			
		||||
  // Use "bzr pull" to update the working tree.
 | 
			
		||||
  std::vector<std::string> bzr_update;
 | 
			
		||||
  bzr_update.push_back(this->CommandLineTool);
 | 
			
		||||
  std::vector<char const*> bzr_update;
 | 
			
		||||
  bzr_update.push_back(this->CommandLineTool.c_str());
 | 
			
		||||
  bzr_update.push_back("pull");
 | 
			
		||||
 | 
			
		||||
  cm::append(bzr_update, args);
 | 
			
		||||
  for (std::string const& arg : args) {
 | 
			
		||||
    bzr_update.push_back(arg.c_str());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bzr_update.push_back(this->URL);
 | 
			
		||||
  bzr_update.push_back(this->URL.c_str());
 | 
			
		||||
 | 
			
		||||
  bzr_update.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  // For some reason bzr uses stderr to display the update status.
 | 
			
		||||
  OutputLogger out(this->Log, "pull-out> ");
 | 
			
		||||
  UpdateParser err(this, "pull-err> ");
 | 
			
		||||
  return this->RunUpdateCommand(bzr_update, &out, &err);
 | 
			
		||||
  return this->RunUpdateCommand(bzr_update.data(), &out, &err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmCTestBZR::LoadRevisions()
 | 
			
		||||
@ -404,9 +408,10 @@ bool cmCTestBZR::LoadRevisions()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Run "bzr log" to get all global revisions of interest.
 | 
			
		||||
  std::string bzr = this->CommandLineTool;
 | 
			
		||||
  std::vector<std::string> bzr_log = { bzr,  "log",   "-v",     "-r",
 | 
			
		||||
                                       revs, "--xml", this->URL };
 | 
			
		||||
  const char* bzr = this->CommandLineTool.c_str();
 | 
			
		||||
  const char* bzr_log[] = {
 | 
			
		||||
    bzr, "log", "-v", "-r", revs.c_str(), "--xml", this->URL.c_str(), nullptr
 | 
			
		||||
  };
 | 
			
		||||
  {
 | 
			
		||||
    LogParser out(this, "log-out> ");
 | 
			
		||||
    OutputLogger err(this->Log, "log-err> ");
 | 
			
		||||
@ -462,8 +467,8 @@ private:
 | 
			
		||||
bool cmCTestBZR::LoadModifications()
 | 
			
		||||
{
 | 
			
		||||
  // Run "bzr status" which reports local modifications.
 | 
			
		||||
  std::string bzr = this->CommandLineTool;
 | 
			
		||||
  std::vector<std::string> bzr_status = { bzr, "status", "-SV" };
 | 
			
		||||
  const char* bzr = this->CommandLineTool.c_str();
 | 
			
		||||
  const char* bzr_status[] = { bzr, "status", "-SV", nullptr };
 | 
			
		||||
  StatusParser out(this, "status-out> ");
 | 
			
		||||
  OutputLogger err(this->Log, "status-err> ");
 | 
			
		||||
  this->RunChild(bzr_status, &out, &err);
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,8 @@
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <ratio>
 | 
			
		||||
 | 
			
		||||
#include "cmsys/Process.h"
 | 
			
		||||
 | 
			
		||||
#include "cmBuildOptions.h"
 | 
			
		||||
#include "cmCTest.h"
 | 
			
		||||
#include "cmCTestTestHandler.h"
 | 
			
		||||
@ -306,11 +308,12 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
 | 
			
		||||
    return 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::vector<std::string> testCommand;
 | 
			
		||||
  testCommand.push_back(fullPath);
 | 
			
		||||
  std::vector<const char*> testCommand;
 | 
			
		||||
  testCommand.push_back(fullPath.c_str());
 | 
			
		||||
  for (std::string const& testCommandArg : this->TestCommandArgs) {
 | 
			
		||||
    testCommand.push_back(testCommandArg);
 | 
			
		||||
    testCommand.push_back(testCommandArg.c_str());
 | 
			
		||||
  }
 | 
			
		||||
  testCommand.push_back(nullptr);
 | 
			
		||||
  std::string outs;
 | 
			
		||||
  int retval = 0;
 | 
			
		||||
  // run the test from the this->BuildRunDir if set
 | 
			
		||||
@ -346,10 +349,10 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, nullptr,
 | 
			
		||||
                                         remainingTime, nullptr);
 | 
			
		||||
  int runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, nullptr,
 | 
			
		||||
                                        remainingTime, nullptr);
 | 
			
		||||
 | 
			
		||||
  if (!runTestRes || retval != 0) {
 | 
			
		||||
  if (runTestRes != cmsysProcess_State_Exited || retval != 0) {
 | 
			
		||||
    out << "Test command failed: " << testCommand[0] << "\n";
 | 
			
		||||
    retval = 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -3,17 +3,15 @@
 | 
			
		||||
#include "cmCTestBuildHandler.h"
 | 
			
		||||
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <ratio>
 | 
			
		||||
#include <set>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include <cmext/algorithm>
 | 
			
		||||
 | 
			
		||||
#include <cm3p/uv.h>
 | 
			
		||||
 | 
			
		||||
#include "cmsys/Directory.hxx"
 | 
			
		||||
#include "cmsys/FStream.hxx"
 | 
			
		||||
#include "cmsys/Process.h"
 | 
			
		||||
 | 
			
		||||
#include "cmCTest.h"
 | 
			
		||||
#include "cmCTestLaunchReporter.h"
 | 
			
		||||
@ -26,9 +24,6 @@
 | 
			
		||||
#include "cmStringAlgorithms.h"
 | 
			
		||||
#include "cmStringReplaceHelper.h"
 | 
			
		||||
#include "cmSystemTools.h"
 | 
			
		||||
#include "cmUVHandlePtr.h"
 | 
			
		||||
#include "cmUVProcessChain.h"
 | 
			
		||||
#include "cmUVStream.h"
 | 
			
		||||
#include "cmValue.h"
 | 
			
		||||
#include "cmXMLWriter.h"
 | 
			
		||||
 | 
			
		||||
@ -425,7 +420,7 @@ int cmCTestBuildHandler::ProcessHandler()
 | 
			
		||||
  cmStringReplaceHelper colorRemover("\x1b\\[[0-9;]*m", "", nullptr);
 | 
			
		||||
  this->ColorRemover = &colorRemover;
 | 
			
		||||
  int retVal = 0;
 | 
			
		||||
  bool res = true;
 | 
			
		||||
  int res = cmsysProcess_State_Exited;
 | 
			
		||||
  if (!this->CTest->GetShowOnly()) {
 | 
			
		||||
    res = this->RunMakeCommand(makeCommand, &retVal, buildDirectory.c_str(), 0,
 | 
			
		||||
                               ofs);
 | 
			
		||||
@ -480,7 +475,7 @@ int cmCTestBuildHandler::ProcessHandler()
 | 
			
		||||
  }
 | 
			
		||||
  this->GenerateXMLFooter(xml, elapsed_build_time);
 | 
			
		||||
 | 
			
		||||
  if (!res || retVal || this->TotalErrors > 0) {
 | 
			
		||||
  if (res != cmsysProcess_State_Exited || retVal || this->TotalErrors > 0) {
 | 
			
		||||
    cmCTestLog(this->CTest, ERROR_MESSAGE,
 | 
			
		||||
               "Error(s) when building project" << std::endl);
 | 
			
		||||
  }
 | 
			
		||||
@ -769,10 +764,10 @@ void cmCTestBuildHandler::LaunchHelper::WriteScrapeMatchers(
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmCTestBuildHandler::RunMakeCommand(const std::string& command,
 | 
			
		||||
                                         int* retVal, const char* dir,
 | 
			
		||||
                                         int timeout, std::ostream& ofs,
 | 
			
		||||
                                         Encoding encoding)
 | 
			
		||||
int cmCTestBuildHandler::RunMakeCommand(const std::string& command,
 | 
			
		||||
                                        int* retVal, const char* dir,
 | 
			
		||||
                                        int timeout, std::ostream& ofs,
 | 
			
		||||
                                        Encoding encoding)
 | 
			
		||||
{
 | 
			
		||||
  // First generate the command and arguments
 | 
			
		||||
  std::vector<std::string> args = cmSystemTools::ParseArguments(command);
 | 
			
		||||
@ -781,9 +776,19 @@ bool cmCTestBuildHandler::RunMakeCommand(const std::string& command,
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::vector<const char*> argv;
 | 
			
		||||
  argv.reserve(args.size() + 1);
 | 
			
		||||
  for (std::string const& arg : args) {
 | 
			
		||||
    argv.push_back(arg.c_str());
 | 
			
		||||
  }
 | 
			
		||||
  argv.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
                     "Run command:", this->Quiet);
 | 
			
		||||
  for (auto const& arg : args) {
 | 
			
		||||
  for (char const* arg : argv) {
 | 
			
		||||
    if (!arg) {
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
                       " \"" << arg << "\"", this->Quiet);
 | 
			
		||||
  }
 | 
			
		||||
@ -795,20 +800,21 @@ bool cmCTestBuildHandler::RunMakeCommand(const std::string& command,
 | 
			
		||||
  static_cast<void>(launchHelper);
 | 
			
		||||
 | 
			
		||||
  // Now create process object
 | 
			
		||||
  cmUVProcessChainBuilder builder;
 | 
			
		||||
  builder.AddCommand(args)
 | 
			
		||||
    .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
 | 
			
		||||
    .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
 | 
			
		||||
  if (dir) {
 | 
			
		||||
    builder.SetWorkingDirectory(dir);
 | 
			
		||||
  }
 | 
			
		||||
  auto chain = builder.Start();
 | 
			
		||||
  cmsysProcess* cp = cmsysProcess_New();
 | 
			
		||||
  cmsysProcess_SetCommand(cp, argv.data());
 | 
			
		||||
  cmsysProcess_SetWorkingDirectory(cp, dir);
 | 
			
		||||
  cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
 | 
			
		||||
  cmsysProcess_SetTimeout(cp, timeout);
 | 
			
		||||
  cmsysProcess_Execute(cp);
 | 
			
		||||
 | 
			
		||||
  // Initialize tick's
 | 
			
		||||
  std::string::size_type tick = 0;
 | 
			
		||||
  static constexpr std::string::size_type tick_len = 1024;
 | 
			
		||||
  const std::string::size_type tick_len = 1024;
 | 
			
		||||
 | 
			
		||||
  char* data;
 | 
			
		||||
  int length;
 | 
			
		||||
  cmProcessOutput processOutput(encoding);
 | 
			
		||||
  std::string strdata;
 | 
			
		||||
  cmCTestOptionalLog(
 | 
			
		||||
    this->CTest, HANDLER_PROGRESS_OUTPUT,
 | 
			
		||||
    "   Each symbol represents "
 | 
			
		||||
@ -830,65 +836,39 @@ bool cmCTestBuildHandler::RunMakeCommand(const std::string& command,
 | 
			
		||||
  this->WarningQuotaReached = false;
 | 
			
		||||
  this->ErrorQuotaReached = false;
 | 
			
		||||
 | 
			
		||||
  cm::uv_timer_ptr timer;
 | 
			
		||||
  bool timedOut = false;
 | 
			
		||||
  timer.init(chain.GetLoop(), &timedOut);
 | 
			
		||||
  if (timeout > 0) {
 | 
			
		||||
    timer.start(
 | 
			
		||||
      [](uv_timer_t* t) {
 | 
			
		||||
        auto* timedOutPtr = static_cast<bool*>(t->data);
 | 
			
		||||
        *timedOutPtr = true;
 | 
			
		||||
      },
 | 
			
		||||
      timeout * 1000, 0);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // For every chunk of data
 | 
			
		||||
  cm::uv_pipe_ptr outputStream;
 | 
			
		||||
  bool outFinished = false;
 | 
			
		||||
  cm::uv_pipe_ptr errorStream;
 | 
			
		||||
  bool errFinished = false;
 | 
			
		||||
  auto startRead = [this, &chain, &processOutput, &tick,
 | 
			
		||||
                    &ofs](cm::uv_pipe_ptr& pipe, int stream,
 | 
			
		||||
                          t_BuildProcessingQueueType& queue, bool& finished,
 | 
			
		||||
                          int id) -> std::unique_ptr<cmUVStreamReadHandle> {
 | 
			
		||||
    pipe.init(chain.GetLoop(), 0);
 | 
			
		||||
    uv_pipe_open(pipe, stream);
 | 
			
		||||
    return cmUVStreamRead(
 | 
			
		||||
      pipe,
 | 
			
		||||
      [this, &processOutput, &queue, id, &tick, &ofs](std::vector<char> data) {
 | 
			
		||||
        // Replace '\0' with '\n', since '\0' does not really make sense. This
 | 
			
		||||
        // is for Visual Studio output
 | 
			
		||||
        for (auto& c : data) {
 | 
			
		||||
          if (c == 0) {
 | 
			
		||||
            c = '\n';
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
  int res;
 | 
			
		||||
  while ((res = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) {
 | 
			
		||||
    // Replace '\0' with '\n', since '\0' does not really make sense. This is
 | 
			
		||||
    // for Visual Studio output
 | 
			
		||||
    for (int cc = 0; cc < length; ++cc) {
 | 
			
		||||
      if (data[cc] == 0) {
 | 
			
		||||
        data[cc] = '\n';
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        // Process the chunk of data
 | 
			
		||||
        std::string strdata;
 | 
			
		||||
        processOutput.DecodeText(data.data(), data.size(), strdata, id);
 | 
			
		||||
        this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len,
 | 
			
		||||
                            ofs, &queue);
 | 
			
		||||
      },
 | 
			
		||||
      [this, &processOutput, &queue, id, &tick, &ofs, &finished]() {
 | 
			
		||||
        std::string strdata;
 | 
			
		||||
        processOutput.DecodeText(std::string(), strdata, id);
 | 
			
		||||
        if (!strdata.empty()) {
 | 
			
		||||
          this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len,
 | 
			
		||||
                              ofs, &queue);
 | 
			
		||||
        }
 | 
			
		||||
        finished = true;
 | 
			
		||||
      });
 | 
			
		||||
  };
 | 
			
		||||
  auto outputHandle = startRead(outputStream, chain.OutputStream(),
 | 
			
		||||
                                this->BuildProcessingQueue, outFinished, 1);
 | 
			
		||||
  auto errorHandle =
 | 
			
		||||
    startRead(errorStream, chain.ErrorStream(),
 | 
			
		||||
              this->BuildProcessingErrorQueue, errFinished, 2);
 | 
			
		||||
 | 
			
		||||
  while (!timedOut && !(outFinished && errFinished && chain.Finished())) {
 | 
			
		||||
    uv_run(&chain.GetLoop(), UV_RUN_ONCE);
 | 
			
		||||
    // Process the chunk of data
 | 
			
		||||
    if (res == cmsysProcess_Pipe_STDERR) {
 | 
			
		||||
      processOutput.DecodeText(data, length, strdata, 1);
 | 
			
		||||
      this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs,
 | 
			
		||||
                          &this->BuildProcessingErrorQueue);
 | 
			
		||||
    } else {
 | 
			
		||||
      processOutput.DecodeText(data, length, strdata, 2);
 | 
			
		||||
      this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs,
 | 
			
		||||
                          &this->BuildProcessingQueue);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  processOutput.DecodeText(std::string(), strdata, 1);
 | 
			
		||||
  if (!strdata.empty()) {
 | 
			
		||||
    this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs,
 | 
			
		||||
                        &this->BuildProcessingErrorQueue);
 | 
			
		||||
  }
 | 
			
		||||
  processOutput.DecodeText(std::string(), strdata, 2);
 | 
			
		||||
  if (!strdata.empty()) {
 | 
			
		||||
    this->ProcessBuffer(strdata.c_str(), strdata.size(), tick, tick_len, ofs,
 | 
			
		||||
                        &this->BuildProcessingQueue);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this->ProcessBuffer(nullptr, 0, tick, tick_len, ofs,
 | 
			
		||||
                      &this->BuildProcessingQueue);
 | 
			
		||||
  this->ProcessBuffer(nullptr, 0, tick, tick_len, ofs,
 | 
			
		||||
@ -899,93 +879,90 @@ bool cmCTestBuildHandler::RunMakeCommand(const std::string& command,
 | 
			
		||||
                       << std::endl,
 | 
			
		||||
                     this->Quiet);
 | 
			
		||||
 | 
			
		||||
  if (chain.Finished()) {
 | 
			
		||||
    auto const& status = chain.GetStatus(0);
 | 
			
		||||
    auto exception = status.GetException();
 | 
			
		||||
    switch (exception.first) {
 | 
			
		||||
      case cmUVProcessChain::ExceptionCode::None:
 | 
			
		||||
        if (retVal) {
 | 
			
		||||
          *retVal = static_cast<int>(status.ExitStatus);
 | 
			
		||||
          cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
                             "Command exited with the value: " << *retVal
 | 
			
		||||
                                                               << std::endl,
 | 
			
		||||
                             this->Quiet);
 | 
			
		||||
          // if a non zero return value
 | 
			
		||||
          if (*retVal) {
 | 
			
		||||
            // If there was an error running command, report that on the
 | 
			
		||||
            // dashboard.
 | 
			
		||||
            if (this->UseCTestLaunch) {
 | 
			
		||||
              // For launchers, do not record this top-level error if other
 | 
			
		||||
              // more granular build errors have already been captured.
 | 
			
		||||
              bool launcherXMLFound = false;
 | 
			
		||||
              cmsys::Directory launchDir;
 | 
			
		||||
              launchDir.Load(this->CTestLaunchDir);
 | 
			
		||||
              unsigned long n = launchDir.GetNumberOfFiles();
 | 
			
		||||
              for (unsigned long i = 0; i < n; ++i) {
 | 
			
		||||
                const char* fname = launchDir.GetFile(i);
 | 
			
		||||
                if (cmHasLiteralSuffix(fname, ".xml")) {
 | 
			
		||||
                  launcherXMLFound = true;
 | 
			
		||||
                  break;
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
              if (!launcherXMLFound) {
 | 
			
		||||
                cmCTestLaunchReporter reporter;
 | 
			
		||||
                reporter.RealArgs = args;
 | 
			
		||||
                reporter.ComputeFileNames();
 | 
			
		||||
                reporter.ExitCode = *retVal;
 | 
			
		||||
                reporter.Status = status;
 | 
			
		||||
                // Use temporary BuildLog file to populate this error for
 | 
			
		||||
                // CDash.
 | 
			
		||||
                ofs.flush();
 | 
			
		||||
                reporter.LogOut = this->LogFileNames["Build"];
 | 
			
		||||
                reporter.LogOut += ".tmp";
 | 
			
		||||
                reporter.WriteXML();
 | 
			
		||||
              }
 | 
			
		||||
            } else {
 | 
			
		||||
              cmCTestBuildErrorWarning errorwarning;
 | 
			
		||||
              errorwarning.LineNumber = 0;
 | 
			
		||||
              errorwarning.LogLine = 1;
 | 
			
		||||
              errorwarning.Text = cmStrCat(
 | 
			
		||||
                "*** WARNING non-zero return value in ctest from: ", args[0]);
 | 
			
		||||
              errorwarning.PreContext.clear();
 | 
			
		||||
              errorwarning.PostContext.clear();
 | 
			
		||||
              errorwarning.Error = false;
 | 
			
		||||
              this->ErrorsAndWarnings.push_back(std::move(errorwarning));
 | 
			
		||||
              this->TotalWarnings++;
 | 
			
		||||
  // Properly handle output of the build command
 | 
			
		||||
  cmsysProcess_WaitForExit(cp, nullptr);
 | 
			
		||||
  int result = cmsysProcess_GetState(cp);
 | 
			
		||||
 | 
			
		||||
  if (result == cmsysProcess_State_Exited) {
 | 
			
		||||
    if (retVal) {
 | 
			
		||||
      *retVal = cmsysProcess_GetExitValue(cp);
 | 
			
		||||
      cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
                         "Command exited with the value: " << *retVal
 | 
			
		||||
                                                           << std::endl,
 | 
			
		||||
                         this->Quiet);
 | 
			
		||||
      // if a non zero return value
 | 
			
		||||
      if (*retVal) {
 | 
			
		||||
        // If there was an error running command, report that on the
 | 
			
		||||
        // dashboard.
 | 
			
		||||
        if (this->UseCTestLaunch) {
 | 
			
		||||
          // For launchers, do not record this top-level error if other
 | 
			
		||||
          // more granular build errors have already been captured.
 | 
			
		||||
          bool launcherXMLFound = false;
 | 
			
		||||
          cmsys::Directory launchDir;
 | 
			
		||||
          launchDir.Load(this->CTestLaunchDir);
 | 
			
		||||
          unsigned long n = launchDir.GetNumberOfFiles();
 | 
			
		||||
          for (unsigned long i = 0; i < n; ++i) {
 | 
			
		||||
            const char* fname = launchDir.GetFile(i);
 | 
			
		||||
            if (cmHasLiteralSuffix(fname, ".xml")) {
 | 
			
		||||
              launcherXMLFound = true;
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          if (!launcherXMLFound) {
 | 
			
		||||
            cmCTestLaunchReporter reporter;
 | 
			
		||||
            reporter.RealArgs = args;
 | 
			
		||||
            reporter.ComputeFileNames();
 | 
			
		||||
            reporter.ExitCode = *retVal;
 | 
			
		||||
            reporter.Process = cp;
 | 
			
		||||
            // Use temporary BuildLog file to populate this error for CDash.
 | 
			
		||||
            ofs.flush();
 | 
			
		||||
            reporter.LogOut = this->LogFileNames["Build"];
 | 
			
		||||
            reporter.LogOut += ".tmp";
 | 
			
		||||
            reporter.WriteXML();
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          cmCTestBuildErrorWarning errorwarning;
 | 
			
		||||
          errorwarning.LineNumber = 0;
 | 
			
		||||
          errorwarning.LogLine = 1;
 | 
			
		||||
          errorwarning.Text = cmStrCat(
 | 
			
		||||
            "*** WARNING non-zero return value in ctest from: ", argv[0]);
 | 
			
		||||
          errorwarning.PreContext.clear();
 | 
			
		||||
          errorwarning.PostContext.clear();
 | 
			
		||||
          errorwarning.Error = false;
 | 
			
		||||
          this->ErrorsAndWarnings.push_back(std::move(errorwarning));
 | 
			
		||||
          this->TotalWarnings++;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case cmUVProcessChain::ExceptionCode::Spawn: {
 | 
			
		||||
        // If there was an error running command, report that on the dashboard.
 | 
			
		||||
        cmCTestBuildErrorWarning errorwarning;
 | 
			
		||||
        errorwarning.LineNumber = 0;
 | 
			
		||||
        errorwarning.LogLine = 1;
 | 
			
		||||
        errorwarning.Text =
 | 
			
		||||
          cmStrCat("*** ERROR executing: ", exception.second);
 | 
			
		||||
        errorwarning.PreContext.clear();
 | 
			
		||||
        errorwarning.PostContext.clear();
 | 
			
		||||
        errorwarning.Error = true;
 | 
			
		||||
        this->ErrorsAndWarnings.push_back(std::move(errorwarning));
 | 
			
		||||
        this->TotalErrors++;
 | 
			
		||||
        cmCTestLog(this->CTest, ERROR_MESSAGE,
 | 
			
		||||
                   "There was an error: " << exception.second << std::endl);
 | 
			
		||||
      } break;
 | 
			
		||||
      default:
 | 
			
		||||
        if (retVal) {
 | 
			
		||||
          *retVal = status.TermSignal;
 | 
			
		||||
          cmCTestOptionalLog(
 | 
			
		||||
            this->CTest, WARNING,
 | 
			
		||||
            "There was an exception: " << *retVal << std::endl, this->Quiet);
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
  } else if (result == cmsysProcess_State_Exception) {
 | 
			
		||||
    if (retVal) {
 | 
			
		||||
      *retVal = cmsysProcess_GetExitException(cp);
 | 
			
		||||
      cmCTestOptionalLog(this->CTest, WARNING,
 | 
			
		||||
                         "There was an exception: " << *retVal << std::endl,
 | 
			
		||||
                         this->Quiet);
 | 
			
		||||
    }
 | 
			
		||||
  } else if (result == cmsysProcess_State_Expired) {
 | 
			
		||||
    cmCTestOptionalLog(this->CTest, WARNING,
 | 
			
		||||
                       "There was a timeout" << std::endl, this->Quiet);
 | 
			
		||||
  } else if (result == cmsysProcess_State_Error) {
 | 
			
		||||
    // If there was an error running command, report that on the dashboard.
 | 
			
		||||
    cmCTestBuildErrorWarning errorwarning;
 | 
			
		||||
    errorwarning.LineNumber = 0;
 | 
			
		||||
    errorwarning.LogLine = 1;
 | 
			
		||||
    errorwarning.Text =
 | 
			
		||||
      cmStrCat("*** ERROR executing: ", cmsysProcess_GetErrorString(cp));
 | 
			
		||||
    errorwarning.PreContext.clear();
 | 
			
		||||
    errorwarning.PostContext.clear();
 | 
			
		||||
    errorwarning.Error = true;
 | 
			
		||||
    this->ErrorsAndWarnings.push_back(std::move(errorwarning));
 | 
			
		||||
    this->TotalErrors++;
 | 
			
		||||
    cmCTestLog(this->CTest, ERROR_MESSAGE,
 | 
			
		||||
               "There was an error: " << cmsysProcess_GetErrorString(cp)
 | 
			
		||||
                                      << std::endl);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
  cmsysProcess_Delete(cp);
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ######################################################################
 | 
			
		||||
 | 
			
		||||
@ -53,9 +53,9 @@ private:
 | 
			
		||||
 | 
			
		||||
  //! Run command specialized for make and configure. Returns process status
 | 
			
		||||
  // and retVal is return value or exception.
 | 
			
		||||
  bool RunMakeCommand(const std::string& command, int* retVal, const char* dir,
 | 
			
		||||
                      int timeout, std::ostream& ofs,
 | 
			
		||||
                      Encoding encoding = cmProcessOutput::Auto);
 | 
			
		||||
  int RunMakeCommand(const std::string& command, int* retVal, const char* dir,
 | 
			
		||||
                     int timeout, std::ostream& ofs,
 | 
			
		||||
                     Encoding encoding = cmProcessOutput::Auto);
 | 
			
		||||
 | 
			
		||||
  enum
 | 
			
		||||
  {
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,6 @@
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include <cm/string_view>
 | 
			
		||||
#include <cmext/algorithm>
 | 
			
		||||
 | 
			
		||||
#include "cmsys/FStream.hxx"
 | 
			
		||||
#include "cmsys/RegularExpression.hxx"
 | 
			
		||||
@ -90,15 +89,18 @@ bool cmCTestCVS::UpdateImpl()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Run "cvs update" to update the work tree.
 | 
			
		||||
  std::vector<std::string> cvs_update;
 | 
			
		||||
  cvs_update.push_back(this->CommandLineTool);
 | 
			
		||||
  std::vector<char const*> cvs_update;
 | 
			
		||||
  cvs_update.push_back(this->CommandLineTool.c_str());
 | 
			
		||||
  cvs_update.push_back("-z3");
 | 
			
		||||
  cvs_update.push_back("update");
 | 
			
		||||
  cm::append(cvs_update, args);
 | 
			
		||||
  for (std::string const& arg : args) {
 | 
			
		||||
    cvs_update.push_back(arg.c_str());
 | 
			
		||||
  }
 | 
			
		||||
  cvs_update.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  UpdateParser out(this, "up-out> ");
 | 
			
		||||
  UpdateParser err(this, "up-err> ");
 | 
			
		||||
  return this->RunUpdateCommand(cvs_update, &out, &err);
 | 
			
		||||
  return this->RunUpdateCommand(cvs_update.data(), &out, &err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class cmCTestCVS::LogParser : public cmCTestVC::LineParser
 | 
			
		||||
@ -219,8 +221,10 @@ void cmCTestCVS::LoadRevisions(std::string const& file, const char* branchFlag,
 | 
			
		||||
  cmCTestLog(this->CTest, HANDLER_OUTPUT, "." << std::flush);
 | 
			
		||||
 | 
			
		||||
  // Run "cvs log" to get revisions of this file on this branch.
 | 
			
		||||
  std::string cvs = this->CommandLineTool;
 | 
			
		||||
  std::vector<std::string> cvs_log = { cvs, "log", "-N", branchFlag, file };
 | 
			
		||||
  const char* cvs = this->CommandLineTool.c_str();
 | 
			
		||||
  const char* cvs_log[] = {
 | 
			
		||||
    cvs, "log", "-N", branchFlag, file.c_str(), nullptr
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  LogParser out(this, "log-out> ", revisions);
 | 
			
		||||
  OutputLogger err(this->Log, "log-err> ");
 | 
			
		||||
 | 
			
		||||
@ -45,7 +45,7 @@ int cmCTestConfigureHandler::ProcessHandler()
 | 
			
		||||
  auto elapsed_time_start = std::chrono::steady_clock::now();
 | 
			
		||||
  std::string output;
 | 
			
		||||
  int retVal = 0;
 | 
			
		||||
  bool res = false;
 | 
			
		||||
  int res = 0;
 | 
			
		||||
  if (!this->CTest->GetShowOnly()) {
 | 
			
		||||
    cmGeneratedFileStream os;
 | 
			
		||||
    if (!this->StartResultingXML(cmCTest::PartConfigure, "Configure", os)) {
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,6 @@
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <ratio>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
@ -19,10 +18,9 @@
 | 
			
		||||
 | 
			
		||||
#include "cmsys/FStream.hxx"
 | 
			
		||||
#include "cmsys/Glob.hxx"
 | 
			
		||||
#include "cmsys/Process.h"
 | 
			
		||||
#include "cmsys/RegularExpression.hxx"
 | 
			
		||||
 | 
			
		||||
#include "cm_fileno.hxx"
 | 
			
		||||
 | 
			
		||||
#include "cmCTest.h"
 | 
			
		||||
#include "cmDuration.h"
 | 
			
		||||
#include "cmGeneratedFileStream.h"
 | 
			
		||||
@ -35,7 +33,6 @@
 | 
			
		||||
#include "cmParsePHPCoverage.h"
 | 
			
		||||
#include "cmStringAlgorithms.h"
 | 
			
		||||
#include "cmSystemTools.h"
 | 
			
		||||
#include "cmUVProcessChain.h"
 | 
			
		||||
#include "cmWorkingDirectory.h"
 | 
			
		||||
#include "cmXMLWriter.h"
 | 
			
		||||
 | 
			
		||||
@ -43,6 +40,85 @@ class cmMakefile;
 | 
			
		||||
 | 
			
		||||
#define SAFEDIV(x, y) (((y) != 0) ? ((x) / (y)) : (0))
 | 
			
		||||
 | 
			
		||||
class cmCTestRunProcess
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
  cmCTestRunProcess()
 | 
			
		||||
  {
 | 
			
		||||
    this->Process = cmsysProcess_New();
 | 
			
		||||
    this->PipeState = -1;
 | 
			
		||||
    this->TimeOut = cmDuration(-1);
 | 
			
		||||
  }
 | 
			
		||||
  ~cmCTestRunProcess()
 | 
			
		||||
  {
 | 
			
		||||
    if (this->PipeState != -1 && this->PipeState != cmsysProcess_Pipe_None &&
 | 
			
		||||
        this->PipeState != cmsysProcess_Pipe_Timeout) {
 | 
			
		||||
      this->WaitForExit();
 | 
			
		||||
    }
 | 
			
		||||
    cmsysProcess_Delete(this->Process);
 | 
			
		||||
  }
 | 
			
		||||
  cmCTestRunProcess(const cmCTestRunProcess&) = delete;
 | 
			
		||||
  cmCTestRunProcess& operator=(const cmCTestRunProcess&) = delete;
 | 
			
		||||
  void SetCommand(const char* command)
 | 
			
		||||
  {
 | 
			
		||||
    this->CommandLineStrings.clear();
 | 
			
		||||
    this->CommandLineStrings.emplace_back(command);
 | 
			
		||||
  }
 | 
			
		||||
  void AddArgument(const char* arg)
 | 
			
		||||
  {
 | 
			
		||||
    if (arg) {
 | 
			
		||||
      this->CommandLineStrings.emplace_back(arg);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  void SetWorkingDirectory(const char* dir) { this->WorkingDirectory = dir; }
 | 
			
		||||
  void SetTimeout(cmDuration t) { this->TimeOut = t; }
 | 
			
		||||
  bool StartProcess()
 | 
			
		||||
  {
 | 
			
		||||
    std::vector<const char*> args;
 | 
			
		||||
    args.reserve(this->CommandLineStrings.size());
 | 
			
		||||
    for (std::string const& cl : this->CommandLineStrings) {
 | 
			
		||||
      args.push_back(cl.c_str());
 | 
			
		||||
    }
 | 
			
		||||
    args.push_back(nullptr); // null terminate
 | 
			
		||||
    cmsysProcess_SetCommand(this->Process, args.data());
 | 
			
		||||
    if (!this->WorkingDirectory.empty()) {
 | 
			
		||||
      cmsysProcess_SetWorkingDirectory(this->Process,
 | 
			
		||||
                                       this->WorkingDirectory.c_str());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cmsysProcess_SetOption(this->Process, cmsysProcess_Option_HideWindow, 1);
 | 
			
		||||
    if (this->TimeOut >= cmDuration::zero()) {
 | 
			
		||||
      cmsysProcess_SetTimeout(this->Process, this->TimeOut.count());
 | 
			
		||||
    }
 | 
			
		||||
    cmsysProcess_Execute(this->Process);
 | 
			
		||||
    this->PipeState = cmsysProcess_GetState(this->Process);
 | 
			
		||||
    // if the process is running or exited return true
 | 
			
		||||
    return this->PipeState == cmsysProcess_State_Executing ||
 | 
			
		||||
      this->PipeState == cmsysProcess_State_Exited;
 | 
			
		||||
  }
 | 
			
		||||
  void SetStdoutFile(const char* fname)
 | 
			
		||||
  {
 | 
			
		||||
    cmsysProcess_SetPipeFile(this->Process, cmsysProcess_Pipe_STDOUT, fname);
 | 
			
		||||
  }
 | 
			
		||||
  void SetStderrFile(const char* fname)
 | 
			
		||||
  {
 | 
			
		||||
    cmsysProcess_SetPipeFile(this->Process, cmsysProcess_Pipe_STDERR, fname);
 | 
			
		||||
  }
 | 
			
		||||
  int WaitForExit(double* timeout = nullptr)
 | 
			
		||||
  {
 | 
			
		||||
    this->PipeState = cmsysProcess_WaitForExit(this->Process, timeout);
 | 
			
		||||
    return this->PipeState;
 | 
			
		||||
  }
 | 
			
		||||
  int GetProcessState() const { return this->PipeState; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  int PipeState;
 | 
			
		||||
  cmsysProcess* Process;
 | 
			
		||||
  std::vector<std::string> CommandLineStrings;
 | 
			
		||||
  std::string WorkingDirectory;
 | 
			
		||||
  cmDuration TimeOut;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
cmCTestCoverageHandler::cmCTestCoverageHandler() = default;
 | 
			
		||||
 | 
			
		||||
void cmCTestCoverageHandler::Initialize()
 | 
			
		||||
@ -1864,35 +1940,34 @@ int cmCTestCoverageHandler::RunBullseyeCommand(
 | 
			
		||||
    cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot find :" << cmd << "\n");
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
  std::vector<std::string> args{ cmd };
 | 
			
		||||
  if (arg) {
 | 
			
		||||
    cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
                       "Run : " << program << " " << arg << "\n", this->Quiet);
 | 
			
		||||
    args.emplace_back(arg);
 | 
			
		||||
  } else {
 | 
			
		||||
    cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
                       "Run : " << program << "\n", this->Quiet);
 | 
			
		||||
  }
 | 
			
		||||
  // create a process object and start it
 | 
			
		||||
  cmUVProcessChainBuilder builder;
 | 
			
		||||
  cmCTestRunProcess runCoverageSrc;
 | 
			
		||||
  runCoverageSrc.SetCommand(program.c_str());
 | 
			
		||||
  runCoverageSrc.AddArgument(arg);
 | 
			
		||||
  std::string stdoutFile =
 | 
			
		||||
    cmStrCat(cont->BinaryDir, "/Testing/Temporary/",
 | 
			
		||||
             this->GetCTestInstance()->GetCurrentTag(), '-', cmd);
 | 
			
		||||
  std::string stderrFile = stdoutFile;
 | 
			
		||||
  stdoutFile += ".stdout";
 | 
			
		||||
  stderrFile += ".stderr";
 | 
			
		||||
  std::unique_ptr<FILE, int (*)(FILE*)> stdoutHandle(
 | 
			
		||||
    cmsys::SystemTools::Fopen(stdoutFile, "w"), fclose);
 | 
			
		||||
  std::unique_ptr<FILE, int (*)(FILE*)> stderrHandle(
 | 
			
		||||
    cmsys::SystemTools::Fopen(stderrFile, "w"), fclose);
 | 
			
		||||
  builder.AddCommand(args)
 | 
			
		||||
    .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT,
 | 
			
		||||
                       cm_fileno(stdoutHandle.get()))
 | 
			
		||||
    .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR,
 | 
			
		||||
                       cm_fileno(stderrHandle.get()));
 | 
			
		||||
  runCoverageSrc.SetStdoutFile(stdoutFile.c_str());
 | 
			
		||||
  runCoverageSrc.SetStderrFile(stderrFile.c_str());
 | 
			
		||||
  if (!runCoverageSrc.StartProcess()) {
 | 
			
		||||
    cmCTestLog(this->CTest, ERROR_MESSAGE,
 | 
			
		||||
               "Could not run : " << program << " " << arg << "\n"
 | 
			
		||||
                                  << "kwsys process state : "
 | 
			
		||||
                                  << runCoverageSrc.GetProcessState());
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
  // since we set the output file names wait for it to end
 | 
			
		||||
  auto chain = builder.Start();
 | 
			
		||||
  chain.Wait();
 | 
			
		||||
  runCoverageSrc.WaitForExit();
 | 
			
		||||
  outputFile = stdoutFile;
 | 
			
		||||
  return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -9,9 +9,8 @@
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include <cmext/algorithm>
 | 
			
		||||
 | 
			
		||||
#include "cmsys/FStream.hxx"
 | 
			
		||||
#include "cmsys/Process.h"
 | 
			
		||||
 | 
			
		||||
#include "cmCTest.h"
 | 
			
		||||
#include "cmCTestVC.h"
 | 
			
		||||
@ -19,7 +18,6 @@
 | 
			
		||||
#include "cmProcessOutput.h"
 | 
			
		||||
#include "cmStringAlgorithms.h"
 | 
			
		||||
#include "cmSystemTools.h"
 | 
			
		||||
#include "cmUVProcessChain.h"
 | 
			
		||||
#include "cmValue.h"
 | 
			
		||||
 | 
			
		||||
static unsigned int cmCTestGITVersion(unsigned int epic, unsigned int major,
 | 
			
		||||
@ -60,9 +58,9 @@ private:
 | 
			
		||||
std::string cmCTestGIT::GetWorkingRevision()
 | 
			
		||||
{
 | 
			
		||||
  // Run plumbing "git rev-list" to get work tree revision.
 | 
			
		||||
  std::string git = this->CommandLineTool;
 | 
			
		||||
  std::vector<std::string> git_rev_list = { git, "rev-list", "-n",
 | 
			
		||||
                                            "1", "HEAD",     "--" };
 | 
			
		||||
  const char* git = this->CommandLineTool.c_str();
 | 
			
		||||
  const char* git_rev_list[] = { git,    "rev-list", "-n",   "1",
 | 
			
		||||
                                 "HEAD", "--",       nullptr };
 | 
			
		||||
  std::string rev;
 | 
			
		||||
  OneLineParser out(this, "rl-out> ", rev);
 | 
			
		||||
  OutputLogger err(this->Log, "rl-err> ");
 | 
			
		||||
@ -94,13 +92,13 @@ std::string cmCTestGIT::FindGitDir()
 | 
			
		||||
  std::string git_dir;
 | 
			
		||||
 | 
			
		||||
  // Run "git rev-parse --git-dir" to locate the real .git directory.
 | 
			
		||||
  std::string git = this->CommandLineTool;
 | 
			
		||||
  std::vector<std::string> git_rev_parse = { git, "rev-parse", "--git-dir" };
 | 
			
		||||
  const char* git = this->CommandLineTool.c_str();
 | 
			
		||||
  char const* git_rev_parse[] = { git, "rev-parse", "--git-dir", nullptr };
 | 
			
		||||
  std::string git_dir_line;
 | 
			
		||||
  OneLineParser rev_parse_out(this, "rev-parse-out> ", git_dir_line);
 | 
			
		||||
  OutputLogger rev_parse_err(this->Log, "rev-parse-err> ");
 | 
			
		||||
  if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err,
 | 
			
		||||
                     std::string{}, cmProcessOutput::UTF8)) {
 | 
			
		||||
  if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, nullptr,
 | 
			
		||||
                     cmProcessOutput::UTF8)) {
 | 
			
		||||
    git_dir = git_dir_line;
 | 
			
		||||
  }
 | 
			
		||||
  if (git_dir.empty()) {
 | 
			
		||||
@ -119,10 +117,11 @@ std::string cmCTestGIT::FindGitDir()
 | 
			
		||||
    std::string cygpath_exe =
 | 
			
		||||
      cmStrCat(cmSystemTools::GetFilenamePath(git), "/cygpath.exe");
 | 
			
		||||
    if (cmSystemTools::FileExists(cygpath_exe)) {
 | 
			
		||||
      std::vector<std::string> cygpath = { cygpath_exe, "-w", git_dir };
 | 
			
		||||
      char const* cygpath[] = { cygpath_exe.c_str(), "-w", git_dir.c_str(),
 | 
			
		||||
                                0 };
 | 
			
		||||
      OneLineParser cygpath_out(this, "cygpath-out> ", git_dir_line);
 | 
			
		||||
      OutputLogger cygpath_err(this->Log, "cygpath-err> ");
 | 
			
		||||
      if (this->RunChild(cygpath, &cygpath_out, &cygpath_err, std::string{},
 | 
			
		||||
      if (this->RunChild(cygpath, &cygpath_out, &cygpath_err, nullptr,
 | 
			
		||||
                         cmProcessOutput::UTF8)) {
 | 
			
		||||
        git_dir = git_dir_line;
 | 
			
		||||
      }
 | 
			
		||||
@ -137,12 +136,12 @@ std::string cmCTestGIT::FindTopDir()
 | 
			
		||||
  std::string top_dir = this->SourceDirectory;
 | 
			
		||||
 | 
			
		||||
  // Run "git rev-parse --show-cdup" to locate the top of the tree.
 | 
			
		||||
  std::string git = this->CommandLineTool;
 | 
			
		||||
  std::vector<std::string> git_rev_parse = { git, "rev-parse", "--show-cdup" };
 | 
			
		||||
  const char* git = this->CommandLineTool.c_str();
 | 
			
		||||
  char const* git_rev_parse[] = { git, "rev-parse", "--show-cdup", nullptr };
 | 
			
		||||
  std::string cdup;
 | 
			
		||||
  OneLineParser rev_parse_out(this, "rev-parse-out> ", cdup);
 | 
			
		||||
  OutputLogger rev_parse_err(this->Log, "rev-parse-err> ");
 | 
			
		||||
  if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, "",
 | 
			
		||||
  if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, nullptr,
 | 
			
		||||
                     cmProcessOutput::UTF8) &&
 | 
			
		||||
      !cdup.empty()) {
 | 
			
		||||
    top_dir += "/";
 | 
			
		||||
@ -154,10 +153,10 @@ std::string cmCTestGIT::FindTopDir()
 | 
			
		||||
 | 
			
		||||
bool cmCTestGIT::UpdateByFetchAndReset()
 | 
			
		||||
{
 | 
			
		||||
  std::string git = this->CommandLineTool;
 | 
			
		||||
  const char* git = this->CommandLineTool.c_str();
 | 
			
		||||
 | 
			
		||||
  // Use "git fetch" to get remote commits.
 | 
			
		||||
  std::vector<std::string> git_fetch;
 | 
			
		||||
  std::vector<char const*> git_fetch;
 | 
			
		||||
  git_fetch.push_back(git);
 | 
			
		||||
  git_fetch.push_back("fetch");
 | 
			
		||||
 | 
			
		||||
@ -167,12 +166,17 @@ bool cmCTestGIT::UpdateByFetchAndReset()
 | 
			
		||||
    opts = this->CTest->GetCTestConfiguration("GITUpdateOptions");
 | 
			
		||||
  }
 | 
			
		||||
  std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
 | 
			
		||||
  cm::append(git_fetch, args);
 | 
			
		||||
  for (std::string const& arg : args) {
 | 
			
		||||
    git_fetch.push_back(arg.c_str());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Sentinel argument.
 | 
			
		||||
  git_fetch.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  // Fetch upstream refs.
 | 
			
		||||
  OutputLogger fetch_out(this->Log, "fetch-out> ");
 | 
			
		||||
  OutputLogger fetch_err(this->Log, "fetch-err> ");
 | 
			
		||||
  if (!this->RunUpdateCommand(git_fetch, &fetch_out, &fetch_err)) {
 | 
			
		||||
  if (!this->RunUpdateCommand(git_fetch.data(), &fetch_out, &fetch_err)) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -203,22 +207,25 @@ bool cmCTestGIT::UpdateByFetchAndReset()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Reset the local branch to point at that tracked from upstream.
 | 
			
		||||
  std::vector<std::string> git_reset = { git, "reset", "--hard", sha1 };
 | 
			
		||||
  char const* git_reset[] = { git, "reset", "--hard", sha1.c_str(), nullptr };
 | 
			
		||||
  OutputLogger reset_out(this->Log, "reset-out> ");
 | 
			
		||||
  OutputLogger reset_err(this->Log, "reset-err> ");
 | 
			
		||||
  return this->RunChild(git_reset, &reset_out, &reset_err);
 | 
			
		||||
  return this->RunChild(&git_reset[0], &reset_out, &reset_err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmCTestGIT::UpdateByCustom(std::string const& custom)
 | 
			
		||||
{
 | 
			
		||||
  cmList git_custom_command{ custom, cmList::EmptyElements::Yes };
 | 
			
		||||
  std::vector<std::string> git_custom;
 | 
			
		||||
  git_custom.reserve(git_custom_command.size());
 | 
			
		||||
  cm::append(git_custom, git_custom_command);
 | 
			
		||||
  std::vector<char const*> git_custom;
 | 
			
		||||
  git_custom.reserve(git_custom_command.size() + 1);
 | 
			
		||||
  for (std::string const& i : git_custom_command) {
 | 
			
		||||
    git_custom.push_back(i.c_str());
 | 
			
		||||
  }
 | 
			
		||||
  git_custom.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  OutputLogger custom_out(this->Log, "custom-out> ");
 | 
			
		||||
  OutputLogger custom_err(this->Log, "custom-err> ");
 | 
			
		||||
  return this->RunUpdateCommand(git_custom, &custom_out, &custom_err);
 | 
			
		||||
  return this->RunUpdateCommand(git_custom.data(), &custom_out, &custom_err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmCTestGIT::UpdateInternal()
 | 
			
		||||
@ -237,14 +244,13 @@ bool cmCTestGIT::UpdateImpl()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::string top_dir = this->FindTopDir();
 | 
			
		||||
  std::string git = this->CommandLineTool;
 | 
			
		||||
  std::string recursive = "--recursive";
 | 
			
		||||
  std::string sync_recursive = "--recursive";
 | 
			
		||||
  const char* git = this->CommandLineTool.c_str();
 | 
			
		||||
  const char* recursive = "--recursive";
 | 
			
		||||
  const char* sync_recursive = "--recursive";
 | 
			
		||||
 | 
			
		||||
  // Git < 1.6.5 did not support submodule --recursive
 | 
			
		||||
  bool support_recursive = true;
 | 
			
		||||
  if (this->GetGitVersion() < cmCTestGITVersion(1, 6, 5, 0)) {
 | 
			
		||||
    support_recursive = false;
 | 
			
		||||
    recursive = nullptr;
 | 
			
		||||
    // No need to require >= 1.6.5 if there are no submodules.
 | 
			
		||||
    if (cmSystemTools::FileExists(top_dir + "/.gitmodules")) {
 | 
			
		||||
      this->Log << "Git < 1.6.5 cannot update submodules recursively\n";
 | 
			
		||||
@ -252,9 +258,8 @@ bool cmCTestGIT::UpdateImpl()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Git < 1.8.1 did not support sync --recursive
 | 
			
		||||
  bool support_sync_recursive = true;
 | 
			
		||||
  if (this->GetGitVersion() < cmCTestGITVersion(1, 8, 1, 0)) {
 | 
			
		||||
    support_sync_recursive = false;
 | 
			
		||||
    sync_recursive = nullptr;
 | 
			
		||||
    // No need to require >= 1.8.1 if there are no submodules.
 | 
			
		||||
    if (cmSystemTools::FileExists(top_dir + "/.gitmodules")) {
 | 
			
		||||
      this->Log << "Git < 1.8.1 cannot synchronize submodules recursively\n";
 | 
			
		||||
@ -269,39 +274,35 @@ bool cmCTestGIT::UpdateImpl()
 | 
			
		||||
  std::string init_submodules =
 | 
			
		||||
    this->CTest->GetCTestConfiguration("GITInitSubmodules");
 | 
			
		||||
  if (cmIsOn(init_submodules)) {
 | 
			
		||||
    std::vector<std::string> git_submodule_init = { git, "submodule", "init" };
 | 
			
		||||
    char const* git_submodule_init[] = { git, "submodule", "init", nullptr };
 | 
			
		||||
    ret = this->RunChild(git_submodule_init, &submodule_out, &submodule_err,
 | 
			
		||||
                         top_dir);
 | 
			
		||||
                         top_dir.c_str());
 | 
			
		||||
 | 
			
		||||
    if (!ret) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::vector<std::string> git_submodule_sync = { git, "submodule", "sync" };
 | 
			
		||||
  if (support_sync_recursive) {
 | 
			
		||||
    git_submodule_sync.push_back(sync_recursive);
 | 
			
		||||
  }
 | 
			
		||||
  char const* git_submodule_sync[] = { git, "submodule", "sync",
 | 
			
		||||
                                       sync_recursive, nullptr };
 | 
			
		||||
  ret = this->RunChild(git_submodule_sync, &submodule_out, &submodule_err,
 | 
			
		||||
                       top_dir);
 | 
			
		||||
                       top_dir.c_str());
 | 
			
		||||
 | 
			
		||||
  if (!ret) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::vector<std::string> git_submodule = { git, "submodule", "update" };
 | 
			
		||||
  if (support_recursive) {
 | 
			
		||||
    git_submodule.push_back(recursive);
 | 
			
		||||
  }
 | 
			
		||||
  char const* git_submodule[] = { git, "submodule", "update", recursive,
 | 
			
		||||
                                  nullptr };
 | 
			
		||||
  return this->RunChild(git_submodule, &submodule_out, &submodule_err,
 | 
			
		||||
                        top_dir);
 | 
			
		||||
                        top_dir.c_str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int cmCTestGIT::GetGitVersion()
 | 
			
		||||
{
 | 
			
		||||
  if (!this->CurrentGitVersion) {
 | 
			
		||||
    std::string git = this->CommandLineTool;
 | 
			
		||||
    std::vector<std::string> git_version = { git, "--version" };
 | 
			
		||||
    const char* git = this->CommandLineTool.c_str();
 | 
			
		||||
    char const* git_version[] = { git, "--version", nullptr };
 | 
			
		||||
    std::string version;
 | 
			
		||||
    OneLineParser version_out(this, "version-out> ", version);
 | 
			
		||||
    OutputLogger version_err(this->Log, "version-err> ");
 | 
			
		||||
@ -604,49 +605,50 @@ bool cmCTestGIT::LoadRevisions()
 | 
			
		||||
{
 | 
			
		||||
  // Use 'git rev-list ... | git diff-tree ...' to get revisions.
 | 
			
		||||
  std::string range = this->OldRevision + ".." + this->NewRevision;
 | 
			
		||||
  std::string git = this->CommandLineTool;
 | 
			
		||||
  std::vector<std::string> git_rev_list = { git, "rev-list", "--reverse",
 | 
			
		||||
                                            range, "--" };
 | 
			
		||||
  std::vector<std::string> git_diff_tree = {
 | 
			
		||||
    git,  "diff-tree", "--stdin",      "--always",
 | 
			
		||||
    "-z", "-r",        "--pretty=raw", "--encoding=utf-8"
 | 
			
		||||
  const char* git = this->CommandLineTool.c_str();
 | 
			
		||||
  const char* git_rev_list[] = { git,           "rev-list", "--reverse",
 | 
			
		||||
                                 range.c_str(), "--",       nullptr };
 | 
			
		||||
  const char* git_diff_tree[] = {
 | 
			
		||||
    git,  "diff-tree",    "--stdin",          "--always", "-z",
 | 
			
		||||
    "-r", "--pretty=raw", "--encoding=utf-8", nullptr
 | 
			
		||||
  };
 | 
			
		||||
  this->Log << cmCTestGIT::ComputeCommandLine(git_rev_list) << " | "
 | 
			
		||||
            << cmCTestGIT::ComputeCommandLine(git_diff_tree) << "\n";
 | 
			
		||||
 | 
			
		||||
  cmUVProcessChainBuilder builder;
 | 
			
		||||
  builder.AddCommand(git_rev_list)
 | 
			
		||||
    .AddCommand(git_diff_tree)
 | 
			
		||||
    .SetWorkingDirectory(this->SourceDirectory);
 | 
			
		||||
  cmsysProcess* cp = cmsysProcess_New();
 | 
			
		||||
  cmsysProcess_AddCommand(cp, git_rev_list);
 | 
			
		||||
  cmsysProcess_AddCommand(cp, git_diff_tree);
 | 
			
		||||
  cmsysProcess_SetWorkingDirectory(cp, this->SourceDirectory.c_str());
 | 
			
		||||
 | 
			
		||||
  CommitParser out(this, "dt-out> ");
 | 
			
		||||
  OutputLogger err(this->Log, "dt-err> ");
 | 
			
		||||
  cmCTestGIT::RunProcess(builder, &out, &err, cmProcessOutput::UTF8);
 | 
			
		||||
  cmCTestGIT::RunProcess(cp, &out, &err, cmProcessOutput::UTF8);
 | 
			
		||||
 | 
			
		||||
  // Send one extra zero-byte to terminate the last record.
 | 
			
		||||
  out.Process("", 1);
 | 
			
		||||
 | 
			
		||||
  cmsysProcess_Delete(cp);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmCTestGIT::LoadModifications()
 | 
			
		||||
{
 | 
			
		||||
  std::string git = this->CommandLineTool;
 | 
			
		||||
  const char* git = this->CommandLineTool.c_str();
 | 
			
		||||
 | 
			
		||||
  // Use 'git update-index' to refresh the index w.r.t. the work tree.
 | 
			
		||||
  std::vector<std::string> git_update_index = { git, "update-index",
 | 
			
		||||
                                                "--refresh" };
 | 
			
		||||
  const char* git_update_index[] = { git, "update-index", "--refresh",
 | 
			
		||||
                                     nullptr };
 | 
			
		||||
  OutputLogger ui_out(this->Log, "ui-out> ");
 | 
			
		||||
  OutputLogger ui_err(this->Log, "ui-err> ");
 | 
			
		||||
  this->RunChild(git_update_index, &ui_out, &ui_err, "",
 | 
			
		||||
  this->RunChild(git_update_index, &ui_out, &ui_err, nullptr,
 | 
			
		||||
                 cmProcessOutput::UTF8);
 | 
			
		||||
 | 
			
		||||
  // Use 'git diff-index' to get modified files.
 | 
			
		||||
  std::vector<std::string> git_diff_index = { git, "diff-index", "-z", "HEAD",
 | 
			
		||||
                                              "--" };
 | 
			
		||||
  const char* git_diff_index[] = { git,    "diff-index", "-z",
 | 
			
		||||
                                   "HEAD", "--",         nullptr };
 | 
			
		||||
  DiffParser out(this, "di-out> ");
 | 
			
		||||
  OutputLogger err(this->Log, "di-err> ");
 | 
			
		||||
  this->RunChild(git_diff_index, &out, &err, "", cmProcessOutput::UTF8);
 | 
			
		||||
  this->RunChild(git_diff_index, &out, &err, nullptr, cmProcessOutput::UTF8);
 | 
			
		||||
 | 
			
		||||
  for (Change const& c : out.Changes) {
 | 
			
		||||
    this->DoModification(PathModified, c.Path);
 | 
			
		||||
 | 
			
		||||
@ -95,8 +95,8 @@ private:
 | 
			
		||||
std::string cmCTestHG::GetWorkingRevision()
 | 
			
		||||
{
 | 
			
		||||
  // Run plumbing "hg identify" to get work tree revision.
 | 
			
		||||
  std::string hg = this->CommandLineTool;
 | 
			
		||||
  std::vector<std::string> hg_identify = { hg, "identify", "-i" };
 | 
			
		||||
  const char* hg = this->CommandLineTool.c_str();
 | 
			
		||||
  const char* hg_identify[] = { hg, "identify", "-i", nullptr };
 | 
			
		||||
  std::string rev;
 | 
			
		||||
  IdentifyParser out(this, "rev-out> ", rev);
 | 
			
		||||
  OutputLogger err(this->Log, "rev-err> ");
 | 
			
		||||
@ -127,16 +127,16 @@ bool cmCTestHG::UpdateImpl()
 | 
			
		||||
{
 | 
			
		||||
  // Use "hg pull" followed by "hg update" to update the working tree.
 | 
			
		||||
  {
 | 
			
		||||
    std::string hg = this->CommandLineTool;
 | 
			
		||||
    std::vector<std::string> hg_pull = { hg, "pull", "-v" };
 | 
			
		||||
    const char* hg = this->CommandLineTool.c_str();
 | 
			
		||||
    const char* hg_pull[] = { hg, "pull", "-v", nullptr };
 | 
			
		||||
    OutputLogger out(this->Log, "pull-out> ");
 | 
			
		||||
    OutputLogger err(this->Log, "pull-err> ");
 | 
			
		||||
    this->RunChild(hg_pull, &out, &err);
 | 
			
		||||
    this->RunChild(&hg_pull[0], &out, &err);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
 | 
			
		||||
 | 
			
		||||
  std::vector<std::string> hg_update;
 | 
			
		||||
  std::vector<char const*> hg_update;
 | 
			
		||||
  hg_update.push_back(this->CommandLineTool.c_str());
 | 
			
		||||
  hg_update.push_back("update");
 | 
			
		||||
  hg_update.push_back("-v");
 | 
			
		||||
@ -147,11 +147,16 @@ bool cmCTestHG::UpdateImpl()
 | 
			
		||||
    opts = this->CTest->GetCTestConfiguration("HGUpdateOptions");
 | 
			
		||||
  }
 | 
			
		||||
  std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
 | 
			
		||||
  cm::append(hg_update, args);
 | 
			
		||||
  for (std::string const& arg : args) {
 | 
			
		||||
    hg_update.push_back(arg.c_str());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Sentinel argument.
 | 
			
		||||
  hg_update.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  OutputLogger out(this->Log, "update-out> ");
 | 
			
		||||
  OutputLogger err(this->Log, "update-err> ");
 | 
			
		||||
  return this->RunUpdateCommand(hg_update, &out, &err);
 | 
			
		||||
  return this->RunUpdateCommand(hg_update.data(), &out, &err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class cmCTestHG::LogParser
 | 
			
		||||
@ -272,8 +277,8 @@ bool cmCTestHG::LoadRevisions()
 | 
			
		||||
  // the project has spaces in the path.  Also, they may not have
 | 
			
		||||
  // proper XML escapes.
 | 
			
		||||
  std::string range = this->OldRevision + ":" + this->NewRevision;
 | 
			
		||||
  std::string hg = this->CommandLineTool;
 | 
			
		||||
  std::string hgXMLTemplate = "<logentry\n"
 | 
			
		||||
  const char* hg = this->CommandLineTool.c_str();
 | 
			
		||||
  const char* hgXMLTemplate = "<logentry\n"
 | 
			
		||||
                              "   revision=\"{node|short}\">\n"
 | 
			
		||||
                              "  <author>{author|person}</author>\n"
 | 
			
		||||
                              "  <email>{author|email}</email>\n"
 | 
			
		||||
@ -283,8 +288,10 @@ bool cmCTestHG::LoadRevisions()
 | 
			
		||||
                              "  <file_adds>{file_adds}</file_adds>\n"
 | 
			
		||||
                              "  <file_dels>{file_dels}</file_dels>\n"
 | 
			
		||||
                              "</logentry>\n";
 | 
			
		||||
  std::vector<std::string> hg_log = { hg,    "log",        "--removed",  "-r",
 | 
			
		||||
                                      range, "--template", hgXMLTemplate };
 | 
			
		||||
  const char* hg_log[] = {
 | 
			
		||||
    hg,           "log",         "--removed", "-r", range.c_str(),
 | 
			
		||||
    "--template", hgXMLTemplate, nullptr
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  LogParser out(this, "log-out> ");
 | 
			
		||||
  out.Process("<?xml version=\"1.0\"?>\n"
 | 
			
		||||
@ -298,8 +305,8 @@ bool cmCTestHG::LoadRevisions()
 | 
			
		||||
bool cmCTestHG::LoadModifications()
 | 
			
		||||
{
 | 
			
		||||
  // Use 'hg status' to get modified files.
 | 
			
		||||
  std::string hg = this->CommandLineTool;
 | 
			
		||||
  std::vector<std::string> hg_status = { hg, "status" };
 | 
			
		||||
  const char* hg = this->CommandLineTool.c_str();
 | 
			
		||||
  const char* hg_status[] = { hg, "status", nullptr };
 | 
			
		||||
  StatusParser out(this, "status-out> ");
 | 
			
		||||
  OutputLogger err(this->Log, "status-err> ");
 | 
			
		||||
  this->RunChild(hg_status, &out, &err);
 | 
			
		||||
 | 
			
		||||
@ -2,19 +2,13 @@
 | 
			
		||||
   file Copyright.txt or https://cmake.org/licensing for details.  */
 | 
			
		||||
#include "cmCTestLaunch.h"
 | 
			
		||||
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include <cm3p/uv.h>
 | 
			
		||||
 | 
			
		||||
#include "cmsys/FStream.hxx"
 | 
			
		||||
#include "cmsys/Process.h"
 | 
			
		||||
#include "cmsys/RegularExpression.hxx"
 | 
			
		||||
 | 
			
		||||
#include "cm_fileno.hxx"
 | 
			
		||||
 | 
			
		||||
#include "cmCTestLaunchReporter.h"
 | 
			
		||||
#include "cmGlobalGenerator.h"
 | 
			
		||||
#include "cmMakefile.h"
 | 
			
		||||
@ -23,9 +17,6 @@
 | 
			
		||||
#include "cmStateSnapshot.h"
 | 
			
		||||
#include "cmStringAlgorithms.h"
 | 
			
		||||
#include "cmSystemTools.h"
 | 
			
		||||
#include "cmUVHandlePtr.h"
 | 
			
		||||
#include "cmUVProcessChain.h"
 | 
			
		||||
#include "cmUVStream.h"
 | 
			
		||||
#include "cmake.h"
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
@ -37,6 +28,8 @@
 | 
			
		||||
 | 
			
		||||
cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv)
 | 
			
		||||
{
 | 
			
		||||
  this->Process = nullptr;
 | 
			
		||||
 | 
			
		||||
  if (!this->ParseArguments(argc, argv)) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
@ -47,9 +40,13 @@ cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv)
 | 
			
		||||
  this->ScrapeRulesLoaded = false;
 | 
			
		||||
  this->HaveOut = false;
 | 
			
		||||
  this->HaveErr = false;
 | 
			
		||||
  this->Process = cmsysProcess_New();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cmCTestLaunch::~cmCTestLaunch() = default;
 | 
			
		||||
cmCTestLaunch::~cmCTestLaunch()
 | 
			
		||||
{
 | 
			
		||||
  cmsysProcess_Delete(this->Process);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
 | 
			
		||||
{
 | 
			
		||||
@ -116,12 +113,15 @@ bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
 | 
			
		||||
 | 
			
		||||
  // Extract the real command line.
 | 
			
		||||
  if (arg0) {
 | 
			
		||||
    for (int i = 0; i < argc - arg0; ++i) {
 | 
			
		||||
      this->RealArgV.emplace_back((argv + arg0)[i]);
 | 
			
		||||
      this->HandleRealArg((argv + arg0)[i]);
 | 
			
		||||
    this->RealArgC = argc - arg0;
 | 
			
		||||
    this->RealArgV = argv + arg0;
 | 
			
		||||
    for (int i = 0; i < this->RealArgC; ++i) {
 | 
			
		||||
      this->HandleRealArg(this->RealArgV[i]);
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  this->RealArgC = 0;
 | 
			
		||||
  this->RealArgV = nullptr;
 | 
			
		||||
  std::cerr << "No launch/command separator ('--') found!\n";
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
@ -151,22 +151,17 @@ void cmCTestLaunch::RunChild()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Prepare to run the real command.
 | 
			
		||||
  cmUVProcessChainBuilder builder;
 | 
			
		||||
  builder.AddCommand(this->RealArgV);
 | 
			
		||||
  cmsysProcess* cp = this->Process;
 | 
			
		||||
  cmsysProcess_SetCommand(cp, this->RealArgV);
 | 
			
		||||
 | 
			
		||||
  cmsys::ofstream fout;
 | 
			
		||||
  cmsys::ofstream ferr;
 | 
			
		||||
  if (this->Reporter.Passthru) {
 | 
			
		||||
    // In passthru mode we just share the output pipes.
 | 
			
		||||
    builder
 | 
			
		||||
      .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT,
 | 
			
		||||
                         cm_fileno(stdout))
 | 
			
		||||
      .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR,
 | 
			
		||||
                         cm_fileno(stderr));
 | 
			
		||||
    cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
 | 
			
		||||
    cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
 | 
			
		||||
  } else {
 | 
			
		||||
    // In full mode we record the child output pipes to log files.
 | 
			
		||||
    builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
 | 
			
		||||
      .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
 | 
			
		||||
    fout.open(this->Reporter.LogOut.c_str(), std::ios::out | std::ios::binary);
 | 
			
		||||
    ferr.open(this->Reporter.LogErr.c_str(), std::ios::out | std::ios::binary);
 | 
			
		||||
  }
 | 
			
		||||
@ -179,65 +174,51 @@ void cmCTestLaunch::RunChild()
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  // Run the real command.
 | 
			
		||||
  auto chain = builder.Start();
 | 
			
		||||
  cmsysProcess_Execute(cp);
 | 
			
		||||
 | 
			
		||||
  // Record child stdout and stderr if necessary.
 | 
			
		||||
  cm::uv_pipe_ptr outPipe;
 | 
			
		||||
  cm::uv_pipe_ptr errPipe;
 | 
			
		||||
  bool outFinished = true;
 | 
			
		||||
  bool errFinished = true;
 | 
			
		||||
  cmProcessOutput processOutput;
 | 
			
		||||
  std::unique_ptr<cmUVStreamReadHandle> outputHandle;
 | 
			
		||||
  std::unique_ptr<cmUVStreamReadHandle> errorHandle;
 | 
			
		||||
  if (!this->Reporter.Passthru) {
 | 
			
		||||
    auto beginRead = [&chain, &processOutput](
 | 
			
		||||
                       cm::uv_pipe_ptr& pipe, int stream, std::ostream& out,
 | 
			
		||||
                       cmsys::ofstream& file, bool& haveData, bool& finished,
 | 
			
		||||
                       int id) -> std::unique_ptr<cmUVStreamReadHandle> {
 | 
			
		||||
      pipe.init(chain.GetLoop(), 0);
 | 
			
		||||
      uv_pipe_open(pipe, stream);
 | 
			
		||||
      finished = false;
 | 
			
		||||
      return cmUVStreamRead(
 | 
			
		||||
        pipe,
 | 
			
		||||
        [&processOutput, &out, &file, id, &haveData](std::vector<char> data) {
 | 
			
		||||
          std::string strdata;
 | 
			
		||||
          processOutput.DecodeText(data.data(), data.size(), strdata, id);
 | 
			
		||||
          file.write(strdata.c_str(), strdata.size());
 | 
			
		||||
          out.write(strdata.c_str(), strdata.size());
 | 
			
		||||
          haveData = true;
 | 
			
		||||
        },
 | 
			
		||||
        [&processOutput, &out, &file, &finished, id]() {
 | 
			
		||||
          std::string strdata;
 | 
			
		||||
          processOutput.DecodeText(std::string(), strdata, id);
 | 
			
		||||
          if (!strdata.empty()) {
 | 
			
		||||
            file.write(strdata.c_str(), strdata.size());
 | 
			
		||||
            out.write(strdata.c_str(), strdata.size());
 | 
			
		||||
          }
 | 
			
		||||
          finished = true;
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
    outputHandle = beginRead(outPipe, chain.OutputStream(), std::cout, fout,
 | 
			
		||||
                             this->HaveOut, outFinished, 1);
 | 
			
		||||
    errorHandle = beginRead(errPipe, chain.ErrorStream(), std::cerr, ferr,
 | 
			
		||||
                            this->HaveErr, errFinished, 2);
 | 
			
		||||
    char* data = nullptr;
 | 
			
		||||
    int length = 0;
 | 
			
		||||
    cmProcessOutput processOutput;
 | 
			
		||||
    std::string strdata;
 | 
			
		||||
    while (int p = cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
 | 
			
		||||
      if (p == cmsysProcess_Pipe_STDOUT) {
 | 
			
		||||
        processOutput.DecodeText(data, length, strdata, 1);
 | 
			
		||||
        fout.write(strdata.c_str(), strdata.size());
 | 
			
		||||
        std::cout.write(strdata.c_str(), strdata.size());
 | 
			
		||||
        this->HaveOut = true;
 | 
			
		||||
      } else if (p == cmsysProcess_Pipe_STDERR) {
 | 
			
		||||
        processOutput.DecodeText(data, length, strdata, 2);
 | 
			
		||||
        ferr.write(strdata.c_str(), strdata.size());
 | 
			
		||||
        std::cerr.write(strdata.c_str(), strdata.size());
 | 
			
		||||
        this->HaveErr = true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    processOutput.DecodeText(std::string(), strdata, 1);
 | 
			
		||||
    if (!strdata.empty()) {
 | 
			
		||||
      fout.write(strdata.c_str(), strdata.size());
 | 
			
		||||
      std::cout.write(strdata.c_str(), strdata.size());
 | 
			
		||||
    }
 | 
			
		||||
    processOutput.DecodeText(std::string(), strdata, 2);
 | 
			
		||||
    if (!strdata.empty()) {
 | 
			
		||||
      ferr.write(strdata.c_str(), strdata.size());
 | 
			
		||||
      std::cerr.write(strdata.c_str(), strdata.size());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Wait for the real command to finish.
 | 
			
		||||
  while (!(chain.Finished() && outFinished && errFinished)) {
 | 
			
		||||
    uv_run(&chain.GetLoop(), UV_RUN_ONCE);
 | 
			
		||||
  }
 | 
			
		||||
  this->Reporter.Status = chain.GetStatus(0);
 | 
			
		||||
  if (this->Reporter.Status.GetException().first ==
 | 
			
		||||
      cmUVProcessChain::ExceptionCode::Spawn) {
 | 
			
		||||
    this->Reporter.ExitCode = 1;
 | 
			
		||||
  } else {
 | 
			
		||||
    this->Reporter.ExitCode =
 | 
			
		||||
      static_cast<int>(this->Reporter.Status.ExitStatus);
 | 
			
		||||
  }
 | 
			
		||||
  cmsysProcess_WaitForExit(cp, nullptr);
 | 
			
		||||
  this->Reporter.ExitCode = cmsysProcess_GetExitValue(cp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cmCTestLaunch::Run()
 | 
			
		||||
{
 | 
			
		||||
  if (!this->Process) {
 | 
			
		||||
    std::cerr << "Could not allocate cmsysProcess instance!\n";
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this->RunChild();
 | 
			
		||||
 | 
			
		||||
  if (this->CheckResults()) {
 | 
			
		||||
@ -245,6 +226,7 @@ int cmCTestLaunch::Run()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this->LoadConfig();
 | 
			
		||||
  this->Reporter.Process = this->Process;
 | 
			
		||||
  this->Reporter.WriteXML();
 | 
			
		||||
 | 
			
		||||
  return this->Reporter.ExitCode;
 | 
			
		||||
 | 
			
		||||
@ -43,12 +43,15 @@ private:
 | 
			
		||||
  bool ParseArguments(int argc, const char* const* argv);
 | 
			
		||||
 | 
			
		||||
  // The real command line appearing after launcher arguments.
 | 
			
		||||
  std::vector<std::string> RealArgV;
 | 
			
		||||
  int RealArgC;
 | 
			
		||||
  const char* const* RealArgV;
 | 
			
		||||
 | 
			
		||||
  // The real command line after response file expansion.
 | 
			
		||||
  std::vector<std::string> RealArgs;
 | 
			
		||||
  void HandleRealArg(const char* arg);
 | 
			
		||||
 | 
			
		||||
  struct cmsysProcess_s* Process;
 | 
			
		||||
 | 
			
		||||
  // Whether or not any data have been written to stdout or stderr.
 | 
			
		||||
  bool HaveOut;
 | 
			
		||||
  bool HaveErr;
 | 
			
		||||
 | 
			
		||||
@ -2,9 +2,8 @@
 | 
			
		||||
   file Copyright.txt or https://cmake.org/licensing for details.  */
 | 
			
		||||
#include "cmCTestLaunchReporter.h"
 | 
			
		||||
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include "cmsys/FStream.hxx"
 | 
			
		||||
#include "cmsys/Process.h"
 | 
			
		||||
#include "cmsys/RegularExpression.hxx"
 | 
			
		||||
 | 
			
		||||
#include "cmCryptoHash.h"
 | 
			
		||||
@ -23,7 +22,6 @@
 | 
			
		||||
cmCTestLaunchReporter::cmCTestLaunchReporter()
 | 
			
		||||
{
 | 
			
		||||
  this->Passthru = true;
 | 
			
		||||
  this->Status.Finished = true;
 | 
			
		||||
  this->ExitCode = 1;
 | 
			
		||||
  this->CWD = cmSystemTools::GetCurrentWorkingDirectory();
 | 
			
		||||
 | 
			
		||||
@ -233,23 +231,35 @@ void cmCTestLaunchReporter::WriteXMLResult(cmXMLElement& e2)
 | 
			
		||||
 | 
			
		||||
  // ExitCondition
 | 
			
		||||
  cmXMLElement e4(e3, "ExitCondition");
 | 
			
		||||
  if (this->Status.Finished) {
 | 
			
		||||
    auto exception = this->Status.GetException();
 | 
			
		||||
    switch (exception.first) {
 | 
			
		||||
      case cmUVProcessChain::ExceptionCode::None:
 | 
			
		||||
        e4.Content(this->ExitCode);
 | 
			
		||||
        break;
 | 
			
		||||
      case cmUVProcessChain::ExceptionCode::Spawn:
 | 
			
		||||
        e4.Content("Error administrating child process: ");
 | 
			
		||||
        e4.Content(exception.second);
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        e4.Content("Terminated abnormally: ");
 | 
			
		||||
        e4.Content(exception.second);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    e4.Content("Killed when timeout expired");
 | 
			
		||||
  cmsysProcess* cp = this->Process;
 | 
			
		||||
  switch (cmsysProcess_GetState(cp)) {
 | 
			
		||||
    case cmsysProcess_State_Starting:
 | 
			
		||||
      e4.Content("No process has been executed");
 | 
			
		||||
      break;
 | 
			
		||||
    case cmsysProcess_State_Executing:
 | 
			
		||||
      e4.Content("The process is still executing");
 | 
			
		||||
      break;
 | 
			
		||||
    case cmsysProcess_State_Disowned:
 | 
			
		||||
      e4.Content("Disowned");
 | 
			
		||||
      break;
 | 
			
		||||
    case cmsysProcess_State_Killed:
 | 
			
		||||
      e4.Content("Killed by parent");
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case cmsysProcess_State_Expired:
 | 
			
		||||
      e4.Content("Killed when timeout expired");
 | 
			
		||||
      break;
 | 
			
		||||
    case cmsysProcess_State_Exited:
 | 
			
		||||
      e4.Content(this->ExitCode);
 | 
			
		||||
      break;
 | 
			
		||||
    case cmsysProcess_State_Exception:
 | 
			
		||||
      e4.Content("Terminated abnormally: ");
 | 
			
		||||
      e4.Content(cmsysProcess_GetExceptionString(cp));
 | 
			
		||||
      break;
 | 
			
		||||
    case cmsysProcess_State_Error:
 | 
			
		||||
      e4.Content("Error administrating child process: ");
 | 
			
		||||
      e4.Content(cmsysProcess_GetErrorString(cp));
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -10,8 +10,6 @@
 | 
			
		||||
 | 
			
		||||
#include "cmsys/RegularExpression.hxx"
 | 
			
		||||
 | 
			
		||||
#include "cmUVProcessChain.h"
 | 
			
		||||
 | 
			
		||||
class cmXMLElement;
 | 
			
		||||
 | 
			
		||||
/** \class cmCTestLaunchReporter
 | 
			
		||||
@ -50,7 +48,7 @@ public:
 | 
			
		||||
  void ComputeFileNames();
 | 
			
		||||
 | 
			
		||||
  bool Passthru;
 | 
			
		||||
  cmUVProcessChain::Status Status;
 | 
			
		||||
  struct cmsysProcess_s* Process;
 | 
			
		||||
  int ExitCode;
 | 
			
		||||
 | 
			
		||||
  // Temporary log files for stdout and stderr of real command.
 | 
			
		||||
 | 
			
		||||
@ -149,16 +149,17 @@ cmCTestP4::User cmCTestP4::GetUserData(const std::string& username)
 | 
			
		||||
  auto it = this->Users.find(username);
 | 
			
		||||
 | 
			
		||||
  if (it == this->Users.end()) {
 | 
			
		||||
    std::vector<std::string> p4_users;
 | 
			
		||||
    std::vector<char const*> p4_users;
 | 
			
		||||
    this->SetP4Options(p4_users);
 | 
			
		||||
    p4_users.push_back("users");
 | 
			
		||||
    p4_users.push_back("-m");
 | 
			
		||||
    p4_users.push_back("1");
 | 
			
		||||
    p4_users.push_back(username);
 | 
			
		||||
    p4_users.push_back(username.c_str());
 | 
			
		||||
    p4_users.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
    UserParser out(this, "users-out> ");
 | 
			
		||||
    OutputLogger err(this->Log, "users-err> ");
 | 
			
		||||
    this->RunChild(p4_users, &out, &err);
 | 
			
		||||
    this->RunChild(p4_users.data(), &out, &err);
 | 
			
		||||
 | 
			
		||||
    // The user should now be added to the map. Search again.
 | 
			
		||||
    it = this->Users.find(username);
 | 
			
		||||
@ -302,10 +303,10 @@ private:
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void cmCTestP4::SetP4Options(std::vector<std::string>& CommandOptions)
 | 
			
		||||
void cmCTestP4::SetP4Options(std::vector<char const*>& CommandOptions)
 | 
			
		||||
{
 | 
			
		||||
  if (this->P4Options.empty()) {
 | 
			
		||||
    std::string p4 = this->CommandLineTool;
 | 
			
		||||
    const char* p4 = this->CommandLineTool.c_str();
 | 
			
		||||
    this->P4Options.emplace_back(p4);
 | 
			
		||||
 | 
			
		||||
    // The CTEST_P4_CLIENT variable sets the P4 client used when issuing
 | 
			
		||||
@ -327,12 +328,15 @@ void cmCTestP4::SetP4Options(std::vector<std::string>& CommandOptions)
 | 
			
		||||
    cm::append(this->P4Options, cmSystemTools::ParseArguments(opts));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  CommandOptions = this->P4Options;
 | 
			
		||||
  CommandOptions.clear();
 | 
			
		||||
  for (std::string const& o : this->P4Options) {
 | 
			
		||||
    CommandOptions.push_back(o.c_str());
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string cmCTestP4::GetWorkingRevision()
 | 
			
		||||
{
 | 
			
		||||
  std::vector<std::string> p4_identify;
 | 
			
		||||
  std::vector<char const*> p4_identify;
 | 
			
		||||
  this->SetP4Options(p4_identify);
 | 
			
		||||
 | 
			
		||||
  p4_identify.push_back("changes");
 | 
			
		||||
@ -341,13 +345,14 @@ std::string cmCTestP4::GetWorkingRevision()
 | 
			
		||||
  p4_identify.push_back("-t");
 | 
			
		||||
 | 
			
		||||
  std::string source = this->SourceDirectory + "/...#have";
 | 
			
		||||
  p4_identify.push_back(source);
 | 
			
		||||
  p4_identify.push_back(source.c_str());
 | 
			
		||||
  p4_identify.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  std::string rev;
 | 
			
		||||
  IdentifyParser out(this, "p4_changes-out> ", rev);
 | 
			
		||||
  OutputLogger err(this->Log, "p4_changes-err> ");
 | 
			
		||||
 | 
			
		||||
  bool result = this->RunChild(p4_identify, &out, &err);
 | 
			
		||||
  bool result = this->RunChild(p4_identify.data(), &out, &err);
 | 
			
		||||
 | 
			
		||||
  // If there was a problem contacting the server return "<unknown>"
 | 
			
		||||
  if (!result) {
 | 
			
		||||
@ -383,7 +388,7 @@ bool cmCTestP4::NoteNewRevision()
 | 
			
		||||
 | 
			
		||||
bool cmCTestP4::LoadRevisions()
 | 
			
		||||
{
 | 
			
		||||
  std::vector<std::string> p4_changes;
 | 
			
		||||
  std::vector<char const*> p4_changes;
 | 
			
		||||
  this->SetP4Options(p4_changes);
 | 
			
		||||
 | 
			
		||||
  // Use 'p4 changes ...@old,new' to get a list of changelists
 | 
			
		||||
@ -404,36 +409,38 @@ bool cmCTestP4::LoadRevisions()
 | 
			
		||||
    .append(this->NewRevision);
 | 
			
		||||
 | 
			
		||||
  p4_changes.push_back("changes");
 | 
			
		||||
  p4_changes.push_back(range);
 | 
			
		||||
  p4_changes.push_back(range.c_str());
 | 
			
		||||
  p4_changes.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  ChangesParser out(this, "p4_changes-out> ");
 | 
			
		||||
  OutputLogger err(this->Log, "p4_changes-err> ");
 | 
			
		||||
 | 
			
		||||
  this->ChangeLists.clear();
 | 
			
		||||
  this->RunChild(p4_changes, &out, &err);
 | 
			
		||||
  this->RunChild(p4_changes.data(), &out, &err);
 | 
			
		||||
 | 
			
		||||
  if (this->ChangeLists.empty()) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // p4 describe -s ...@1111111,2222222
 | 
			
		||||
  std::vector<std::string> p4_describe;
 | 
			
		||||
  std::vector<char const*> p4_describe;
 | 
			
		||||
  for (std::string const& i : cmReverseRange(this->ChangeLists)) {
 | 
			
		||||
    this->SetP4Options(p4_describe);
 | 
			
		||||
    p4_describe.push_back("describe");
 | 
			
		||||
    p4_describe.push_back("-s");
 | 
			
		||||
    p4_describe.push_back(i);
 | 
			
		||||
    p4_describe.push_back(i.c_str());
 | 
			
		||||
    p4_describe.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
    DescribeParser outDescribe(this, "p4_describe-out> ");
 | 
			
		||||
    OutputLogger errDescribe(this->Log, "p4_describe-err> ");
 | 
			
		||||
    this->RunChild(p4_describe, &outDescribe, &errDescribe);
 | 
			
		||||
    this->RunChild(p4_describe.data(), &outDescribe, &errDescribe);
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmCTestP4::LoadModifications()
 | 
			
		||||
{
 | 
			
		||||
  std::vector<std::string> p4_diff;
 | 
			
		||||
  std::vector<char const*> p4_diff;
 | 
			
		||||
  this->SetP4Options(p4_diff);
 | 
			
		||||
 | 
			
		||||
  p4_diff.push_back("diff");
 | 
			
		||||
@ -441,11 +448,12 @@ bool cmCTestP4::LoadModifications()
 | 
			
		||||
  // Ideally we would use -Od but not all clients support it
 | 
			
		||||
  p4_diff.push_back("-dn");
 | 
			
		||||
  std::string source = this->SourceDirectory + "/...";
 | 
			
		||||
  p4_diff.push_back(source);
 | 
			
		||||
  p4_diff.push_back(source.c_str());
 | 
			
		||||
  p4_diff.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  DiffParser out(this, "p4_diff-out> ");
 | 
			
		||||
  OutputLogger err(this->Log, "p4_diff-err> ");
 | 
			
		||||
  this->RunChild(p4_diff, &out, &err);
 | 
			
		||||
  this->RunChild(p4_diff.data(), &out, &err);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -453,14 +461,17 @@ bool cmCTestP4::UpdateCustom(const std::string& custom)
 | 
			
		||||
{
 | 
			
		||||
  cmList p4_custom_command{ custom, cmList::EmptyElements::Yes };
 | 
			
		||||
 | 
			
		||||
  std::vector<std::string> p4_custom;
 | 
			
		||||
  p4_custom.reserve(p4_custom_command.size());
 | 
			
		||||
  cm::append(p4_custom, p4_custom_command);
 | 
			
		||||
  std::vector<char const*> p4_custom;
 | 
			
		||||
  p4_custom.reserve(p4_custom_command.size() + 1);
 | 
			
		||||
  for (std::string const& i : p4_custom_command) {
 | 
			
		||||
    p4_custom.push_back(i.c_str());
 | 
			
		||||
  }
 | 
			
		||||
  p4_custom.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  OutputLogger custom_out(this->Log, "p4_customsync-out> ");
 | 
			
		||||
  OutputLogger custom_err(this->Log, "p4_customsync-err> ");
 | 
			
		||||
 | 
			
		||||
  return this->RunUpdateCommand(p4_custom, &custom_out, &custom_err);
 | 
			
		||||
  return this->RunUpdateCommand(p4_custom.data(), &custom_out, &custom_err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmCTestP4::UpdateImpl()
 | 
			
		||||
@ -477,7 +488,7 @@ bool cmCTestP4::UpdateImpl()
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::vector<std::string> p4_sync;
 | 
			
		||||
  std::vector<char const*> p4_sync;
 | 
			
		||||
  this->SetP4Options(p4_sync);
 | 
			
		||||
 | 
			
		||||
  p4_sync.push_back("sync");
 | 
			
		||||
@ -488,7 +499,9 @@ bool cmCTestP4::UpdateImpl()
 | 
			
		||||
    opts = this->CTest->GetCTestConfiguration("P4UpdateOptions");
 | 
			
		||||
  }
 | 
			
		||||
  std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
 | 
			
		||||
  cm::append(p4_sync, args);
 | 
			
		||||
  for (std::string const& arg : args) {
 | 
			
		||||
    p4_sync.push_back(arg.c_str());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::string source = this->SourceDirectory + "/...";
 | 
			
		||||
 | 
			
		||||
@ -502,10 +515,11 @@ bool cmCTestP4::UpdateImpl()
 | 
			
		||||
    source.append("@\"").append(date).append("\"");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  p4_sync.push_back(source);
 | 
			
		||||
  p4_sync.push_back(source.c_str());
 | 
			
		||||
  p4_sync.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  OutputLogger out(this->Log, "p4_sync-out> ");
 | 
			
		||||
  OutputLogger err(this->Log, "p4_sync-err> ");
 | 
			
		||||
 | 
			
		||||
  return this->RunUpdateCommand(p4_sync, &out, &err);
 | 
			
		||||
  return this->RunUpdateCommand(p4_sync.data(), &out, &err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -39,7 +39,7 @@ private:
 | 
			
		||||
  std::vector<std::string> P4Options;
 | 
			
		||||
 | 
			
		||||
  User GetUserData(const std::string& username);
 | 
			
		||||
  void SetP4Options(std::vector<std::string>& options);
 | 
			
		||||
  void SetP4Options(std::vector<char const*>& options);
 | 
			
		||||
 | 
			
		||||
  std::string GetWorkingRevision();
 | 
			
		||||
  bool NoteOldRevision() override;
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ cmCTestSVN::~cmCTestSVN() = default;
 | 
			
		||||
 | 
			
		||||
void cmCTestSVN::CleanupImpl()
 | 
			
		||||
{
 | 
			
		||||
  std::vector<std::string> svn_cleanup;
 | 
			
		||||
  std::vector<const char*> svn_cleanup;
 | 
			
		||||
  svn_cleanup.push_back("cleanup");
 | 
			
		||||
  OutputLogger out(this->Log, "cleanup-out> ");
 | 
			
		||||
  OutputLogger err(this->Log, "cleanup-err> ");
 | 
			
		||||
@ -88,9 +88,9 @@ static bool cmCTestSVNPathStarts(std::string const& p1, std::string const& p2)
 | 
			
		||||
std::string cmCTestSVN::LoadInfo(SVNInfo& svninfo)
 | 
			
		||||
{
 | 
			
		||||
  // Run "svn info" to get the repository info from the work tree.
 | 
			
		||||
  std::vector<std::string> svn_info;
 | 
			
		||||
  std::vector<const char*> svn_info;
 | 
			
		||||
  svn_info.push_back("info");
 | 
			
		||||
  svn_info.push_back(svninfo.LocalPath);
 | 
			
		||||
  svn_info.push_back(svninfo.LocalPath.c_str());
 | 
			
		||||
  std::string rev;
 | 
			
		||||
  InfoParser out(this, "info-out> ", rev, svninfo);
 | 
			
		||||
  OutputLogger err(this->Log, "info-err> ");
 | 
			
		||||
@ -251,24 +251,26 @@ bool cmCTestSVN::UpdateImpl()
 | 
			
		||||
    args.push_back("-r{" + this->GetNightlyTime() + " +0000}");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::vector<std::string> svn_update;
 | 
			
		||||
  std::vector<char const*> svn_update;
 | 
			
		||||
  svn_update.push_back("update");
 | 
			
		||||
  cm::append(svn_update, args);
 | 
			
		||||
  for (std::string const& arg : args) {
 | 
			
		||||
    svn_update.push_back(arg.c_str());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  UpdateParser out(this, "up-out> ");
 | 
			
		||||
  OutputLogger err(this->Log, "up-err> ");
 | 
			
		||||
  return this->RunSVNCommand(svn_update, &out, &err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmCTestSVN::RunSVNCommand(std::vector<std::string> const& parameters,
 | 
			
		||||
bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters,
 | 
			
		||||
                               OutputParser* out, OutputParser* err)
 | 
			
		||||
{
 | 
			
		||||
  if (parameters.empty()) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::vector<std::string> args;
 | 
			
		||||
  args.push_back(this->CommandLineTool);
 | 
			
		||||
  std::vector<char const*> args;
 | 
			
		||||
  args.push_back(this->CommandLineTool.c_str());
 | 
			
		||||
  cm::append(args, parameters);
 | 
			
		||||
  args.push_back("--non-interactive");
 | 
			
		||||
 | 
			
		||||
@ -276,12 +278,16 @@ bool cmCTestSVN::RunSVNCommand(std::vector<std::string> const& parameters,
 | 
			
		||||
 | 
			
		||||
  std::vector<std::string> parsedUserOptions =
 | 
			
		||||
    cmSystemTools::ParseArguments(userOptions);
 | 
			
		||||
  cm::append(args, parsedUserOptions);
 | 
			
		||||
 | 
			
		||||
  if (parameters[0] == "update") {
 | 
			
		||||
    return this->RunUpdateCommand(args, out, err);
 | 
			
		||||
  for (std::string const& opt : parsedUserOptions) {
 | 
			
		||||
    args.push_back(opt.c_str());
 | 
			
		||||
  }
 | 
			
		||||
  return this->RunChild(args, out, err);
 | 
			
		||||
 | 
			
		||||
  args.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  if (strcmp(parameters[0], "update") == 0) {
 | 
			
		||||
    return this->RunUpdateCommand(args.data(), out, err);
 | 
			
		||||
  }
 | 
			
		||||
  return this->RunChild(args.data(), out, err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class cmCTestSVN::LogParser
 | 
			
		||||
@ -387,7 +393,7 @@ bool cmCTestSVN::LoadRevisions(SVNInfo& svninfo)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Run "svn log" to get all global revisions of interest.
 | 
			
		||||
  std::vector<std::string> svn_log;
 | 
			
		||||
  std::vector<const char*> svn_log;
 | 
			
		||||
  svn_log.push_back("log");
 | 
			
		||||
  svn_log.push_back("--xml");
 | 
			
		||||
  svn_log.push_back("-v");
 | 
			
		||||
@ -466,7 +472,7 @@ private:
 | 
			
		||||
bool cmCTestSVN::LoadModifications()
 | 
			
		||||
{
 | 
			
		||||
  // Run "svn status" which reports local modifications.
 | 
			
		||||
  std::vector<std::string> svn_status;
 | 
			
		||||
  std::vector<const char*> svn_status;
 | 
			
		||||
  svn_status.push_back("status");
 | 
			
		||||
  StatusParser out(this, "status-out> ");
 | 
			
		||||
  OutputLogger err(this->Log, "status-err> ");
 | 
			
		||||
@ -528,7 +534,7 @@ bool cmCTestSVN::LoadRepositories()
 | 
			
		||||
  this->RootInfo = &(this->Repositories.back());
 | 
			
		||||
 | 
			
		||||
  // Run "svn status" to get the list of external repositories
 | 
			
		||||
  std::vector<std::string> svn_status;
 | 
			
		||||
  std::vector<const char*> svn_status;
 | 
			
		||||
  svn_status.push_back("status");
 | 
			
		||||
  ExternalParser out(this, "external-out> ");
 | 
			
		||||
  OutputLogger err(this->Log, "external-err> ");
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ private:
 | 
			
		||||
  bool NoteNewRevision() override;
 | 
			
		||||
  bool UpdateImpl() override;
 | 
			
		||||
 | 
			
		||||
  bool RunSVNCommand(std::vector<std::string> const& parameters,
 | 
			
		||||
  bool RunSVNCommand(std::vector<char const*> const& parameters,
 | 
			
		||||
                     OutputParser* out, OutputParser* err);
 | 
			
		||||
 | 
			
		||||
  // Information about an SVN repository (root repository or external)
 | 
			
		||||
 | 
			
		||||
@ -11,9 +11,8 @@
 | 
			
		||||
 | 
			
		||||
#include <cm/memory>
 | 
			
		||||
 | 
			
		||||
#include <cm3p/uv.h>
 | 
			
		||||
 | 
			
		||||
#include "cmsys/Directory.hxx"
 | 
			
		||||
#include "cmsys/Process.h"
 | 
			
		||||
 | 
			
		||||
#include "cmCTest.h"
 | 
			
		||||
#include "cmCTestBuildCommand.h"
 | 
			
		||||
@ -41,8 +40,6 @@
 | 
			
		||||
#include "cmStateSnapshot.h"
 | 
			
		||||
#include "cmStringAlgorithms.h"
 | 
			
		||||
#include "cmSystemTools.h"
 | 
			
		||||
#include "cmUVHandlePtr.h"
 | 
			
		||||
#include "cmUVProcessChain.h"
 | 
			
		||||
#include "cmValue.h"
 | 
			
		||||
#include "cmake.h"
 | 
			
		||||
 | 
			
		||||
@ -151,65 +148,66 @@ int cmCTestScriptHandler::ExecuteScript(const std::string& total_script_arg)
 | 
			
		||||
  // now pass through all the other arguments
 | 
			
		||||
  std::vector<std::string>& initArgs =
 | 
			
		||||
    this->CTest->GetInitialCommandLineArguments();
 | 
			
		||||
  //*** need to make sure this does not have the current script ***
 | 
			
		||||
  for (size_t i = 1; i < initArgs.size(); ++i) {
 | 
			
		||||
    argv.push_back(initArgs[i].c_str());
 | 
			
		||||
  }
 | 
			
		||||
  argv.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  // Now create process object
 | 
			
		||||
  cmUVProcessChainBuilder builder;
 | 
			
		||||
  builder.AddCommand(initArgs)
 | 
			
		||||
    .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
 | 
			
		||||
    .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
 | 
			
		||||
  auto process = builder.Start();
 | 
			
		||||
  cm::uv_pipe_ptr outPipe;
 | 
			
		||||
  outPipe.init(process.GetLoop(), 0);
 | 
			
		||||
  uv_pipe_open(outPipe, process.OutputStream());
 | 
			
		||||
  cm::uv_pipe_ptr errPipe;
 | 
			
		||||
  errPipe.init(process.GetLoop(), 0);
 | 
			
		||||
  uv_pipe_open(errPipe, process.ErrorStream());
 | 
			
		||||
  cmsysProcess* cp = cmsysProcess_New();
 | 
			
		||||
  cmsysProcess_SetCommand(cp, argv.data());
 | 
			
		||||
  // cmsysProcess_SetWorkingDirectory(cp, dir);
 | 
			
		||||
  cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
 | 
			
		||||
  // cmsysProcess_SetTimeout(cp, timeout);
 | 
			
		||||
  cmsysProcess_Execute(cp);
 | 
			
		||||
 | 
			
		||||
  std::vector<char> out;
 | 
			
		||||
  std::vector<char> err;
 | 
			
		||||
  std::string line;
 | 
			
		||||
  auto pipe =
 | 
			
		||||
    cmSystemTools::WaitForLine(&process.GetLoop(), outPipe, errPipe, line,
 | 
			
		||||
                               std::chrono::seconds(100), out, err);
 | 
			
		||||
  while (pipe != cmSystemTools::WaitForLineResult::None) {
 | 
			
		||||
  int pipe =
 | 
			
		||||
    cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, err);
 | 
			
		||||
  while (pipe != cmsysProcess_Pipe_None) {
 | 
			
		||||
    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
               "Output: " << line << "\n");
 | 
			
		||||
    if (pipe == cmSystemTools::WaitForLineResult::STDERR) {
 | 
			
		||||
    if (pipe == cmsysProcess_Pipe_STDERR) {
 | 
			
		||||
      cmCTestLog(this->CTest, ERROR_MESSAGE, line << "\n");
 | 
			
		||||
    } else if (pipe == cmSystemTools::WaitForLineResult::STDOUT) {
 | 
			
		||||
    } else if (pipe == cmsysProcess_Pipe_STDOUT) {
 | 
			
		||||
      cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, line << "\n");
 | 
			
		||||
    }
 | 
			
		||||
    pipe =
 | 
			
		||||
      cmSystemTools::WaitForLine(&process.GetLoop(), outPipe, errPipe, line,
 | 
			
		||||
                                 std::chrono::seconds(100), out, err);
 | 
			
		||||
    pipe = cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out,
 | 
			
		||||
                                      err);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Properly handle output of the build command
 | 
			
		||||
  process.Wait();
 | 
			
		||||
  auto const& status = process.GetStatus(0);
 | 
			
		||||
  auto result = status.GetException();
 | 
			
		||||
  cmsysProcess_WaitForExit(cp, nullptr);
 | 
			
		||||
  int result = cmsysProcess_GetState(cp);
 | 
			
		||||
  int retVal = 0;
 | 
			
		||||
  bool failed = false;
 | 
			
		||||
  switch (result.first) {
 | 
			
		||||
    case cmUVProcessChain::ExceptionCode::None:
 | 
			
		||||
      retVal = static_cast<int>(status.ExitStatus);
 | 
			
		||||
      break;
 | 
			
		||||
    case cmUVProcessChain::ExceptionCode::Spawn:
 | 
			
		||||
      cmCTestLog(this->CTest, ERROR_MESSAGE,
 | 
			
		||||
                 "\tError executing ctest: " << result.second << std::endl);
 | 
			
		||||
      failed = true;
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      retVal = status.TermSignal;
 | 
			
		||||
      cmCTestLog(this->CTest, ERROR_MESSAGE,
 | 
			
		||||
                 "\tThere was an exception: " << result.second << " " << retVal
 | 
			
		||||
                                              << std::endl);
 | 
			
		||||
      failed = true;
 | 
			
		||||
  if (result == cmsysProcess_State_Exited) {
 | 
			
		||||
    retVal = cmsysProcess_GetExitValue(cp);
 | 
			
		||||
  } else if (result == cmsysProcess_State_Exception) {
 | 
			
		||||
    retVal = cmsysProcess_GetExitException(cp);
 | 
			
		||||
    cmCTestLog(this->CTest, ERROR_MESSAGE,
 | 
			
		||||
               "\tThere was an exception: "
 | 
			
		||||
                 << cmsysProcess_GetExceptionString(cp) << " " << retVal
 | 
			
		||||
                 << std::endl);
 | 
			
		||||
    failed = true;
 | 
			
		||||
  } else if (result == cmsysProcess_State_Expired) {
 | 
			
		||||
    cmCTestLog(this->CTest, ERROR_MESSAGE,
 | 
			
		||||
               "\tThere was a timeout" << std::endl);
 | 
			
		||||
    failed = true;
 | 
			
		||||
  } else if (result == cmsysProcess_State_Error) {
 | 
			
		||||
    cmCTestLog(this->CTest, ERROR_MESSAGE,
 | 
			
		||||
               "\tError executing ctest: " << cmsysProcess_GetErrorString(cp)
 | 
			
		||||
                                           << std::endl);
 | 
			
		||||
    failed = true;
 | 
			
		||||
  }
 | 
			
		||||
  cmsysProcess_Delete(cp);
 | 
			
		||||
  if (failed) {
 | 
			
		||||
    std::ostringstream message;
 | 
			
		||||
    message << "Error running command: [";
 | 
			
		||||
    message << static_cast<int>(result.first) << "] ";
 | 
			
		||||
    message << result << "] ";
 | 
			
		||||
    for (const char* arg : argv) {
 | 
			
		||||
      if (arg) {
 | 
			
		||||
        message << arg << " ";
 | 
			
		||||
 | 
			
		||||
@ -7,9 +7,10 @@
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "cmsys/Process.h"
 | 
			
		||||
 | 
			
		||||
#include "cmCTest.h"
 | 
			
		||||
#include "cmSystemTools.h"
 | 
			
		||||
#include "cmUVProcessChain.h"
 | 
			
		||||
#include "cmValue.h"
 | 
			
		||||
#include "cmXMLWriter.h"
 | 
			
		||||
 | 
			
		||||
@ -54,12 +55,18 @@ bool cmCTestVC::InitialCheckout(const std::string& command)
 | 
			
		||||
 | 
			
		||||
  // Construct the initial checkout command line.
 | 
			
		||||
  std::vector<std::string> args = cmSystemTools::ParseArguments(command);
 | 
			
		||||
  std::vector<char const*> vc_co;
 | 
			
		||||
  vc_co.reserve(args.size() + 1);
 | 
			
		||||
  for (std::string const& arg : args) {
 | 
			
		||||
    vc_co.push_back(arg.c_str());
 | 
			
		||||
  }
 | 
			
		||||
  vc_co.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  // Run the initial checkout command and log its output.
 | 
			
		||||
  this->Log << "--- Begin Initial Checkout ---\n";
 | 
			
		||||
  OutputLogger out(this->Log, "co-out> ");
 | 
			
		||||
  OutputLogger err(this->Log, "co-err> ");
 | 
			
		||||
  bool result = this->RunChild(args, &out, &err, parent);
 | 
			
		||||
  bool result = this->RunChild(vc_co.data(), &out, &err, parent.c_str());
 | 
			
		||||
  this->Log << "--- End Initial Checkout ---\n";
 | 
			
		||||
  if (!result) {
 | 
			
		||||
    cmCTestLog(this->CTest, ERROR_MESSAGE,
 | 
			
		||||
@ -68,35 +75,35 @@ bool cmCTestVC::InitialCheckout(const std::string& command)
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmCTestVC::RunChild(const std::vector<std::string>& cmd,
 | 
			
		||||
                         OutputParser* out, OutputParser* err,
 | 
			
		||||
                         std::string workDir, Encoding encoding)
 | 
			
		||||
bool cmCTestVC::RunChild(char const* const* cmd, OutputParser* out,
 | 
			
		||||
                         OutputParser* err, const char* workDir,
 | 
			
		||||
                         Encoding encoding)
 | 
			
		||||
{
 | 
			
		||||
  this->Log << cmCTestVC::ComputeCommandLine(cmd) << "\n";
 | 
			
		||||
 | 
			
		||||
  cmUVProcessChainBuilder builder;
 | 
			
		||||
  if (workDir.empty()) {
 | 
			
		||||
    workDir = this->SourceDirectory;
 | 
			
		||||
  }
 | 
			
		||||
  builder.AddCommand(cmd).SetWorkingDirectory(workDir);
 | 
			
		||||
  auto status = cmCTestVC::RunProcess(builder, out, err, encoding);
 | 
			
		||||
  return status.front().SpawnResult == 0 && status.front().ExitStatus == 0;
 | 
			
		||||
  cmsysProcess* cp = cmsysProcess_New();
 | 
			
		||||
  cmsysProcess_SetCommand(cp, cmd);
 | 
			
		||||
  workDir = workDir ? workDir : this->SourceDirectory.c_str();
 | 
			
		||||
  cmsysProcess_SetWorkingDirectory(cp, workDir);
 | 
			
		||||
  cmCTestVC::RunProcess(cp, out, err, encoding);
 | 
			
		||||
  int result = cmsysProcess_GetExitValue(cp);
 | 
			
		||||
  cmsysProcess_Delete(cp);
 | 
			
		||||
  return result == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string cmCTestVC::ComputeCommandLine(const std::vector<std::string>& cmd)
 | 
			
		||||
std::string cmCTestVC::ComputeCommandLine(char const* const* cmd)
 | 
			
		||||
{
 | 
			
		||||
  std::ostringstream line;
 | 
			
		||||
  const char* sep = "";
 | 
			
		||||
  for (auto const& arg : cmd) {
 | 
			
		||||
    line << sep << "\"" << arg << "\"";
 | 
			
		||||
  for (const char* const* arg = cmd; *arg; ++arg) {
 | 
			
		||||
    line << sep << "\"" << *arg << "\"";
 | 
			
		||||
    sep = " ";
 | 
			
		||||
  }
 | 
			
		||||
  return line.str();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmCTestVC::RunUpdateCommand(const std::vector<std::string>& cmd,
 | 
			
		||||
                                 OutputParser* out, OutputParser* err,
 | 
			
		||||
                                 Encoding encoding)
 | 
			
		||||
bool cmCTestVC::RunUpdateCommand(char const* const* cmd, OutputParser* out,
 | 
			
		||||
                                 OutputParser* err, Encoding encoding)
 | 
			
		||||
{
 | 
			
		||||
  // Report the command line.
 | 
			
		||||
  this->UpdateCommandLine = this->ComputeCommandLine(cmd);
 | 
			
		||||
@ -106,7 +113,7 @@ bool cmCTestVC::RunUpdateCommand(const std::vector<std::string>& cmd,
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Run the command.
 | 
			
		||||
  return this->RunChild(cmd, out, err, "", encoding);
 | 
			
		||||
  return this->RunChild(cmd, out, err, nullptr, encoding);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string cmCTestVC::GetNightlyTime()
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,6 @@
 | 
			
		||||
 | 
			
		||||
#include <iosfwd>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "cmProcessOutput.h"
 | 
			
		||||
#include "cmProcessTools.h"
 | 
			
		||||
@ -109,15 +108,15 @@ protected:
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /** Convert a list of arguments to a human-readable command line.  */
 | 
			
		||||
  static std::string ComputeCommandLine(const std::vector<std::string>& cmd);
 | 
			
		||||
  static std::string ComputeCommandLine(char const* const* cmd);
 | 
			
		||||
 | 
			
		||||
  /** Run a command line and send output to given parsers.  */
 | 
			
		||||
  bool RunChild(const std::vector<std::string>& cmd, OutputParser* out,
 | 
			
		||||
                OutputParser* err, std::string workDir = {},
 | 
			
		||||
  bool RunChild(char const* const* cmd, OutputParser* out, OutputParser* err,
 | 
			
		||||
                const char* workDir = nullptr,
 | 
			
		||||
                Encoding encoding = cmProcessOutput::Auto);
 | 
			
		||||
 | 
			
		||||
  /** Run VC update command line and send output to given parsers.  */
 | 
			
		||||
  bool RunUpdateCommand(const std::vector<std::string>& cmd, OutputParser* out,
 | 
			
		||||
  bool RunUpdateCommand(char const* const* cmd, OutputParser* out,
 | 
			
		||||
                        OutputParser* err = nullptr,
 | 
			
		||||
                        Encoding encoding = cmProcessOutput::Auto);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -667,10 +667,6 @@ Modify cmCTestResourceGroupsLexer.cxx:
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
#  include <termios.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
#define INITIAL 0
 | 
			
		||||
 | 
			
		||||
@ -26,10 +26,6 @@ Modify cmCTestResourceGroupsLexer.cxx:
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
#  include <termios.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------------------------------*/
 | 
			
		||||
%}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,6 @@
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cctype>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
@ -25,13 +24,13 @@
 | 
			
		||||
#include <cmext/string_view>
 | 
			
		||||
 | 
			
		||||
#include <cm3p/curl/curl.h>
 | 
			
		||||
#include <cm3p/uv.h>
 | 
			
		||||
#include <cm3p/zlib.h>
 | 
			
		||||
 | 
			
		||||
#include "cmsys/Base64.h"
 | 
			
		||||
#include "cmsys/Directory.hxx"
 | 
			
		||||
#include "cmsys/FStream.hxx"
 | 
			
		||||
#include "cmsys/Glob.hxx"
 | 
			
		||||
#include "cmsys/Process.h"
 | 
			
		||||
#include "cmsys/RegularExpression.hxx"
 | 
			
		||||
#include "cmsys/SystemInformation.hxx"
 | 
			
		||||
#if defined(_WIN32)
 | 
			
		||||
@ -65,9 +64,6 @@
 | 
			
		||||
#include "cmStateTypes.h"
 | 
			
		||||
#include "cmStringAlgorithms.h"
 | 
			
		||||
#include "cmSystemTools.h"
 | 
			
		||||
#include "cmUVHandlePtr.h"
 | 
			
		||||
#include "cmUVProcessChain.h"
 | 
			
		||||
#include "cmUVStream.h"
 | 
			
		||||
#include "cmValue.h"
 | 
			
		||||
#include "cmVersion.h"
 | 
			
		||||
#include "cmVersionConfig.h"
 | 
			
		||||
@ -1077,9 +1073,9 @@ int cmCTest::GetTestModelFromString(const std::string& str)
 | 
			
		||||
// ######################################################################
 | 
			
		||||
// ######################################################################
 | 
			
		||||
 | 
			
		||||
bool cmCTest::RunMakeCommand(const std::string& command, std::string& output,
 | 
			
		||||
                             int* retVal, const char* dir, cmDuration timeout,
 | 
			
		||||
                             std::ostream& ofs, Encoding encoding)
 | 
			
		||||
int cmCTest::RunMakeCommand(const std::string& command, std::string& output,
 | 
			
		||||
                            int* retVal, const char* dir, cmDuration timeout,
 | 
			
		||||
                            std::ostream& ofs, Encoding encoding)
 | 
			
		||||
{
 | 
			
		||||
  // First generate the command and arguments
 | 
			
		||||
  std::vector<std::string> args = cmSystemTools::ParseArguments(command);
 | 
			
		||||
@ -1088,107 +1084,107 @@ bool cmCTest::RunMakeCommand(const std::string& command, std::string& output,
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::vector<const char*> argv;
 | 
			
		||||
  argv.reserve(args.size() + 1);
 | 
			
		||||
  for (std::string const& a : args) {
 | 
			
		||||
    argv.push_back(a.c_str());
 | 
			
		||||
  }
 | 
			
		||||
  argv.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  output.clear();
 | 
			
		||||
  cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Run command:");
 | 
			
		||||
  for (auto const& arg : args) {
 | 
			
		||||
  for (char const* arg : argv) {
 | 
			
		||||
    if (!arg) {
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, " \"" << arg << "\"");
 | 
			
		||||
  }
 | 
			
		||||
  cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, std::endl);
 | 
			
		||||
 | 
			
		||||
  // Now create process object
 | 
			
		||||
  cmUVProcessChainBuilder builder;
 | 
			
		||||
  builder.AddCommand(args).SetMergedBuiltinStreams();
 | 
			
		||||
  if (dir) {
 | 
			
		||||
    builder.SetWorkingDirectory(dir);
 | 
			
		||||
  }
 | 
			
		||||
  auto chain = builder.Start();
 | 
			
		||||
  cm::uv_pipe_ptr outputStream;
 | 
			
		||||
  outputStream.init(chain.GetLoop(), 0);
 | 
			
		||||
  uv_pipe_open(outputStream, chain.OutputStream());
 | 
			
		||||
  cmsysProcess* cp = cmsysProcess_New();
 | 
			
		||||
  cmsysProcess_SetCommand(cp, argv.data());
 | 
			
		||||
  cmsysProcess_SetWorkingDirectory(cp, dir);
 | 
			
		||||
  cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
 | 
			
		||||
  cmsysProcess_SetTimeout(cp, timeout.count());
 | 
			
		||||
  cmsysProcess_Execute(cp);
 | 
			
		||||
 | 
			
		||||
  // Initialize tick's
 | 
			
		||||
  std::string::size_type tick = 0;
 | 
			
		||||
  std::string::size_type tick_len = 1024;
 | 
			
		||||
  std::string::size_type tick_line_len = 50;
 | 
			
		||||
 | 
			
		||||
  char* data;
 | 
			
		||||
  int length;
 | 
			
		||||
  cmProcessOutput processOutput(encoding);
 | 
			
		||||
  std::string strdata;
 | 
			
		||||
  cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
 | 
			
		||||
             "   Each . represents " << tick_len
 | 
			
		||||
                                     << " bytes of output\n"
 | 
			
		||||
                                        "    "
 | 
			
		||||
                                     << std::flush);
 | 
			
		||||
  auto outputHandle = cmUVStreamRead(
 | 
			
		||||
    outputStream,
 | 
			
		||||
    [this, &processOutput, &output, &tick, &tick_len, &tick_line_len,
 | 
			
		||||
     &ofs](std::vector<char> data) {
 | 
			
		||||
      std::string strdata;
 | 
			
		||||
      processOutput.DecodeText(data.data(), data.size(), strdata);
 | 
			
		||||
      for (char& cc : strdata) {
 | 
			
		||||
        if (cc == 0) {
 | 
			
		||||
          cc = '\n';
 | 
			
		||||
        }
 | 
			
		||||
  while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
 | 
			
		||||
    processOutput.DecodeText(data, length, strdata);
 | 
			
		||||
    for (char& cc : strdata) {
 | 
			
		||||
      if (cc == 0) {
 | 
			
		||||
        cc = '\n';
 | 
			
		||||
      }
 | 
			
		||||
      output.append(strdata);
 | 
			
		||||
      while (output.size() > (tick * tick_len)) {
 | 
			
		||||
        tick++;
 | 
			
		||||
        cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, "." << std::flush);
 | 
			
		||||
        if (tick % tick_line_len == 0 && tick > 0) {
 | 
			
		||||
          cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
 | 
			
		||||
                     "  Size: " << int((double(output.size()) / 1024.0) + 1)
 | 
			
		||||
                                << "K\n    " << std::flush);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    output.append(strdata);
 | 
			
		||||
    while (output.size() > (tick * tick_len)) {
 | 
			
		||||
      tick++;
 | 
			
		||||
      cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, "." << std::flush);
 | 
			
		||||
      if (tick % tick_line_len == 0 && tick > 0) {
 | 
			
		||||
        cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
 | 
			
		||||
                   "  Size: " << int((double(output.size()) / 1024.0) + 1)
 | 
			
		||||
                              << "K\n    " << std::flush);
 | 
			
		||||
      }
 | 
			
		||||
      cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
                 cmCTestLogWrite(strdata.c_str(), strdata.size()));
 | 
			
		||||
      if (ofs) {
 | 
			
		||||
        ofs << cmCTestLogWrite(strdata.c_str(), strdata.size());
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    [this, &processOutput, &output, &ofs]() {
 | 
			
		||||
      std::string strdata;
 | 
			
		||||
      processOutput.DecodeText(std::string(), strdata);
 | 
			
		||||
      if (!strdata.empty()) {
 | 
			
		||||
        output.append(strdata);
 | 
			
		||||
        cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
                   cmCTestLogWrite(strdata.c_str(), strdata.size()));
 | 
			
		||||
        if (ofs) {
 | 
			
		||||
          ofs << cmCTestLogWrite(strdata.c_str(), strdata.size());
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
  bool finished = chain.Wait(static_cast<uint64_t>(timeout.count() * 1000.0));
 | 
			
		||||
    }
 | 
			
		||||
    cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
               cmCTestLogWrite(strdata.c_str(), strdata.size()));
 | 
			
		||||
    if (ofs) {
 | 
			
		||||
      ofs << cmCTestLogWrite(strdata.c_str(), strdata.size());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  processOutput.DecodeText(std::string(), strdata);
 | 
			
		||||
  if (!strdata.empty()) {
 | 
			
		||||
    output.append(strdata);
 | 
			
		||||
    cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
               cmCTestLogWrite(strdata.c_str(), strdata.size()));
 | 
			
		||||
    if (ofs) {
 | 
			
		||||
      ofs << cmCTestLogWrite(strdata.c_str(), strdata.size());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
 | 
			
		||||
             " Size of output: " << int(double(output.size()) / 1024.0) << "K"
 | 
			
		||||
                                 << std::endl);
 | 
			
		||||
 | 
			
		||||
  if (finished) {
 | 
			
		||||
    auto const& status = chain.GetStatus(0);
 | 
			
		||||
    auto exception = status.GetException();
 | 
			
		||||
    switch (exception.first) {
 | 
			
		||||
      case cmUVProcessChain::ExceptionCode::None:
 | 
			
		||||
        *retVal = static_cast<int>(status.ExitStatus);
 | 
			
		||||
        cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
                   "Command exited with the value: " << *retVal << std::endl);
 | 
			
		||||
        break;
 | 
			
		||||
      case cmUVProcessChain::ExceptionCode::Spawn:
 | 
			
		||||
        output += "\n*** ERROR executing: ";
 | 
			
		||||
        output += exception.second;
 | 
			
		||||
        output += "\n***The build process failed.";
 | 
			
		||||
        cmCTestLog(this, ERROR_MESSAGE,
 | 
			
		||||
                   "There was an error: " << exception.second << std::endl);
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        *retVal = static_cast<int>(exception.first);
 | 
			
		||||
        cmCTestLog(this, WARNING,
 | 
			
		||||
                   "There was an exception: " << *retVal << std::endl);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
  cmsysProcess_WaitForExit(cp, nullptr);
 | 
			
		||||
 | 
			
		||||
  int result = cmsysProcess_GetState(cp);
 | 
			
		||||
 | 
			
		||||
  if (result == cmsysProcess_State_Exited) {
 | 
			
		||||
    *retVal = cmsysProcess_GetExitValue(cp);
 | 
			
		||||
    cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
               "Command exited with the value: " << *retVal << std::endl);
 | 
			
		||||
  } else if (result == cmsysProcess_State_Exception) {
 | 
			
		||||
    *retVal = cmsysProcess_GetExitException(cp);
 | 
			
		||||
    cmCTestLog(this, WARNING,
 | 
			
		||||
               "There was an exception: " << *retVal << std::endl);
 | 
			
		||||
  } else if (result == cmsysProcess_State_Expired) {
 | 
			
		||||
    cmCTestLog(this, WARNING, "There was a timeout" << std::endl);
 | 
			
		||||
  } else if (result == cmsysProcess_State_Error) {
 | 
			
		||||
    output += "\n*** ERROR executing: ";
 | 
			
		||||
    output += cmsysProcess_GetErrorString(cp);
 | 
			
		||||
    output += "\n***The build process failed.";
 | 
			
		||||
    cmCTestLog(this, ERROR_MESSAGE,
 | 
			
		||||
               "There was an error: " << cmsysProcess_GetErrorString(cp)
 | 
			
		||||
                                      << std::endl);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
  cmsysProcess_Delete(cp);
 | 
			
		||||
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ######################################################################
 | 
			
		||||
@ -1196,10 +1192,9 @@ bool cmCTest::RunMakeCommand(const std::string& command, std::string& output,
 | 
			
		||||
// ######################################################################
 | 
			
		||||
// ######################################################################
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
 | 
			
		||||
                     int* retVal, std::ostream* log, cmDuration testTimeOut,
 | 
			
		||||
                     std::vector<std::string>* environment, Encoding encoding)
 | 
			
		||||
{
 | 
			
		||||
  bool modifyEnv = (environment && !environment->empty());
 | 
			
		||||
 | 
			
		||||
@ -1238,16 +1233,19 @@ bool cmCTest::RunTest(const std::vector<std::string>& argv,
 | 
			
		||||
    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)));
 | 
			
		||||
    for (char const* i : argv) {
 | 
			
		||||
      if (i) {
 | 
			
		||||
        // 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 (strcmp(i, "--build-generator") == 0 &&
 | 
			
		||||
            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);
 | 
			
		||||
      }
 | 
			
		||||
      args.emplace_back(i);
 | 
			
		||||
    }
 | 
			
		||||
    if (log) {
 | 
			
		||||
      *log << "* Run internal CTest" << std::endl;
 | 
			
		||||
@ -1273,7 +1271,7 @@ bool cmCTest::RunTest(const std::vector<std::string>& argv,
 | 
			
		||||
                                                             << std::endl);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
    return cmsysProcess_State_Exited;
 | 
			
		||||
  }
 | 
			
		||||
  std::vector<char> tempOutput;
 | 
			
		||||
  if (output) {
 | 
			
		||||
@ -1286,43 +1284,41 @@ bool cmCTest::RunTest(const std::vector<std::string>& argv,
 | 
			
		||||
    cmSystemTools::AppendEnv(*environment);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  cmUVProcessChainBuilder builder;
 | 
			
		||||
  builder.AddCommand(argv).SetMergedBuiltinStreams();
 | 
			
		||||
  cmsysProcess* cp = cmsysProcess_New();
 | 
			
		||||
  cmsysProcess_SetCommand(cp, argv.data());
 | 
			
		||||
  cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
 | 
			
		||||
  auto chain = builder.Start();
 | 
			
		||||
  if (cmSystemTools::GetRunCommandHideConsole()) {
 | 
			
		||||
    cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  cmsysProcess_SetTimeout(cp, timeout.count());
 | 
			
		||||
  cmsysProcess_Execute(cp);
 | 
			
		||||
 | 
			
		||||
  char* data;
 | 
			
		||||
  int length;
 | 
			
		||||
  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,
 | 
			
		||||
                 cmCTestLogWrite(strdata.c_str(), strdata.size()));
 | 
			
		||||
      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,
 | 
			
		||||
                   cmCTestLogWrite(strdata.c_str(), strdata.size()));
 | 
			
		||||
        if (log) {
 | 
			
		||||
          log->write(strdata.c_str(), strdata.size());
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  std::string strdata;
 | 
			
		||||
  while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
 | 
			
		||||
    processOutput.DecodeText(data, length, strdata);
 | 
			
		||||
    if (output) {
 | 
			
		||||
      cm::append(tempOutput, data, data + length);
 | 
			
		||||
    }
 | 
			
		||||
    cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
               cmCTestLogWrite(strdata.c_str(), strdata.size()));
 | 
			
		||||
    if (log) {
 | 
			
		||||
      log->write(strdata.c_str(), strdata.size());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  processOutput.DecodeText(std::string(), strdata);
 | 
			
		||||
  if (!strdata.empty()) {
 | 
			
		||||
    cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
               cmCTestLogWrite(strdata.c_str(), strdata.size()));
 | 
			
		||||
    if (log) {
 | 
			
		||||
      log->write(strdata.c_str(), strdata.size());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool complete = chain.Wait(static_cast<uint64_t>(timeout.count() * 1000.0));
 | 
			
		||||
  cmsysProcess_WaitForExit(cp, nullptr);
 | 
			
		||||
  processOutput.DecodeText(tempOutput, tempOutput);
 | 
			
		||||
  if (output && tempOutput.begin() != tempOutput.end()) {
 | 
			
		||||
    output->append(tempOutput.data(), tempOutput.size());
 | 
			
		||||
@ -1330,41 +1326,33 @@ bool cmCTest::RunTest(const std::vector<std::string>& argv,
 | 
			
		||||
  cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
 | 
			
		||||
             "-- Process completed" << std::endl);
 | 
			
		||||
 | 
			
		||||
  bool result = false;
 | 
			
		||||
  int result = cmsysProcess_GetState(cp);
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
  if (result == cmsysProcess_State_Exited) {
 | 
			
		||||
    *retVal = cmsysProcess_GetExitValue(cp);
 | 
			
		||||
    if (*retVal != 0 && this->Impl->OutputTestOutputOnTestFailure) {
 | 
			
		||||
      this->OutputTestErrors(tempOutput);
 | 
			
		||||
    }
 | 
			
		||||
  } else if (result == cmsysProcess_State_Exception) {
 | 
			
		||||
    if (this->Impl->OutputTestOutputOnTestFailure) {
 | 
			
		||||
      this->OutputTestErrors(tempOutput);
 | 
			
		||||
    }
 | 
			
		||||
    *retVal = cmsysProcess_GetExitException(cp);
 | 
			
		||||
    std::string outerr = cmStrCat("\n*** Exception executing: ",
 | 
			
		||||
                                  cmsysProcess_GetExceptionString(cp));
 | 
			
		||||
    if (output) {
 | 
			
		||||
      *output += outerr;
 | 
			
		||||
    }
 | 
			
		||||
    cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl);
 | 
			
		||||
  } else if (result == cmsysProcess_State_Error) {
 | 
			
		||||
    std::string outerr =
 | 
			
		||||
      cmStrCat("\n*** ERROR executing: ", cmsysProcess_GetErrorString(cp));
 | 
			
		||||
    if (output) {
 | 
			
		||||
      *output += outerr;
 | 
			
		||||
    }
 | 
			
		||||
    cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl);
 | 
			
		||||
  }
 | 
			
		||||
  cmsysProcess_Delete(cp);
 | 
			
		||||
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
@ -3482,70 +3470,49 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
 | 
			
		||||
  stdOut->clear();
 | 
			
		||||
  stdErr->clear();
 | 
			
		||||
 | 
			
		||||
  cmUVProcessChainBuilder builder;
 | 
			
		||||
  builder.AddCommand(args)
 | 
			
		||||
    .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
 | 
			
		||||
    .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
 | 
			
		||||
  if (dir) {
 | 
			
		||||
    builder.SetWorkingDirectory(dir);
 | 
			
		||||
  }
 | 
			
		||||
  auto chain = builder.Start();
 | 
			
		||||
 | 
			
		||||
  cm::uv_timer_ptr timer;
 | 
			
		||||
  bool timedOut = false;
 | 
			
		||||
  if (timeout.count()) {
 | 
			
		||||
    timer.init(chain.GetLoop(), &timedOut);
 | 
			
		||||
    timer.start(
 | 
			
		||||
      [](uv_timer_t* t) {
 | 
			
		||||
        auto* timedOutPtr = static_cast<bool*>(t->data);
 | 
			
		||||
        *timedOutPtr = true;
 | 
			
		||||
      },
 | 
			
		||||
      static_cast<uint64_t>(timeout.count() * 1000.0), 0);
 | 
			
		||||
  cmsysProcess* cp = cmsysProcess_New();
 | 
			
		||||
  cmsysProcess_SetCommand(cp, argv.data());
 | 
			
		||||
  cmsysProcess_SetWorkingDirectory(cp, dir);
 | 
			
		||||
  if (cmSystemTools::GetRunCommandHideConsole()) {
 | 
			
		||||
    cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
 | 
			
		||||
  }
 | 
			
		||||
  cmsysProcess_SetTimeout(cp, timeout.count());
 | 
			
		||||
  cmsysProcess_Execute(cp);
 | 
			
		||||
 | 
			
		||||
  std::vector<char> tempOutput;
 | 
			
		||||
  bool outFinished = false;
 | 
			
		||||
  cm::uv_pipe_ptr outStream;
 | 
			
		||||
  std::vector<char> tempError;
 | 
			
		||||
  bool errFinished = false;
 | 
			
		||||
  cm::uv_pipe_ptr errStream;
 | 
			
		||||
  char* data;
 | 
			
		||||
  int length;
 | 
			
		||||
  cmProcessOutput processOutput(encoding);
 | 
			
		||||
  auto startRead = [this, &chain, &processOutput](
 | 
			
		||||
                     cm::uv_pipe_ptr& pipe, int stream,
 | 
			
		||||
                     std::vector<char>& temp,
 | 
			
		||||
                     bool& finished) -> std::unique_ptr<cmUVStreamReadHandle> {
 | 
			
		||||
    pipe.init(chain.GetLoop(), 0);
 | 
			
		||||
    uv_pipe_open(pipe, stream);
 | 
			
		||||
    return cmUVStreamRead(
 | 
			
		||||
      pipe,
 | 
			
		||||
      [this, &temp, &processOutput](std::vector<char> data) {
 | 
			
		||||
        cm::append(temp, data);
 | 
			
		||||
        if (this->Impl->ExtraVerbose) {
 | 
			
		||||
          std::string strdata;
 | 
			
		||||
          processOutput.DecodeText(data.data(), data.size(), strdata);
 | 
			
		||||
          cmSystemTools::Stdout(strdata);
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      [&finished]() { finished = true; });
 | 
			
		||||
  };
 | 
			
		||||
  auto outputHandle =
 | 
			
		||||
    startRead(outStream, chain.OutputStream(), tempOutput, outFinished);
 | 
			
		||||
  auto errorHandle =
 | 
			
		||||
    startRead(errStream, chain.ErrorStream(), tempError, errFinished);
 | 
			
		||||
  while (!timedOut && !(outFinished && errFinished)) {
 | 
			
		||||
    uv_run(&chain.GetLoop(), UV_RUN_ONCE);
 | 
			
		||||
  std::string strdata;
 | 
			
		||||
  int res;
 | 
			
		||||
  bool done = false;
 | 
			
		||||
  while (!done) {
 | 
			
		||||
    res = cmsysProcess_WaitForData(cp, &data, &length, nullptr);
 | 
			
		||||
    switch (res) {
 | 
			
		||||
      case cmsysProcess_Pipe_STDOUT:
 | 
			
		||||
        cm::append(tempOutput, data, data + length);
 | 
			
		||||
        break;
 | 
			
		||||
      case cmsysProcess_Pipe_STDERR:
 | 
			
		||||
        cm::append(tempError, data, data + length);
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        done = true;
 | 
			
		||||
    }
 | 
			
		||||
    if ((res == cmsysProcess_Pipe_STDOUT || res == cmsysProcess_Pipe_STDERR) &&
 | 
			
		||||
        this->Impl->ExtraVerbose) {
 | 
			
		||||
      processOutput.DecodeText(data, length, strdata);
 | 
			
		||||
      cmSystemTools::Stdout(strdata);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (this->Impl->ExtraVerbose) {
 | 
			
		||||
    std::string strdata;
 | 
			
		||||
    processOutput.DecodeText(std::string(), strdata);
 | 
			
		||||
    if (!strdata.empty()) {
 | 
			
		||||
      cmSystemTools::Stdout(strdata);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  while (!timedOut && !chain.Finished()) {
 | 
			
		||||
    uv_run(&chain.GetLoop(), UV_RUN_ONCE);
 | 
			
		||||
  }
 | 
			
		||||
  cmsysProcess_WaitForExit(cp, nullptr);
 | 
			
		||||
  if (!tempOutput.empty()) {
 | 
			
		||||
    processOutput.DecodeText(tempOutput, tempOutput);
 | 
			
		||||
    stdOut->append(tempOutput.data(), tempOutput.size());
 | 
			
		||||
@ -3556,32 +3523,32 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool result = true;
 | 
			
		||||
  if (timedOut) {
 | 
			
		||||
  if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
 | 
			
		||||
    if (retVal) {
 | 
			
		||||
      *retVal = cmsysProcess_GetExitValue(cp);
 | 
			
		||||
    } else {
 | 
			
		||||
      if (cmsysProcess_GetExitValue(cp) != 0) {
 | 
			
		||||
        result = false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) {
 | 
			
		||||
    const char* exception_str = cmsysProcess_GetExceptionString(cp);
 | 
			
		||||
    cmCTestLog(this, ERROR_MESSAGE, exception_str << std::endl);
 | 
			
		||||
    stdErr->append(exception_str, strlen(exception_str));
 | 
			
		||||
    result = false;
 | 
			
		||||
  } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
 | 
			
		||||
    const char* error_str = cmsysProcess_GetErrorString(cp);
 | 
			
		||||
    cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
 | 
			
		||||
    stdErr->append(error_str, strlen(error_str));
 | 
			
		||||
    result = false;
 | 
			
		||||
  } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) {
 | 
			
		||||
    const char* error_str = "Process terminated due to timeout\n";
 | 
			
		||||
    cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl);
 | 
			
		||||
    stdErr->append(error_str, strlen(error_str));
 | 
			
		||||
    result = false;
 | 
			
		||||
  } else {
 | 
			
		||||
    auto const& status = chain.GetStatus(0);
 | 
			
		||||
    auto exception = status.GetException();
 | 
			
		||||
    switch (exception.first) {
 | 
			
		||||
      case cmUVProcessChain::ExceptionCode::None:
 | 
			
		||||
        if (retVal) {
 | 
			
		||||
          *retVal = static_cast<int>(status.ExitStatus);
 | 
			
		||||
        } else {
 | 
			
		||||
          if (status.ExitStatus != 0) {
 | 
			
		||||
            result = false;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      default: {
 | 
			
		||||
        cmCTestLog(this, ERROR_MESSAGE, exception.second << std::endl);
 | 
			
		||||
        stdErr->append(exception.second);
 | 
			
		||||
        result = false;
 | 
			
		||||
      } break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  cmsysProcess_Delete(cp);
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -254,10 +254,10 @@ public:
 | 
			
		||||
   * Run command specialized for make and configure. Returns process status
 | 
			
		||||
   * and retVal is return value or exception.
 | 
			
		||||
   */
 | 
			
		||||
  bool RunMakeCommand(const std::string& command, std::string& output,
 | 
			
		||||
                      int* retVal, const char* dir, cmDuration timeout,
 | 
			
		||||
                      std::ostream& ofs,
 | 
			
		||||
                      Encoding encoding = cmProcessOutput::Auto);
 | 
			
		||||
  int RunMakeCommand(const std::string& command, std::string& output,
 | 
			
		||||
                     int* retVal, const char* dir, cmDuration timeout,
 | 
			
		||||
                     std::ostream& ofs,
 | 
			
		||||
                     Encoding encoding = cmProcessOutput::Auto);
 | 
			
		||||
 | 
			
		||||
  /** Return the current tag */
 | 
			
		||||
  std::string GetCurrentTag();
 | 
			
		||||
@ -303,10 +303,10 @@ public:
 | 
			
		||||
   * 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);
 | 
			
		||||
  int RunTest(std::vector<const char*> args, std::string* output, int* retVal,
 | 
			
		||||
              std::ostream* logfile, cmDuration testTimeOut,
 | 
			
		||||
              std::vector<std::string>* environment,
 | 
			
		||||
              Encoding encoding = cmProcessOutput::Auto);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Get the handler object
 | 
			
		||||
 | 
			
		||||
@ -260,7 +260,7 @@ cmComputeLinkInformation::cmComputeLinkInformation(
 | 
			
		||||
  , Config(config)
 | 
			
		||||
{
 | 
			
		||||
  // Check whether to recognize OpenBSD-style library versioned names.
 | 
			
		||||
  this->OpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
 | 
			
		||||
  this->IsOpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
 | 
			
		||||
    "FIND_LIBRARY_USE_OPENBSD_VERSIONING");
 | 
			
		||||
 | 
			
		||||
  // Allocate internals.
 | 
			
		||||
@ -553,7 +553,8 @@ bool cmComputeLinkInformation::Compute()
 | 
			
		||||
        this->Target->GetType() == cmStateEnums::MODULE_LIBRARY ||
 | 
			
		||||
        this->Target->GetType() == cmStateEnums::STATIC_LIBRARY ||
 | 
			
		||||
        (this->Target->CanCompileSources() &&
 | 
			
		||||
         (this->Target->HaveCxx20ModuleSources() ||
 | 
			
		||||
         (this->Target->HaveCxxModuleSupport(this->Config) ==
 | 
			
		||||
            cmGeneratorTarget::Cxx20SupportLevel::Supported ||
 | 
			
		||||
          this->Target->HaveFortranSources())))) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
@ -1574,7 +1575,7 @@ std::string cmComputeLinkInformation::CreateExtensionRegex(
 | 
			
		||||
  libext += ')';
 | 
			
		||||
 | 
			
		||||
  // Add an optional OpenBSD-style version or major.minor.version component.
 | 
			
		||||
  if (this->OpenBSD || type == LinkShared) {
 | 
			
		||||
  if (this->IsOpenBSD || type == LinkShared) {
 | 
			
		||||
    libext += "(\\.[0-9]+)*";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -254,7 +254,7 @@ private:
 | 
			
		||||
  std::unique_ptr<cmOrderDirectories> OrderRuntimeSearchPath;
 | 
			
		||||
 | 
			
		||||
  bool OldLinkDirMode;
 | 
			
		||||
  bool OpenBSD;
 | 
			
		||||
  bool IsOpenBSD;
 | 
			
		||||
  bool LinkDependsNoShared;
 | 
			
		||||
  bool RuntimeUseChrpath;
 | 
			
		||||
  bool NoSONameUsesPath;
 | 
			
		||||
 | 
			
		||||
@ -493,7 +493,8 @@ bool cmDyndepCollation::WriteDyndepMetadata(
 | 
			
		||||
      if (!has_provides) {
 | 
			
		||||
        cmSystemTools::Error(
 | 
			
		||||
          cmStrCat("Output ", object.PrimaryOutput,
 | 
			
		||||
                   " is of type `CXX_MODULES` but does not provide a module"));
 | 
			
		||||
                   " is of type `CXX_MODULES` but does not provide a module "
 | 
			
		||||
                   "interface unit or partition"));
 | 
			
		||||
        result = false;
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -2,8 +2,8 @@
 | 
			
		||||
   file Copyright.txt or https://cmake.org/licensing for details.  */
 | 
			
		||||
#include "cmExecuteProcessCommand.h"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cctype> /* isspace */
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <map>
 | 
			
		||||
@ -16,9 +16,7 @@
 | 
			
		||||
#include <cmext/algorithm>
 | 
			
		||||
#include <cmext/string_view>
 | 
			
		||||
 | 
			
		||||
#include <cm3p/uv.h>
 | 
			
		||||
 | 
			
		||||
#include "cm_fileno.hxx"
 | 
			
		||||
#include "cmsys/Process.h"
 | 
			
		||||
 | 
			
		||||
#include "cmArgumentParser.h"
 | 
			
		||||
#include "cmExecutionStatus.h"
 | 
			
		||||
@ -28,9 +26,6 @@
 | 
			
		||||
#include "cmProcessOutput.h"
 | 
			
		||||
#include "cmStringAlgorithms.h"
 | 
			
		||||
#include "cmSystemTools.h"
 | 
			
		||||
#include "cmUVHandlePtr.h"
 | 
			
		||||
#include "cmUVProcessChain.h"
 | 
			
		||||
#include "cmUVStream.h"
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
bool cmExecuteProcessCommandIsWhitespace(char c)
 | 
			
		||||
@ -41,7 +36,7 @@ bool cmExecuteProcessCommandIsWhitespace(char c)
 | 
			
		||||
void cmExecuteProcessCommandFixText(std::vector<char>& output,
 | 
			
		||||
                                    bool strip_trailing_whitespace);
 | 
			
		||||
void cmExecuteProcessCommandAppend(std::vector<char>& output, const char* data,
 | 
			
		||||
                                   std::size_t length);
 | 
			
		||||
                                   int length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// cmExecuteProcessCommand
 | 
			
		||||
@ -166,69 +161,57 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // Create a process instance.
 | 
			
		||||
  cmUVProcessChainBuilder builder;
 | 
			
		||||
  std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp_ptr(
 | 
			
		||||
    cmsysProcess_New(), cmsysProcess_Delete);
 | 
			
		||||
  cmsysProcess* cp = cp_ptr.get();
 | 
			
		||||
 | 
			
		||||
  // Set the command sequence.
 | 
			
		||||
  for (std::vector<std::string> const& cmd : arguments.Commands) {
 | 
			
		||||
    builder.AddCommand(cmd);
 | 
			
		||||
    std::vector<const char*> argv(cmd.size() + 1);
 | 
			
		||||
    std::transform(cmd.begin(), cmd.end(), argv.begin(),
 | 
			
		||||
                   [](std::string const& s) { return s.c_str(); });
 | 
			
		||||
    argv.back() = nullptr;
 | 
			
		||||
    cmsysProcess_AddCommand(cp, argv.data());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Set the process working directory.
 | 
			
		||||
  if (!arguments.WorkingDirectory.empty()) {
 | 
			
		||||
    builder.SetWorkingDirectory(arguments.WorkingDirectory);
 | 
			
		||||
    cmsysProcess_SetWorkingDirectory(cp, arguments.WorkingDirectory.c_str());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Always hide the process window.
 | 
			
		||||
  cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
 | 
			
		||||
 | 
			
		||||
  // Check the output variables.
 | 
			
		||||
  std::unique_ptr<FILE, int (*)(FILE*)> inputFile(nullptr, fclose);
 | 
			
		||||
  if (!inputFilename.empty()) {
 | 
			
		||||
    inputFile.reset(cmsys::SystemTools::Fopen(inputFilename, "rb"));
 | 
			
		||||
    if (inputFile) {
 | 
			
		||||
      builder.SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT,
 | 
			
		||||
                                cm_fileno(inputFile.get()));
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    builder.SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT,
 | 
			
		||||
                              cm_fileno(stdin));
 | 
			
		||||
  bool merge_output = false;
 | 
			
		||||
  if (!arguments.InputFile.empty()) {
 | 
			
		||||
    cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN,
 | 
			
		||||
                             arguments.InputFile.c_str());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::unique_ptr<FILE, int (*)(FILE*)> outputFile(nullptr, fclose);
 | 
			
		||||
  if (!outputFilename.empty()) {
 | 
			
		||||
    outputFile.reset(cmsys::SystemTools::Fopen(outputFilename, "wb"));
 | 
			
		||||
    if (outputFile) {
 | 
			
		||||
      builder.SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT,
 | 
			
		||||
                                cm_fileno(outputFile.get()));
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    if (arguments.OutputVariable == arguments.ErrorVariable &&
 | 
			
		||||
        !arguments.ErrorVariable.empty()) {
 | 
			
		||||
      builder.SetMergedBuiltinStreams();
 | 
			
		||||
  if (!arguments.OutputFile.empty()) {
 | 
			
		||||
    cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDOUT,
 | 
			
		||||
                             arguments.OutputFile.c_str());
 | 
			
		||||
  }
 | 
			
		||||
  if (!arguments.ErrorFile.empty()) {
 | 
			
		||||
    if (arguments.ErrorFile == arguments.OutputFile) {
 | 
			
		||||
      merge_output = true;
 | 
			
		||||
    } else {
 | 
			
		||||
      builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
 | 
			
		||||
      cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR,
 | 
			
		||||
                               arguments.ErrorFile.c_str());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::unique_ptr<FILE, int (*)(FILE*)> errorFile(nullptr, fclose);
 | 
			
		||||
  if (!errorFilename.empty()) {
 | 
			
		||||
    if (errorFilename == outputFilename) {
 | 
			
		||||
      if (outputFile) {
 | 
			
		||||
        builder.SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR,
 | 
			
		||||
                                  cm_fileno(outputFile.get()));
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      errorFile.reset(cmsys::SystemTools::Fopen(errorFilename, "wb"));
 | 
			
		||||
      if (errorFile) {
 | 
			
		||||
        builder.SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR,
 | 
			
		||||
                                  cm_fileno(errorFile.get()));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  } else if (arguments.ErrorVariable.empty() ||
 | 
			
		||||
             (!arguments.ErrorVariable.empty() &&
 | 
			
		||||
              arguments.OutputVariable != arguments.ErrorVariable)) {
 | 
			
		||||
    builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
 | 
			
		||||
  if (!arguments.OutputVariable.empty() &&
 | 
			
		||||
      arguments.OutputVariable == arguments.ErrorVariable) {
 | 
			
		||||
    merge_output = true;
 | 
			
		||||
  }
 | 
			
		||||
  if (merge_output) {
 | 
			
		||||
    cmsysProcess_SetOption(cp, cmsysProcess_Option_MergeOutput, 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Set the timeout if any.
 | 
			
		||||
  int64_t timeoutMillis = static_cast<int64_t>(timeout * 1000.0);
 | 
			
		||||
  if (timeout >= 0) {
 | 
			
		||||
    cmsysProcess_SetTimeout(cp, timeout);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool echo_stdout = false;
 | 
			
		||||
  bool echo_stderr = false;
 | 
			
		||||
@ -276,86 +259,36 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // Start the process.
 | 
			
		||||
  auto chain = builder.Start();
 | 
			
		||||
 | 
			
		||||
  bool timedOut = false;
 | 
			
		||||
  cm::uv_timer_ptr timer;
 | 
			
		||||
 | 
			
		||||
  if (timeoutMillis >= 0) {
 | 
			
		||||
    timer.init(chain.GetLoop(), &timedOut);
 | 
			
		||||
    timer.start(
 | 
			
		||||
      [](uv_timer_t* handle) {
 | 
			
		||||
        auto* timeoutPtr = static_cast<bool*>(handle->data);
 | 
			
		||||
        *timeoutPtr = true;
 | 
			
		||||
      },
 | 
			
		||||
      timeoutMillis, 0);
 | 
			
		||||
  }
 | 
			
		||||
  cmsysProcess_Execute(cp);
 | 
			
		||||
 | 
			
		||||
  // Read the process output.
 | 
			
		||||
  struct ReadData
 | 
			
		||||
  {
 | 
			
		||||
    bool Finished = false;
 | 
			
		||||
    std::vector<char> Output;
 | 
			
		||||
    cm::uv_pipe_ptr Stream;
 | 
			
		||||
  };
 | 
			
		||||
  ReadData outputData;
 | 
			
		||||
  ReadData errorData;
 | 
			
		||||
  std::vector<char> tempOutput;
 | 
			
		||||
  std::vector<char> tempError;
 | 
			
		||||
  int length;
 | 
			
		||||
  char* data;
 | 
			
		||||
  int p;
 | 
			
		||||
  cmProcessOutput processOutput(
 | 
			
		||||
    cmProcessOutput::FindEncoding(arguments.Encoding));
 | 
			
		||||
  std::string strdata;
 | 
			
		||||
 | 
			
		||||
  std::unique_ptr<cmUVStreamReadHandle> outputHandle;
 | 
			
		||||
  if (chain.OutputStream() >= 0) {
 | 
			
		||||
    outputData.Stream.init(chain.GetLoop(), 0);
 | 
			
		||||
    uv_pipe_open(outputData.Stream, chain.OutputStream());
 | 
			
		||||
    outputHandle = cmUVStreamRead(
 | 
			
		||||
      outputData.Stream,
 | 
			
		||||
      [&arguments, &processOutput, &outputData,
 | 
			
		||||
       &strdata](std::vector<char> data) {
 | 
			
		||||
        if (!arguments.OutputQuiet) {
 | 
			
		||||
          if (arguments.OutputVariable.empty() ||
 | 
			
		||||
              arguments.EchoOutputVariable) {
 | 
			
		||||
            processOutput.DecodeText(data.data(), data.size(), strdata, 1);
 | 
			
		||||
            cmSystemTools::Stdout(strdata);
 | 
			
		||||
          }
 | 
			
		||||
          if (!arguments.OutputVariable.empty()) {
 | 
			
		||||
            cmExecuteProcessCommandAppend(outputData.Output, data.data(),
 | 
			
		||||
                                          data.size());
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      [&outputData]() { outputData.Finished = true; });
 | 
			
		||||
  } else {
 | 
			
		||||
    outputData.Finished = true;
 | 
			
		||||
  }
 | 
			
		||||
  std::unique_ptr<cmUVStreamReadHandle> errorHandle;
 | 
			
		||||
  if (chain.ErrorStream() >= 0 &&
 | 
			
		||||
      chain.ErrorStream() != chain.OutputStream()) {
 | 
			
		||||
    errorData.Stream.init(chain.GetLoop(), 0);
 | 
			
		||||
    uv_pipe_open(errorData.Stream, chain.ErrorStream());
 | 
			
		||||
    errorHandle = cmUVStreamRead(
 | 
			
		||||
      errorData.Stream,
 | 
			
		||||
      [&arguments, &processOutput, &errorData,
 | 
			
		||||
       &strdata](std::vector<char> data) {
 | 
			
		||||
        if (!arguments.ErrorQuiet) {
 | 
			
		||||
          if (arguments.ErrorVariable.empty() || arguments.EchoErrorVariable) {
 | 
			
		||||
            processOutput.DecodeText(data.data(), data.size(), strdata, 2);
 | 
			
		||||
            cmSystemTools::Stderr(strdata);
 | 
			
		||||
          }
 | 
			
		||||
          if (!arguments.ErrorVariable.empty()) {
 | 
			
		||||
            cmExecuteProcessCommandAppend(errorData.Output, data.data(),
 | 
			
		||||
                                          data.size());
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      [&errorData]() { errorData.Finished = true; });
 | 
			
		||||
  } else {
 | 
			
		||||
    errorData.Finished = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  while (chain.Valid() && !timedOut &&
 | 
			
		||||
         !(chain.Finished() && outputData.Finished && errorData.Finished)) {
 | 
			
		||||
    uv_run(&chain.GetLoop(), UV_RUN_ONCE);
 | 
			
		||||
  while ((p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) {
 | 
			
		||||
    // Put the output in the right place.
 | 
			
		||||
    if (p == cmsysProcess_Pipe_STDOUT && !arguments.OutputQuiet) {
 | 
			
		||||
      if (arguments.OutputVariable.empty() || arguments.EchoOutputVariable) {
 | 
			
		||||
        processOutput.DecodeText(data, length, strdata, 1);
 | 
			
		||||
        cmSystemTools::Stdout(strdata);
 | 
			
		||||
      }
 | 
			
		||||
      if (!arguments.OutputVariable.empty()) {
 | 
			
		||||
        cmExecuteProcessCommandAppend(tempOutput, data, length);
 | 
			
		||||
      }
 | 
			
		||||
    } else if (p == cmsysProcess_Pipe_STDERR && !arguments.ErrorQuiet) {
 | 
			
		||||
      if (arguments.ErrorVariable.empty() || arguments.EchoErrorVariable) {
 | 
			
		||||
        processOutput.DecodeText(data, length, strdata, 2);
 | 
			
		||||
        cmSystemTools::Stderr(strdata);
 | 
			
		||||
      }
 | 
			
		||||
      if (!arguments.ErrorVariable.empty()) {
 | 
			
		||||
        cmExecuteProcessCommandAppend(tempError, data, length);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (!arguments.OutputQuiet &&
 | 
			
		||||
      (arguments.OutputVariable.empty() || arguments.EchoOutputVariable)) {
 | 
			
		||||
@ -372,102 +305,151 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // All output has been read.
 | 
			
		||||
  processOutput.DecodeText(outputData.Output, outputData.Output);
 | 
			
		||||
  processOutput.DecodeText(errorData.Output, errorData.Output);
 | 
			
		||||
  // All output has been read.  Wait for the process to exit.
 | 
			
		||||
  cmsysProcess_WaitForExit(cp, nullptr);
 | 
			
		||||
  processOutput.DecodeText(tempOutput, tempOutput);
 | 
			
		||||
  processOutput.DecodeText(tempError, tempError);
 | 
			
		||||
 | 
			
		||||
  // Fix the text in the output strings.
 | 
			
		||||
  cmExecuteProcessCommandFixText(outputData.Output,
 | 
			
		||||
  cmExecuteProcessCommandFixText(tempOutput,
 | 
			
		||||
                                 arguments.OutputStripTrailingWhitespace);
 | 
			
		||||
  cmExecuteProcessCommandFixText(errorData.Output,
 | 
			
		||||
  cmExecuteProcessCommandFixText(tempError,
 | 
			
		||||
                                 arguments.ErrorStripTrailingWhitespace);
 | 
			
		||||
 | 
			
		||||
  // Store the output obtained.
 | 
			
		||||
  if (!arguments.OutputVariable.empty() && !outputData.Output.empty()) {
 | 
			
		||||
  if (!arguments.OutputVariable.empty() && !tempOutput.empty()) {
 | 
			
		||||
    status.GetMakefile().AddDefinition(arguments.OutputVariable,
 | 
			
		||||
                                       outputData.Output.data());
 | 
			
		||||
                                       tempOutput.data());
 | 
			
		||||
  }
 | 
			
		||||
  if (arguments.ErrorVariable != arguments.OutputVariable &&
 | 
			
		||||
      !arguments.ErrorVariable.empty() && !errorData.Output.empty()) {
 | 
			
		||||
  if (!merge_output && !arguments.ErrorVariable.empty() &&
 | 
			
		||||
      !tempError.empty()) {
 | 
			
		||||
    status.GetMakefile().AddDefinition(arguments.ErrorVariable,
 | 
			
		||||
                                       errorData.Output.data());
 | 
			
		||||
                                       tempError.data());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Store the result of running the process.
 | 
			
		||||
  if (!arguments.ResultVariable.empty()) {
 | 
			
		||||
    if (timedOut) {
 | 
			
		||||
      status.GetMakefile().AddDefinition(arguments.ResultVariable,
 | 
			
		||||
                                         "Process terminated due to timeout");
 | 
			
		||||
    } else {
 | 
			
		||||
      auto const* lastStatus = chain.GetStatus().back();
 | 
			
		||||
      auto exception = lastStatus->GetException();
 | 
			
		||||
      if (exception.first == cmUVProcessChain::ExceptionCode::None) {
 | 
			
		||||
    switch (cmsysProcess_GetState(cp)) {
 | 
			
		||||
      case cmsysProcess_State_Exited: {
 | 
			
		||||
        int v = cmsysProcess_GetExitValue(cp);
 | 
			
		||||
        char buf[16];
 | 
			
		||||
        snprintf(buf, sizeof(buf), "%d", v);
 | 
			
		||||
        status.GetMakefile().AddDefinition(arguments.ResultVariable, buf);
 | 
			
		||||
      } break;
 | 
			
		||||
      case cmsysProcess_State_Exception:
 | 
			
		||||
        status.GetMakefile().AddDefinition(
 | 
			
		||||
          arguments.ResultVariable,
 | 
			
		||||
          std::to_string(static_cast<int>(lastStatus->ExitStatus)));
 | 
			
		||||
      } else {
 | 
			
		||||
          arguments.ResultVariable, cmsysProcess_GetExceptionString(cp));
 | 
			
		||||
        break;
 | 
			
		||||
      case cmsysProcess_State_Error:
 | 
			
		||||
        status.GetMakefile().AddDefinition(arguments.ResultVariable,
 | 
			
		||||
                                           exception.second);
 | 
			
		||||
      }
 | 
			
		||||
                                           cmsysProcess_GetErrorString(cp));
 | 
			
		||||
        break;
 | 
			
		||||
      case cmsysProcess_State_Expired:
 | 
			
		||||
        status.GetMakefile().AddDefinition(
 | 
			
		||||
          arguments.ResultVariable, "Process terminated due to timeout");
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // Store the result of running the processes.
 | 
			
		||||
  if (!arguments.ResultsVariable.empty()) {
 | 
			
		||||
    if (timedOut) {
 | 
			
		||||
      status.GetMakefile().AddDefinition(arguments.ResultsVariable,
 | 
			
		||||
                                         "Process terminated due to timeout");
 | 
			
		||||
    } else {
 | 
			
		||||
      std::vector<std::string> res;
 | 
			
		||||
      for (auto const* processStatus : chain.GetStatus()) {
 | 
			
		||||
        auto exception = processStatus->GetException();
 | 
			
		||||
        if (exception.first == cmUVProcessChain::ExceptionCode::None) {
 | 
			
		||||
          res.emplace_back(
 | 
			
		||||
            std::to_string(static_cast<int>(processStatus->ExitStatus)));
 | 
			
		||||
        } else {
 | 
			
		||||
          res.emplace_back(exception.second);
 | 
			
		||||
    switch (cmsysProcess_GetState(cp)) {
 | 
			
		||||
      case cmsysProcess_State_Exited: {
 | 
			
		||||
        std::vector<std::string> res;
 | 
			
		||||
        for (size_t i = 0; i < arguments.Commands.size(); ++i) {
 | 
			
		||||
          switch (cmsysProcess_GetStateByIndex(cp, static_cast<int>(i))) {
 | 
			
		||||
            case kwsysProcess_StateByIndex_Exited: {
 | 
			
		||||
              int exitCode =
 | 
			
		||||
                cmsysProcess_GetExitValueByIndex(cp, static_cast<int>(i));
 | 
			
		||||
              char buf[16];
 | 
			
		||||
              snprintf(buf, sizeof(buf), "%d", exitCode);
 | 
			
		||||
              res.emplace_back(buf);
 | 
			
		||||
            } break;
 | 
			
		||||
            case kwsysProcess_StateByIndex_Exception:
 | 
			
		||||
              res.emplace_back(cmsysProcess_GetExceptionStringByIndex(
 | 
			
		||||
                cp, static_cast<int>(i)));
 | 
			
		||||
              break;
 | 
			
		||||
            case kwsysProcess_StateByIndex_Error:
 | 
			
		||||
            default:
 | 
			
		||||
              res.emplace_back("Error getting the child return code");
 | 
			
		||||
              break;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      status.GetMakefile().AddDefinition(arguments.ResultsVariable,
 | 
			
		||||
                                         cmList::to_string(res));
 | 
			
		||||
        status.GetMakefile().AddDefinition(arguments.ResultsVariable,
 | 
			
		||||
                                           cmList::to_string(res));
 | 
			
		||||
      } break;
 | 
			
		||||
      case cmsysProcess_State_Exception:
 | 
			
		||||
        status.GetMakefile().AddDefinition(
 | 
			
		||||
          arguments.ResultsVariable, cmsysProcess_GetExceptionString(cp));
 | 
			
		||||
        break;
 | 
			
		||||
      case cmsysProcess_State_Error:
 | 
			
		||||
        status.GetMakefile().AddDefinition(arguments.ResultsVariable,
 | 
			
		||||
                                           cmsysProcess_GetErrorString(cp));
 | 
			
		||||
        break;
 | 
			
		||||
      case cmsysProcess_State_Expired:
 | 
			
		||||
        status.GetMakefile().AddDefinition(
 | 
			
		||||
          arguments.ResultsVariable, "Process terminated due to timeout");
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  auto queryProcessStatusByIndex = [&chain](std::size_t index) -> std::string {
 | 
			
		||||
    auto const& processStatus = chain.GetStatus(index);
 | 
			
		||||
    auto exception = processStatus.GetException();
 | 
			
		||||
    if (exception.first == cmUVProcessChain::ExceptionCode::None) {
 | 
			
		||||
      if (processStatus.ExitStatus) {
 | 
			
		||||
        return cmStrCat("Child return code: ", processStatus.ExitStatus);
 | 
			
		||||
  auto queryProcessStatusByIndex = [&cp](int index) -> std::string {
 | 
			
		||||
    std::string processStatus;
 | 
			
		||||
    switch (cmsysProcess_GetStateByIndex(cp, static_cast<int>(index))) {
 | 
			
		||||
      case kwsysProcess_StateByIndex_Exited: {
 | 
			
		||||
        int exitCode = cmsysProcess_GetExitValueByIndex(cp, index);
 | 
			
		||||
        if (exitCode) {
 | 
			
		||||
          processStatus = "Child return code: " + std::to_string(exitCode);
 | 
			
		||||
        }
 | 
			
		||||
      } break;
 | 
			
		||||
      case kwsysProcess_StateByIndex_Exception: {
 | 
			
		||||
        processStatus = cmStrCat(
 | 
			
		||||
          "Abnormal exit with child return code: ",
 | 
			
		||||
          cmsysProcess_GetExceptionStringByIndex(cp, static_cast<int>(index)));
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      return "";
 | 
			
		||||
      case kwsysProcess_StateByIndex_Error:
 | 
			
		||||
      default:
 | 
			
		||||
        processStatus = "Error getting the child return code";
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    return cmStrCat("Abnormal exit with child return code: ",
 | 
			
		||||
                    exception.second);
 | 
			
		||||
    return processStatus;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if (arguments.CommandErrorIsFatal == "ANY"_s) {
 | 
			
		||||
    bool ret = true;
 | 
			
		||||
    if (timedOut) {
 | 
			
		||||
      status.SetError("Process terminated due to timeout");
 | 
			
		||||
      ret = false;
 | 
			
		||||
    } else {
 | 
			
		||||
      std::map<std::size_t, std::string> failureIndices;
 | 
			
		||||
      auto statuses = chain.GetStatus();
 | 
			
		||||
      for (std::size_t i = 0; i < statuses.size(); ++i) {
 | 
			
		||||
        std::string processStatus = queryProcessStatusByIndex(i);
 | 
			
		||||
        if (!processStatus.empty()) {
 | 
			
		||||
          failureIndices[i] = processStatus;
 | 
			
		||||
    switch (cmsysProcess_GetState(cp)) {
 | 
			
		||||
      case cmsysProcess_State_Exited: {
 | 
			
		||||
        std::map<int, std::string> failureIndices;
 | 
			
		||||
        for (int i = 0; i < static_cast<int>(arguments.Commands.size()); ++i) {
 | 
			
		||||
          std::string processStatus = queryProcessStatusByIndex(i);
 | 
			
		||||
          if (!processStatus.empty()) {
 | 
			
		||||
            failureIndices[i] = processStatus;
 | 
			
		||||
          }
 | 
			
		||||
          if (!failureIndices.empty()) {
 | 
			
		||||
            std::ostringstream oss;
 | 
			
		||||
            oss << "failed command indexes:\n";
 | 
			
		||||
            for (auto const& e : failureIndices) {
 | 
			
		||||
              oss << "  " << e.first + 1 << ": \"" << e.second << "\"\n";
 | 
			
		||||
            }
 | 
			
		||||
            status.SetError(oss.str());
 | 
			
		||||
            ret = false;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (!failureIndices.empty()) {
 | 
			
		||||
        std::ostringstream oss;
 | 
			
		||||
        oss << "failed command indexes:\n";
 | 
			
		||||
        for (auto const& e : failureIndices) {
 | 
			
		||||
          oss << "  " << e.first + 1 << ": \"" << e.second << "\"\n";
 | 
			
		||||
        }
 | 
			
		||||
        status.SetError(oss.str());
 | 
			
		||||
      } break;
 | 
			
		||||
      case cmsysProcess_State_Exception:
 | 
			
		||||
        status.SetError(
 | 
			
		||||
          cmStrCat("abnormal exit: ", cmsysProcess_GetExceptionString(cp)));
 | 
			
		||||
        ret = false;
 | 
			
		||||
      }
 | 
			
		||||
        break;
 | 
			
		||||
      case cmsysProcess_State_Error:
 | 
			
		||||
        status.SetError(cmStrCat("error getting child return code: ",
 | 
			
		||||
                                 cmsysProcess_GetErrorString(cp)));
 | 
			
		||||
        ret = false;
 | 
			
		||||
        break;
 | 
			
		||||
      case cmsysProcess_State_Expired:
 | 
			
		||||
        status.SetError("Process terminated due to timeout");
 | 
			
		||||
        ret = false;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!ret) {
 | 
			
		||||
@ -478,23 +460,29 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
 | 
			
		||||
 | 
			
		||||
  if (arguments.CommandErrorIsFatal == "LAST"_s) {
 | 
			
		||||
    bool ret = true;
 | 
			
		||||
    if (timedOut) {
 | 
			
		||||
      status.SetError("Process terminated due to timeout");
 | 
			
		||||
      ret = false;
 | 
			
		||||
    } else {
 | 
			
		||||
      auto const& lastStatus = chain.GetStatus(arguments.Commands.size() - 1);
 | 
			
		||||
      auto exception = lastStatus.GetException();
 | 
			
		||||
      if (exception.first != cmUVProcessChain::ExceptionCode::None) {
 | 
			
		||||
        status.SetError(cmStrCat("Abnormal exit: ", exception.second));
 | 
			
		||||
        ret = false;
 | 
			
		||||
      } else {
 | 
			
		||||
    switch (cmsysProcess_GetState(cp)) {
 | 
			
		||||
      case cmsysProcess_State_Exited: {
 | 
			
		||||
        int lastIndex = static_cast<int>(arguments.Commands.size() - 1);
 | 
			
		||||
        const std::string processStatus = queryProcessStatusByIndex(lastIndex);
 | 
			
		||||
        if (!processStatus.empty()) {
 | 
			
		||||
          status.SetError("last command failed");
 | 
			
		||||
          ret = false;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      } break;
 | 
			
		||||
      case cmsysProcess_State_Exception:
 | 
			
		||||
        status.SetError(
 | 
			
		||||
          cmStrCat("Abnormal exit: ", cmsysProcess_GetExceptionString(cp)));
 | 
			
		||||
        ret = false;
 | 
			
		||||
        break;
 | 
			
		||||
      case cmsysProcess_State_Error:
 | 
			
		||||
        status.SetError(cmStrCat("Error getting child return code: ",
 | 
			
		||||
                                 cmsysProcess_GetErrorString(cp)));
 | 
			
		||||
        ret = false;
 | 
			
		||||
        break;
 | 
			
		||||
      case cmsysProcess_State_Expired:
 | 
			
		||||
        status.SetError("Process terminated due to timeout");
 | 
			
		||||
        ret = false;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    if (!ret) {
 | 
			
		||||
      cmSystemTools::SetFatalErrorOccurred();
 | 
			
		||||
@ -537,7 +525,7 @@ void cmExecuteProcessCommandFixText(std::vector<char>& output,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cmExecuteProcessCommandAppend(std::vector<char>& output, const char* data,
 | 
			
		||||
                                   std::size_t length)
 | 
			
		||||
                                   int length)
 | 
			
		||||
{
 | 
			
		||||
#if defined(__APPLE__)
 | 
			
		||||
  // HACK on Apple to work around bug with inserting at the
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
#include "cmExportBuildFileGenerator.h"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <set>
 | 
			
		||||
@ -13,6 +14,7 @@
 | 
			
		||||
#include <cmext/algorithm>
 | 
			
		||||
#include <cmext/string_view>
 | 
			
		||||
 | 
			
		||||
#include "cmCryptoHash.h"
 | 
			
		||||
#include "cmExportSet.h"
 | 
			
		||||
#include "cmFileSet.h"
 | 
			
		||||
#include "cmGeneratedFileStream.h"
 | 
			
		||||
@ -156,7 +158,19 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
 | 
			
		||||
    this->GenerateTargetFileSets(gte, os);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this->GenerateCxxModuleInformation(os);
 | 
			
		||||
  std::string cxx_modules_name;
 | 
			
		||||
  if (this->ExportSet) {
 | 
			
		||||
    cxx_modules_name = this->ExportSet->GetName();
 | 
			
		||||
  } else {
 | 
			
		||||
    cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512);
 | 
			
		||||
    constexpr std::size_t HASH_TRUNCATION = 12;
 | 
			
		||||
    for (auto const& target : this->Targets) {
 | 
			
		||||
      hasher.Append(target);
 | 
			
		||||
    }
 | 
			
		||||
    cxx_modules_name = hasher.FinalizeHex().substr(0, HASH_TRUNCATION);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this->GenerateCxxModuleInformation(cxx_modules_name, os);
 | 
			
		||||
 | 
			
		||||
  // Generate import file content for each configuration.
 | 
			
		||||
  for (std::string const& c : this->Configurations) {
 | 
			
		||||
@ -165,7 +179,7 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
 | 
			
		||||
 | 
			
		||||
  // Generate import file content for each configuration.
 | 
			
		||||
  for (std::string const& c : this->Configurations) {
 | 
			
		||||
    this->GenerateImportCxxModuleConfigTargetInclusion(c);
 | 
			
		||||
    this->GenerateImportCxxModuleConfigTargetInclusion(cxx_modules_name, c);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this->GenerateMissingTargetsCheckCode(os);
 | 
			
		||||
@ -506,7 +520,7 @@ std::string cmExportBuildFileGenerator::GetCxxModulesDirectory() const
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cmExportBuildFileGenerator::GenerateCxxModuleConfigInformation(
 | 
			
		||||
  std::ostream& os) const
 | 
			
		||||
  std::string const& name, std::ostream& os) const
 | 
			
		||||
{
 | 
			
		||||
  const char* opt = "";
 | 
			
		||||
  if (this->Configurations.size() > 1) {
 | 
			
		||||
@ -519,13 +533,13 @@ void cmExportBuildFileGenerator::GenerateCxxModuleConfigInformation(
 | 
			
		||||
    if (c.empty()) {
 | 
			
		||||
      c = "noconfig";
 | 
			
		||||
    }
 | 
			
		||||
    os << "include(\"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << c << ".cmake\""
 | 
			
		||||
       << opt << ")\n";
 | 
			
		||||
    os << "include(\"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << name << '-'
 | 
			
		||||
       << c << ".cmake\"" << opt << ")\n";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmExportBuildFileGenerator::GenerateImportCxxModuleConfigTargetInclusion(
 | 
			
		||||
  std::string config) const
 | 
			
		||||
  std::string const& name, std::string config) const
 | 
			
		||||
{
 | 
			
		||||
  auto cxx_modules_dirname = this->GetCxxModulesDirectory();
 | 
			
		||||
  if (cxx_modules_dirname.empty()) {
 | 
			
		||||
@ -536,8 +550,9 @@ bool cmExportBuildFileGenerator::GenerateImportCxxModuleConfigTargetInclusion(
 | 
			
		||||
    config = "noconfig";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::string fileName = cmStrCat(this->FileDir, '/', cxx_modules_dirname,
 | 
			
		||||
                                  "/cxx-modules-", config, ".cmake");
 | 
			
		||||
  std::string fileName =
 | 
			
		||||
    cmStrCat(this->FileDir, '/', cxx_modules_dirname, "/cxx-modules-", name,
 | 
			
		||||
             '-', config, ".cmake");
 | 
			
		||||
 | 
			
		||||
  cmGeneratedFileStream os(fileName, true);
 | 
			
		||||
  if (!os) {
 | 
			
		||||
 | 
			
		||||
@ -92,8 +92,10 @@ protected:
 | 
			
		||||
                              cmTargetExport* te) override;
 | 
			
		||||
 | 
			
		||||
  std::string GetCxxModulesDirectory() const override;
 | 
			
		||||
  void GenerateCxxModuleConfigInformation(std::ostream&) const override;
 | 
			
		||||
  bool GenerateImportCxxModuleConfigTargetInclusion(std::string) const;
 | 
			
		||||
  void GenerateCxxModuleConfigInformation(std::string const&,
 | 
			
		||||
                                          std::ostream&) const override;
 | 
			
		||||
  bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&,
 | 
			
		||||
                                                    std::string) const;
 | 
			
		||||
 | 
			
		||||
  std::pair<std::vector<std::string>, std::string> FindBuildExportInfo(
 | 
			
		||||
    cmGlobalGenerator* gg, const std::string& name);
 | 
			
		||||
 | 
			
		||||
@ -1461,7 +1461,8 @@ void cmExportFileGenerator::GenerateTargetFileSets(cmGeneratorTarget* gte,
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cmExportFileGenerator::GenerateCxxModuleInformation(std::ostream& os)
 | 
			
		||||
void cmExportFileGenerator::GenerateCxxModuleInformation(
 | 
			
		||||
  std::string const& name, std::ostream& os)
 | 
			
		||||
{
 | 
			
		||||
  auto const cxx_module_dirname = this->GetCxxModulesDirectory();
 | 
			
		||||
  if (cxx_module_dirname.empty()) {
 | 
			
		||||
@ -1471,17 +1472,17 @@ void cmExportFileGenerator::GenerateCxxModuleInformation(std::ostream& os)
 | 
			
		||||
  // Write the include.
 | 
			
		||||
  os << "# Include C++ module properties\n"
 | 
			
		||||
     << "include(\"${CMAKE_CURRENT_LIST_DIR}/" << cxx_module_dirname
 | 
			
		||||
     << "/cxx-modules.cmake\")\n\n";
 | 
			
		||||
     << "/cxx-modules-" << name << ".cmake\")\n\n";
 | 
			
		||||
 | 
			
		||||
  // Get the path to the file we're going to write.
 | 
			
		||||
  std::string path = this->MainImportFile;
 | 
			
		||||
  path = cmSystemTools::GetFilenamePath(path);
 | 
			
		||||
  auto trampoline_path =
 | 
			
		||||
    cmStrCat(path, '/', cxx_module_dirname, "/cxx-modules.cmake");
 | 
			
		||||
    cmStrCat(path, '/', cxx_module_dirname, "/cxx-modules-", name, ".cmake");
 | 
			
		||||
 | 
			
		||||
  // Include all configuration-specific include files.
 | 
			
		||||
  cmGeneratedFileStream ap(trampoline_path, true);
 | 
			
		||||
  ap.SetCopyIfDifferent(true);
 | 
			
		||||
 | 
			
		||||
  this->GenerateCxxModuleConfigInformation(ap);
 | 
			
		||||
  this->GenerateCxxModuleConfigInformation(name, ap);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -187,7 +187,7 @@ protected:
 | 
			
		||||
  void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os,
 | 
			
		||||
                              cmTargetExport* te = nullptr);
 | 
			
		||||
 | 
			
		||||
  void GenerateCxxModuleInformation(std::ostream& os);
 | 
			
		||||
  void GenerateCxxModuleInformation(std::string const& name, std::ostream& os);
 | 
			
		||||
 | 
			
		||||
  virtual std::string GetFileSetDirectories(cmGeneratorTarget* gte,
 | 
			
		||||
                                            cmFileSet* fileSet,
 | 
			
		||||
@ -235,5 +235,6 @@ private:
 | 
			
		||||
                                     const std::string& config) = 0;
 | 
			
		||||
 | 
			
		||||
  virtual std::string GetCxxModulesDirectory() const = 0;
 | 
			
		||||
  virtual void GenerateCxxModuleConfigInformation(std::ostream& os) const = 0;
 | 
			
		||||
  virtual void GenerateCxxModuleConfigInformation(std::string const&,
 | 
			
		||||
                                                  std::ostream& os) const = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -181,10 +181,12 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
 | 
			
		||||
 | 
			
		||||
  bool result = true;
 | 
			
		||||
 | 
			
		||||
  this->GenerateCxxModuleInformation(os);
 | 
			
		||||
  std::string cxx_modules_name = this->IEGen->GetExportSet()->GetName();
 | 
			
		||||
  this->GenerateCxxModuleInformation(cxx_modules_name, os);
 | 
			
		||||
  if (requiresConfigFiles) {
 | 
			
		||||
    for (std::string const& c : this->Configurations) {
 | 
			
		||||
      if (!this->GenerateImportCxxModuleConfigTargetInclusion(c)) {
 | 
			
		||||
      if (!this->GenerateImportCxxModuleConfigTargetInclusion(cxx_modules_name,
 | 
			
		||||
                                                              c)) {
 | 
			
		||||
        result = false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
@ -718,12 +720,12 @@ std::string cmExportInstallFileGenerator::GetCxxModulesDirectory() const
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cmExportInstallFileGenerator::GenerateCxxModuleConfigInformation(
 | 
			
		||||
  std::ostream& os) const
 | 
			
		||||
  std::string const& name, std::ostream& os) const
 | 
			
		||||
{
 | 
			
		||||
  // Now load per-configuration properties for them.
 | 
			
		||||
  /* clang-format off */
 | 
			
		||||
  os << "# Load information for each installed configuration.\n"
 | 
			
		||||
        "file(GLOB _cmake_cxx_module_includes \"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-*.cmake\")\n"
 | 
			
		||||
        "file(GLOB _cmake_cxx_module_includes \"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << name << "-*.cmake\")\n"
 | 
			
		||||
        "foreach(_cmake_cxx_module_include IN LISTS _cmake_cxx_module_includes)\n"
 | 
			
		||||
        "  include(\"${_cmake_cxx_module_include}\")\n"
 | 
			
		||||
        "endforeach()\n"
 | 
			
		||||
@ -733,7 +735,8 @@ void cmExportInstallFileGenerator::GenerateCxxModuleConfigInformation(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmExportInstallFileGenerator::
 | 
			
		||||
  GenerateImportCxxModuleConfigTargetInclusion(std::string const& config)
 | 
			
		||||
  GenerateImportCxxModuleConfigTargetInclusion(std::string const& name,
 | 
			
		||||
                                               std::string const& config)
 | 
			
		||||
{
 | 
			
		||||
  auto cxx_modules_dirname = this->GetCxxModulesDirectory();
 | 
			
		||||
  if (cxx_modules_dirname.empty()) {
 | 
			
		||||
@ -748,7 +751,7 @@ bool cmExportInstallFileGenerator::
 | 
			
		||||
  std::string const dest =
 | 
			
		||||
    cmStrCat(this->FileDir, '/', cxx_modules_dirname, '/');
 | 
			
		||||
  std::string fileName =
 | 
			
		||||
    cmStrCat(dest, "cxx-modules-", filename_config, ".cmake");
 | 
			
		||||
    cmStrCat(dest, "cxx-modules-", name, '-', filename_config, ".cmake");
 | 
			
		||||
 | 
			
		||||
  cmGeneratedFileStream os(fileName, true);
 | 
			
		||||
  if (!os) {
 | 
			
		||||
 | 
			
		||||
@ -118,8 +118,10 @@ protected:
 | 
			
		||||
                              cmTargetExport* te) override;
 | 
			
		||||
 | 
			
		||||
  std::string GetCxxModulesDirectory() const override;
 | 
			
		||||
  void GenerateCxxModuleConfigInformation(std::ostream&) const override;
 | 
			
		||||
  bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&);
 | 
			
		||||
  void GenerateCxxModuleConfigInformation(std::string const&,
 | 
			
		||||
                                          std::ostream&) const override;
 | 
			
		||||
  bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&,
 | 
			
		||||
                                                    std::string const&);
 | 
			
		||||
 | 
			
		||||
  cmInstallExportGenerator* IEGen;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -56,7 +56,10 @@ protected:
 | 
			
		||||
                              cmTargetExport* te) override;
 | 
			
		||||
 | 
			
		||||
  std::string GetCxxModulesDirectory() const override { return {}; }
 | 
			
		||||
  void GenerateCxxModuleConfigInformation(std::ostream&) const override {}
 | 
			
		||||
  void GenerateCxxModuleConfigInformation(std::string const&,
 | 
			
		||||
                                          std::ostream&) const override
 | 
			
		||||
  {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  std::string FindTargets(const std::string& prop,
 | 
			
		||||
 | 
			
		||||
@ -207,7 +207,7 @@ struct cmFindLibraryHelper
 | 
			
		||||
  std::string BestPath;
 | 
			
		||||
 | 
			
		||||
  // Support for OpenBSD shared library naming: lib<name>.so.<major>.<minor>
 | 
			
		||||
  bool OpenBSD;
 | 
			
		||||
  bool IsOpenBSD;
 | 
			
		||||
 | 
			
		||||
  bool DebugMode;
 | 
			
		||||
 | 
			
		||||
@ -320,7 +320,7 @@ cmFindLibraryHelper::cmFindLibraryHelper(std::string debugName, cmMakefile* mf,
 | 
			
		||||
  this->RegexFromList(this->SuffixRegexStr, this->Suffixes);
 | 
			
		||||
 | 
			
		||||
  // Check whether to use OpenBSD-style library version comparisons.
 | 
			
		||||
  this->OpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
 | 
			
		||||
  this->IsOpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
 | 
			
		||||
    "FIND_LIBRARY_USE_OPENBSD_VERSIONING");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -390,7 +390,7 @@ void cmFindLibraryHelper::AddName(std::string const& name)
 | 
			
		||||
  std::string regex = cmStrCat('^', this->PrefixRegexStr);
 | 
			
		||||
  this->RegexFromLiteral(regex, name);
 | 
			
		||||
  regex += this->SuffixRegexStr;
 | 
			
		||||
  if (this->OpenBSD) {
 | 
			
		||||
  if (this->IsOpenBSD) {
 | 
			
		||||
    regex += "(\\.[0-9]+\\.[0-9]+)?";
 | 
			
		||||
  }
 | 
			
		||||
  regex += "$";
 | 
			
		||||
@ -472,7 +472,7 @@ bool cmFindLibraryHelper::CheckDirectoryForName(std::string const& path,
 | 
			
		||||
        size_type suffix = this->GetSuffixIndex(name.Regex.match(2));
 | 
			
		||||
        unsigned int major = 0;
 | 
			
		||||
        unsigned int minor = 0;
 | 
			
		||||
        if (this->OpenBSD) {
 | 
			
		||||
        if (this->IsOpenBSD) {
 | 
			
		||||
          sscanf(name.Regex.match(3).c_str(), ".%u.%u", &major, &minor);
 | 
			
		||||
        }
 | 
			
		||||
        if (this->BestPath.empty() || prefix < bestPrefix ||
 | 
			
		||||
 | 
			
		||||
@ -8319,14 +8319,14 @@ bool cmGeneratorTarget::DiscoverSyntheticTargets(cmSyntheticTargetCache& cache,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (gt->HaveCxx20ModuleSources()) {
 | 
			
		||||
      auto hasher = cmCryptoHash::New("SHA3_512");
 | 
			
		||||
      cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512);
 | 
			
		||||
      constexpr size_t HASH_TRUNCATION = 12;
 | 
			
		||||
      auto dirhash = hasher->HashString(
 | 
			
		||||
      auto dirhash = hasher.HashString(
 | 
			
		||||
        gt->GetLocalGenerator()->GetCurrentBinaryDirectory());
 | 
			
		||||
      std::string safeName = gt->GetName();
 | 
			
		||||
      cmSystemTools::ReplaceString(safeName, ":", "_");
 | 
			
		||||
      auto targetIdent =
 | 
			
		||||
        hasher->HashString(cmStrCat("@d_", dirhash, "@u_", usage.GetHash()));
 | 
			
		||||
        hasher.HashString(cmStrCat("@d_", dirhash, "@u_", usage.GetHash()));
 | 
			
		||||
      std::string targetName =
 | 
			
		||||
        cmStrCat(safeName, "@synth_", targetIdent.substr(0, HASH_TRUNCATION));
 | 
			
		||||
 | 
			
		||||
@ -8762,11 +8762,23 @@ bool cmGeneratorTarget::IsFrameworkOnApple() const
 | 
			
		||||
bool cmGeneratorTarget::IsImportedFrameworkFolderOnApple(
 | 
			
		||||
  const std::string& config) const
 | 
			
		||||
{
 | 
			
		||||
  return this->IsApple() && this->IsImported() &&
 | 
			
		||||
    (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
 | 
			
		||||
     this->GetType() == cmStateEnums::SHARED_LIBRARY ||
 | 
			
		||||
     this->GetType() == cmStateEnums::UNKNOWN_LIBRARY) &&
 | 
			
		||||
    cmSystemTools::IsPathToFramework(this->GetLocation(config));
 | 
			
		||||
  if (this->IsApple() && this->IsImported() &&
 | 
			
		||||
      (this->GetType() == cmStateEnums::STATIC_LIBRARY ||
 | 
			
		||||
       this->GetType() == cmStateEnums::SHARED_LIBRARY ||
 | 
			
		||||
       this->GetType() == cmStateEnums::UNKNOWN_LIBRARY)) {
 | 
			
		||||
    std::string cfg = config;
 | 
			
		||||
    if (cfg.empty() && this->GetGlobalGenerator()->IsXcode()) {
 | 
			
		||||
      // FIXME(#25515): Remove the need for this workaround.
 | 
			
		||||
      // The Xcode generator queries include directories without any
 | 
			
		||||
      // specific configuration.  Pick one in case this target does
 | 
			
		||||
      // not set either IMPORTED_LOCATION or IMPORTED_CONFIGURATIONS.
 | 
			
		||||
      cfg =
 | 
			
		||||
        this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig)[0];
 | 
			
		||||
    }
 | 
			
		||||
    return cmSystemTools::IsPathToFramework(this->GetLocation(cfg));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmGeneratorTarget::IsAppBundleOnApple() const
 | 
			
		||||
 | 
			
		||||
@ -1587,6 +1587,13 @@ bool cmGlobalGenerator::Compute()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Add unity sources after computing compile features.  Unity sources do
 | 
			
		||||
  // not change the set of languages or features, but we need to know them
 | 
			
		||||
  // to filter out sources that are scanned for C++ module dependencies.
 | 
			
		||||
  if (!this->AddUnitySources()) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (const auto& localGen : this->LocalGenerators) {
 | 
			
		||||
    cmMakefile* mf = localGen->GetMakefile();
 | 
			
		||||
    for (const auto& g : mf->GetInstallGenerators()) {
 | 
			
		||||
@ -1863,7 +1870,6 @@ bool cmGlobalGenerator::AddAutomaticSources()
 | 
			
		||||
      if (!gt->CanCompileSources()) {
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      lg->AddUnityBuild(gt.get());
 | 
			
		||||
      lg->AddISPCDependencies(gt.get());
 | 
			
		||||
      // Targets that reuse a PCH are handled below.
 | 
			
		||||
      if (!gt->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
 | 
			
		||||
@ -1895,6 +1901,28 @@ bool cmGlobalGenerator::AddAutomaticSources()
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmGlobalGenerator::AddUnitySources()
 | 
			
		||||
{
 | 
			
		||||
  for (const auto& lg : this->LocalGenerators) {
 | 
			
		||||
    for (const auto& gt : lg->GetGeneratorTargets()) {
 | 
			
		||||
      if (!gt->CanCompileSources()) {
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      lg->AddUnityBuild(gt.get());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // The above transformation may have changed the classification of sources.
 | 
			
		||||
  // Clear the source list and classification cache (KindedSources) of all
 | 
			
		||||
  // targets so that it will be recomputed correctly by the generators later
 | 
			
		||||
  // now that the above transformations are done for all targets.
 | 
			
		||||
  for (const auto& lg : this->LocalGenerators) {
 | 
			
		||||
    for (const auto& gt : lg->GetGeneratorTargets()) {
 | 
			
		||||
      gt->ClearSourcesCache();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<cmLinkLineComputer> cmGlobalGenerator::CreateLinkLineComputer(
 | 
			
		||||
  cmOutputConverter* outputConverter, cmStateDirectory const& stateDir) const
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
@ -677,6 +677,7 @@ protected:
 | 
			
		||||
  bool AddHeaderSetVerification();
 | 
			
		||||
 | 
			
		||||
  bool AddAutomaticSources();
 | 
			
		||||
  bool AddUnitySources();
 | 
			
		||||
 | 
			
		||||
  std::string SelectMakeProgram(const std::string& makeProgram,
 | 
			
		||||
                                const std::string& makeDefault = "") const;
 | 
			
		||||
 | 
			
		||||
@ -564,6 +564,7 @@ cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm)
 | 
			
		||||
    this->Comspec = "cmd.exe";
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
  cm->GetState()->SetNinja(true);
 | 
			
		||||
  this->FindMakeProgramFile = "CMakeNinjaFindMake.cmake";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,6 @@
 | 
			
		||||
#include "cmImportedCxxModuleInfo.h"
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <vector>
 | 
			
		||||
@ -60,13 +59,13 @@ std::string ImportedCxxModuleLookup::BmiNameForSource(std::string const& path)
 | 
			
		||||
 | 
			
		||||
  auto importit = this->ImportedInfo.find(path);
 | 
			
		||||
  std::string bmiName;
 | 
			
		||||
  auto hasher = cmCryptoHash::New("SHA3_512");
 | 
			
		||||
  cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512);
 | 
			
		||||
  constexpr size_t HASH_TRUNCATION = 12;
 | 
			
		||||
  if (importit != this->ImportedInfo.end()) {
 | 
			
		||||
    auto safename = hasher->HashString(importit->second.Name);
 | 
			
		||||
    auto safename = hasher.HashString(importit->second.Name);
 | 
			
		||||
    bmiName = cmStrCat(safename.substr(0, HASH_TRUNCATION), ".bmi");
 | 
			
		||||
  } else {
 | 
			
		||||
    auto dirhash = hasher->HashString(path);
 | 
			
		||||
    auto dirhash = hasher.HashString(path);
 | 
			
		||||
    bmiName = cmStrCat(dirhash.substr(0, HASH_TRUNCATION), ".bmi");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -158,10 +158,11 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os,
 | 
			
		||||
    // Remove old per-configuration export files if the main changes.
 | 
			
		||||
    std::string installedDir = cmStrCat(
 | 
			
		||||
      "$ENV{DESTDIR}", ConvertToAbsoluteDestination(cxx_module_dest), '/');
 | 
			
		||||
    std::string installedFile = cmStrCat(installedDir, "/cxx-modules.cmake");
 | 
			
		||||
    std::string installedFile = cmStrCat(installedDir, "/cxx-modules-",
 | 
			
		||||
                                         this->ExportSet->GetName(), ".cmake");
 | 
			
		||||
    std::string toInstallFile =
 | 
			
		||||
      cmStrCat(cmSystemTools::GetFilenamePath(config_file_example),
 | 
			
		||||
               "/cxx-modules.cmake");
 | 
			
		||||
               "/cxx-modules-", this->ExportSet->GetName(), ".cmake");
 | 
			
		||||
    os << indent << "if(EXISTS \"" << installedFile << "\")\n";
 | 
			
		||||
    Indent indentN = indent.Next();
 | 
			
		||||
    Indent indentNN = indentN.Next();
 | 
			
		||||
 | 
			
		||||
@ -3134,6 +3134,15 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target)
 | 
			
		||||
    std::vector<cmSourceFile*> sources;
 | 
			
		||||
    target->GetSourceFiles(sources, configs[ci]);
 | 
			
		||||
    for (cmSourceFile* sf : sources) {
 | 
			
		||||
      // Files which need C++ scanning cannot participate in unity builds as
 | 
			
		||||
      // there is a single place in TUs that may perform module-dependency bits
 | 
			
		||||
      // and a unity source cannot `#include` them in-order and represent a
 | 
			
		||||
      // valid TU.
 | 
			
		||||
      if (sf->GetLanguage() == "CXX"_s &&
 | 
			
		||||
          target->NeedDyndepForSource("CXX", configs[ci], sf)) {
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      auto mi = index.find(sf);
 | 
			
		||||
      if (mi == index.end()) {
 | 
			
		||||
        unitySources.emplace_back(sf);
 | 
			
		||||
 | 
			
		||||
@ -1722,11 +1722,10 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile(
 | 
			
		||||
 | 
			
		||||
  if (!ccg.GetCC().GetDepfile().empty()) {
 | 
			
		||||
    // Add dependency over timestamp file for dependencies management
 | 
			
		||||
    auto dependTimestamp = cmSystemTools::ConvertToOutputPath(
 | 
			
		||||
      this->LocalGenerator->MaybeRelativeToTopBinDir(
 | 
			
		||||
        cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts")));
 | 
			
		||||
    auto dependTimestamp = this->LocalGenerator->MaybeRelativeToTopBinDir(
 | 
			
		||||
      cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts"));
 | 
			
		||||
 | 
			
		||||
    depends.push_back(dependTimestamp);
 | 
			
		||||
    depends.emplace_back(std::move(dependTimestamp));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Write the rule.
 | 
			
		||||
 | 
			
		||||
@ -1373,8 +1373,10 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
 | 
			
		||||
  bool const needDyndep = !isPch &&
 | 
			
		||||
    this->GeneratorTarget->NeedDyndepForSource(language, config, source);
 | 
			
		||||
 | 
			
		||||
  cmNinjaBuild objBuild(this->LanguageCompilerRule(
 | 
			
		||||
    language, config, needDyndep ? WithScanning::Yes : WithScanning::No));
 | 
			
		||||
  WithScanning withScanning =
 | 
			
		||||
    needDyndep ? WithScanning::Yes : WithScanning::No;
 | 
			
		||||
  cmNinjaBuild objBuild(
 | 
			
		||||
    this->LanguageCompilerRule(language, config, withScanning));
 | 
			
		||||
  cmNinjaVars& vars = objBuild.Variables;
 | 
			
		||||
  vars["FLAGS"] =
 | 
			
		||||
    this->ComputeFlagsForObject(source, language, config, objectFileName);
 | 
			
		||||
@ -1434,7 +1436,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
 | 
			
		||||
  if (firstForConfig) {
 | 
			
		||||
    this->ExportObjectCompileCommand(
 | 
			
		||||
      language, sourceFilePath, objectDir, objectFileName, objectFileDir,
 | 
			
		||||
      vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"], config);
 | 
			
		||||
      vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"], config, withScanning);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  objBuild.Outputs.push_back(objectFileName);
 | 
			
		||||
@ -1780,7 +1782,7 @@ void cmNinjaTargetGenerator::WriteCxxModuleBmiBuildStatement(
 | 
			
		||||
  if (firstForConfig) {
 | 
			
		||||
    this->ExportObjectCompileCommand(
 | 
			
		||||
      language, sourceFilePath, bmiDir, bmiFileName, bmiFileDir, vars["FLAGS"],
 | 
			
		||||
      vars["DEFINES"], vars["INCLUDES"], config);
 | 
			
		||||
      vars["DEFINES"], vars["INCLUDES"], config, WithScanning::Yes);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bmiBuild.Outputs.push_back(bmiFileName);
 | 
			
		||||
@ -1992,7 +1994,7 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand(
 | 
			
		||||
  std::string const& objectDir, std::string const& objectFileName,
 | 
			
		||||
  std::string const& objectFileDir, std::string const& flags,
 | 
			
		||||
  std::string const& defines, std::string const& includes,
 | 
			
		||||
  std::string const& outputConfig)
 | 
			
		||||
  std::string const& outputConfig, WithScanning withScanning)
 | 
			
		||||
{
 | 
			
		||||
  if (!this->GeneratorTarget->GetPropertyAsBool("EXPORT_COMPILE_COMMANDS")) {
 | 
			
		||||
    return;
 | 
			
		||||
@ -2015,14 +2017,12 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand(
 | 
			
		||||
    escapedSourceFileName, cmOutputConverter::SHELL);
 | 
			
		||||
 | 
			
		||||
  std::string fullFlags = flags;
 | 
			
		||||
  {
 | 
			
		||||
    bool const needDyndep =
 | 
			
		||||
      this->GetGeneratorTarget()->NeedDyndep(language, outputConfig);
 | 
			
		||||
  if (withScanning == WithScanning::Yes) {
 | 
			
		||||
    std::string const modmapFormatVar =
 | 
			
		||||
      cmStrCat("CMAKE_", language, "_MODULE_MAP_FORMAT");
 | 
			
		||||
    std::string const modmapFormat =
 | 
			
		||||
      this->Makefile->GetSafeDefinition(modmapFormatVar);
 | 
			
		||||
    if (needDyndep && !modmapFormat.empty()) {
 | 
			
		||||
    if (!modmapFormat.empty()) {
 | 
			
		||||
      std::string modmapFlags = this->GetMakefile()->GetRequiredDefinition(
 | 
			
		||||
        cmStrCat("CMAKE_", language, "_MODULE_MAP_FLAG"));
 | 
			
		||||
      // XXX(modmap): If changing this path construction, change
 | 
			
		||||
 | 
			
		||||
@ -189,7 +189,7 @@ protected:
 | 
			
		||||
    std::string const& objectDir, std::string const& objectFileName,
 | 
			
		||||
    std::string const& objectFileDir, std::string const& flags,
 | 
			
		||||
    std::string const& defines, std::string const& includes,
 | 
			
		||||
    std::string const& outputConfig);
 | 
			
		||||
    std::string const& outputConfig, WithScanning withScanning);
 | 
			
		||||
 | 
			
		||||
  void AdditionalCleanFiles(const std::string& config);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -275,6 +275,9 @@ std::string cmOutputConverter::EscapeForShell(cm::string_view str,
 | 
			
		||||
  if (this->GetState()->UseNMake()) {
 | 
			
		||||
    flags |= Shell_Flag_NMake;
 | 
			
		||||
  }
 | 
			
		||||
  if (this->GetState()->UseNinja()) {
 | 
			
		||||
    flags |= Shell_Flag_Ninja;
 | 
			
		||||
  }
 | 
			
		||||
  if (!this->GetState()->UseWindowsShell()) {
 | 
			
		||||
    flags |= Shell_Flag_IsUnix;
 | 
			
		||||
  }
 | 
			
		||||
@ -677,6 +680,12 @@ std::string cmOutputConverter::Shell_GetArgument(cm::string_view in, int flags)
 | 
			
		||||
        /* Otherwise a semicolon is written just ;. */
 | 
			
		||||
        out += ';';
 | 
			
		||||
      }
 | 
			
		||||
    } else if (*cit == '\n') {
 | 
			
		||||
      if (flags & Shell_Flag_Ninja) {
 | 
			
		||||
        out += "$\n";
 | 
			
		||||
      } else {
 | 
			
		||||
        out += '\n';
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      /* Store this character.  */
 | 
			
		||||
      out += *cit;
 | 
			
		||||
 | 
			
		||||
@ -100,7 +100,10 @@ public:
 | 
			
		||||
 | 
			
		||||
    Shell_Flag_UnescapeNinjaConfiguration = (1 << 9),
 | 
			
		||||
 | 
			
		||||
    Shell_Flag_IsResponse = (1 << 10)
 | 
			
		||||
    Shell_Flag_IsResponse = (1 << 10),
 | 
			
		||||
 | 
			
		||||
    /** The target shell is in a Ninja build file.  */
 | 
			
		||||
    Shell_Flag_Ninja = (1 << 11)
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  std::string EscapeForShell(cm::string_view str, bool makeVars = false,
 | 
			
		||||
 | 
			
		||||
@ -2,68 +2,48 @@
 | 
			
		||||
   file Copyright.txt or https://cmake.org/licensing for details.  */
 | 
			
		||||
#include "cmProcessTools.h"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <ostream>
 | 
			
		||||
 | 
			
		||||
#include <cm3p/uv.h>
 | 
			
		||||
#include "cmsys/Process.h"
 | 
			
		||||
 | 
			
		||||
#include "cmProcessOutput.h"
 | 
			
		||||
#include "cmUVHandlePtr.h"
 | 
			
		||||
#include "cmUVStream.h"
 | 
			
		||||
 | 
			
		||||
std::vector<cmUVProcessChain::Status> cmProcessTools::RunProcess(
 | 
			
		||||
  cmUVProcessChainBuilder& builder, OutputParser* out, OutputParser* err,
 | 
			
		||||
  Encoding encoding)
 | 
			
		||||
void cmProcessTools::RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
 | 
			
		||||
                                OutputParser* err, Encoding encoding)
 | 
			
		||||
{
 | 
			
		||||
  cmsysProcess_Execute(cp);
 | 
			
		||||
  char* data = nullptr;
 | 
			
		||||
  int length = 0;
 | 
			
		||||
  int p;
 | 
			
		||||
  cmProcessOutput processOutput(encoding);
 | 
			
		||||
 | 
			
		||||
  builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
 | 
			
		||||
    .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
 | 
			
		||||
 | 
			
		||||
  auto chain = builder.Start();
 | 
			
		||||
 | 
			
		||||
  std::string strdata;
 | 
			
		||||
  cm::uv_pipe_ptr outputPipe;
 | 
			
		||||
  outputPipe.init(chain.GetLoop(), 0);
 | 
			
		||||
  uv_pipe_open(outputPipe, chain.OutputStream());
 | 
			
		||||
  auto outputHandle = cmUVStreamRead(
 | 
			
		||||
    outputPipe,
 | 
			
		||||
    [&out, &processOutput, &strdata](std::vector<char> data) {
 | 
			
		||||
      if (out) {
 | 
			
		||||
        processOutput.DecodeText(data.data(), data.size(), strdata, 1);
 | 
			
		||||
        if (!out->Process(strdata.c_str(), static_cast<int>(strdata.size()))) {
 | 
			
		||||
          out = nullptr;
 | 
			
		||||
        }
 | 
			
		||||
  while ((out || err) &&
 | 
			
		||||
         (p = cmsysProcess_WaitForData(cp, &data, &length, nullptr))) {
 | 
			
		||||
    if (out && p == cmsysProcess_Pipe_STDOUT) {
 | 
			
		||||
      processOutput.DecodeText(data, length, strdata, 1);
 | 
			
		||||
      if (!out->Process(strdata.c_str(), static_cast<int>(strdata.size()))) {
 | 
			
		||||
        out = nullptr;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    [&out]() { out = nullptr; });
 | 
			
		||||
  cm::uv_pipe_ptr errorPipe;
 | 
			
		||||
  errorPipe.init(chain.GetLoop(), 0);
 | 
			
		||||
  uv_pipe_open(errorPipe, chain.ErrorStream());
 | 
			
		||||
  auto errorHandle = cmUVStreamRead(
 | 
			
		||||
    errorPipe,
 | 
			
		||||
    [&err, &processOutput, &strdata](std::vector<char> data) {
 | 
			
		||||
      if (err) {
 | 
			
		||||
        processOutput.DecodeText(data.data(), data.size(), strdata, 2);
 | 
			
		||||
        if (!err->Process(strdata.c_str(), static_cast<int>(strdata.size()))) {
 | 
			
		||||
          err = nullptr;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (err && p == cmsysProcess_Pipe_STDERR) {
 | 
			
		||||
      processOutput.DecodeText(data, length, strdata, 2);
 | 
			
		||||
      if (!err->Process(strdata.c_str(), static_cast<int>(strdata.size()))) {
 | 
			
		||||
        err = nullptr;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    [&err]() { err = nullptr; });
 | 
			
		||||
  while (out || err || !chain.Finished()) {
 | 
			
		||||
    uv_run(&chain.GetLoop(), UV_RUN_ONCE);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::vector<cmUVProcessChain::Status> result;
 | 
			
		||||
  auto status = chain.GetStatus();
 | 
			
		||||
  std::transform(
 | 
			
		||||
    status.begin(), status.end(), std::back_inserter(result),
 | 
			
		||||
    [](const cmUVProcessChain::Status* s) -> cmUVProcessChain::Status {
 | 
			
		||||
      return *s;
 | 
			
		||||
    });
 | 
			
		||||
  return result;
 | 
			
		||||
  if (out) {
 | 
			
		||||
    processOutput.DecodeText(std::string(), strdata, 1);
 | 
			
		||||
    if (!strdata.empty()) {
 | 
			
		||||
      out->Process(strdata.c_str(), static_cast<int>(strdata.size()));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (err) {
 | 
			
		||||
    processOutput.DecodeText(std::string(), strdata, 2);
 | 
			
		||||
    if (!strdata.empty()) {
 | 
			
		||||
      err->Process(strdata.c_str(), static_cast<int>(strdata.size()));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  cmsysProcess_WaitForExit(cp, nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cmProcessTools::LineParser::LineParser(char sep, bool ignoreCR)
 | 
			
		||||
 | 
			
		||||
@ -7,10 +7,8 @@
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <iosfwd>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "cmProcessOutput.h"
 | 
			
		||||
#include "cmUVProcessChain.h"
 | 
			
		||||
 | 
			
		||||
/** \class cmProcessTools
 | 
			
		||||
 * \brief Helper classes for process output parsing
 | 
			
		||||
@ -83,7 +81,7 @@ public:
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /** Run a process and send output to given parsers.  */
 | 
			
		||||
  static std::vector<cmUVProcessChain::Status> RunProcess(
 | 
			
		||||
    cmUVProcessChainBuilder& builder, OutputParser* out,
 | 
			
		||||
    OutputParser* err = nullptr, Encoding encoding = cmProcessOutput::Auto);
 | 
			
		||||
  static void RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
 | 
			
		||||
                         OutputParser* err = nullptr,
 | 
			
		||||
                         Encoding encoding = cmProcessOutput::Auto);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -70,7 +70,7 @@ unsigned int GetParallelCPUCount()
 | 
			
		||||
  return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string FileProjectRelativePath(cmMakefile* makefile,
 | 
			
		||||
std::string FileProjectRelativePath(cmMakefile const* makefile,
 | 
			
		||||
                                    std::string const& fileName)
 | 
			
		||||
{
 | 
			
		||||
  std::string res;
 | 
			
		||||
@ -1369,7 +1369,6 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
 | 
			
		||||
    std::vector<std::string> dependencies(
 | 
			
		||||
      this->AutogenTarget.DependFiles.begin(),
 | 
			
		||||
      this->AutogenTarget.DependFiles.end());
 | 
			
		||||
 | 
			
		||||
    if (useDepfile) {
 | 
			
		||||
      // Create a custom command that generates a timestamp file and
 | 
			
		||||
      // has a depfile assigned. The depfile is created by JobDepFilesMergeT.
 | 
			
		||||
@ -1408,6 +1407,16 @@ bool cmQtAutoGenInitializer::InitAutogenTarget()
 | 
			
		||||
      cc->SetEscapeOldStyle(false);
 | 
			
		||||
      cmTarget* timestampTarget = this->LocalGen->AddUtilityCommand(
 | 
			
		||||
        timestampTargetName, true, std::move(cc));
 | 
			
		||||
      auto const isMake =
 | 
			
		||||
        this->GlobalGen->GetName().find("Make") != std::string::npos;
 | 
			
		||||
      if (this->AutogenTarget.DependOrigin && isMake) {
 | 
			
		||||
        for (BT<std::pair<std::string, bool>> const& depName :
 | 
			
		||||
             this->GenTarget->GetUtilities()) {
 | 
			
		||||
          timestampTarget->AddUtility(depName.Value.first, false,
 | 
			
		||||
                                      this->Makefile);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this->LocalGen->AddGeneratorTarget(
 | 
			
		||||
        cm::make_unique<cmGeneratorTarget>(timestampTarget, this->LocalGen));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -752,6 +752,16 @@ bool cmState::UseMSYSShell() const
 | 
			
		||||
  return this->MSYSShell;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cmState::SetNinja(bool ninja)
 | 
			
		||||
{
 | 
			
		||||
  this->Ninja = ninja;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmState::UseNinja() const
 | 
			
		||||
{
 | 
			
		||||
  return this->Ninja;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cmState::SetNinjaMulti(bool ninjaMulti)
 | 
			
		||||
{
 | 
			
		||||
  this->NinjaMulti = ninjaMulti;
 | 
			
		||||
 | 
			
		||||
@ -220,6 +220,8 @@ public:
 | 
			
		||||
  bool UseNMake() const;
 | 
			
		||||
  void SetMSYSShell(bool mSYSShell);
 | 
			
		||||
  bool UseMSYSShell() const;
 | 
			
		||||
  void SetNinja(bool ninja);
 | 
			
		||||
  bool UseNinja() const;
 | 
			
		||||
  void SetNinjaMulti(bool ninjaMulti);
 | 
			
		||||
  bool UseNinjaMulti() const;
 | 
			
		||||
 | 
			
		||||
@ -297,6 +299,7 @@ private:
 | 
			
		||||
  bool MinGWMake = false;
 | 
			
		||||
  bool NMake = false;
 | 
			
		||||
  bool MSYSShell = false;
 | 
			
		||||
  bool Ninja = false;
 | 
			
		||||
  bool NinjaMulti = false;
 | 
			
		||||
  Mode StateMode = Unknown;
 | 
			
		||||
  ProjectKind StateProjectKind = ProjectKind::Normal;
 | 
			
		||||
 | 
			
		||||
@ -25,17 +25,12 @@
 | 
			
		||||
 | 
			
		||||
#include <cm3p/uv.h>
 | 
			
		||||
 | 
			
		||||
#include "cm_fileno.hxx"
 | 
			
		||||
 | 
			
		||||
#include "cmDuration.h"
 | 
			
		||||
#include "cmELF.h"
 | 
			
		||||
#include "cmMessageMetadata.h"
 | 
			
		||||
#include "cmProcessOutput.h"
 | 
			
		||||
#include "cmRange.h"
 | 
			
		||||
#include "cmStringAlgorithms.h"
 | 
			
		||||
#include "cmUVHandlePtr.h"
 | 
			
		||||
#include "cmUVProcessChain.h"
 | 
			
		||||
#include "cmUVStream.h"
 | 
			
		||||
#include "cmValue.h"
 | 
			
		||||
 | 
			
		||||
#if !defined(CMAKE_BOOTSTRAP)
 | 
			
		||||
@ -64,14 +59,12 @@
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <cctype>
 | 
			
		||||
#include <cerrno>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <ctime>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <vector>
 | 
			
		||||
@ -575,115 +568,85 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
 | 
			
		||||
                                     const char* dir, OutputOption outputflag,
 | 
			
		||||
                                     cmDuration timeout, Encoding encoding)
 | 
			
		||||
{
 | 
			
		||||
  cmUVProcessChainBuilder builder;
 | 
			
		||||
  builder
 | 
			
		||||
    .SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT, cm_fileno(stdin))
 | 
			
		||||
    .AddCommand(command);
 | 
			
		||||
  if (dir) {
 | 
			
		||||
    builder.SetWorkingDirectory(dir);
 | 
			
		||||
  std::vector<const char*> argv;
 | 
			
		||||
  argv.reserve(command.size() + 1);
 | 
			
		||||
  for (std::string const& cmd : command) {
 | 
			
		||||
    argv.push_back(cmd.c_str());
 | 
			
		||||
  }
 | 
			
		||||
  argv.push_back(nullptr);
 | 
			
		||||
 | 
			
		||||
  cmsysProcess* cp = cmsysProcess_New();
 | 
			
		||||
  cmsysProcess_SetCommand(cp, argv.data());
 | 
			
		||||
  cmsysProcess_SetWorkingDirectory(cp, dir);
 | 
			
		||||
  if (cmSystemTools::GetRunCommandHideConsole()) {
 | 
			
		||||
    cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (outputflag == OUTPUT_PASSTHROUGH) {
 | 
			
		||||
    cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
 | 
			
		||||
    cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
 | 
			
		||||
    captureStdOut = nullptr;
 | 
			
		||||
    captureStdErr = nullptr;
 | 
			
		||||
    builder
 | 
			
		||||
      .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT,
 | 
			
		||||
                         cm_fileno(stdout))
 | 
			
		||||
      .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR,
 | 
			
		||||
                         cm_fileno(stderr));
 | 
			
		||||
  } else if (outputflag == OUTPUT_MERGE ||
 | 
			
		||||
             (captureStdErr && captureStdErr == captureStdOut)) {
 | 
			
		||||
    builder.SetMergedBuiltinStreams();
 | 
			
		||||
    cmsysProcess_SetOption(cp, cmsysProcess_Option_MergeOutput, 1);
 | 
			
		||||
    captureStdErr = nullptr;
 | 
			
		||||
  } else {
 | 
			
		||||
    builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
 | 
			
		||||
      .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
 | 
			
		||||
  }
 | 
			
		||||
  assert(!captureStdErr || captureStdErr != captureStdOut);
 | 
			
		||||
 | 
			
		||||
  auto chain = builder.Start();
 | 
			
		||||
  bool timedOut = false;
 | 
			
		||||
  cm::uv_timer_ptr timer;
 | 
			
		||||
  if (timeout.count()) {
 | 
			
		||||
    timer.init(chain.GetLoop(), &timedOut);
 | 
			
		||||
    timer.start(
 | 
			
		||||
      [](uv_timer_t* t) {
 | 
			
		||||
        auto* timedOutPtr = static_cast<bool*>(t->data);
 | 
			
		||||
        *timedOutPtr = true;
 | 
			
		||||
      },
 | 
			
		||||
      static_cast<uint64_t>(timeout.count() * 1000.0), 0);
 | 
			
		||||
  }
 | 
			
		||||
  cmsysProcess_SetTimeout(cp, timeout.count());
 | 
			
		||||
  cmsysProcess_Execute(cp);
 | 
			
		||||
 | 
			
		||||
  std::vector<char> tempStdOut;
 | 
			
		||||
  std::vector<char> tempStdErr;
 | 
			
		||||
  cm::uv_pipe_ptr outStream;
 | 
			
		||||
  bool outFinished = true;
 | 
			
		||||
  cm::uv_pipe_ptr errStream;
 | 
			
		||||
  bool errFinished = true;
 | 
			
		||||
  char* data;
 | 
			
		||||
  int length;
 | 
			
		||||
  int pipe;
 | 
			
		||||
  cmProcessOutput processOutput(encoding);
 | 
			
		||||
  std::unique_ptr<cmUVStreamReadHandle> outputHandle;
 | 
			
		||||
  std::unique_ptr<cmUVStreamReadHandle> errorHandle;
 | 
			
		||||
  std::string strdata;
 | 
			
		||||
  if (outputflag != OUTPUT_PASSTHROUGH &&
 | 
			
		||||
      (captureStdOut || captureStdErr || outputflag != OUTPUT_NONE)) {
 | 
			
		||||
    auto startRead =
 | 
			
		||||
      [&outputflag, &processOutput,
 | 
			
		||||
       &chain](cm::uv_pipe_ptr& pipe, int stream, std::string* captureStd,
 | 
			
		||||
               std::vector<char>& tempStd, int id,
 | 
			
		||||
               void (*outputFunc)(const std::string&),
 | 
			
		||||
               bool& finished) -> std::unique_ptr<cmUVStreamReadHandle> {
 | 
			
		||||
      if (stream < 0) {
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    while ((pipe = cmsysProcess_WaitForData(cp, &data, &length, nullptr)) >
 | 
			
		||||
           0) {
 | 
			
		||||
      // Translate NULL characters in the output into valid text.
 | 
			
		||||
      for (int i = 0; i < length; ++i) {
 | 
			
		||||
        if (data[i] == '\0') {
 | 
			
		||||
          data[i] = ' ';
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      pipe.init(chain.GetLoop(), 0);
 | 
			
		||||
      uv_pipe_open(pipe, stream);
 | 
			
		||||
      if (pipe == cmsysProcess_Pipe_STDOUT) {
 | 
			
		||||
        if (outputflag != OUTPUT_NONE) {
 | 
			
		||||
          processOutput.DecodeText(data, length, strdata, 1);
 | 
			
		||||
          cmSystemTools::Stdout(strdata);
 | 
			
		||||
        }
 | 
			
		||||
        if (captureStdOut) {
 | 
			
		||||
          cm::append(tempStdOut, data, data + length);
 | 
			
		||||
        }
 | 
			
		||||
      } else if (pipe == cmsysProcess_Pipe_STDERR) {
 | 
			
		||||
        if (outputflag != OUTPUT_NONE) {
 | 
			
		||||
          processOutput.DecodeText(data, length, strdata, 2);
 | 
			
		||||
          cmSystemTools::Stderr(strdata);
 | 
			
		||||
        }
 | 
			
		||||
        if (captureStdErr) {
 | 
			
		||||
          cm::append(tempStdErr, data, data + length);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      finished = false;
 | 
			
		||||
      return cmUVStreamRead(
 | 
			
		||||
        pipe,
 | 
			
		||||
        [outputflag, &processOutput, captureStd, &tempStd, id,
 | 
			
		||||
         outputFunc](std::vector<char> data) {
 | 
			
		||||
          // Translate NULL characters in the output into valid text.
 | 
			
		||||
          for (auto& c : data) {
 | 
			
		||||
            if (c == '\0') {
 | 
			
		||||
              c = ' ';
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          if (outputflag != OUTPUT_NONE) {
 | 
			
		||||
            std::string strdata;
 | 
			
		||||
            processOutput.DecodeText(data.data(), data.size(), strdata, id);
 | 
			
		||||
            outputFunc(strdata);
 | 
			
		||||
          }
 | 
			
		||||
          if (captureStd) {
 | 
			
		||||
            cm::append(tempStd, data.data(), data.data() + data.size());
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        [&finished, outputflag, &processOutput, id, outputFunc]() {
 | 
			
		||||
          finished = true;
 | 
			
		||||
          if (outputflag != OUTPUT_NONE) {
 | 
			
		||||
            std::string strdata;
 | 
			
		||||
            processOutput.DecodeText(std::string(), strdata, id);
 | 
			
		||||
            if (!strdata.empty()) {
 | 
			
		||||
              outputFunc(strdata);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    outputHandle =
 | 
			
		||||
      startRead(outStream, chain.OutputStream(), captureStdOut, tempStdOut, 1,
 | 
			
		||||
                cmSystemTools::Stdout, outFinished);
 | 
			
		||||
    if (chain.OutputStream() != chain.ErrorStream()) {
 | 
			
		||||
      errorHandle =
 | 
			
		||||
        startRead(errStream, chain.ErrorStream(), captureStdErr, tempStdErr, 2,
 | 
			
		||||
                  cmSystemTools::Stderr, errFinished);
 | 
			
		||||
    if (outputflag != OUTPUT_NONE) {
 | 
			
		||||
      processOutput.DecodeText(std::string(), strdata, 1);
 | 
			
		||||
      if (!strdata.empty()) {
 | 
			
		||||
        cmSystemTools::Stdout(strdata);
 | 
			
		||||
      }
 | 
			
		||||
      processOutput.DecodeText(std::string(), strdata, 2);
 | 
			
		||||
      if (!strdata.empty()) {
 | 
			
		||||
        cmSystemTools::Stderr(strdata);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  while (!timedOut && !(chain.Finished() && outFinished && errFinished)) {
 | 
			
		||||
    uv_run(&chain.GetLoop(), UV_RUN_ONCE);
 | 
			
		||||
  }
 | 
			
		||||
  cmsysProcess_WaitForExit(cp, nullptr);
 | 
			
		||||
 | 
			
		||||
  if (captureStdOut) {
 | 
			
		||||
    captureStdOut->assign(tempStdOut.begin(), tempStdOut.end());
 | 
			
		||||
@ -695,7 +658,37 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool result = true;
 | 
			
		||||
  if (timedOut) {
 | 
			
		||||
  if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
 | 
			
		||||
    if (retVal) {
 | 
			
		||||
      *retVal = cmsysProcess_GetExitValue(cp);
 | 
			
		||||
    } else {
 | 
			
		||||
      if (cmsysProcess_GetExitValue(cp) != 0) {
 | 
			
		||||
        result = false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) {
 | 
			
		||||
    const char* exception_str = cmsysProcess_GetExceptionString(cp);
 | 
			
		||||
    if (outputflag != OUTPUT_NONE) {
 | 
			
		||||
      std::cerr << exception_str << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
    if (captureStdErr) {
 | 
			
		||||
      captureStdErr->append(exception_str, strlen(exception_str));
 | 
			
		||||
    } else if (captureStdOut) {
 | 
			
		||||
      captureStdOut->append(exception_str, strlen(exception_str));
 | 
			
		||||
    }
 | 
			
		||||
    result = false;
 | 
			
		||||
  } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
 | 
			
		||||
    const char* error_str = cmsysProcess_GetErrorString(cp);
 | 
			
		||||
    if (outputflag != OUTPUT_NONE) {
 | 
			
		||||
      std::cerr << error_str << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
    if (captureStdErr) {
 | 
			
		||||
      captureStdErr->append(error_str, strlen(error_str));
 | 
			
		||||
    } else if (captureStdOut) {
 | 
			
		||||
      captureStdOut->append(error_str, strlen(error_str));
 | 
			
		||||
    }
 | 
			
		||||
    result = false;
 | 
			
		||||
  } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) {
 | 
			
		||||
    const char* error_str = "Process terminated due to timeout\n";
 | 
			
		||||
    if (outputflag != OUTPUT_NONE) {
 | 
			
		||||
      std::cerr << error_str << std::endl;
 | 
			
		||||
@ -704,34 +697,9 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
 | 
			
		||||
      captureStdErr->append(error_str, strlen(error_str));
 | 
			
		||||
    }
 | 
			
		||||
    result = false;
 | 
			
		||||
  } else {
 | 
			
		||||
    auto const& status = chain.GetStatus(0);
 | 
			
		||||
    auto exception = status.GetException();
 | 
			
		||||
 | 
			
		||||
    switch (exception.first) {
 | 
			
		||||
      case cmUVProcessChain::ExceptionCode::None:
 | 
			
		||||
        if (retVal) {
 | 
			
		||||
          *retVal = static_cast<int>(status.ExitStatus);
 | 
			
		||||
        } else {
 | 
			
		||||
          if (status.ExitStatus != 0) {
 | 
			
		||||
            result = false;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      default: {
 | 
			
		||||
        if (outputflag != OUTPUT_NONE) {
 | 
			
		||||
          std::cerr << exception.second << std::endl;
 | 
			
		||||
        }
 | 
			
		||||
        if (captureStdErr) {
 | 
			
		||||
          captureStdErr->append(exception.second);
 | 
			
		||||
        } else if (captureStdOut) {
 | 
			
		||||
          captureStdOut->append(exception.second);
 | 
			
		||||
        }
 | 
			
		||||
        result = false;
 | 
			
		||||
      } break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  cmsysProcess_Delete(cp);
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2245,10 +2213,9 @@ bool cmSystemTools::ListTar(const std::string& outFileName,
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine(
 | 
			
		||||
  uv_loop_t* loop, uv_stream_t* outPipe, uv_stream_t* errPipe,
 | 
			
		||||
  std::string& line, cmDuration timeout, std::vector<char>& out,
 | 
			
		||||
  std::vector<char>& err)
 | 
			
		||||
int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
 | 
			
		||||
                               cmDuration timeout, std::vector<char>& out,
 | 
			
		||||
                               std::vector<char>& err)
 | 
			
		||||
{
 | 
			
		||||
  line.clear();
 | 
			
		||||
  auto outiter = out.begin();
 | 
			
		||||
@ -2270,7 +2237,7 @@ cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine(
 | 
			
		||||
          line.append(out.data(), length);
 | 
			
		||||
        }
 | 
			
		||||
        out.erase(out.begin(), outiter + 1);
 | 
			
		||||
        return WaitForLineResult::STDOUT;
 | 
			
		||||
        return cmsysProcess_Pipe_STDOUT;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -2288,66 +2255,33 @@ cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine(
 | 
			
		||||
          line.append(err.data(), length);
 | 
			
		||||
        }
 | 
			
		||||
        err.erase(err.begin(), erriter + 1);
 | 
			
		||||
        return WaitForLineResult::STDERR;
 | 
			
		||||
        return cmsysProcess_Pipe_STDERR;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // No newlines found.  Wait for more data from the process.
 | 
			
		||||
    struct ReadData
 | 
			
		||||
    {
 | 
			
		||||
      uv_stream_t* Stream;
 | 
			
		||||
      std::vector<char> Buffer;
 | 
			
		||||
      bool Read = false;
 | 
			
		||||
      bool Finished = false;
 | 
			
		||||
    };
 | 
			
		||||
    auto startRead =
 | 
			
		||||
      [](uv_stream_t* stream,
 | 
			
		||||
         ReadData& data) -> std::unique_ptr<cmUVStreamReadHandle> {
 | 
			
		||||
      data.Stream = stream;
 | 
			
		||||
      return cmUVStreamRead(
 | 
			
		||||
        stream,
 | 
			
		||||
        [&data](std::vector<char> buf) {
 | 
			
		||||
          data.Buffer = std::move(buf);
 | 
			
		||||
          data.Read = true;
 | 
			
		||||
          uv_read_stop(data.Stream);
 | 
			
		||||
        },
 | 
			
		||||
        [&data]() { data.Finished = true; });
 | 
			
		||||
    };
 | 
			
		||||
    ReadData outData;
 | 
			
		||||
    auto outHandle = startRead(outPipe, outData);
 | 
			
		||||
    ReadData errData;
 | 
			
		||||
    auto errHandle = startRead(errPipe, errData);
 | 
			
		||||
 | 
			
		||||
    cm::uv_timer_ptr timer;
 | 
			
		||||
    bool timedOut = false;
 | 
			
		||||
    timer.init(*loop, &timedOut);
 | 
			
		||||
    timer.start(
 | 
			
		||||
      [](uv_timer_t* handle) {
 | 
			
		||||
        auto* timedOutPtr = static_cast<bool*>(handle->data);
 | 
			
		||||
        *timedOutPtr = true;
 | 
			
		||||
      },
 | 
			
		||||
      static_cast<uint64_t>(timeout.count() * 1000.0), 0);
 | 
			
		||||
 | 
			
		||||
    uv_run(loop, UV_RUN_ONCE);
 | 
			
		||||
    if (timedOut) {
 | 
			
		||||
    int length;
 | 
			
		||||
    char* data;
 | 
			
		||||
    double timeoutAsDbl = timeout.count();
 | 
			
		||||
    int pipe =
 | 
			
		||||
      cmsysProcess_WaitForData(process, &data, &length, &timeoutAsDbl);
 | 
			
		||||
    if (pipe == cmsysProcess_Pipe_Timeout) {
 | 
			
		||||
      // Timeout has been exceeded.
 | 
			
		||||
      return WaitForLineResult::Timeout;
 | 
			
		||||
      return pipe;
 | 
			
		||||
    }
 | 
			
		||||
    if (outData.Read) {
 | 
			
		||||
      processOutput.DecodeText(outData.Buffer.data(), outData.Buffer.size(),
 | 
			
		||||
                               strdata, 1);
 | 
			
		||||
    if (pipe == cmsysProcess_Pipe_STDOUT) {
 | 
			
		||||
      processOutput.DecodeText(data, length, strdata, 1);
 | 
			
		||||
      // Append to the stdout buffer.
 | 
			
		||||
      std::vector<char>::size_type size = out.size();
 | 
			
		||||
      cm::append(out, strdata);
 | 
			
		||||
      outiter = out.begin() + size;
 | 
			
		||||
    } else if (errData.Read) {
 | 
			
		||||
      processOutput.DecodeText(errData.Buffer.data(), errData.Buffer.size(),
 | 
			
		||||
                               strdata, 2);
 | 
			
		||||
    } else if (pipe == cmsysProcess_Pipe_STDERR) {
 | 
			
		||||
      processOutput.DecodeText(data, length, strdata, 2);
 | 
			
		||||
      // Append to the stderr buffer.
 | 
			
		||||
      std::vector<char>::size_type size = err.size();
 | 
			
		||||
      cm::append(err, strdata);
 | 
			
		||||
      erriter = err.begin() + size;
 | 
			
		||||
    } else if (outData.Finished && errData.Finished) {
 | 
			
		||||
    } else if (pipe == cmsysProcess_Pipe_None) {
 | 
			
		||||
      // Both stdout and stderr pipes have broken.  Return leftover data.
 | 
			
		||||
      processOutput.DecodeText(std::string(), strdata, 1);
 | 
			
		||||
      if (!strdata.empty()) {
 | 
			
		||||
@ -2364,20 +2298,14 @@ cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine(
 | 
			
		||||
      if (!out.empty()) {
 | 
			
		||||
        line.append(out.data(), outiter - out.begin());
 | 
			
		||||
        out.erase(out.begin(), out.end());
 | 
			
		||||
        return WaitForLineResult::STDOUT;
 | 
			
		||||
        return cmsysProcess_Pipe_STDOUT;
 | 
			
		||||
      }
 | 
			
		||||
      if (!err.empty()) {
 | 
			
		||||
        line.append(err.data(), erriter - err.begin());
 | 
			
		||||
        err.erase(err.begin(), err.end());
 | 
			
		||||
        return WaitForLineResult::STDERR;
 | 
			
		||||
        return cmsysProcess_Pipe_STDERR;
 | 
			
		||||
      }
 | 
			
		||||
      return WaitForLineResult::None;
 | 
			
		||||
    }
 | 
			
		||||
    if (!outData.Finished) {
 | 
			
		||||
      uv_read_stop(outPipe);
 | 
			
		||||
    }
 | 
			
		||||
    if (!errData.Finished) {
 | 
			
		||||
      uv_read_stop(errPipe);
 | 
			
		||||
      return cmsysProcess_Pipe_None;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -18,8 +18,7 @@
 | 
			
		||||
#include <cm/optional>
 | 
			
		||||
#include <cm/string_view>
 | 
			
		||||
 | 
			
		||||
#include <cm3p/uv.h>
 | 
			
		||||
 | 
			
		||||
#include "cmsys/Process.h"
 | 
			
		||||
#include "cmsys/Status.hxx"      // IWYU pragma: export
 | 
			
		||||
#include "cmsys/SystemTools.hxx" // IWYU pragma: export
 | 
			
		||||
 | 
			
		||||
@ -340,20 +339,10 @@ public:
 | 
			
		||||
   */
 | 
			
		||||
  static void ReportLastSystemError(const char* m);
 | 
			
		||||
 | 
			
		||||
  enum class WaitForLineResult
 | 
			
		||||
  {
 | 
			
		||||
    None,
 | 
			
		||||
    STDOUT,
 | 
			
		||||
    STDERR,
 | 
			
		||||
    Timeout,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /** a general output handler for libuv  */
 | 
			
		||||
  static WaitForLineResult WaitForLine(uv_loop_t* loop, uv_stream_t* outPipe,
 | 
			
		||||
                                       uv_stream_t* errPipe, std::string& line,
 | 
			
		||||
                                       cmDuration timeout,
 | 
			
		||||
                                       std::vector<char>& out,
 | 
			
		||||
                                       std::vector<char>& err);
 | 
			
		||||
  /** a general output handler for cmsysProcess  */
 | 
			
		||||
  static int WaitForLine(cmsysProcess* process, std::string& line,
 | 
			
		||||
                         cmDuration timeout, std::vector<char>& out,
 | 
			
		||||
                         std::vector<char>& err);
 | 
			
		||||
 | 
			
		||||
  static void SetForceUnixPaths(bool v) { s_ForceUnixPaths = v; }
 | 
			
		||||
  static bool GetForceUnixPaths() { return s_ForceUnixPaths; }
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,8 @@
 | 
			
		||||
 | 
			
		||||
#include <cm3p/uv.h>
 | 
			
		||||
 | 
			
		||||
#include "cm_fileno.hxx"
 | 
			
		||||
 | 
			
		||||
#include "cmGetPipes.h"
 | 
			
		||||
#include "cmUVHandlePtr.h"
 | 
			
		||||
 | 
			
		||||
@ -57,12 +59,7 @@ struct cmUVProcessChain::InternalData
 | 
			
		||||
  void Finish();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
cmUVProcessChainBuilder::cmUVProcessChainBuilder()
 | 
			
		||||
{
 | 
			
		||||
  this->SetNoStream(Stream_INPUT)
 | 
			
		||||
    .SetNoStream(Stream_OUTPUT)
 | 
			
		||||
    .SetNoStream(Stream_ERROR);
 | 
			
		||||
}
 | 
			
		||||
cmUVProcessChainBuilder::cmUVProcessChainBuilder() = default;
 | 
			
		||||
 | 
			
		||||
cmUVProcessChainBuilder& cmUVProcessChainBuilder::AddCommand(
 | 
			
		||||
  const std::vector<std::string>& arguments)
 | 
			
		||||
@ -122,6 +119,16 @@ cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalStream(
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalStream(
 | 
			
		||||
  Stream stdio, FILE* stream)
 | 
			
		||||
{
 | 
			
		||||
  int fd = cm_fileno(stream);
 | 
			
		||||
  if (fd >= 0) {
 | 
			
		||||
    return this->SetExternalStream(stdio, fd);
 | 
			
		||||
  }
 | 
			
		||||
  return this->SetNoStream(stdio);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetMergedBuiltinStreams()
 | 
			
		||||
{
 | 
			
		||||
  this->MergedBuiltinStreams = true;
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <cstddef> // IWYU pragma: keep
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <utility>
 | 
			
		||||
@ -34,6 +35,7 @@ public:
 | 
			
		||||
  cmUVProcessChainBuilder& SetBuiltinStream(Stream stdio);
 | 
			
		||||
  cmUVProcessChainBuilder& SetMergedBuiltinStreams();
 | 
			
		||||
  cmUVProcessChainBuilder& SetExternalStream(Stream stdio, int fd);
 | 
			
		||||
  cmUVProcessChainBuilder& SetExternalStream(Stream stdio, FILE* stream);
 | 
			
		||||
  cmUVProcessChainBuilder& SetWorkingDirectory(std::string dir);
 | 
			
		||||
 | 
			
		||||
  cmUVProcessChain Start() const;
 | 
			
		||||
@ -50,8 +52,8 @@ private:
 | 
			
		||||
 | 
			
		||||
  struct StdioConfiguration
 | 
			
		||||
  {
 | 
			
		||||
    StdioType Type;
 | 
			
		||||
    int FileDescriptor;
 | 
			
		||||
    StdioType Type = None;
 | 
			
		||||
    int FileDescriptor = -1;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  struct ProcessConfiguration
 | 
			
		||||
 | 
			
		||||
@ -2784,7 +2784,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
 | 
			
		||||
          isCppModule = true;
 | 
			
		||||
          if (shouldScanForModules &&
 | 
			
		||||
              this->GlobalGenerator->IsScanDependenciesSupported()) {
 | 
			
		||||
            // ScanSourceforModuleDependencies uses 'cl /scanDependencies' and
 | 
			
		||||
            // ScanSourceForModuleDependencies uses 'cl /scanDependencies' and
 | 
			
		||||
            // can distinguish module interface units and internal partitions.
 | 
			
		||||
            compileAsPerConfig = "CompileAsCpp";
 | 
			
		||||
          } else {
 | 
			
		||||
@ -2827,7 +2827,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
 | 
			
		||||
    // use them
 | 
			
		||||
    if (!flags.empty() || !options.empty() || !configDefines.empty() ||
 | 
			
		||||
        !includes.empty() || compileAsPerConfig || noWinRT ||
 | 
			
		||||
        !options.empty() || needsPCHFlags) {
 | 
			
		||||
        !options.empty() || needsPCHFlags || shouldScanForModules) {
 | 
			
		||||
      cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator;
 | 
			
		||||
      cmIDEFlagTable const* flagtable = nullptr;
 | 
			
		||||
      const std::string& srclang = source->GetLanguage();
 | 
			
		||||
@ -2856,9 +2856,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
 | 
			
		||||
        clOptions.AddFlag("CompileAs", compileAsPerConfig);
 | 
			
		||||
      }
 | 
			
		||||
      if (shouldScanForModules) {
 | 
			
		||||
        clOptions.AddFlag("ScanSourceforModuleDependencies", "true");
 | 
			
		||||
      } else {
 | 
			
		||||
        clOptions.AddFlag("ScanSourceforModuleDependencies", "false");
 | 
			
		||||
        clOptions.AddFlag("ScanSourceForModuleDependencies", "true");
 | 
			
		||||
      }
 | 
			
		||||
      if (noWinRT) {
 | 
			
		||||
        clOptions.AddFlag("CompileAsWinRT", "false");
 | 
			
		||||
@ -3564,6 +3562,9 @@ void cmVisualStudio10TargetGenerator::WriteClOptions(
 | 
			
		||||
      e2.Element("AdditionalUsingDirectories", dirs);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Disable C++ source scanning by default.
 | 
			
		||||
  e2.Element("ScanSourceForModuleDependencies", "false");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cmVisualStudio10TargetGenerator::ComputeRcOptions()
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,6 @@
 | 
			
		||||
#include "cmsys/Glob.hxx"
 | 
			
		||||
#include "cmsys/RegularExpression.hxx"
 | 
			
		||||
 | 
			
		||||
#include "cm_fileno.hxx"
 | 
			
		||||
#include "cm_sys_stat.h"
 | 
			
		||||
 | 
			
		||||
#include "cmBuildOptions.h"
 | 
			
		||||
@ -3916,10 +3915,8 @@ std::function<int()> cmake::BuildWorkflowStep(
 | 
			
		||||
{
 | 
			
		||||
  cmUVProcessChainBuilder builder;
 | 
			
		||||
  builder.AddCommand(args)
 | 
			
		||||
    .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT,
 | 
			
		||||
                       cm_fileno(stdout))
 | 
			
		||||
    .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR,
 | 
			
		||||
                       cm_fileno(stderr));
 | 
			
		||||
    .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT, stdout)
 | 
			
		||||
    .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR, stderr);
 | 
			
		||||
  return [builder]() -> int {
 | 
			
		||||
    auto chain = builder.Start();
 | 
			
		||||
    chain.Wait();
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										102
									
								
								Source/cmcmd.cxx
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								Source/cmcmd.cxx
									
									
									
									
									
								
							@ -11,8 +11,6 @@
 | 
			
		||||
#include <cm3p/uv.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
#include "cm_fileno.hxx"
 | 
			
		||||
 | 
			
		||||
#include "cmCommandLineArgument.h"
 | 
			
		||||
#include "cmConsoleBuf.h"
 | 
			
		||||
#include "cmCryptoHash.h"
 | 
			
		||||
@ -74,6 +72,7 @@
 | 
			
		||||
 | 
			
		||||
#include "cmsys/Directory.hxx"
 | 
			
		||||
#include "cmsys/FStream.hxx"
 | 
			
		||||
#include "cmsys/Process.h"
 | 
			
		||||
#include "cmsys/RegularExpression.hxx"
 | 
			
		||||
#include "cmsys/Terminal.h"
 | 
			
		||||
 | 
			
		||||
@ -296,8 +295,14 @@ int CLCompileAndDependencies(const std::vector<std::string>& args)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  cmUVProcessChainBuilder builder;
 | 
			
		||||
  builder.AddCommand(command).SetWorkingDirectory(currentBinaryDir);
 | 
			
		||||
  std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp(
 | 
			
		||||
    cmsysProcess_New(), cmsysProcess_Delete);
 | 
			
		||||
  std::vector<const char*> argv(command.size() + 1);
 | 
			
		||||
  std::transform(command.begin(), command.end(), argv.begin(),
 | 
			
		||||
                 [](std::string const& s) { return s.c_str(); });
 | 
			
		||||
  argv.back() = nullptr;
 | 
			
		||||
  cmsysProcess_SetCommand(cp.get(), argv.data());
 | 
			
		||||
  cmsysProcess_SetWorkingDirectory(cp.get(), currentBinaryDir.c_str());
 | 
			
		||||
 | 
			
		||||
  cmsys::ofstream fout(depFile.c_str());
 | 
			
		||||
  if (!fout) {
 | 
			
		||||
@ -308,18 +313,22 @@ int CLCompileAndDependencies(const std::vector<std::string>& args)
 | 
			
		||||
  CLOutputLogger errLogger(std::cerr);
 | 
			
		||||
 | 
			
		||||
  // Start the process.
 | 
			
		||||
  auto result =
 | 
			
		||||
    cmProcessTools::RunProcess(builder, &includeParser, &errLogger);
 | 
			
		||||
  auto const& subStatus = result.front();
 | 
			
		||||
  cmProcessTools::RunProcess(cp.get(), &includeParser, &errLogger);
 | 
			
		||||
 | 
			
		||||
  int status = 0;
 | 
			
		||||
  // handle status of process
 | 
			
		||||
  if (subStatus.SpawnResult != 0) {
 | 
			
		||||
    status = 2;
 | 
			
		||||
  } else if (subStatus.TermSignal != 0) {
 | 
			
		||||
    status = 1;
 | 
			
		||||
  } else {
 | 
			
		||||
    status = static_cast<int>(subStatus.ExitStatus);
 | 
			
		||||
  switch (cmsysProcess_GetState(cp.get())) {
 | 
			
		||||
    case cmsysProcess_State_Exited:
 | 
			
		||||
      status = cmsysProcess_GetExitValue(cp.get());
 | 
			
		||||
      break;
 | 
			
		||||
    case cmsysProcess_State_Exception:
 | 
			
		||||
      status = 1;
 | 
			
		||||
      break;
 | 
			
		||||
    case cmsysProcess_State_Error:
 | 
			
		||||
      status = 2;
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (status != 0) {
 | 
			
		||||
@ -1107,8 +1116,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
 | 
			
		||||
 | 
			
		||||
      int ret = 0;
 | 
			
		||||
      auto time_start = std::chrono::steady_clock::now();
 | 
			
		||||
      cmSystemTools::RunSingleCommand(command, nullptr, nullptr, &ret, nullptr,
 | 
			
		||||
                                      cmSystemTools::OUTPUT_PASSTHROUGH);
 | 
			
		||||
      cmSystemTools::RunSingleCommand(command, nullptr, nullptr, &ret);
 | 
			
		||||
      auto time_finish = std::chrono::steady_clock::now();
 | 
			
		||||
 | 
			
		||||
      std::chrono::duration<double> time_elapsed = time_finish - time_start;
 | 
			
		||||
@ -1882,6 +1890,21 @@ int cmcmd::ExecuteLinkScript(std::vector<std::string> const& args)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Allocate a process instance.
 | 
			
		||||
  cmsysProcess* cp = cmsysProcess_New();
 | 
			
		||||
  if (!cp) {
 | 
			
		||||
    std::cerr << "Error allocating process instance in link script."
 | 
			
		||||
              << std::endl;
 | 
			
		||||
    return 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Children should share stdout and stderr with this process.
 | 
			
		||||
  cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
 | 
			
		||||
  cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
 | 
			
		||||
 | 
			
		||||
  // Run the command lines verbatim.
 | 
			
		||||
  cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1);
 | 
			
		||||
 | 
			
		||||
  // Read command lines from the script.
 | 
			
		||||
  cmsys::ifstream fin(args[2].c_str());
 | 
			
		||||
  if (!fin) {
 | 
			
		||||
@ -1899,24 +1922,9 @@ int cmcmd::ExecuteLinkScript(std::vector<std::string> const& args)
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Allocate a process instance.
 | 
			
		||||
    cmUVProcessChainBuilder builder;
 | 
			
		||||
 | 
			
		||||
    // Children should share stdout and stderr with this process.
 | 
			
		||||
    builder
 | 
			
		||||
      .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT,
 | 
			
		||||
                         cm_fileno(stdout))
 | 
			
		||||
      .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR,
 | 
			
		||||
                         cm_fileno(stderr));
 | 
			
		||||
 | 
			
		||||
    // Setup this command line.
 | 
			
		||||
    std::vector<std::string> args2;
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    cmSystemTools::ParseWindowsCommandLine(command.c_str(), args2);
 | 
			
		||||
#else
 | 
			
		||||
    cmSystemTools::ParseUnixCommandLine(command.c_str(), args2);
 | 
			
		||||
#endif
 | 
			
		||||
    builder.AddCommand(args2);
 | 
			
		||||
    const char* cmd[2] = { command.c_str(), nullptr };
 | 
			
		||||
    cmsysProcess_SetCommand(cp, cmd);
 | 
			
		||||
 | 
			
		||||
    // Report the command if verbose output is enabled.
 | 
			
		||||
    if (verbose) {
 | 
			
		||||
@ -1924,29 +1932,35 @@ int cmcmd::ExecuteLinkScript(std::vector<std::string> const& args)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Run the command and wait for it to exit.
 | 
			
		||||
    auto chain = builder.Start();
 | 
			
		||||
    chain.Wait();
 | 
			
		||||
    cmsysProcess_Execute(cp);
 | 
			
		||||
    cmsysProcess_WaitForExit(cp, nullptr);
 | 
			
		||||
 | 
			
		||||
    // Report failure if any.
 | 
			
		||||
    auto const& status = chain.GetStatus(0);
 | 
			
		||||
    auto exception = status.GetException();
 | 
			
		||||
    switch (exception.first) {
 | 
			
		||||
      case cmUVProcessChain::ExceptionCode::None:
 | 
			
		||||
        if (status.ExitStatus != 0) {
 | 
			
		||||
          result = static_cast<int>(status.ExitStatus);
 | 
			
		||||
    switch (cmsysProcess_GetState(cp)) {
 | 
			
		||||
      case cmsysProcess_State_Exited: {
 | 
			
		||||
        int value = cmsysProcess_GetExitValue(cp);
 | 
			
		||||
        if (value != 0) {
 | 
			
		||||
          result = value;
 | 
			
		||||
        }
 | 
			
		||||
      } break;
 | 
			
		||||
      case cmsysProcess_State_Exception:
 | 
			
		||||
        std::cerr << "Error running link command: "
 | 
			
		||||
                  << cmsysProcess_GetExceptionString(cp) << std::endl;
 | 
			
		||||
        result = 1;
 | 
			
		||||
        break;
 | 
			
		||||
      case cmUVProcessChain::ExceptionCode::Spawn:
 | 
			
		||||
        std::cerr << "Error running link command: " << exception.second;
 | 
			
		||||
      case cmsysProcess_State_Error:
 | 
			
		||||
        std::cerr << "Error running link command: "
 | 
			
		||||
                  << cmsysProcess_GetErrorString(cp) << std::endl;
 | 
			
		||||
        result = 2;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        std::cerr << "Error running link command: " << exception.second;
 | 
			
		||||
        result = 1;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Free the process instance.
 | 
			
		||||
  cmsysProcess_Delete(cp);
 | 
			
		||||
 | 
			
		||||
  // Return the final resulting return value.
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -12,8 +12,6 @@
 | 
			
		||||
 | 
			
		||||
#include <cm3p/uv.h>
 | 
			
		||||
 | 
			
		||||
#include "cm_fileno.hxx"
 | 
			
		||||
 | 
			
		||||
#include "cmGetPipes.h"
 | 
			
		||||
#include "cmStringAlgorithms.h"
 | 
			
		||||
#include "cmUVHandlePtr.h"
 | 
			
		||||
@ -632,8 +630,7 @@ bool testUVProcessChainInputFile(const char* helperCommand)
 | 
			
		||||
 | 
			
		||||
  cmUVProcessChainBuilder builder;
 | 
			
		||||
  builder.AddCommand({ helperCommand, "dedup" })
 | 
			
		||||
    .SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT,
 | 
			
		||||
                       cm_fileno(f.get()))
 | 
			
		||||
    .SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT, f.get())
 | 
			
		||||
    .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
 | 
			
		||||
 | 
			
		||||
  auto chain = builder.Start();
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,10 @@
 | 
			
		||||
 | 
			
		||||
#include "cmSystemTools.h"
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#  include <windows.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static std::string getStdin()
 | 
			
		||||
{
 | 
			
		||||
  char buffer[1024];
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,13 @@ add_CMakeOnly_test(CheckCXXSymbolExists)
 | 
			
		||||
add_CMakeOnly_test(CheckCXXCompilerFlag)
 | 
			
		||||
 | 
			
		||||
add_CMakeOnly_test(CheckLanguage)
 | 
			
		||||
if (CMake_TEST_HIP)
 | 
			
		||||
  set_property(TEST CMakeOnly.CheckLanguage APPEND PROPERTY LABELS "HIP")
 | 
			
		||||
  add_CMakeOnly_test(CheckLanguageHIPPlatform)
 | 
			
		||||
  set_property(TEST CMakeOnly.CheckLanguageHIPPlatform APPEND PROPERTY LABELS "HIP")
 | 
			
		||||
  add_CMakeOnly_test(CheckLanguageHIPPlatform2)
 | 
			
		||||
  set_property(TEST CMakeOnly.CheckLanguageHIPPlatform2 APPEND PROPERTY LABELS "HIP")
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
add_CMakeOnly_test(CheckStructHasMember)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								Tests/CMakeOnly/CheckLanguageHIPPlatform/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								Tests/CMakeOnly/CheckLanguageHIPPlatform/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
cmake_minimum_required (VERSION 3.28)
 | 
			
		||||
project(CheckLanguageHIPPlatform NONE)
 | 
			
		||||
include(CheckLanguage)
 | 
			
		||||
 | 
			
		||||
check_language(HIP)
 | 
			
		||||
 | 
			
		||||
if(NOT DEFINED CMAKE_HIP_COMPILER)
 | 
			
		||||
  message(FATAL_ERROR "check_language did not set result")
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if (NOT CMAKE_HIP_COMPILER)
 | 
			
		||||
  message(FATAL_ERROR "check_language should not fail!")
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if (NOT DEFINED CMAKE_HIP_PLATFORM)
 | 
			
		||||
  message(FATAL_ERROR "check_language did not set CMAKE_HIP_PLATFORM!")
 | 
			
		||||
endif()
 | 
			
		||||
							
								
								
									
										14
									
								
								Tests/CMakeOnly/CheckLanguageHIPPlatform2/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Tests/CMakeOnly/CheckLanguageHIPPlatform2/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
			
		||||
cmake_minimum_required (VERSION 3.28)
 | 
			
		||||
project(CheckLanguageHIPPlatform2 NONE)
 | 
			
		||||
include(CheckLanguage)
 | 
			
		||||
 | 
			
		||||
set(CMAKE_HIP_PLATFORM "not-a-hip-platform" CACHE STRING "")
 | 
			
		||||
check_language(HIP)
 | 
			
		||||
 | 
			
		||||
if(NOT DEFINED CMAKE_HIP_COMPILER)
 | 
			
		||||
  message(FATAL_ERROR "check_language did not set result")
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if (CMAKE_HIP_COMPILER)
 | 
			
		||||
  message(FATAL_ERROR "check_language should have failed")
 | 
			
		||||
endif()
 | 
			
		||||
@ -14,6 +14,7 @@ add_cuda_test_macro(Cuda.MixedStandardLevels5 MixedStandardLevels5)
 | 
			
		||||
add_cuda_test_macro(Cuda.NotEnabled CudaNotEnabled)
 | 
			
		||||
add_cuda_test_macro(Cuda.SeparableCompCXXOnly SeparableCompCXXOnly)
 | 
			
		||||
add_cuda_test_macro(Cuda.StubRPATH StubRPATH)
 | 
			
		||||
set(Cuda.Toolkit_BUILD_OPTIONS -DHAS_CUPTI:BOOL=${CMake_TEST_CUDA_CUPTI})
 | 
			
		||||
add_cuda_test_macro(Cuda.Toolkit Toolkit)
 | 
			
		||||
add_cuda_test_macro(Cuda.IncludePathNoToolkit IncludePathNoToolkit)
 | 
			
		||||
add_cuda_test_macro(Cuda.SharedRuntimePlusToolkit SharedRuntimePlusToolkit)
 | 
			
		||||
 | 
			
		||||
@ -79,6 +79,23 @@ endforeach()
 | 
			
		||||
add_executable(Toolkit main.cpp)
 | 
			
		||||
target_link_libraries(Toolkit PRIVATE CUDA::toolkit)
 | 
			
		||||
 | 
			
		||||
if(HAS_CUPTI)
 | 
			
		||||
  set(cupti_libs )
 | 
			
		||||
  if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 10.2)
 | 
			
		||||
    list(APPEND cupti_libs cupti nvperf_target)
 | 
			
		||||
  endif()
 | 
			
		||||
  if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 11.3)
 | 
			
		||||
    list(APPEND cupti_libs pcsamplingutil)
 | 
			
		||||
  endif()
 | 
			
		||||
  foreach (cuda_lib IN LISTS cupti_libs)
 | 
			
		||||
    if(NOT CUDA_${cuda_lib}_LIBRARY)
 | 
			
		||||
      message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
 | 
			
		||||
    endif()
 | 
			
		||||
    if(NOT TARGET CUDA::${cuda_lib})
 | 
			
		||||
      message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
 | 
			
		||||
    endif()
 | 
			
		||||
  endforeach()
 | 
			
		||||
endif()
 | 
			
		||||
# cupti is an optional component of the CUDA toolkit
 | 
			
		||||
if(TARGET CUDA::cupti)
 | 
			
		||||
  add_executable(cupti cupti.cpp)
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,7 @@ add_cuda_test_macro(CudaOnly.ExportPTX CudaOnlyExportPTX)
 | 
			
		||||
add_cuda_test_macro(CudaOnly.SharedRuntimePlusToolkit CudaOnlySharedRuntimePlusToolkit)
 | 
			
		||||
add_cuda_test_macro(CudaOnly.StaticRuntimePlusToolkit CudaOnlyStaticRuntimePlusToolkit)
 | 
			
		||||
add_cuda_test_macro(CudaOnly.Standard98 CudaOnlyStandard98)
 | 
			
		||||
set(CudaOnly.Toolkit_BUILD_OPTIONS -DHAS_CUPTI:BOOL=${CMake_TEST_CUDA_CUPTI})
 | 
			
		||||
add_cuda_test_macro(CudaOnly.Toolkit CudaOnlyToolkit)
 | 
			
		||||
add_cuda_test_macro(CudaOnly.ToolkitBeforeLang CudaOnlyToolkitBeforeLang)
 | 
			
		||||
add_cuda_test_macro(CudaOnly.ToolkitMultipleDirs CudaOnlyToolkitMultipleDirs)
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,6 @@ if(CUDAToolkit_VERSION_MAJOR VERSION_LESS 11)
 | 
			
		||||
  list(APPEND cuda_libs nvgraph)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Verify that all the CUDA:: targets and variables exist
 | 
			
		||||
foreach (cuda_lib IN LISTS cuda_libs)
 | 
			
		||||
  if(NOT CUDA_${cuda_lib}_LIBRARY)
 | 
			
		||||
@ -81,5 +80,24 @@ foreach (cuda_lib nvrtc nvToolsExt OpenCL)
 | 
			
		||||
  endif()
 | 
			
		||||
endforeach()
 | 
			
		||||
 | 
			
		||||
if(HAS_CUPTI)
 | 
			
		||||
  set(cupti_libs )
 | 
			
		||||
  if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 10.2)
 | 
			
		||||
    list(APPEND cupti_libs cupti nvperf_target)
 | 
			
		||||
  endif()
 | 
			
		||||
  if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 11.3)
 | 
			
		||||
    list(APPEND cupti_libs pcsamplingutil)
 | 
			
		||||
  endif()
 | 
			
		||||
 | 
			
		||||
  foreach (cuda_lib IN LISTS cupti_libs)
 | 
			
		||||
    if(NOT CUDA_${cuda_lib}_LIBRARY)
 | 
			
		||||
      message(FATAL_ERROR "expected CUDAToolkit variable CUDA_${cuda_lib}_LIBRARY not found")
 | 
			
		||||
    endif()
 | 
			
		||||
    if(NOT TARGET CUDA::${cuda_lib})
 | 
			
		||||
      message(FATAL_ERROR "expected CUDAToolkit target CUDA::${cuda_lib} not found")
 | 
			
		||||
    endif()
 | 
			
		||||
  endforeach()
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
add_executable(CudaOnlyToolkit main.cu)
 | 
			
		||||
target_link_libraries(CudaOnlyToolkit PRIVATE CUDA::toolkit)
 | 
			
		||||
 | 
			
		||||
@ -16,14 +16,14 @@ static int CCONV InitialPass(void* inf, void* mf, int argc, char* argv[])
 | 
			
		||||
{
 | 
			
		||||
  char* file;
 | 
			
		||||
  char* str;
 | 
			
		||||
  char* srcs;
 | 
			
		||||
  const char* srcs;
 | 
			
		||||
  const char* cstr;
 | 
			
		||||
  char buffer[1024];
 | 
			
		||||
  void* source_file;
 | 
			
		||||
  char* args[2];
 | 
			
		||||
  char* ccArgs[4];
 | 
			
		||||
  char* ccDep[1];
 | 
			
		||||
  char* ccOut[1];
 | 
			
		||||
  const char* ccArgs[4];
 | 
			
		||||
  const char* ccDep[1];
 | 
			
		||||
  const char* ccOut[1];
 | 
			
		||||
  cmLoadedCommandInfo* info = (cmLoadedCommandInfo*)inf;
 | 
			
		||||
 | 
			
		||||
  cmVTKWrapTclData* cdata =
 | 
			
		||||
@ -148,7 +148,10 @@ static int CCONV InitialPass(void* inf, void* mf, int argc, char* argv[])
 | 
			
		||||
  if (info->CAPI->GetTotalArgumentSize(2, args) != 13) {
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
  info->CAPI->ExecuteCommand(mf, "SET", 2, args);
 | 
			
		||||
 | 
			
		||||
  ccArgs[0] = "TEST_EXEC";
 | 
			
		||||
  ccArgs[1] = "TRUE";
 | 
			
		||||
  info->CAPI->ExecuteCommand(mf, "SET", 2, ccArgs);
 | 
			
		||||
 | 
			
		||||
  /* make sure we can find the source file */
 | 
			
		||||
  if (!info->CAPI->GetSource(mf, argv[1])) {
 | 
			
		||||
 | 
			
		||||
@ -16,14 +16,14 @@ static int CCONV InitialPass(void* inf, void* mf, int argc, char* argv[])
 | 
			
		||||
{
 | 
			
		||||
  char* file;
 | 
			
		||||
  char* str;
 | 
			
		||||
  char* srcs;
 | 
			
		||||
  const char* cstr;
 | 
			
		||||
  const char* srcs;
 | 
			
		||||
  char* cstr;
 | 
			
		||||
  char buffer[1024];
 | 
			
		||||
  void* source_file;
 | 
			
		||||
  char* args[2];
 | 
			
		||||
  char* ccArgs[4];
 | 
			
		||||
  char* ccDep[1];
 | 
			
		||||
  char* ccOut[1];
 | 
			
		||||
  const char* ccArgs[4];
 | 
			
		||||
  const char* ccDep[1];
 | 
			
		||||
  const char* ccOut[1];
 | 
			
		||||
  cmLoadedCommandInfo* info = (cmLoadedCommandInfo*)inf;
 | 
			
		||||
 | 
			
		||||
  cmVTKWrapTclData* cdata =
 | 
			
		||||
@ -148,7 +148,10 @@ static int CCONV InitialPass(void* inf, void* mf, int argc, char* argv[])
 | 
			
		||||
  if (info->CAPI->GetTotalArgumentSize(2, args) != 13) {
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
  info->CAPI->ExecuteCommand(mf, "SET", 2, args);
 | 
			
		||||
 | 
			
		||||
  ccArgs[0] = "TEST_EXEC";
 | 
			
		||||
  ccArgs[1] = "TRUE";
 | 
			
		||||
  info->CAPI->ExecuteCommand(mf, "SET", 2, ccArgs);
 | 
			
		||||
 | 
			
		||||
  /* make sure we can find the source file */
 | 
			
		||||
  if (!info->CAPI->GetSource(mf, argv[1])) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								Tests/QtAutogen/AutogenTimestampDeps/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Tests/QtAutogen/AutogenTimestampDeps/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
cmake_minimum_required(VERSION 3.28)
 | 
			
		||||
project(AutogenTimestampDeps)
 | 
			
		||||
include("../AutogenCoreTest.cmake")
 | 
			
		||||
 | 
			
		||||
set(CMAKE_AUTOMOC ON)
 | 
			
		||||
 | 
			
		||||
add_custom_target(ProjectInfo
 | 
			
		||||
  COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/UpdateProjectInfo.cmake
 | 
			
		||||
  BYPRODUCTS ${CMAKE_BINARY_DIR}/ProjectInfo.hpp)
 | 
			
		||||
 | 
			
		||||
add_subdirectory(src)
 | 
			
		||||
							
								
								
									
										6
									
								
								Tests/QtAutogen/AutogenTimestampDeps/ProjectInfo.hpp.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Tests/QtAutogen/AutogenTimestampDeps/ProjectInfo.hpp.in
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
#ifndef PROJECTINFO_HPP
 | 
			
		||||
#define PROJECTINFO_HPP
 | 
			
		||||
 | 
			
		||||
extern int VersionMajor;
 | 
			
		||||
 | 
			
		||||
#endif // PROJECTINFO_HPP
 | 
			
		||||
@ -0,0 +1,2 @@
 | 
			
		||||
 | 
			
		||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/../ProjectInfo.hpp.in ${CMAKE_BINARY_DIR}/ProjectInfo.hpp @ONLY)
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user