Update upstream source from tag 'upstream/3.28.2'

Update to upstream version '3.28.2'
with Debian dir 2a246ae1c6
ci/unstable
Timo Röhling 11 months ago
commit b90b3c6c70

@ -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.
The CTest resource allocation feature consists of two inputs:
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`).
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}")
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})
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}
)
_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()
file(READ ${_XMLfile} versioninfo_string)
if(EXISTS ${_XMLfile})
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.c_str());
bzr_update.push_back(this->URL);
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);
for (std::string const& opt : parsedUserOptions) {
args.push_back(opt.c_str());
}
args.push_back(nullptr);
if (parameters[0] == "update") {
return this->RunUpdateCommand(args, out, err);
if (strcmp(parameters[0], "update") == 0) {
return this->RunUpdateCommand(args.data(), out, err);
}
return this->RunChild(args, 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);
}
}
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());
}
}
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);
}
});
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());
}
// 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));
}
// Always hide the process window.
cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
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();
// Check the output variables.
bool merge_output = false;
if (!arguments.InputFile.empty()) {
cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN,
arguments.InputFile.c_str());
}
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;
}
}
if (!failureIndices.empty()) {
std::ostringstream oss;
oss << "failed command indexes:\n";
for (auto const& e : failureIndices) {
oss << " " << e.first + 1 << ": \"" << e.second << "\"\n";
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;
}
}
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;
}
pipe.init(chain.GetLoop(), 0);
uv_pipe_open(pipe, stream);
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 = ' ';
}
}
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] = ' ';
}
}
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);
}
}
});
};
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);
}
}
}
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,43 +658,48 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
}
bool result = true;
if (timedOut) {
const char* error_str = "Process terminated due to timeout\n";
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 {
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;
} 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;
}
if (captureStdErr) {
captureStdErr->append(error_str, strlen(error_str));
}
result = false;
}
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();

@ -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)

@ -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()

@ -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])) {

@ -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)

@ -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…
Cancel
Save