summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x.gitlab/ci/env_windows_vs2022_x64.ps14
-rwxr-xr-x.gitlab/ci/qt-env.ps15
-rw-r--r--.gitlab/os-windows.yml1
-rw-r--r--Help/guide/tutorial/Adding Usage Requirements for a Library.rst12
-rw-r--r--Help/guide/tutorial/Adding a Library.rst2
-rw-r--r--Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt3
-rw-r--r--Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt3
-rw-r--r--Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt3
-rw-r--r--Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt3
-rw-r--r--Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt2
-rw-r--r--Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt7
-rw-r--r--Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt5
-rw-r--r--Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt4
-rw-r--r--Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt3
-rw-r--r--Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt3
-rw-r--r--Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt3
-rw-r--r--Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT.rst2
-rw-r--r--Help/release/dev/xcode-no-legacy-buildsystem.rst8
-rw-r--r--Help/variable/CMAKE_XCODE_BUILD_SYSTEM.rst3
-rw-r--r--Modules/Compiler/IntelLLVM.cmake7
-rw-r--r--Modules/FindFreetype.cmake58
-rw-r--r--Modules/FindGLEW.cmake4
-rw-r--r--Modules/FindMatlab.cmake20
-rw-r--r--Modules/FindPkgConfig.cmake14
-rw-r--r--Modules/Internal/CPack/NSIS.template.in2
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CPack/cmCPackSTGZGenerator.cxx2
-rw-r--r--Source/CTest/cmCTestBZR.cxx31
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.cxx15
-rw-r--r--Source/CTest/cmCTestBuildHandler.cxx291
-rw-r--r--Source/CTest/cmCTestBuildHandler.h6
-rw-r--r--Source/CTest/cmCTestCVS.cxx18
-rw-r--r--Source/CTest/cmCTestConfigureHandler.cxx2
-rw-r--r--Source/CTest/cmCTestCoverageHandler.cxx111
-rw-r--r--Source/CTest/cmCTestGIT.cxx130
-rw-r--r--Source/CTest/cmCTestHG.cxx35
-rw-r--r--Source/CTest/cmCTestLaunch.cxx126
-rw-r--r--Source/CTest/cmCTestLaunch.h5
-rw-r--r--Source/CTest/cmCTestLaunchReporter.cxx50
-rw-r--r--Source/CTest/cmCTestLaunchReporter.h4
-rw-r--r--Source/CTest/cmCTestP4.cxx66
-rw-r--r--Source/CTest/cmCTestP4.h2
-rw-r--r--Source/CTest/cmCTestSVN.cxx36
-rw-r--r--Source/CTest/cmCTestSVN.h2
-rw-r--r--Source/CTest/cmCTestScriptHandler.cxx84
-rw-r--r--Source/CTest/cmCTestSubmitHandler.cxx3
-rw-r--r--Source/CTest/cmCTestVC.cxx45
-rw-r--r--Source/CTest/cmCTestVC.h9
-rw-r--r--Source/LexerParser/cmCTestResourceGroupsLexer.cxx4
-rw-r--r--Source/LexerParser/cmCTestResourceGroupsLexer.in.l4
-rw-r--r--Source/cmCTest.cxx429
-rw-r--r--Source/cmCTest.h16
-rw-r--r--Source/cmComputeLinkInformation.cxx7
-rw-r--r--Source/cmExecuteProcessCommand.cxx384
-rw-r--r--Source/cmGeneratorTarget.cxx9
-rw-r--r--Source/cmGeneratorTarget.h1
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx6
-rw-r--r--Source/cmList.h10
-rw-r--r--Source/cmProcessTools.cxx82
-rw-r--r--Source/cmProcessTools.h8
-rw-r--r--Source/cmString.hxx4
-rw-r--r--Source/cmSystemTools.cxx288
-rw-r--r--Source/cmSystemTools.h21
-rw-r--r--Source/cmcmd.cxx102
-rw-r--r--Tests/CMakeLib/testUVProcessChainHelper.cxx4
-rw-r--r--Tests/CMakeLists.txt23
-rw-r--r--Tests/CTestTestFailure/CMakeLists.txt8
-rw-r--r--Tests/CTestTestFailure/CTestConfig.cmake4
-rw-r--r--Tests/CTestTestFailure/testNoBuild.cmake.in23
-rw-r--r--Tests/CTestTestFailure/testNoExe.cmake.in21
-rw-r--r--Tests/RunCMake/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/CTestCommandLine/output-junit-stderr.txt3
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH-stdout.txt3
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_SYSTEM_PATH-stdout.txt4
-rw-r--r--Tests/RunCMake/FindPkgConfig/FindPkgConfig_SYSTEM_PATH.cmake (renamed from Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH.cmake)8
-rw-r--r--Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem1-result.txt1
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem1-stderr.txt10
-rw-r--r--Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem1.cmake1
-rw-r--r--Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake6
-rw-r--r--Tests/RunCMake/XcodeProject-Device/RunCMakeTest.cmake6
-rw-r--r--Tests/RunCMake/ctest_build/BuildFailure.cxx (renamed from Tests/CTestTestFailure/badCode.cxx)0
-rw-r--r--Tests/RunCMake/ctest_build/RunCMakeTest.cmake21
-rw-r--r--Tests/RunCMake/ctest_test/NotRun-result.txt1
-rw-r--r--Tests/RunCMake/ctest_test/NotRun-stderr.txt2
-rw-r--r--Tests/RunCMake/ctest_test/NotRun-stdout.txt7
-rw-r--r--Tests/RunCMake/ctest_test/RunCMakeTest.cmake10
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatNotRun-stderr.txt3
-rw-r--r--Tests/RunCMake/ctest_test/TestRepeatNotRun-stdout.txt4
-rw-r--r--Tests/RunCMake/execute_process/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/execute_process/Stdin-stdin.txt1
-rw-r--r--Tests/RunCMake/execute_process/Stdin-stdout.txt1
-rw-r--r--Tests/RunCMake/execute_process/Stdin.cmake1
-rw-r--r--Utilities/IWYU/mapping.imp4
-rwxr-xr-xbootstrap1
96 files changed, 1489 insertions, 1329 deletions
diff --git a/.gitlab/ci/env_windows_vs2022_x64.ps1 b/.gitlab/ci/env_windows_vs2022_x64.ps1
new file mode 100755
index 0000000..42aec11
--- /dev/null
+++ b/.gitlab/ci/env_windows_vs2022_x64.ps1
@@ -0,0 +1,4 @@
+if ("$env:CMAKE_CI_NIGHTLY" -eq "true") {
+ $cmake = "build\install\bin\cmake"
+ . ".gitlab/ci/qt-env.ps1"
+}
diff --git a/.gitlab/ci/qt-env.ps1 b/.gitlab/ci/qt-env.ps1
index 7eff55f..22b1099 100755
--- a/.gitlab/ci/qt-env.ps1
+++ b/.gitlab/ci/qt-env.ps1
@@ -1,6 +1,9 @@
+if ($cmake -eq $null) {
+ throw ('$cmake powershell variable not set ')
+}
if ("$env:PROCESSOR_ARCHITECTURE" -eq "AMD64") {
$pwdpath = $pwd.Path
- cmake -P .gitlab/ci/download_qt.cmake
+ & $cmake -P .gitlab/ci/download_qt.cmake
Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\qt\bin;$env:PATH"
qmake -v
} elseif ("$env:PROCESSOR_ARCHITECTURE" -eq "ARM64") {
diff --git a/.gitlab/os-windows.yml b/.gitlab/os-windows.yml
index 422e147..81944cb 100644
--- a/.gitlab/os-windows.yml
+++ b/.gitlab/os-windows.yml
@@ -366,6 +366,7 @@
- Set-Item -Force -Path "env:WIX" -Value "$pwdpath\.gitlab\wix"
- (& "$pwsh" -File ".gitlab/ci/cmake.ps1")
- Set-Item -Force -Path "env:PATH" -Value "$pwdpath\.gitlab\cmake\bin;$env:PATH"
+ - $cmake = "cmake"
- . .gitlab/ci/ninja-env.ps1
- (& "$env:WIX\bin\light.exe" -help) | Select -First 1
- cmake --version
diff --git a/Help/guide/tutorial/Adding Usage Requirements for a Library.rst b/Help/guide/tutorial/Adding Usage Requirements for a Library.rst
index 5e803f5..e7aff9c 100644
--- a/Help/guide/tutorial/Adding Usage Requirements for a Library.rst
+++ b/Help/guide/tutorial/Adding Usage Requirements for a Library.rst
@@ -245,10 +245,9 @@ then use :command:`target_compile_features` to add the compiler feature
</details>
Finally, with our interface library set up, we need to link our
-executable ``Target``, our ``MathFunctions`` library, and our ``SqrtLibrary``
-library to our new
-``tutorial_compiler_flags`` library. Respectively, the code will look like
-this:
+executable ``Tutorial``, our ``SqrtLibrary`` library and our ``MathFunctions``
+library to our new ``tutorial_compiler_flags`` library. Respectively, the code
+will look like this:
.. raw:: html
@@ -275,7 +274,7 @@ this:
:caption: TODO 6: MathFunctions/CMakeLists.txt
:name: MathFunctions-CMakeLists.txt-target_link_libraries-step4
:language: cmake
- :start-after: # link our compiler flags interface library
+ :start-after: # link SqrtLibrary to tutorial_compiler_flags
:end-before: target_link_libraries(MathFunctions
.. raw:: html
@@ -292,8 +291,7 @@ and this:
:caption: TODO 7: MathFunctions/CMakeLists.txt
:name: MathFunctions-SqrtLibrary-target_link_libraries-step4
:language: cmake
- :start-after: # link our compiler flags interface library
- :end-before: target_link_libraries(MathFunctions PUBLIC SqrtLibrary)
+ :start-after: # link MathFunctions to tutorial_compiler_flags
.. raw:: html
diff --git a/Help/guide/tutorial/Adding a Library.rst b/Help/guide/tutorial/Adding a Library.rst
index 178334a..18ced97 100644
--- a/Help/guide/tutorial/Adding a Library.rst
+++ b/Help/guide/tutorial/Adding a Library.rst
@@ -184,7 +184,7 @@ Now let's use our library. In ``tutorial.cxx``, include ``MathFunctions.h``:
</details>
-Lastly, replace ``sqrt`` with our library function ``mathfunctions::mysqrt``.
+Lastly, replace ``sqrt`` with the wrapper function ``mathfunctions::sqrt``.
.. raw:: html
diff --git a/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt
index b221506..1654564 100644
--- a/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt
@@ -33,10 +33,13 @@ if(USE_MYMATH)
POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
)
+ # link SqrtLibrary to tutorial_compiler_flags
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
+
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
+# link MathFunctions to tutorial_compiler_flags
target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
# define the symbol stating we are using the declspec(dllexport) when
diff --git a/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt
index 36b3fe1..210563a 100644
--- a/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt
@@ -26,10 +26,13 @@ if(USE_MYMATH)
${CMAKE_CURRENT_BINARY_DIR}
)
+ # link SqrtLibrary to tutorial_compiler_flags
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
+
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
+# link MathFunctions to tutorial_compiler_flags
target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
# install libs
diff --git a/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt
index 813bf90..eacc538 100644
--- a/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt
@@ -31,10 +31,13 @@ if(USE_MYMATH)
POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
)
+ # link SqrtLibrary to tutorial_compiler_flags
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
+
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
+# link MathFunctions to tutorial_compiler_flags
target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
# define the symbol stating we are using the declspec(dllexport) when
diff --git a/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt
index 38694dd..8aa5904 100644
--- a/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt
@@ -33,10 +33,13 @@ if(USE_MYMATH)
POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
)
+ # link SqrtLibrary to tutorial_compiler_flags
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
+
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
+# link MathFunctions to tutorial_compiler_flags
target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
# define the symbol stating we are using the declspec(dllexport) when
diff --git a/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt
index 0ffb9e1..ffb2f35 100644
--- a/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt
@@ -16,7 +16,7 @@ if (USE_MYMATH)
# TODO 7: Link SqrtLibrary to tutorial_compiler_flags
- target_link_libraries(MathFunctions PUBLIC SqrtLibrary)
+ target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
# TODO 6: Link MathFunctions to tutorial_compiler_flags
diff --git a/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt
index 48561eb..6931898 100644
--- a/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt
@@ -17,10 +17,11 @@ if (USE_MYMATH)
mysqrt.cxx
)
- # link our compiler flags interface library
+ # link SqrtLibrary to tutorial_compiler_flags
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
- target_link_libraries(MathFunctions PUBLIC SqrtLibrary)
+
+ target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
-# link our compiler flags interface library
+# link MathFunctions to tutorial_compiler_flags
target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
diff --git a/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt
index 0c688f2..61b3899 100644
--- a/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt
@@ -16,12 +16,13 @@ if (USE_MYMATH)
mysqrt.cxx
)
- # link our compiler flags interface library
+ # link SqrtLibrary to tutorial_compiler_flags
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
+
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
-# link our compiler flags interface library
+# link MathFunctions to tutorial_compiler_flags
target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
# TODO 1: Create a variable called installable_libs that is a list of all
diff --git a/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt
index b1b925e..8499a51 100644
--- a/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt
@@ -16,11 +16,13 @@ if (USE_MYMATH)
mysqrt.cxx
)
+ # link SqrtLibrary to tutorial_compiler_flags
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
+
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
-# link our compiler flags interface library
+# link MathFunctions to tutorial_compiler_flags
target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
# install libs
diff --git a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt
index 897ec0e..a0b3037 100644
--- a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt
@@ -16,6 +16,7 @@ if (USE_MYMATH)
mysqrt.cxx
)
+ # link SqrtLibrary to tutorial_compiler_flags
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
# TODO 1: Include CheckCXXSourceCompiles
@@ -41,7 +42,7 @@ if (USE_MYMATH)
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
-# link our compiler flags interface library
+# link MathFunctions to tutorial_compiler_flags
target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
# install libs
diff --git a/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt
index 872a24a..b14d180 100644
--- a/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt
@@ -10,6 +10,7 @@ if (USE_MYMATH)
mysqrt.cxx
)
+ # link SqrtLibrary to tutorial_compiler_flags
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
# does this system provide the log and exp functions?
@@ -45,7 +46,7 @@ target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
-# link our compiler flags interface library
+# link MathFunctions to tutorial_compiler_flags
target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
# install libs
diff --git a/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt
index 54cecf8..5addc6d 100644
--- a/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt
@@ -25,10 +25,13 @@ if (USE_MYMATH)
${CMAKE_CURRENT_BINARY_DIR}
)
+ # link SqrtLibrary to tutorial_compiler_flags
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
+
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
+# link MathFunctions to tutorial_compiler_flags
target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
# install libs
diff --git a/Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT.rst b/Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT.rst
index 0c7845c..7e08b48 100644
--- a/Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT.rst
+++ b/Help/prop_tgt/MSVC_DEBUG_INFORMATION_FORMAT.rst
@@ -21,6 +21,8 @@ support per-configuration specification. For example, the code:
selects for the target ``foo`` the program database debug information format
for the Debug configuration.
+This property is initialized from the value of the
+:variable:`CMAKE_MSVC_DEBUG_INFORMATION_FORMAT` variable, if it is set.
If this property is not set, CMake selects a debug information format using
the default value ``$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>``, if
supported by the compiler, and otherwise
diff --git a/Help/release/dev/xcode-no-legacy-buildsystem.rst b/Help/release/dev/xcode-no-legacy-buildsystem.rst
new file mode 100644
index 0000000..f3d1f67
--- /dev/null
+++ b/Help/release/dev/xcode-no-legacy-buildsystem.rst
@@ -0,0 +1,8 @@
+xcode-no-legacy-buildsystem
+---------------------------
+
+* The :generator:`Xcode` generator will now issue a fatal error if
+ the Legacy Build System has been selected for Xcode 14 and
+ newer. Those Xcode versions dropped support for the Legacy Build
+ System and expect the project being set-up for their current
+ Build System.
diff --git a/Help/variable/CMAKE_XCODE_BUILD_SYSTEM.rst b/Help/variable/CMAKE_XCODE_BUILD_SYSTEM.rst
index d153061..f3c213c 100644
--- a/Help/variable/CMAKE_XCODE_BUILD_SYSTEM.rst
+++ b/Help/variable/CMAKE_XCODE_BUILD_SYSTEM.rst
@@ -12,7 +12,8 @@ mature enough for use by CMake. The possible values are:
``1``
The original Xcode build system.
- This is the default when using Xcode 11.x or below.
+ This is the default when using Xcode 11.x or below and supported
+ up to Xcode 13.x.
``12``
The Xcode "new build system" introduced by Xcode 10.
diff --git a/Modules/Compiler/IntelLLVM.cmake b/Modules/Compiler/IntelLLVM.cmake
index e256c8f..f3c0bf4 100644
--- a/Modules/Compiler/IntelLLVM.cmake
+++ b/Modules/Compiler/IntelLLVM.cmake
@@ -44,6 +44,13 @@ else()
string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g")
+ if(CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 2023.0.0)
+ if("x${lang}" STREQUAL "xFortran")
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -diag-disable:10440")
+ else()
+ string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -Rno-debug-disables-optimization")
+ endif()
+ endif()
string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Os")
string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3")
string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
diff --git a/Modules/FindFreetype.cmake b/Modules/FindFreetype.cmake
index 82885cb..dcf271d 100644
--- a/Modules/FindFreetype.cmake
+++ b/Modules/FindFreetype.cmake
@@ -65,6 +65,64 @@ 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_QUIETLY)
+ list(APPEND _Freetype_args
+ QUIET)
+endif ()
+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)
+find_package(freetype CONFIG ${_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 LOCATION)
+ list(APPEND FREETYPE_LIBRARIES
+ "${_Freetype_location}")
+ unset(_Freetype_location)
+ 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)
+ return ()
+endif ()
+
set(FREETYPE_FIND_ARGS
HINTS
ENV FREETYPE_DIR
diff --git a/Modules/FindGLEW.cmake b/Modules/FindGLEW.cmake
index bfde40b..dff53e1 100644
--- a/Modules/FindGLEW.cmake
+++ b/Modules/FindGLEW.cmake
@@ -126,6 +126,10 @@ function(__glew_set_find_library_suffix shared_or_static)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib;.so" PARENT_SCOPE)
elseif(APPLE AND "${shared_or_static}" MATCHES "STATIC")
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE)
+ elseif(WIN32 AND MINGW AND "${shared_or_static}" MATCHES "SHARED")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll.a" PARENT_SCOPE)
+ elseif(WIN32 AND MINGW AND "${shared_or_static}" MATCHES "STATIC")
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE)
elseif(WIN32 AND "${shared_or_static}" MATCHES "SHARED")
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" PARENT_SCOPE)
elseif(WIN32 AND "${shared_or_static}" MATCHES "STATIC")
diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake
index 3ab6bc1..8a2e1a1 100644
--- a/Modules/FindMatlab.cmake
+++ b/Modules/FindMatlab.cmake
@@ -336,9 +336,7 @@ set(MATLAB_VERSIONS_MAPPING
# temporary folder for all Matlab runs
set(_matlab_temporary_folder ${CMAKE_BINARY_DIR}/Matlab)
-if(NOT EXISTS "${_matlab_temporary_folder}")
- file(MAKE_DIRECTORY "${_matlab_temporary_folder}")
-endif()
+file(MAKE_DIRECTORY "${_matlab_temporary_folder}")
#[=======================================================================[.rst:
.. command:: matlab_get_version_from_release_name
@@ -567,7 +565,7 @@ function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${_matlab_current_version};MATLABROOT]"
ABSOLUTE)
- if(EXISTS "${current_MATLAB_ROOT}")
+ if(IS_DIRECTORY "${current_MATLAB_ROOT}")
list(APPEND _matlab_roots_list "MATLAB" ${_matlab_current_version} ${current_MATLAB_ROOT})
endif()
@@ -583,7 +581,7 @@ function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_
# remove the dot
string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}")
- if(EXISTS "${current_MATLAB_ROOT}")
+ if(IS_DIRECTORY "${current_MATLAB_ROOT}")
list(APPEND _matlab_roots_list "MCR" ${_matlab_current_version} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}")
endif()
@@ -599,7 +597,7 @@ function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_
# remove the dot
string(REPLACE "." "" _matlab_current_version_without_dot "${_matlab_current_version}")
- if(EXISTS "${current_MATLAB_ROOT}")
+ if(IS_DIRECTORY "${current_MATLAB_ROOT}")
list(APPEND _matlab_roots_list "MCR" ${_matlab_current_version} "${current_MATLAB_ROOT}/v${_matlab_current_version_without_dot}")
endif()
@@ -1325,7 +1323,7 @@ function(_Matlab_get_version_from_root matlab_root matlab_or_mcr matlab_known_ve
if(NOT _matlab_current_program)
set(_find_matlab_options)
- if(matlab_root AND EXISTS ${matlab_root})
+ if(IS_DIRECTORY "${matlab_root}")
set(_find_matlab_options PATHS ${matlab_root} ${matlab_root}/bin NO_DEFAULT_PATH)
endif()
@@ -1337,7 +1335,7 @@ function(_Matlab_get_version_from_root matlab_root matlab_or_mcr matlab_known_ve
)
endif()
- if(NOT _matlab_current_program OR NOT EXISTS ${_matlab_current_program})
+ if(NOT _matlab_current_program)
# if not found, clear the dependent variables
if(MATLAB_FIND_DEBUG)
message(WARNING "[MATLAB] Cannot find the main matlab program under ${matlab_root}")
@@ -1463,7 +1461,7 @@ function(_Matlab_find_instances_osx matlab_roots)
set(_matlab_base_path "/Applications/MATLAB_${_matlab_current_release}.app")
# Check Matlab, has precedence over MCR
- if(EXISTS ${_matlab_base_path})
+ if(IS_DIRECTORY "${_matlab_base_path}")
if(MATLAB_FIND_DEBUG)
message(STATUS "[MATLAB] Found version ${_matlab_current_release} (${_matlab_current_version}) in ${_matlab_base_path}")
endif()
@@ -1472,7 +1470,7 @@ function(_Matlab_find_instances_osx matlab_roots)
# Checks MCR
set(_mcr_path "/Applications/MATLAB/MATLAB_Runtime/v${_matlab_current_version_without_dot}")
- if(EXISTS "${_mcr_path}")
+ if(IS_DIRECTORY "${_mcr_path}")
if(MATLAB_FIND_DEBUG)
message(STATUS "[MATLAB] Found MCR version ${_matlab_current_release} (${_matlab_current_version}) in ${_mcr_path}")
endif()
@@ -1565,7 +1563,7 @@ endif()
if(Matlab_ROOT_DIR)
# if the user specifies a possible root, we keep this one
- if(NOT EXISTS "${Matlab_ROOT_DIR}")
+ if(NOT IS_DIRECTORY "${Matlab_ROOT_DIR}")
# if Matlab_ROOT_DIR specified but erroneous
if(MATLAB_FIND_DEBUG)
message(WARNING "[MATLAB] the specified path for Matlab_ROOT_DIR does not exist (${Matlab_ROOT_DIR})")
diff --git a/Modules/FindPkgConfig.cmake b/Modules/FindPkgConfig.cmake
index 02f7fb4..4d29f45 100644
--- a/Modules/FindPkgConfig.cmake
+++ b/Modules/FindPkgConfig.cmake
@@ -425,13 +425,19 @@ macro(_pkg_set_path_internal)
unset(_pkgconfig_path)
endif()
- # Tell pkg-config not to strip any -L paths so we can search them all.
+ # Tell pkg-config not to strip any -I or -L paths so we can search them all.
if(DEFINED ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS})
set(_pkgconfig_allow_system_libs_old "$ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS}")
else()
unset(_pkgconfig_allow_system_libs_old)
endif()
set(ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS} 1)
+ if(DEFINED ENV{PKG_CONFIG_ALLOW_SYSTEM_CFLAGS})
+ set(_pkgconfig_allow_system_cflags_old "$ENV{PKG_CONFIG_ALLOW_SYSTEM_CFLAGS}")
+ else()
+ unset(_pkgconfig_allow_system_cflags_old)
+ endif()
+ set(ENV{PKG_CONFIG_ALLOW_SYSTEM_CFLAGS} 1)
endmacro()
macro(_pkg_restore_path_internal)
@@ -445,6 +451,12 @@ macro(_pkg_restore_path_internal)
else()
unset(ENV{PKG_CONFIG_ALLOW_SYSTEM_LIBS})
endif()
+ if(DEFINED _pkgconfig_allow_system_cflags_old)
+ set(ENV{PKG_CONFIG_ALLOW_SYSTEM_CFLAGS} "${_pkgconfig_allow_system_cflags_old}")
+ unset(_pkgconfig_allow_system_cflags_old)
+ else()
+ unset(ENV{PKG_CONFIG_ALLOW_SYSTEM_CFLAGS})
+ endif()
unset(_extra_paths)
unset(_pkgconfig_path_old)
diff --git a/Modules/Internal/CPack/NSIS.template.in b/Modules/Internal/CPack/NSIS.template.in
index 21753af..6349f9d 100644
--- a/Modules/Internal/CPack/NSIS.template.in
+++ b/Modules/Internal/CPack/NSIS.template.in
@@ -981,7 +981,7 @@ inst:
;MessageBox MB_OK 'User "$0" is in the Admin group'
StrCpy $SV_ALLUSERS "AllUsers"
Goto done
- StrCmp $1 "Power" 0 +4
+ StrCmp $1 "Power" 0 +3
SetShellVarContext all
;MessageBox MB_OK 'User "$0" is in the Power Users group'
StrCpy $SV_ALLUSERS "AllUsers"
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 1f8d8a8..e8ebae6 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 27)
-set(CMake_VERSION_PATCH 20230905)
+set(CMake_VERSION_PATCH 20230908)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
diff --git a/Source/CPack/cmCPackSTGZGenerator.cxx b/Source/CPack/cmCPackSTGZGenerator.cxx
index 6ad3755..1248d17 100644
--- a/Source/CPack/cmCPackSTGZGenerator.cxx
+++ b/Source/CPack/cmCPackSTGZGenerator.cxx
@@ -7,6 +7,8 @@
#include <string>
#include <vector>
+#include <fcntl.h>
+
#include "cmsys/FStream.hxx"
#include "cm_sys_stat.h"
diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx
index 246e811..36df344 100644
--- a/Source/CTest/cmCTestBZR.cxx
+++ b/Source/CTest/cmCTestBZR.cxx
@@ -135,14 +135,14 @@ private:
std::string cmCTestBZR::LoadInfo()
{
// Run "bzr info" to get the repository info from the work tree.
- const char* bzr = this->CommandLineTool.c_str();
- const char* bzr_info[] = { bzr, "info", nullptr };
+ std::string bzr = this->CommandLineTool;
+ std::vector<std::string> bzr_info = { bzr, "info" };
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.
- const char* bzr_revno[] = { bzr, "revno", nullptr };
+ std::vector<std::string> bzr_revno = { bzr, "revno" };
std::string rev;
RevnoParser rout(this, "revno-out> ", rev);
OutputLogger rerr(this->Log, "revno-err> ");
@@ -372,22 +372,18 @@ bool cmCTestBZR::UpdateImpl()
// TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
// Use "bzr pull" to update the working tree.
- std::vector<char const*> bzr_update;
- bzr_update.push_back(this->CommandLineTool.c_str());
+ std::vector<std::string> bzr_update;
+ bzr_update.push_back(this->CommandLineTool);
bzr_update.push_back("pull");
- for (std::string const& arg : args) {
- bzr_update.push_back(arg.c_str());
- }
-
- bzr_update.push_back(this->URL.c_str());
+ cm::append(bzr_update, args);
- bzr_update.push_back(nullptr);
+ bzr_update.push_back(this->URL);
// 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.data(), &out, &err);
+ return this->RunUpdateCommand(bzr_update, &out, &err);
}
bool cmCTestBZR::LoadRevisions()
@@ -408,10 +404,9 @@ bool cmCTestBZR::LoadRevisions()
}
// Run "bzr log" to get all global revisions of interest.
- const char* bzr = this->CommandLineTool.c_str();
- const char* bzr_log[] = {
- bzr, "log", "-v", "-r", revs.c_str(), "--xml", this->URL.c_str(), nullptr
- };
+ std::string bzr = this->CommandLineTool;
+ std::vector<std::string> bzr_log = { bzr, "log", "-v", "-r",
+ revs, "--xml", this->URL };
{
LogParser out(this, "log-out> ");
OutputLogger err(this->Log, "log-err> ");
@@ -467,8 +462,8 @@ private:
bool cmCTestBZR::LoadModifications()
{
// Run "bzr status" which reports local modifications.
- const char* bzr = this->CommandLineTool.c_str();
- const char* bzr_status[] = { bzr, "status", "-SV", nullptr };
+ std::string bzr = this->CommandLineTool;
+ std::vector<std::string> bzr_status = { bzr, "status", "-SV" };
StatusParser out(this, "status-out> ");
OutputLogger err(this->Log, "status-err> ");
this->RunChild(bzr_status, &out, &err);
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index 5feb953..bb6ccc3 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -7,8 +7,6 @@
#include <cstring>
#include <ratio>
-#include "cmsys/Process.h"
-
#include "cmBuildOptions.h"
#include "cmCTest.h"
#include "cmCTestTestHandler.h"
@@ -308,12 +306,11 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
return 1;
}
- std::vector<const char*> testCommand;
- testCommand.push_back(fullPath.c_str());
+ std::vector<std::string> testCommand;
+ testCommand.push_back(fullPath);
for (std::string const& testCommandArg : this->TestCommandArgs) {
- testCommand.push_back(testCommandArg.c_str());
+ testCommand.push_back(testCommandArg);
}
- testCommand.push_back(nullptr);
std::string outs;
int retval = 0;
// run the test from the this->BuildRunDir if set
@@ -349,10 +346,10 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
}
}
- int runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, nullptr,
- remainingTime, nullptr);
+ bool runTestRes = this->CTest->RunTest(testCommand, &outs, &retval, nullptr,
+ remainingTime, nullptr);
- if (runTestRes != cmsysProcess_State_Exited || retval != 0) {
+ if (!runTestRes || retval != 0) {
out << "Test command failed: " << testCommand[0] << "\n";
retval = 1;
}
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index 00ecf42..859798e 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -3,15 +3,17 @@
#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"
@@ -24,6 +26,9 @@
#include "cmStringAlgorithms.h"
#include "cmStringReplaceHelper.h"
#include "cmSystemTools.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVProcessChain.h"
+#include "cmUVStream.h"
#include "cmValue.h"
#include "cmXMLWriter.h"
@@ -420,7 +425,7 @@ int cmCTestBuildHandler::ProcessHandler()
cmStringReplaceHelper colorRemover("\x1b\\[[0-9;]*m", "", nullptr);
this->ColorRemover = &colorRemover;
int retVal = 0;
- int res = cmsysProcess_State_Exited;
+ bool res = true;
if (!this->CTest->GetShowOnly()) {
res = this->RunMakeCommand(makeCommand, &retVal, buildDirectory.c_str(), 0,
ofs);
@@ -475,7 +480,7 @@ int cmCTestBuildHandler::ProcessHandler()
}
this->GenerateXMLFooter(xml, elapsed_build_time);
- if (res != cmsysProcess_State_Exited || retVal || this->TotalErrors > 0) {
+ if (!res || retVal || this->TotalErrors > 0) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
"Error(s) when building project" << std::endl);
}
@@ -764,10 +769,10 @@ void cmCTestBuildHandler::LaunchHelper::WriteScrapeMatchers(
}
}
-int cmCTestBuildHandler::RunMakeCommand(const std::string& command,
- int* retVal, const char* dir,
- int timeout, std::ostream& ofs,
- Encoding encoding)
+bool 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);
@@ -776,19 +781,9 @@ int 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 (char const* arg : argv) {
- if (!arg) {
- break;
- }
+ for (auto const& arg : args) {
cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
" \"" << arg << "\"", this->Quiet);
}
@@ -800,21 +795,20 @@ int cmCTestBuildHandler::RunMakeCommand(const std::string& command,
static_cast<void>(launchHelper);
// Now create process object
- 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);
+ cmUVProcessChainBuilder builder;
+ builder.AddCommand(args)
+ .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
+ .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
+ if (dir) {
+ builder.SetWorkingDirectory(dir);
+ }
+ auto chain = builder.Start();
// Initialize tick's
std::string::size_type tick = 0;
- const std::string::size_type tick_len = 1024;
+ static constexpr 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 "
@@ -836,39 +830,65 @@ int 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
- 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';
- }
- }
+ 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';
+ }
+ }
- // 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);
+ // 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);
}
-
this->ProcessBuffer(nullptr, 0, tick, tick_len, ofs,
&this->BuildProcessingQueue);
this->ProcessBuffer(nullptr, 0, tick, tick_len, ofs,
@@ -879,90 +899,93 @@ int cmCTestBuildHandler::RunMakeCommand(const std::string& command,
<< std::endl,
this->Quiet);
- // 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 (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++;
}
}
- 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++;
}
- }
- }
- } 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);
+ 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 if (result == cmsysProcess_State_Expired) {
+ } else {
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);
}
- cmsysProcess_Delete(cp);
- return result;
+ return true;
}
// ######################################################################
diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h
index e33294d..90945b1 100644
--- a/Source/CTest/cmCTestBuildHandler.h
+++ b/Source/CTest/cmCTestBuildHandler.h
@@ -53,9 +53,9 @@ private:
//! Run command specialized for make and configure. Returns process status
// and retVal is return value or exception.
- int RunMakeCommand(const std::string& command, int* retVal, const char* dir,
- int timeout, std::ostream& ofs,
- Encoding encoding = cmProcessOutput::Auto);
+ bool RunMakeCommand(const std::string& command, int* retVal, const char* dir,
+ int timeout, std::ostream& ofs,
+ Encoding encoding = cmProcessOutput::Auto);
enum
{
diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx
index 95e898c..ef95b25 100644
--- a/Source/CTest/cmCTestCVS.cxx
+++ b/Source/CTest/cmCTestCVS.cxx
@@ -5,6 +5,7 @@
#include <utility>
#include <cm/string_view>
+#include <cmext/algorithm>
#include "cmsys/FStream.hxx"
#include "cmsys/RegularExpression.hxx"
@@ -89,18 +90,15 @@ bool cmCTestCVS::UpdateImpl()
}
// Run "cvs update" to update the work tree.
- std::vector<char const*> cvs_update;
- cvs_update.push_back(this->CommandLineTool.c_str());
+ std::vector<std::string> cvs_update;
+ cvs_update.push_back(this->CommandLineTool);
cvs_update.push_back("-z3");
cvs_update.push_back("update");
- for (std::string const& arg : args) {
- cvs_update.push_back(arg.c_str());
- }
- cvs_update.push_back(nullptr);
+ cm::append(cvs_update, args);
UpdateParser out(this, "up-out> ");
UpdateParser err(this, "up-err> ");
- return this->RunUpdateCommand(cvs_update.data(), &out, &err);
+ return this->RunUpdateCommand(cvs_update, &out, &err);
}
class cmCTestCVS::LogParser : public cmCTestVC::LineParser
@@ -221,10 +219,8 @@ 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.
- const char* cvs = this->CommandLineTool.c_str();
- const char* cvs_log[] = {
- cvs, "log", "-N", branchFlag, file.c_str(), nullptr
- };
+ std::string cvs = this->CommandLineTool;
+ std::vector<std::string> cvs_log = { cvs, "log", "-N", branchFlag, file };
LogParser out(this, "log-out> ", revisions);
OutputLogger err(this->Log, "log-err> ");
diff --git a/Source/CTest/cmCTestConfigureHandler.cxx b/Source/CTest/cmCTestConfigureHandler.cxx
index 914930e..dd8952f 100644
--- a/Source/CTest/cmCTestConfigureHandler.cxx
+++ b/Source/CTest/cmCTestConfigureHandler.cxx
@@ -45,7 +45,7 @@ int cmCTestConfigureHandler::ProcessHandler()
auto elapsed_time_start = std::chrono::steady_clock::now();
std::string output;
int retVal = 0;
- int res = 0;
+ bool res = false;
if (!this->CTest->GetShowOnly()) {
cmGeneratedFileStream os;
if (!this->StartResultingXML(cmCTest::PartConfigure, "Configure", os)) {
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index 2874be7..1aa49cf 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -9,6 +9,7 @@
#include <cstring>
#include <iomanip>
#include <iterator>
+#include <memory>
#include <ratio>
#include <sstream>
#include <type_traits>
@@ -18,9 +19,10 @@
#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"
@@ -33,6 +35,7 @@
#include "cmParsePHPCoverage.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
+#include "cmUVProcessChain.h"
#include "cmWorkingDirectory.h"
#include "cmXMLWriter.h"
@@ -40,85 +43,6 @@ 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()
@@ -1940,34 +1864,35 @@ 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
- cmCTestRunProcess runCoverageSrc;
- runCoverageSrc.SetCommand(program.c_str());
- runCoverageSrc.AddArgument(arg);
+ cmUVProcessChainBuilder builder;
std::string stdoutFile =
cmStrCat(cont->BinaryDir, "/Testing/Temporary/",
this->GetCTestInstance()->GetCurrentTag(), '-', cmd);
std::string stderrFile = stdoutFile;
stdoutFile += ".stdout";
stderrFile += ".stderr";
- 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;
- }
+ 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()));
// since we set the output file names wait for it to end
- runCoverageSrc.WaitForExit();
+ auto chain = builder.Start();
+ chain.Wait();
outputFile = stdoutFile;
return 1;
}
diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx
index 5f8cb74..ca8659e 100644
--- a/Source/CTest/cmCTestGIT.cxx
+++ b/Source/CTest/cmCTestGIT.cxx
@@ -9,8 +9,9 @@
#include <utility>
#include <vector>
+#include <cmext/algorithm>
+
#include "cmsys/FStream.hxx"
-#include "cmsys/Process.h"
#include "cmCTest.h"
#include "cmCTestVC.h"
@@ -18,6 +19,7 @@
#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,
@@ -58,9 +60,9 @@ private:
std::string cmCTestGIT::GetWorkingRevision()
{
// Run plumbing "git rev-list" to get work tree revision.
- const char* git = this->CommandLineTool.c_str();
- const char* git_rev_list[] = { git, "rev-list", "-n", "1",
- "HEAD", "--", nullptr };
+ std::string git = this->CommandLineTool;
+ std::vector<std::string> git_rev_list = { git, "rev-list", "-n",
+ "1", "HEAD", "--" };
std::string rev;
OneLineParser out(this, "rl-out> ", rev);
OutputLogger err(this->Log, "rl-err> ");
@@ -92,13 +94,13 @@ std::string cmCTestGIT::FindGitDir()
std::string git_dir;
// Run "git rev-parse --git-dir" to locate the real .git directory.
- const char* git = this->CommandLineTool.c_str();
- char const* git_rev_parse[] = { git, "rev-parse", "--git-dir", nullptr };
+ std::string git = this->CommandLineTool;
+ std::vector<std::string> git_rev_parse = { git, "rev-parse", "--git-dir" };
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, nullptr,
- cmProcessOutput::UTF8)) {
+ if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err,
+ std::string{}, cmProcessOutput::UTF8)) {
git_dir = git_dir_line;
}
if (git_dir.empty()) {
@@ -117,11 +119,10 @@ std::string cmCTestGIT::FindGitDir()
std::string cygpath_exe =
cmStrCat(cmSystemTools::GetFilenamePath(git), "/cygpath.exe");
if (cmSystemTools::FileExists(cygpath_exe)) {
- char const* cygpath[] = { cygpath_exe.c_str(), "-w", git_dir.c_str(),
- 0 };
+ std::vector<std::string> cygpath = { cygpath_exe, "-w", git_dir };
OneLineParser cygpath_out(this, "cygpath-out> ", git_dir_line);
OutputLogger cygpath_err(this->Log, "cygpath-err> ");
- if (this->RunChild(cygpath, &cygpath_out, &cygpath_err, nullptr,
+ if (this->RunChild(cygpath, &cygpath_out, &cygpath_err, std::string{},
cmProcessOutput::UTF8)) {
git_dir = git_dir_line;
}
@@ -136,12 +137,12 @@ std::string cmCTestGIT::FindTopDir()
std::string top_dir = this->SourceDirectory;
// Run "git rev-parse --show-cdup" to locate the top of the tree.
- const char* git = this->CommandLineTool.c_str();
- char const* git_rev_parse[] = { git, "rev-parse", "--show-cdup", nullptr };
+ std::string git = this->CommandLineTool;
+ std::vector<std::string> git_rev_parse = { git, "rev-parse", "--show-cdup" };
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, nullptr,
+ if (this->RunChild(git_rev_parse, &rev_parse_out, &rev_parse_err, "",
cmProcessOutput::UTF8) &&
!cdup.empty()) {
top_dir += "/";
@@ -153,10 +154,10 @@ std::string cmCTestGIT::FindTopDir()
bool cmCTestGIT::UpdateByFetchAndReset()
{
- const char* git = this->CommandLineTool.c_str();
+ std::string git = this->CommandLineTool;
// Use "git fetch" to get remote commits.
- std::vector<char const*> git_fetch;
+ std::vector<std::string> git_fetch;
git_fetch.push_back(git);
git_fetch.push_back("fetch");
@@ -166,17 +167,12 @@ bool cmCTestGIT::UpdateByFetchAndReset()
opts = this->CTest->GetCTestConfiguration("GITUpdateOptions");
}
std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
- for (std::string const& arg : args) {
- git_fetch.push_back(arg.c_str());
- }
-
- // Sentinel argument.
- git_fetch.push_back(nullptr);
+ cm::append(git_fetch, args);
// Fetch upstream refs.
OutputLogger fetch_out(this->Log, "fetch-out> ");
OutputLogger fetch_err(this->Log, "fetch-err> ");
- if (!this->RunUpdateCommand(git_fetch.data(), &fetch_out, &fetch_err)) {
+ if (!this->RunUpdateCommand(git_fetch, &fetch_out, &fetch_err)) {
return false;
}
@@ -207,25 +203,22 @@ bool cmCTestGIT::UpdateByFetchAndReset()
}
// Reset the local branch to point at that tracked from upstream.
- char const* git_reset[] = { git, "reset", "--hard", sha1.c_str(), nullptr };
+ std::vector<std::string> git_reset = { git, "reset", "--hard", sha1 };
OutputLogger reset_out(this->Log, "reset-out> ");
OutputLogger reset_err(this->Log, "reset-err> ");
- return this->RunChild(&git_reset[0], &reset_out, &reset_err);
+ return this->RunChild(git_reset, &reset_out, &reset_err);
}
bool cmCTestGIT::UpdateByCustom(std::string const& custom)
{
cmList git_custom_command{ custom, cmList::EmptyElements::Yes };
- 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);
+ std::vector<std::string> git_custom;
+ git_custom.reserve(git_custom_command.size());
+ cm::append(git_custom, git_custom_command);
OutputLogger custom_out(this->Log, "custom-out> ");
OutputLogger custom_err(this->Log, "custom-err> ");
- return this->RunUpdateCommand(git_custom.data(), &custom_out, &custom_err);
+ return this->RunUpdateCommand(git_custom, &custom_out, &custom_err);
}
bool cmCTestGIT::UpdateInternal()
@@ -244,13 +237,14 @@ bool cmCTestGIT::UpdateImpl()
}
std::string top_dir = this->FindTopDir();
- const char* git = this->CommandLineTool.c_str();
- const char* recursive = "--recursive";
- const char* sync_recursive = "--recursive";
+ std::string git = this->CommandLineTool;
+ std::string recursive = "--recursive";
+ std::string sync_recursive = "--recursive";
// Git < 1.6.5 did not support submodule --recursive
+ bool support_recursive = true;
if (this->GetGitVersion() < cmCTestGITVersion(1, 6, 5, 0)) {
- recursive = nullptr;
+ support_recursive = false;
// 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";
@@ -258,8 +252,9 @@ 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)) {
- sync_recursive = nullptr;
+ support_sync_recursive = false;
// 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";
@@ -274,35 +269,39 @@ bool cmCTestGIT::UpdateImpl()
std::string init_submodules =
this->CTest->GetCTestConfiguration("GITInitSubmodules");
if (cmIsOn(init_submodules)) {
- char const* git_submodule_init[] = { git, "submodule", "init", nullptr };
+ std::vector<std::string> git_submodule_init = { git, "submodule", "init" };
ret = this->RunChild(git_submodule_init, &submodule_out, &submodule_err,
- top_dir.c_str());
+ top_dir);
if (!ret) {
return false;
}
}
- char const* git_submodule_sync[] = { git, "submodule", "sync",
- sync_recursive, nullptr };
+ std::vector<std::string> git_submodule_sync = { git, "submodule", "sync" };
+ if (support_sync_recursive) {
+ git_submodule_sync.push_back(sync_recursive);
+ }
ret = this->RunChild(git_submodule_sync, &submodule_out, &submodule_err,
- top_dir.c_str());
+ top_dir);
if (!ret) {
return false;
}
- char const* git_submodule[] = { git, "submodule", "update", recursive,
- nullptr };
+ std::vector<std::string> git_submodule = { git, "submodule", "update" };
+ if (support_recursive) {
+ git_submodule.push_back(recursive);
+ }
return this->RunChild(git_submodule, &submodule_out, &submodule_err,
- top_dir.c_str());
+ top_dir);
}
unsigned int cmCTestGIT::GetGitVersion()
{
if (!this->CurrentGitVersion) {
- const char* git = this->CommandLineTool.c_str();
- char const* git_version[] = { git, "--version", nullptr };
+ std::string git = this->CommandLineTool;
+ std::vector<std::string> git_version = { git, "--version" };
std::string version;
OneLineParser version_out(this, "version-out> ", version);
OutputLogger version_err(this->Log, "version-err> ");
@@ -605,50 +604,49 @@ bool cmCTestGIT::LoadRevisions()
{
// Use 'git rev-list ... | git diff-tree ...' to get revisions.
std::string range = this->OldRevision + ".." + this->NewRevision;
- 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
+ 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"
};
this->Log << cmCTestGIT::ComputeCommandLine(git_rev_list) << " | "
<< cmCTestGIT::ComputeCommandLine(git_diff_tree) << "\n";
- cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_AddCommand(cp, git_rev_list);
- cmsysProcess_AddCommand(cp, git_diff_tree);
- cmsysProcess_SetWorkingDirectory(cp, this->SourceDirectory.c_str());
+ cmUVProcessChainBuilder builder;
+ builder.AddCommand(git_rev_list)
+ .AddCommand(git_diff_tree)
+ .SetWorkingDirectory(this->SourceDirectory);
CommitParser out(this, "dt-out> ");
OutputLogger err(this->Log, "dt-err> ");
- cmCTestGIT::RunProcess(cp, &out, &err, cmProcessOutput::UTF8);
+ cmCTestGIT::RunProcess(builder, &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()
{
- const char* git = this->CommandLineTool.c_str();
+ std::string git = this->CommandLineTool;
// Use 'git update-index' to refresh the index w.r.t. the work tree.
- const char* git_update_index[] = { git, "update-index", "--refresh",
- nullptr };
+ std::vector<std::string> git_update_index = { git, "update-index",
+ "--refresh" };
OutputLogger ui_out(this->Log, "ui-out> ");
OutputLogger ui_err(this->Log, "ui-err> ");
- this->RunChild(git_update_index, &ui_out, &ui_err, nullptr,
+ this->RunChild(git_update_index, &ui_out, &ui_err, "",
cmProcessOutput::UTF8);
// Use 'git diff-index' to get modified files.
- const char* git_diff_index[] = { git, "diff-index", "-z",
- "HEAD", "--", nullptr };
+ std::vector<std::string> git_diff_index = { git, "diff-index", "-z", "HEAD",
+ "--" };
DiffParser out(this, "di-out> ");
OutputLogger err(this->Log, "di-err> ");
- this->RunChild(git_diff_index, &out, &err, nullptr, cmProcessOutput::UTF8);
+ this->RunChild(git_diff_index, &out, &err, "", cmProcessOutput::UTF8);
for (Change const& c : out.Changes) {
this->DoModification(PathModified, c.Path);
diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx
index 02837ba..e1a945d 100644
--- a/Source/CTest/cmCTestHG.cxx
+++ b/Source/CTest/cmCTestHG.cxx
@@ -95,8 +95,8 @@ private:
std::string cmCTestHG::GetWorkingRevision()
{
// Run plumbing "hg identify" to get work tree revision.
- const char* hg = this->CommandLineTool.c_str();
- const char* hg_identify[] = { hg, "identify", "-i", nullptr };
+ std::string hg = this->CommandLineTool;
+ std::vector<std::string> hg_identify = { hg, "identify", "-i" };
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.
{
- const char* hg = this->CommandLineTool.c_str();
- const char* hg_pull[] = { hg, "pull", "-v", nullptr };
+ std::string hg = this->CommandLineTool;
+ std::vector<std::string> hg_pull = { hg, "pull", "-v" };
OutputLogger out(this->Log, "pull-out> ");
OutputLogger err(this->Log, "pull-err> ");
- this->RunChild(&hg_pull[0], &out, &err);
+ this->RunChild(hg_pull, &out, &err);
}
// TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY)
- std::vector<char const*> hg_update;
+ std::vector<std::string> hg_update;
hg_update.push_back(this->CommandLineTool.c_str());
hg_update.push_back("update");
hg_update.push_back("-v");
@@ -147,16 +147,11 @@ bool cmCTestHG::UpdateImpl()
opts = this->CTest->GetCTestConfiguration("HGUpdateOptions");
}
std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
- for (std::string const& arg : args) {
- hg_update.push_back(arg.c_str());
- }
-
- // Sentinel argument.
- hg_update.push_back(nullptr);
+ cm::append(hg_update, args);
OutputLogger out(this->Log, "update-out> ");
OutputLogger err(this->Log, "update-err> ");
- return this->RunUpdateCommand(hg_update.data(), &out, &err);
+ return this->RunUpdateCommand(hg_update, &out, &err);
}
class cmCTestHG::LogParser
@@ -277,8 +272,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;
- const char* hg = this->CommandLineTool.c_str();
- const char* hgXMLTemplate = "<logentry\n"
+ std::string hg = this->CommandLineTool;
+ std::string hgXMLTemplate = "<logentry\n"
" revision=\"{node|short}\">\n"
" <author>{author|person}</author>\n"
" <email>{author|email}</email>\n"
@@ -288,10 +283,8 @@ bool cmCTestHG::LoadRevisions()
" <file_adds>{file_adds}</file_adds>\n"
" <file_dels>{file_dels}</file_dels>\n"
"</logentry>\n";
- const char* hg_log[] = {
- hg, "log", "--removed", "-r", range.c_str(),
- "--template", hgXMLTemplate, nullptr
- };
+ std::vector<std::string> hg_log = { hg, "log", "--removed", "-r",
+ range, "--template", hgXMLTemplate };
LogParser out(this, "log-out> ");
out.Process("<?xml version=\"1.0\"?>\n"
@@ -305,8 +298,8 @@ bool cmCTestHG::LoadRevisions()
bool cmCTestHG::LoadModifications()
{
// Use 'hg status' to get modified files.
- const char* hg = this->CommandLineTool.c_str();
- const char* hg_status[] = { hg, "status", nullptr };
+ std::string hg = this->CommandLineTool;
+ std::vector<std::string> hg_status = { hg, "status" };
StatusParser out(this, "status-out> ");
OutputLogger err(this->Log, "status-err> ");
this->RunChild(hg_status, &out, &err);
diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx
index 4a33869..6b13ad1 100644
--- a/Source/CTest/cmCTestLaunch.cxx
+++ b/Source/CTest/cmCTestLaunch.cxx
@@ -2,13 +2,19 @@
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"
@@ -17,6 +23,9 @@
#include "cmStateSnapshot.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVProcessChain.h"
+#include "cmUVStream.h"
#include "cmake.h"
#ifdef _WIN32
@@ -28,8 +37,6 @@
cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv)
{
- this->Process = nullptr;
-
if (!this->ParseArguments(argc, argv)) {
return;
}
@@ -40,13 +47,9 @@ cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv)
this->ScrapeRulesLoaded = false;
this->HaveOut = false;
this->HaveErr = false;
- this->Process = cmsysProcess_New();
}
-cmCTestLaunch::~cmCTestLaunch()
-{
- cmsysProcess_Delete(this->Process);
-}
+cmCTestLaunch::~cmCTestLaunch() = default;
bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
{
@@ -113,15 +116,12 @@ bool cmCTestLaunch::ParseArguments(int argc, const char* const* argv)
// Extract the real command line.
if (arg0) {
- this->RealArgC = argc - arg0;
- this->RealArgV = argv + arg0;
- for (int i = 0; i < this->RealArgC; ++i) {
- this->HandleRealArg(this->RealArgV[i]);
+ for (int i = 0; i < argc - arg0; ++i) {
+ this->RealArgV.emplace_back((argv + arg0)[i]);
+ this->HandleRealArg((argv + arg0)[i]);
}
return true;
}
- this->RealArgC = 0;
- this->RealArgV = nullptr;
std::cerr << "No launch/command separator ('--') found!\n";
return false;
}
@@ -151,17 +151,22 @@ void cmCTestLaunch::RunChild()
}
// Prepare to run the real command.
- cmsysProcess* cp = this->Process;
- cmsysProcess_SetCommand(cp, this->RealArgV);
+ cmUVProcessChainBuilder builder;
+ builder.AddCommand(this->RealArgV);
cmsys::ofstream fout;
cmsys::ofstream ferr;
if (this->Reporter.Passthru) {
// In passthru mode we just share the output pipes.
- cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1);
- cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1);
+ builder
+ .SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT,
+ cm_fileno(stdout))
+ .SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR,
+ cm_fileno(stderr));
} 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);
}
@@ -174,51 +179,65 @@ void cmCTestLaunch::RunChild()
#endif
// Run the real command.
- cmsysProcess_Execute(cp);
+ auto chain = builder.Start();
// 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) {
- 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());
- }
+ 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);
}
// Wait for the real command to finish.
- cmsysProcess_WaitForExit(cp, nullptr);
- this->Reporter.ExitCode = cmsysProcess_GetExitValue(cp);
+ 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);
+ }
}
int cmCTestLaunch::Run()
{
- if (!this->Process) {
- std::cerr << "Could not allocate cmsysProcess instance!\n";
- return -1;
- }
-
this->RunChild();
if (this->CheckResults()) {
@@ -226,7 +245,6 @@ int cmCTestLaunch::Run()
}
this->LoadConfig();
- this->Reporter.Process = this->Process;
this->Reporter.WriteXML();
return this->Reporter.ExitCode;
diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h
index c5a6476..ef21a26 100644
--- a/Source/CTest/cmCTestLaunch.h
+++ b/Source/CTest/cmCTestLaunch.h
@@ -43,15 +43,12 @@ private:
bool ParseArguments(int argc, const char* const* argv);
// The real command line appearing after launcher arguments.
- int RealArgC;
- const char* const* RealArgV;
+ std::vector<std::string> 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;
diff --git a/Source/CTest/cmCTestLaunchReporter.cxx b/Source/CTest/cmCTestLaunchReporter.cxx
index 149ba5d..4b4e5c5 100644
--- a/Source/CTest/cmCTestLaunchReporter.cxx
+++ b/Source/CTest/cmCTestLaunchReporter.cxx
@@ -2,8 +2,9 @@
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"
@@ -22,6 +23,7 @@
cmCTestLaunchReporter::cmCTestLaunchReporter()
{
this->Passthru = true;
+ this->Status.Finished = true;
this->ExitCode = 1;
this->CWD = cmSystemTools::GetCurrentWorkingDirectory();
@@ -231,35 +233,23 @@ void cmCTestLaunchReporter::WriteXMLResult(cmXMLElement& e2)
// ExitCondition
cmXMLElement e4(e3, "ExitCondition");
- 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;
+ 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");
}
}
diff --git a/Source/CTest/cmCTestLaunchReporter.h b/Source/CTest/cmCTestLaunchReporter.h
index 4be0d9b..2bb78f8 100644
--- a/Source/CTest/cmCTestLaunchReporter.h
+++ b/Source/CTest/cmCTestLaunchReporter.h
@@ -10,6 +10,8 @@
#include "cmsys/RegularExpression.hxx"
+#include "cmUVProcessChain.h"
+
class cmXMLElement;
/** \class cmCTestLaunchReporter
@@ -48,7 +50,7 @@ public:
void ComputeFileNames();
bool Passthru;
- struct cmsysProcess_s* Process;
+ cmUVProcessChain::Status Status;
int ExitCode;
// Temporary log files for stdout and stderr of real command.
diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx
index 0e002b9..5d71b84 100644
--- a/Source/CTest/cmCTestP4.cxx
+++ b/Source/CTest/cmCTestP4.cxx
@@ -149,17 +149,16 @@ cmCTestP4::User cmCTestP4::GetUserData(const std::string& username)
auto it = this->Users.find(username);
if (it == this->Users.end()) {
- std::vector<char const*> p4_users;
+ std::vector<std::string> 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.c_str());
- p4_users.push_back(nullptr);
+ p4_users.push_back(username);
UserParser out(this, "users-out> ");
OutputLogger err(this->Log, "users-err> ");
- this->RunChild(p4_users.data(), &out, &err);
+ this->RunChild(p4_users, &out, &err);
// The user should now be added to the map. Search again.
it = this->Users.find(username);
@@ -303,10 +302,10 @@ private:
}
};
-void cmCTestP4::SetP4Options(std::vector<char const*>& CommandOptions)
+void cmCTestP4::SetP4Options(std::vector<std::string>& CommandOptions)
{
if (this->P4Options.empty()) {
- const char* p4 = this->CommandLineTool.c_str();
+ std::string p4 = this->CommandLineTool;
this->P4Options.emplace_back(p4);
// The CTEST_P4_CLIENT variable sets the P4 client used when issuing
@@ -328,15 +327,12 @@ void cmCTestP4::SetP4Options(std::vector<char const*>& CommandOptions)
cm::append(this->P4Options, cmSystemTools::ParseArguments(opts));
}
- CommandOptions.clear();
- for (std::string const& o : this->P4Options) {
- CommandOptions.push_back(o.c_str());
- }
+ CommandOptions = this->P4Options;
}
std::string cmCTestP4::GetWorkingRevision()
{
- std::vector<char const*> p4_identify;
+ std::vector<std::string> p4_identify;
this->SetP4Options(p4_identify);
p4_identify.push_back("changes");
@@ -345,14 +341,13 @@ std::string cmCTestP4::GetWorkingRevision()
p4_identify.push_back("-t");
std::string source = this->SourceDirectory + "/...#have";
- p4_identify.push_back(source.c_str());
- p4_identify.push_back(nullptr);
+ p4_identify.push_back(source);
std::string rev;
IdentifyParser out(this, "p4_changes-out> ", rev);
OutputLogger err(this->Log, "p4_changes-err> ");
- bool result = this->RunChild(p4_identify.data(), &out, &err);
+ bool result = this->RunChild(p4_identify, &out, &err);
// If there was a problem contacting the server return "<unknown>"
if (!result) {
@@ -388,7 +383,7 @@ bool cmCTestP4::NoteNewRevision()
bool cmCTestP4::LoadRevisions()
{
- std::vector<char const*> p4_changes;
+ std::vector<std::string> p4_changes;
this->SetP4Options(p4_changes);
// Use 'p4 changes ...@old,new' to get a list of changelists
@@ -409,38 +404,36 @@ bool cmCTestP4::LoadRevisions()
.append(this->NewRevision);
p4_changes.push_back("changes");
- p4_changes.push_back(range.c_str());
- p4_changes.push_back(nullptr);
+ p4_changes.push_back(range);
ChangesParser out(this, "p4_changes-out> ");
OutputLogger err(this->Log, "p4_changes-err> ");
this->ChangeLists.clear();
- this->RunChild(p4_changes.data(), &out, &err);
+ this->RunChild(p4_changes, &out, &err);
if (this->ChangeLists.empty()) {
return true;
}
// p4 describe -s ...@1111111,2222222
- std::vector<char const*> p4_describe;
+ std::vector<std::string> 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.c_str());
- p4_describe.push_back(nullptr);
+ p4_describe.push_back(i);
DescribeParser outDescribe(this, "p4_describe-out> ");
OutputLogger errDescribe(this->Log, "p4_describe-err> ");
- this->RunChild(p4_describe.data(), &outDescribe, &errDescribe);
+ this->RunChild(p4_describe, &outDescribe, &errDescribe);
}
return true;
}
bool cmCTestP4::LoadModifications()
{
- std::vector<char const*> p4_diff;
+ std::vector<std::string> p4_diff;
this->SetP4Options(p4_diff);
p4_diff.push_back("diff");
@@ -448,12 +441,11 @@ 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.c_str());
- p4_diff.push_back(nullptr);
+ p4_diff.push_back(source);
DiffParser out(this, "p4_diff-out> ");
OutputLogger err(this->Log, "p4_diff-err> ");
- this->RunChild(p4_diff.data(), &out, &err);
+ this->RunChild(p4_diff, &out, &err);
return true;
}
@@ -461,17 +453,14 @@ bool cmCTestP4::UpdateCustom(const std::string& custom)
{
cmList p4_custom_command{ custom, cmList::EmptyElements::Yes };
- 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);
+ std::vector<std::string> p4_custom;
+ p4_custom.reserve(p4_custom_command.size());
+ cm::append(p4_custom, p4_custom_command);
OutputLogger custom_out(this->Log, "p4_customsync-out> ");
OutputLogger custom_err(this->Log, "p4_customsync-err> ");
- return this->RunUpdateCommand(p4_custom.data(), &custom_out, &custom_err);
+ return this->RunUpdateCommand(p4_custom, &custom_out, &custom_err);
}
bool cmCTestP4::UpdateImpl()
@@ -488,7 +477,7 @@ bool cmCTestP4::UpdateImpl()
return false;
}
- std::vector<char const*> p4_sync;
+ std::vector<std::string> p4_sync;
this->SetP4Options(p4_sync);
p4_sync.push_back("sync");
@@ -499,9 +488,7 @@ bool cmCTestP4::UpdateImpl()
opts = this->CTest->GetCTestConfiguration("P4UpdateOptions");
}
std::vector<std::string> args = cmSystemTools::ParseArguments(opts);
- for (std::string const& arg : args) {
- p4_sync.push_back(arg.c_str());
- }
+ cm::append(p4_sync, args);
std::string source = this->SourceDirectory + "/...";
@@ -515,11 +502,10 @@ bool cmCTestP4::UpdateImpl()
source.append("@\"").append(date).append("\"");
}
- p4_sync.push_back(source.c_str());
- p4_sync.push_back(nullptr);
+ p4_sync.push_back(source);
OutputLogger out(this->Log, "p4_sync-out> ");
OutputLogger err(this->Log, "p4_sync-err> ");
- return this->RunUpdateCommand(p4_sync.data(), &out, &err);
+ return this->RunUpdateCommand(p4_sync, &out, &err);
}
diff --git a/Source/CTest/cmCTestP4.h b/Source/CTest/cmCTestP4.h
index 1889520..827caa1 100644
--- a/Source/CTest/cmCTestP4.h
+++ b/Source/CTest/cmCTestP4.h
@@ -39,7 +39,7 @@ private:
std::vector<std::string> P4Options;
User GetUserData(const std::string& username);
- void SetP4Options(std::vector<char const*>& options);
+ void SetP4Options(std::vector<std::string>& options);
std::string GetWorkingRevision();
bool NoteOldRevision() override;
diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx
index 91a1177..14bc510 100644
--- a/Source/CTest/cmCTestSVN.cxx
+++ b/Source/CTest/cmCTestSVN.cxx
@@ -33,7 +33,7 @@ cmCTestSVN::~cmCTestSVN() = default;
void cmCTestSVN::CleanupImpl()
{
- std::vector<const char*> svn_cleanup;
+ std::vector<std::string> 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<const char*> svn_info;
+ std::vector<std::string> svn_info;
svn_info.push_back("info");
- svn_info.push_back(svninfo.LocalPath.c_str());
+ svn_info.push_back(svninfo.LocalPath);
std::string rev;
InfoParser out(this, "info-out> ", rev, svninfo);
OutputLogger err(this->Log, "info-err> ");
@@ -251,26 +251,24 @@ bool cmCTestSVN::UpdateImpl()
args.push_back("-r{" + this->GetNightlyTime() + " +0000}");
}
- std::vector<char const*> svn_update;
+ std::vector<std::string> svn_update;
svn_update.push_back("update");
- for (std::string const& arg : args) {
- svn_update.push_back(arg.c_str());
- }
+ cm::append(svn_update, args);
UpdateParser out(this, "up-out> ");
OutputLogger err(this->Log, "up-err> ");
return this->RunSVNCommand(svn_update, &out, &err);
}
-bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters,
+bool cmCTestSVN::RunSVNCommand(std::vector<std::string> const& parameters,
OutputParser* out, OutputParser* err)
{
if (parameters.empty()) {
return false;
}
- std::vector<char const*> args;
- args.push_back(this->CommandLineTool.c_str());
+ std::vector<std::string> args;
+ args.push_back(this->CommandLineTool);
cm::append(args, parameters);
args.push_back("--non-interactive");
@@ -278,16 +276,12 @@ bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters,
std::vector<std::string> parsedUserOptions =
cmSystemTools::ParseArguments(userOptions);
- for (std::string const& opt : parsedUserOptions) {
- args.push_back(opt.c_str());
- }
-
- args.push_back(nullptr);
+ cm::append(args, parsedUserOptions);
- if (strcmp(parameters[0], "update") == 0) {
- return this->RunUpdateCommand(args.data(), out, err);
+ if (parameters[0] == "update") {
+ return this->RunUpdateCommand(args, out, err);
}
- return this->RunChild(args.data(), out, err);
+ return this->RunChild(args, out, err);
}
class cmCTestSVN::LogParser
@@ -393,7 +387,7 @@ bool cmCTestSVN::LoadRevisions(SVNInfo& svninfo)
}
// Run "svn log" to get all global revisions of interest.
- std::vector<const char*> svn_log;
+ std::vector<std::string> svn_log;
svn_log.push_back("log");
svn_log.push_back("--xml");
svn_log.push_back("-v");
@@ -472,7 +466,7 @@ private:
bool cmCTestSVN::LoadModifications()
{
// Run "svn status" which reports local modifications.
- std::vector<const char*> svn_status;
+ std::vector<std::string> svn_status;
svn_status.push_back("status");
StatusParser out(this, "status-out> ");
OutputLogger err(this->Log, "status-err> ");
@@ -534,7 +528,7 @@ bool cmCTestSVN::LoadRepositories()
this->RootInfo = &(this->Repositories.back());
// Run "svn status" to get the list of external repositories
- std::vector<const char*> svn_status;
+ std::vector<std::string> svn_status;
svn_status.push_back("status");
ExternalParser out(this, "external-out> ");
OutputLogger err(this->Log, "external-err> ");
diff --git a/Source/CTest/cmCTestSVN.h b/Source/CTest/cmCTestSVN.h
index 370d176..1485dc0 100644
--- a/Source/CTest/cmCTestSVN.h
+++ b/Source/CTest/cmCTestSVN.h
@@ -33,7 +33,7 @@ private:
bool NoteNewRevision() override;
bool UpdateImpl() override;
- bool RunSVNCommand(std::vector<char const*> const& parameters,
+ bool RunSVNCommand(std::vector<std::string> const& parameters,
OutputParser* out, OutputParser* err);
// Information about an SVN repository (root repository or external)
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index 461ad1a..48f8f6d 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -11,8 +11,9 @@
#include <cm/memory>
+#include <cm3p/uv.h>
+
#include "cmsys/Directory.hxx"
-#include "cmsys/Process.h"
#include "cmCTest.h"
#include "cmCTestBuildCommand.h"
@@ -40,6 +41,8 @@
#include "cmStateSnapshot.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVProcessChain.h"
#include "cmValue.h"
#include "cmake.h"
@@ -148,66 +151,65 @@ 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
- 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);
+ 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());
std::vector<char> out;
std::vector<char> err;
std::string line;
- int pipe =
- cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out, err);
- while (pipe != cmsysProcess_Pipe_None) {
+ auto pipe =
+ cmSystemTools::WaitForLine(&process.GetLoop(), outPipe, errPipe, line,
+ std::chrono::seconds(100), out, err);
+ while (pipe != cmSystemTools::WaitForLineResult::None) {
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
"Output: " << line << "\n");
- if (pipe == cmsysProcess_Pipe_STDERR) {
+ if (pipe == cmSystemTools::WaitForLineResult::STDERR) {
cmCTestLog(this->CTest, ERROR_MESSAGE, line << "\n");
- } else if (pipe == cmsysProcess_Pipe_STDOUT) {
+ } else if (pipe == cmSystemTools::WaitForLineResult::STDOUT) {
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, line << "\n");
}
- pipe = cmSystemTools::WaitForLine(cp, line, std::chrono::seconds(100), out,
- err);
+ pipe =
+ cmSystemTools::WaitForLine(&process.GetLoop(), outPipe, errPipe, line,
+ std::chrono::seconds(100), out, err);
}
// Properly handle output of the build command
- cmsysProcess_WaitForExit(cp, nullptr);
- int result = cmsysProcess_GetState(cp);
+ process.Wait();
+ auto const& status = process.GetStatus(0);
+ auto result = status.GetException();
int retVal = 0;
bool failed = false;
- 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;
+ 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;
}
- cmsysProcess_Delete(cp);
if (failed) {
std::ostringstream message;
message << "Error running command: [";
- message << result << "] ";
+ message << static_cast<int>(result.first) << "] ";
for (const char* arg : argv) {
if (arg) {
message << arg << " ";
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index 1934d8c..77af889 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -309,6 +309,9 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(
// specify target
::curl_easy_setopt(curl, CURLOPT_URL, upload_as.c_str());
+ // follow redirects
+ ::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
+
// CURLAUTH_BASIC is default, and here we allow additional methods,
// including more secure ones
::curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx
index 609ccba..cbbb5a5 100644
--- a/Source/CTest/cmCTestVC.cxx
+++ b/Source/CTest/cmCTestVC.cxx
@@ -7,10 +7,9 @@
#include <sstream>
#include <vector>
-#include "cmsys/Process.h"
-
#include "cmCTest.h"
#include "cmSystemTools.h"
+#include "cmUVProcessChain.h"
#include "cmValue.h"
#include "cmXMLWriter.h"
@@ -55,18 +54,12 @@ 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(vc_co.data(), &out, &err, parent.c_str());
+ bool result = this->RunChild(args, &out, &err, parent);
this->Log << "--- End Initial Checkout ---\n";
if (!result) {
cmCTestLog(this->CTest, ERROR_MESSAGE,
@@ -75,35 +68,35 @@ bool cmCTestVC::InitialCheckout(const std::string& command)
return result;
}
-bool cmCTestVC::RunChild(char const* const* cmd, OutputParser* out,
- OutputParser* err, const char* workDir,
- Encoding encoding)
+bool cmCTestVC::RunChild(const std::vector<std::string>& cmd,
+ OutputParser* out, OutputParser* err,
+ std::string workDir, Encoding encoding)
{
this->Log << cmCTestVC::ComputeCommandLine(cmd) << "\n";
- 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;
+ 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;
}
-std::string cmCTestVC::ComputeCommandLine(char const* const* cmd)
+std::string cmCTestVC::ComputeCommandLine(const std::vector<std::string>& cmd)
{
std::ostringstream line;
const char* sep = "";
- for (const char* const* arg = cmd; *arg; ++arg) {
- line << sep << "\"" << *arg << "\"";
+ for (auto const& arg : cmd) {
+ line << sep << "\"" << arg << "\"";
sep = " ";
}
return line.str();
}
-bool cmCTestVC::RunUpdateCommand(char const* const* cmd, OutputParser* out,
- OutputParser* err, Encoding encoding)
+bool cmCTestVC::RunUpdateCommand(const std::vector<std::string>& cmd,
+ OutputParser* out, OutputParser* err,
+ Encoding encoding)
{
// Report the command line.
this->UpdateCommandLine = this->ComputeCommandLine(cmd);
@@ -113,7 +106,7 @@ bool cmCTestVC::RunUpdateCommand(char const* const* cmd, OutputParser* out,
}
// Run the command.
- return this->RunChild(cmd, out, err, nullptr, encoding);
+ return this->RunChild(cmd, out, err, "", encoding);
}
std::string cmCTestVC::GetNightlyTime()
diff --git a/Source/CTest/cmCTestVC.h b/Source/CTest/cmCTestVC.h
index 7b03d10..dd5456d 100644
--- a/Source/CTest/cmCTestVC.h
+++ b/Source/CTest/cmCTestVC.h
@@ -6,6 +6,7 @@
#include <iosfwd>
#include <string>
+#include <vector>
#include "cmProcessOutput.h"
#include "cmProcessTools.h"
@@ -108,15 +109,15 @@ protected:
};
/** Convert a list of arguments to a human-readable command line. */
- static std::string ComputeCommandLine(char const* const* cmd);
+ static std::string ComputeCommandLine(const std::vector<std::string>& cmd);
/** Run a command line and send output to given parsers. */
- bool RunChild(char const* const* cmd, OutputParser* out, OutputParser* err,
- const char* workDir = nullptr,
+ bool RunChild(const std::vector<std::string>& cmd, OutputParser* out,
+ OutputParser* err, std::string workDir = {},
Encoding encoding = cmProcessOutput::Auto);
/** Run VC update command line and send output to given parsers. */
- bool RunUpdateCommand(char const* const* cmd, OutputParser* out,
+ bool RunUpdateCommand(const std::vector<std::string>& cmd, OutputParser* out,
OutputParser* err = nullptr,
Encoding encoding = cmProcessOutput::Auto);
diff --git a/Source/LexerParser/cmCTestResourceGroupsLexer.cxx b/Source/LexerParser/cmCTestResourceGroupsLexer.cxx
index 85b379b..f1d351a 100644
--- a/Source/LexerParser/cmCTestResourceGroupsLexer.cxx
+++ b/Source/LexerParser/cmCTestResourceGroupsLexer.cxx
@@ -667,6 +667,10 @@ Modify cmCTestResourceGroupsLexer.cxx:
#include <cstddef>
+#ifndef _WIN32
+# include <termios.h>
+#endif
+
/*--------------------------------------------------------------------------*/
#define INITIAL 0
diff --git a/Source/LexerParser/cmCTestResourceGroupsLexer.in.l b/Source/LexerParser/cmCTestResourceGroupsLexer.in.l
index 2befa85..ac9cbaf 100644
--- a/Source/LexerParser/cmCTestResourceGroupsLexer.in.l
+++ b/Source/LexerParser/cmCTestResourceGroupsLexer.in.l
@@ -26,6 +26,10 @@ Modify cmCTestResourceGroupsLexer.cxx:
#include <cstddef>
+#ifndef _WIN32
+# include <termios.h>
+#endif
+
/*--------------------------------------------------------------------------*/
%}
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 6ff6437..36fd3a8 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -5,6 +5,7 @@
#include <algorithm>
#include <cctype>
#include <chrono>
+#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
@@ -24,13 +25,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)
@@ -64,6 +65,9 @@
#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"
@@ -1074,9 +1078,9 @@ int cmCTest::GetTestModelFromString(const std::string& str)
// ######################################################################
// ######################################################################
-int cmCTest::RunMakeCommand(const std::string& command, std::string& output,
- int* retVal, const char* dir, cmDuration timeout,
- std::ostream& ofs, Encoding encoding)
+bool 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);
@@ -1085,107 +1089,107 @@ int 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 (char const* arg : argv) {
- if (!arg) {
- break;
- }
+ for (auto const& arg : args) {
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, " \"" << arg << "\"");
}
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, std::endl);
// Now create process object
- 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);
+ 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());
// 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);
- while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) {
- processOutput.DecodeText(data, length, strdata);
- for (char& cc : strdata) {
- if (cc == 0) {
- cc = '\n';
+ 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';
+ }
}
- }
- output.append(strdata);
- while (output.size() > (tick * tick_len)) {
- tick++;
- cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, "." << std::flush);
- if (tick % tick_line_len == 0 && tick > 0) {
- cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
- " Size: " << int((double(output.size()) / 1024.0) + 1)
- << "K\n " << std::flush);
+ output.append(strdata);
+ while (output.size() > (tick * tick_len)) {
+ tick++;
+ cmCTestLog(this, HANDLER_PROGRESS_OUTPUT, "." << std::flush);
+ if (tick % tick_line_len == 0 && tick > 0) {
+ cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
+ " Size: " << int((double(output.size()) / 1024.0) + 1)
+ << "K\n " << std::flush);
+ }
}
- }
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
- cmCTestLogWrite(strdata.c_str(), strdata.size()));
- if (ofs) {
- ofs << cmCTestLogWrite(strdata.c_str(), strdata.size());
- }
- }
- 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_VERBOSE_OUTPUT,
+ cmCTestLogWrite(strdata.c_str(), strdata.size()));
+ if (ofs) {
+ ofs << cmCTestLogWrite(strdata.c_str(), strdata.size());
+ }
+ },
+ [this, &processOutput, &output, &ofs]() {
+ std::string strdata;
+ processOutput.DecodeText(std::string(), strdata);
+ if (!strdata.empty()) {
+ output.append(strdata);
+ cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
+ cmCTestLogWrite(strdata.c_str(), strdata.size()));
+ if (ofs) {
+ ofs << cmCTestLogWrite(strdata.c_str(), strdata.size());
+ }
+ }
+ });
+
+ bool finished = chain.Wait(static_cast<uint64_t>(timeout.count() * 1000.0));
cmCTestLog(this, HANDLER_PROGRESS_OUTPUT,
" Size of output: " << int(double(output.size()) / 1024.0) << "K"
<< std::endl);
- 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) {
+ 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 {
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);
}
- cmsysProcess_Delete(cp);
-
- return result;
+ return true;
}
// ######################################################################
@@ -1193,9 +1197,10 @@ int cmCTest::RunMakeCommand(const std::string& command, std::string& output,
// ######################################################################
// ######################################################################
-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 cmCTest::RunTest(const std::vector<std::string>& argv,
+ std::string* output, int* retVal, std::ostream* log,
+ cmDuration testTimeOut,
+ std::vector<std::string>* environment, Encoding encoding)
{
bool modifyEnv = (environment && !environment->empty());
@@ -1234,19 +1239,16 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
inst.SetStreams(&oss, &oss);
std::vector<std::string> args;
- 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);
+ for (auto const& i : argv) {
+ // make sure we pass the timeout in for any build and test
+ // invocations. Since --build-generator is required this is a
+ // good place to check for it, and to add the arguments in
+ if (i == "--build-generator" && timeout != cmCTest::MaxDuration() &&
+ timeout > cmDuration::zero()) {
+ args.emplace_back("--test-timeout");
+ args.push_back(std::to_string(cmDurationTo<unsigned int>(timeout)));
}
+ args.emplace_back(i);
}
if (log) {
*log << "* Run internal CTest" << std::endl;
@@ -1272,7 +1274,7 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
<< std::endl);
}
- return cmsysProcess_State_Exited;
+ return true;
}
std::vector<char> tempOutput;
if (output) {
@@ -1285,41 +1287,43 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
cmSystemTools::AppendEnv(*environment);
}
- cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, argv.data());
+ cmUVProcessChainBuilder builder;
+ builder.AddCommand(argv).SetMergedBuiltinStreams();
cmCTestLog(this, DEBUG, "Command is: " << argv[0] << std::endl);
- if (cmSystemTools::GetRunCommandHideConsole()) {
- cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
- }
+ auto chain = builder.Start();
- cmsysProcess_SetTimeout(cp, timeout.count());
- cmsysProcess_Execute(cp);
-
- char* data;
- int length;
cmProcessOutput processOutput(encoding);
- 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());
- }
- }
+ 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());
+ }
+ }
+ });
- cmsysProcess_WaitForExit(cp, nullptr);
+ bool complete = chain.Wait(static_cast<uint64_t>(timeout.count() * 1000.0));
processOutput.DecodeText(tempOutput, tempOutput);
if (output && tempOutput.begin() != tempOutput.end()) {
output->append(tempOutput.data(), tempOutput.size());
@@ -1327,33 +1331,41 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output,
cmCTestLog(this, HANDLER_VERBOSE_OUTPUT,
"-- Process completed" << std::endl);
- int result = cmsysProcess_GetState(cp);
+ bool result = false;
- 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;
+ 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;
}
- cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl);
}
- cmsysProcess_Delete(cp);
return result;
}
@@ -3471,49 +3483,70 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
stdOut->clear();
stdErr->clear();
- cmsysProcess* cp = cmsysProcess_New();
- cmsysProcess_SetCommand(cp, argv.data());
- cmsysProcess_SetWorkingDirectory(cp, dir);
- if (cmSystemTools::GetRunCommandHideConsole()) {
- cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ 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_SetTimeout(cp, timeout.count());
- cmsysProcess_Execute(cp);
std::vector<char> tempOutput;
+ bool outFinished = false;
+ cm::uv_pipe_ptr outStream;
std::vector<char> tempError;
- char* data;
- int length;
+ bool errFinished = false;
+ cm::uv_pipe_ptr errStream;
cmProcessOutput processOutput(encoding);
- 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);
- }
+ 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);
}
if (this->Impl->ExtraVerbose) {
+ std::string strdata;
processOutput.DecodeText(std::string(), strdata);
if (!strdata.empty()) {
cmSystemTools::Stdout(strdata);
}
}
- cmsysProcess_WaitForExit(cp, nullptr);
+ while (!timedOut && !chain.Finished()) {
+ uv_run(&chain.GetLoop(), UV_RUN_ONCE);
+ }
if (!tempOutput.empty()) {
processOutput.DecodeText(tempOutput, tempOutput);
stdOut->append(tempOutput.data(), tempOutput.size());
@@ -3524,32 +3557,32 @@ bool cmCTest::RunCommand(std::vector<std::string> const& args,
}
bool result = true;
- 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) {
+ if (timedOut) {
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;
}
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index 9a8d5a6..1644d84 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -254,10 +254,10 @@ public:
* Run command specialized for make and configure. Returns process status
* and retVal is return value or exception.
*/
- int RunMakeCommand(const std::string& command, std::string& output,
- int* retVal, const char* dir, cmDuration timeout,
- std::ostream& ofs,
- Encoding encoding = cmProcessOutput::Auto);
+ bool 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.
*/
- 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);
+ bool RunTest(const std::vector<std::string>& args, std::string* output,
+ int* retVal, std::ostream* logfile, cmDuration testTimeOut,
+ std::vector<std::string>* environment,
+ Encoding encoding = cmProcessOutput::Auto);
/**
* Get the handler object
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index ccd20a0..91395e2 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -538,11 +538,14 @@ cmComputeLinkInformation::GetSharedLibrariesLinked() const
bool cmComputeLinkInformation::Compute()
{
- // Skip targets that do not link.
+ // Skip targets that do not link or have link-like information consumers may
+ // need (namely modules).
if (!(this->Target->GetType() == cmStateEnums::EXECUTABLE ||
this->Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
this->Target->GetType() == cmStateEnums::MODULE_LIBRARY ||
- this->Target->GetType() == cmStateEnums::STATIC_LIBRARY)) {
+ this->Target->GetType() == cmStateEnums::STATIC_LIBRARY ||
+ this->Target->HaveCxx20ModuleSources() ||
+ this->Target->HaveFortranSources())) {
return false;
}
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index 3b98219..9b5f2b4 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -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,7 +16,9 @@
#include <cmext/algorithm>
#include <cmext/string_view>
-#include "cmsys/Process.h"
+#include <cm3p/uv.h>
+
+#include "cm_fileno.hxx"
#include "cmArgumentParser.h"
#include "cmExecutionStatus.h"
@@ -26,6 +28,9 @@
#include "cmProcessOutput.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVProcessChain.h"
+#include "cmUVStream.h"
namespace {
bool cmExecuteProcessCommandIsWhitespace(char c)
@@ -36,7 +41,7 @@ bool cmExecuteProcessCommandIsWhitespace(char c)
void cmExecuteProcessCommandFixText(std::vector<char>& output,
bool strip_trailing_whitespace);
void cmExecuteProcessCommandAppend(std::vector<char>& output, const char* data,
- int length);
+ std::size_t length);
}
// cmExecuteProcessCommand
@@ -143,57 +148,61 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
}
}
// Create a process instance.
- std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp_ptr(
- cmsysProcess_New(), cmsysProcess_Delete);
- cmsysProcess* cp = cp_ptr.get();
+ cmUVProcessChainBuilder builder;
// Set the command sequence.
for (std::vector<std::string> const& cmd : arguments.Commands) {
- 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());
+ builder.AddCommand(cmd);
}
// Set the process working directory.
if (!arguments.WorkingDirectory.empty()) {
- cmsysProcess_SetWorkingDirectory(cp, arguments.WorkingDirectory.c_str());
+ builder.SetWorkingDirectory(arguments.WorkingDirectory);
}
- // Always hide the process window.
- cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
-
// Check the output variables.
- bool merge_output = false;
+ std::unique_ptr<FILE, int (*)(FILE*)> inputFile(nullptr, fclose);
if (!arguments.InputFile.empty()) {
- cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDIN,
- arguments.InputFile.c_str());
+ inputFile.reset(cmsys::SystemTools::Fopen(arguments.InputFile, "rb"));
+ builder.SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT,
+ cm_fileno(inputFile.get()));
+ } else {
+ builder.SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT,
+ cm_fileno(stdin));
}
+
+ std::unique_ptr<FILE, int (*)(FILE*)> outputFile(nullptr, fclose);
if (!arguments.OutputFile.empty()) {
- cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDOUT,
- arguments.OutputFile.c_str());
+ outputFile.reset(cmsys::SystemTools::Fopen(arguments.OutputFile, "wb"));
+ builder.SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT,
+ cm_fileno(outputFile.get()));
+ } else {
+ if (arguments.OutputVariable == arguments.ErrorVariable &&
+ !arguments.ErrorVariable.empty()) {
+ builder.SetMergedBuiltinStreams();
+ } else {
+ builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
+ }
}
+
+ std::unique_ptr<FILE, int (*)(FILE*)> errorFile(nullptr, fclose);
if (!arguments.ErrorFile.empty()) {
if (arguments.ErrorFile == arguments.OutputFile) {
- merge_output = true;
+ builder.SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR,
+ cm_fileno(outputFile.get()));
} else {
- cmsysProcess_SetPipeFile(cp, cmsysProcess_Pipe_STDERR,
- arguments.ErrorFile.c_str());
+ errorFile.reset(cmsys::SystemTools::Fopen(arguments.ErrorFile, "wb"));
+ builder.SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR,
+ cm_fileno(errorFile.get()));
}
- }
- if (!arguments.OutputVariable.empty() &&
- arguments.OutputVariable == arguments.ErrorVariable) {
- merge_output = true;
- }
- if (merge_output) {
- cmsysProcess_SetOption(cp, cmsysProcess_Option_MergeOutput, 1);
+ } else if (arguments.ErrorVariable.empty() ||
+ (!arguments.ErrorVariable.empty() &&
+ arguments.OutputVariable != arguments.ErrorVariable)) {
+ builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
}
// Set the timeout if any.
- if (timeout >= 0) {
- cmsysProcess_SetTimeout(cp, timeout);
- }
+ int64_t timeoutMillis = static_cast<int64_t>(timeout * 1000.0);
bool echo_stdout = false;
bool echo_stderr = false;
@@ -241,36 +250,86 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
}
}
// Start the process.
- cmsysProcess_Execute(cp);
+ 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);
+ }
// Read the process output.
- std::vector<char> tempOutput;
- std::vector<char> tempError;
- int length;
- char* data;
- int p;
+ struct ReadData
+ {
+ bool Finished = false;
+ std::vector<char> Output;
+ cm::uv_pipe_ptr Stream;
+ };
+ ReadData outputData;
+ ReadData errorData;
cmProcessOutput processOutput(
cmProcessOutput::FindEncoding(arguments.Encoding));
std::string strdata;
- 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);
- }
- }
+
+ 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);
}
if (!arguments.OutputQuiet &&
(arguments.OutputVariable.empty() || arguments.EchoOutputVariable)) {
@@ -287,151 +346,102 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
}
}
- // All output has been read. Wait for the process to exit.
- cmsysProcess_WaitForExit(cp, nullptr);
- processOutput.DecodeText(tempOutput, tempOutput);
- processOutput.DecodeText(tempError, tempError);
+ // All output has been read.
+ processOutput.DecodeText(outputData.Output, outputData.Output);
+ processOutput.DecodeText(errorData.Output, errorData.Output);
// Fix the text in the output strings.
- cmExecuteProcessCommandFixText(tempOutput,
+ cmExecuteProcessCommandFixText(outputData.Output,
arguments.OutputStripTrailingWhitespace);
- cmExecuteProcessCommandFixText(tempError,
+ cmExecuteProcessCommandFixText(errorData.Output,
arguments.ErrorStripTrailingWhitespace);
// Store the output obtained.
- if (!arguments.OutputVariable.empty() && !tempOutput.empty()) {
+ if (!arguments.OutputVariable.empty() && !outputData.Output.empty()) {
status.GetMakefile().AddDefinition(arguments.OutputVariable,
- tempOutput.data());
+ outputData.Output.data());
}
- if (!merge_output && !arguments.ErrorVariable.empty() &&
- !tempError.empty()) {
+ if (arguments.ErrorVariable != arguments.OutputVariable &&
+ !arguments.ErrorVariable.empty() && !errorData.Output.empty()) {
status.GetMakefile().AddDefinition(arguments.ErrorVariable,
- tempError.data());
+ errorData.Output.data());
}
// Store the result of running the process.
if (!arguments.ResultVariable.empty()) {
- 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:
+ 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) {
status.GetMakefile().AddDefinition(
- arguments.ResultVariable, cmsysProcess_GetExceptionString(cp));
- break;
- case cmsysProcess_State_Error:
+ arguments.ResultVariable,
+ std::to_string(static_cast<int>(lastStatus->ExitStatus)));
+ } else {
status.GetMakefile().AddDefinition(arguments.ResultVariable,
- cmsysProcess_GetErrorString(cp));
- break;
- case cmsysProcess_State_Expired:
- status.GetMakefile().AddDefinition(
- arguments.ResultVariable, "Process terminated due to timeout");
- break;
+ exception.second);
+ }
}
}
// Store the result of running the processes.
if (!arguments.ResultsVariable.empty()) {
- 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;
- }
+ 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);
}
- 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;
+ }
+ status.GetMakefile().AddDefinition(arguments.ResultsVariable,
+ cmList::to_string(res));
}
}
- 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;
+ 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);
}
- case kwsysProcess_StateByIndex_Error:
- default:
- processStatus = "Error getting the child return code";
- break;
+ return "";
}
- return processStatus;
+ return cmStrCat("Abnormal exit with child return code: ",
+ exception.second);
};
if (arguments.CommandErrorIsFatal == "ANY"_s) {
bool ret = true;
- switch (cmsysProcess_GetState(cp)) {
- case cmsysProcess_State_Exited: {
- std::map<int, std::string> failureIndices;
- for (int i = 0; i < static_cast<int>(arguments.Commands.size()); ++i) {
- std::string processStatus = queryProcessStatusByIndex(i);
- if (!processStatus.empty()) {
- failureIndices[i] = processStatus;
- }
- if (!failureIndices.empty()) {
- std::ostringstream oss;
- oss << "failed command indexes:\n";
- for (auto const& e : failureIndices) {
- oss << " " << e.first + 1 << ": \"" << e.second << "\"\n";
- }
- status.SetError(oss.str());
- ret = false;
- }
+ if (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;
}
- } 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");
+ }
+ 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;
- break;
+ }
}
if (!ret) {
@@ -442,29 +452,23 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
if (arguments.CommandErrorIsFatal == "LAST"_s) {
bool ret = true;
- switch (cmsysProcess_GetState(cp)) {
- case cmsysProcess_State_Exited: {
+ 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 {
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();
@@ -507,7 +511,7 @@ void cmExecuteProcessCommandFixText(std::vector<char>& output,
}
void cmExecuteProcessCommandAppend(std::vector<char>& output, const char* data,
- int length)
+ std::size_t length)
{
#if defined(__APPLE__)
// HACK on Apple to work around bug with inserting at the
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 7799e1c..764618e 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -9042,6 +9042,15 @@ bool cmGeneratorTarget::HaveFortranSources(std::string const& config) const
});
}
+bool cmGeneratorTarget::HaveFortranSources() const
+{
+ auto sources = cmGeneratorTarget::GetAllConfigSources();
+ return std::any_of(sources.begin(), sources.end(),
+ [](AllConfigSource const& sf) -> bool {
+ return sf.Source->GetLanguage() == "Fortran"_s;
+ });
+}
+
bool cmGeneratorTarget::HaveCxx20ModuleSources(std::string* errorMessage) const
{
auto const& fs_names = this->Target->GetAllFileSetNames();
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index f347133..7673bef 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -1262,6 +1262,7 @@ public:
cmGeneratorTarget const* t2) const;
};
+ bool HaveFortranSources() const;
bool HaveFortranSources(std::string const& config) const;
// C++20 module support queries.
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 3b9d2fd..90b8839 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -407,8 +407,10 @@ bool cmGlobalXCodeGenerator::ProcessGeneratorToolsetField(
mf->IssueMessage(MessageType::FATAL_ERROR, e);
return false;
}
- if (this->XcodeBuildSystem == BuildSystem::Twelve &&
- this->XcodeVersion < 120) {
+ if ((this->XcodeBuildSystem == BuildSystem::Twelve &&
+ this->XcodeVersion < 120) ||
+ (this->XcodeBuildSystem == BuildSystem::One &&
+ this->XcodeVersion >= 140)) {
/* clang-format off */
std::string const& e = cmStrCat(
"Generator\n"
diff --git a/Source/cmList.h b/Source/cmList.h
index 0f875e7..1b94c2f 100644
--- a/Source/cmList.h
+++ b/Source/cmList.h
@@ -747,8 +747,10 @@ public:
ExpandElements expandElements = ExpandElements::Yes,
EmptyElements emptyElements = EmptyElements::No)
{
- this->insert(this->begin() + this->ComputeInsertIndex(index), first, last,
- expandElements, emptyElements);
+ auto const offset =
+ static_cast<difference_type>(this->ComputeInsertIndex(index));
+ this->insert(this->begin() + offset, first, last, expandElements,
+ emptyElements);
return *this;
}
template <typename InputIterator>
@@ -1186,13 +1188,13 @@ private:
auto size = container.size();
insertPos = cmList::Insert(container, insertPos, *first,
expandElements, emptyElements);
- insertPos += container.size() - size;
+ insertPos += static_cast<decltype(delta)>(container.size() - size);
}
} else {
for (; first != last; ++first) {
if (!first->empty() || emptyElements == EmptyElements::Yes) {
insertPos = container.insert(insertPos, *first);
- insertPos++;
+ ++insertPos;
}
}
}
diff --git a/Source/cmProcessTools.cxx b/Source/cmProcessTools.cxx
index 9e7854b..1dd1dce 100644
--- a/Source/cmProcessTools.cxx
+++ b/Source/cmProcessTools.cxx
@@ -2,48 +2,68 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmProcessTools.h"
+#include <algorithm>
+#include <iterator>
#include <ostream>
-#include "cmsys/Process.h"
+#include <cm3p/uv.h>
#include "cmProcessOutput.h"
+#include "cmUVHandlePtr.h"
+#include "cmUVStream.h"
-void cmProcessTools::RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
- OutputParser* err, Encoding encoding)
+std::vector<cmUVProcessChain::Status> cmProcessTools::RunProcess(
+ cmUVProcessChainBuilder& builder, 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;
- 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;
+ 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;
+ }
}
- } 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;
+ },
+ [&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;
+ }
}
- }
+ },
+ [&err]() { err = nullptr; });
+ while (out || err || !chain.Finished()) {
+ uv_run(&chain.GetLoop(), UV_RUN_ONCE);
}
- 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);
+
+ 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;
}
cmProcessTools::LineParser::LineParser(char sep, bool ignoreCR)
diff --git a/Source/cmProcessTools.h b/Source/cmProcessTools.h
index 74ec5e0..2bdabea 100644
--- a/Source/cmProcessTools.h
+++ b/Source/cmProcessTools.h
@@ -7,8 +7,10 @@
#include <cstring>
#include <iosfwd>
#include <string>
+#include <vector>
#include "cmProcessOutput.h"
+#include "cmUVProcessChain.h"
/** \class cmProcessTools
* \brief Helper classes for process output parsing
@@ -81,7 +83,7 @@ public:
};
/** Run a process and send output to given parsers. */
- static void RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
- OutputParser* err = nullptr,
- Encoding encoding = cmProcessOutput::Auto);
+ static std::vector<cmUVProcessChain::Status> RunProcess(
+ cmUVProcessChainBuilder& builder, OutputParser* out,
+ OutputParser* err = nullptr, Encoding encoding = cmProcessOutput::Auto);
};
diff --git a/Source/cmString.hxx b/Source/cmString.hxx
index 86b21c8..1994c2c 100644
--- a/Source/cmString.hxx
+++ b/Source/cmString.hxx
@@ -493,8 +493,8 @@ public:
char ch)
{
std::string out;
- out.reserve((first - this->view_.begin()) + count2 +
- (this->view_.end() - last));
+ out.reserve(static_cast<size_type>(first - this->view_.begin()) + count2 +
+ static_cast<size_type>(this->view_.end() - last));
out.append(this->view_.begin(), first);
out.append(count2, ch);
out.append(last, this->view_.end());
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 2bdc928..fe421ba 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -25,12 +25,17 @@
#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)
@@ -59,12 +64,14 @@
#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>
@@ -568,85 +575,113 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
const char* dir, OutputOption outputflag,
cmDuration timeout, Encoding encoding)
{
- 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);
+ cmUVProcessChainBuilder builder;
+ builder.AddCommand(command);
+ if (dir) {
+ builder.SetWorkingDirectory(dir);
}
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)) {
- cmsysProcess_SetOption(cp, cmsysProcess_Option_MergeOutput, 1);
+ builder.SetMergedBuiltinStreams();
captureStdErr = nullptr;
+ } else {
+ builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
+ .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
}
assert(!captureStdErr || captureStdErr != captureStdOut);
- cmsysProcess_SetTimeout(cp, timeout.count());
- cmsysProcess_Execute(cp);
+ 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);
+ }
std::vector<char> tempStdOut;
std::vector<char> tempStdErr;
- char* data;
- int length;
- int pipe;
+ cm::uv_pipe_ptr outStream;
+ bool outFinished = true;
+ cm::uv_pipe_ptr errStream;
+ bool errFinished = true;
cmProcessOutput processOutput(encoding);
- std::string strdata;
+ std::unique_ptr<cmUVStreamReadHandle> outputHandle;
+ std::unique_ptr<cmUVStreamReadHandle> errorHandle;
if (outputflag != OUTPUT_PASSTHROUGH &&
(captureStdOut || captureStdErr || outputflag != OUTPUT_NONE)) {
- 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] = ' ';
- }
- }
+ 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 = ' ';
+ }
+ }
- 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);
- }
- }
- }
+ 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 (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);
- }
+ 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);
}
}
- cmsysProcess_WaitForExit(cp, nullptr);
+ while (!timedOut && !(chain.Finished() && outFinished && errFinished)) {
+ uv_run(&chain.GetLoop(), UV_RUN_ONCE);
+ }
if (captureStdOut) {
captureStdOut->assign(tempStdOut.begin(), tempStdOut.end());
@@ -658,37 +693,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
}
bool result = true;
- if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
- if (retVal) {
- *retVal = cmsysProcess_GetExitValue(cp);
- } else {
- if (cmsysProcess_GetExitValue(cp) != 0) {
- result = false;
- }
- }
- } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) {
- const char* exception_str = cmsysProcess_GetExceptionString(cp);
- if (outputflag != OUTPUT_NONE) {
- std::cerr << exception_str << std::endl;
- }
- if (captureStdErr) {
- captureStdErr->append(exception_str, strlen(exception_str));
- } else if (captureStdOut) {
- captureStdOut->append(exception_str, strlen(exception_str));
- }
- result = false;
- } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
- const char* error_str = cmsysProcess_GetErrorString(cp);
- if (outputflag != OUTPUT_NONE) {
- std::cerr << error_str << std::endl;
- }
- if (captureStdErr) {
- captureStdErr->append(error_str, strlen(error_str));
- } else if (captureStdOut) {
- captureStdOut->append(error_str, strlen(error_str));
- }
- result = false;
- } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) {
+ if (timedOut) {
const char* error_str = "Process terminated due to timeout\n";
if (outputflag != OUTPUT_NONE) {
std::cerr << error_str << std::endl;
@@ -697,9 +702,34 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
captureStdErr->append(error_str, strlen(error_str));
}
result = false;
+ } else {
+ auto const& status = chain.GetStatus(0);
+ auto exception = status.GetException();
+
+ switch (exception.first) {
+ case cmUVProcessChain::ExceptionCode::None:
+ if (retVal) {
+ *retVal = static_cast<int>(status.ExitStatus);
+ } else {
+ if (status.ExitStatus != 0) {
+ result = false;
+ }
+ }
+ break;
+ default: {
+ if (outputflag != OUTPUT_NONE) {
+ std::cerr << exception.second << std::endl;
+ }
+ if (captureStdErr) {
+ captureStdErr->append(exception.second);
+ } else if (captureStdOut) {
+ captureStdOut->append(exception.second);
+ }
+ result = false;
+ } break;
+ }
}
- cmsysProcess_Delete(cp);
return result;
}
@@ -2213,9 +2243,10 @@ bool cmSystemTools::ListTar(const std::string& outFileName,
#endif
}
-int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
- cmDuration timeout, std::vector<char>& out,
- std::vector<char>& err)
+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)
{
line.clear();
auto outiter = out.begin();
@@ -2237,7 +2268,7 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
line.append(out.data(), length);
}
out.erase(out.begin(), outiter + 1);
- return cmsysProcess_Pipe_STDOUT;
+ return WaitForLineResult::STDOUT;
}
}
@@ -2255,33 +2286,66 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
line.append(err.data(), length);
}
err.erase(err.begin(), erriter + 1);
- return cmsysProcess_Pipe_STDERR;
+ return WaitForLineResult::STDERR;
}
}
// No newlines found. Wait for more data from the process.
- int length;
- char* data;
- double timeoutAsDbl = timeout.count();
- int pipe =
- cmsysProcess_WaitForData(process, &data, &length, &timeoutAsDbl);
- if (pipe == cmsysProcess_Pipe_Timeout) {
+ 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) {
// Timeout has been exceeded.
- return pipe;
+ return WaitForLineResult::Timeout;
}
- if (pipe == cmsysProcess_Pipe_STDOUT) {
- processOutput.DecodeText(data, length, strdata, 1);
+ if (outData.Read) {
+ processOutput.DecodeText(outData.Buffer.data(), outData.Buffer.size(),
+ 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 (pipe == cmsysProcess_Pipe_STDERR) {
- processOutput.DecodeText(data, length, strdata, 2);
+ } else if (errData.Read) {
+ processOutput.DecodeText(errData.Buffer.data(), errData.Buffer.size(),
+ 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 (pipe == cmsysProcess_Pipe_None) {
+ } else if (outData.Finished && errData.Finished) {
// Both stdout and stderr pipes have broken. Return leftover data.
processOutput.DecodeText(std::string(), strdata, 1);
if (!strdata.empty()) {
@@ -2298,14 +2362,20 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
if (!out.empty()) {
line.append(out.data(), outiter - out.begin());
out.erase(out.begin(), out.end());
- return cmsysProcess_Pipe_STDOUT;
+ return WaitForLineResult::STDOUT;
}
if (!err.empty()) {
line.append(err.data(), erriter - err.begin());
err.erase(err.begin(), err.end());
- return cmsysProcess_Pipe_STDERR;
+ return WaitForLineResult::STDERR;
}
- return cmsysProcess_Pipe_None;
+ return WaitForLineResult::None;
+ }
+ if (!outData.Finished) {
+ uv_read_stop(outPipe);
+ }
+ if (!errData.Finished) {
+ uv_read_stop(errPipe);
}
}
}
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 9563fd6..7e33e58 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -18,7 +18,8 @@
#include <cm/optional>
#include <cm/string_view>
-#include "cmsys/Process.h"
+#include <cm3p/uv.h>
+
#include "cmsys/Status.hxx" // IWYU pragma: export
#include "cmsys/SystemTools.hxx" // IWYU pragma: export
@@ -339,10 +340,20 @@ public:
*/
static void ReportLastSystemError(const char* m);
- /** a general output handler for cmsysProcess */
- static int WaitForLine(cmsysProcess* process, std::string& line,
- cmDuration timeout, std::vector<char>& out,
- std::vector<char>& err);
+ 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);
static void SetForceUnixPaths(bool v) { s_ForceUnixPaths = v; }
static bool GetForceUnixPaths() { return s_ForceUnixPaths; }
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 2ac9d8e..94f4d38 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -11,6 +11,8 @@
#include <cm3p/uv.h>
#include <fcntl.h>
+#include "cm_fileno.hxx"
+
#include "cmCommandLineArgument.h"
#include "cmConsoleBuf.h"
#include "cmCryptoHash.h"
@@ -72,7 +74,6 @@
#include "cmsys/Directory.hxx"
#include "cmsys/FStream.hxx"
-#include "cmsys/Process.h"
#include "cmsys/RegularExpression.hxx"
#include "cmsys/Terminal.h"
@@ -295,14 +296,8 @@ int CLCompileAndDependencies(const std::vector<std::string>& args)
}
}
- 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());
+ cmUVProcessChainBuilder builder;
+ builder.AddCommand(command).SetWorkingDirectory(currentBinaryDir);
cmsys::ofstream fout(depFile.c_str());
if (!fout) {
@@ -313,22 +308,18 @@ int CLCompileAndDependencies(const std::vector<std::string>& args)
CLOutputLogger errLogger(std::cerr);
// Start the process.
- cmProcessTools::RunProcess(cp.get(), &includeParser, &errLogger);
+ auto result =
+ cmProcessTools::RunProcess(builder, &includeParser, &errLogger);
+ auto const& subStatus = result.front();
int status = 0;
// handle status of process
- 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 (subStatus.SpawnResult != 0) {
+ status = 2;
+ } else if (subStatus.TermSignal != 0) {
+ status = 1;
+ } else {
+ status = static_cast<int>(subStatus.ExitStatus);
}
if (status != 0) {
@@ -1116,7 +1107,8 @@ 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);
+ cmSystemTools::RunSingleCommand(command, nullptr, nullptr, &ret, nullptr,
+ cmSystemTools::OUTPUT_PASSTHROUGH);
auto time_finish = std::chrono::steady_clock::now();
std::chrono::duration<double> time_elapsed = time_finish - time_start;
@@ -1892,21 +1884,6 @@ 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) {
@@ -1924,9 +1901,24 @@ 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.
- const char* cmd[2] = { command.c_str(), nullptr };
- cmsysProcess_SetCommand(cp, cmd);
+ std::vector<std::string> args2;
+#ifdef _WIN32
+ cmSystemTools::ParseWindowsCommandLine(command.c_str(), args2);
+#else
+ cmSystemTools::ParseUnixCommandLine(command.c_str(), args2);
+#endif
+ builder.AddCommand(args2);
// Report the command if verbose output is enabled.
if (verbose) {
@@ -1934,35 +1926,29 @@ int cmcmd::ExecuteLinkScript(std::vector<std::string> const& args)
}
// Run the command and wait for it to exit.
- cmsysProcess_Execute(cp);
- cmsysProcess_WaitForExit(cp, nullptr);
+ auto chain = builder.Start();
+ chain.Wait();
// Report failure if any.
- switch (cmsysProcess_GetState(cp)) {
- case cmsysProcess_State_Exited: {
- int value = cmsysProcess_GetExitValue(cp);
- if (value != 0) {
- result = value;
+ 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);
}
- } break;
- case cmsysProcess_State_Exception:
- std::cerr << "Error running link command: "
- << cmsysProcess_GetExceptionString(cp) << std::endl;
- result = 1;
break;
- case cmsysProcess_State_Error:
- std::cerr << "Error running link command: "
- << cmsysProcess_GetErrorString(cp) << std::endl;
+ case cmUVProcessChain::ExceptionCode::Spawn:
+ std::cerr << "Error running link command: " << exception.second;
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;
}
diff --git a/Tests/CMakeLib/testUVProcessChainHelper.cxx b/Tests/CMakeLib/testUVProcessChainHelper.cxx
index fcc45b0..b53cac4 100644
--- a/Tests/CMakeLib/testUVProcessChainHelper.cxx
+++ b/Tests/CMakeLib/testUVProcessChainHelper.cxx
@@ -7,10 +7,6 @@
#include <string>
#include <thread>
-#ifdef _WIN32
-# include <windows.h>
-#endif
-
#include "cmSystemTools.h"
static std::string getStdin()
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index d9fa0e1..7a71c0a 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -2765,29 +2765,6 @@ if(BUILD_TESTING)
list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/${CTestUpdateP4_DIR}")
endif()
- configure_file(
- "${CMake_SOURCE_DIR}/Tests/CTestTestFailure/testNoBuild.cmake.in"
- "${CMake_BINARY_DIR}/Tests/CTestTestFailure/testNoBuild.cmake"
- @ONLY ESCAPE_QUOTES)
- add_test(CTestTestNoBuild ${CMAKE_CTEST_COMMAND}
- -S "${CMake_BINARY_DIR}/Tests/CTestTestFailure/testNoBuild.cmake" -V
- --output-log "${CMake_BINARY_DIR}/Tests/CTestTestFailure/testOut1.log"
- )
- set_tests_properties(CTestTestNoBuild PROPERTIES
- FAIL_REGULAR_EXPRESSION "Error" WILL_FAIL true)
-
- configure_file(
- "${CMake_SOURCE_DIR}/Tests/CTestTestFailure/testNoExe.cmake.in"
- "${CMake_BINARY_DIR}/Tests/CTestTestFailure/testNoExe.cmake"
- @ONLY ESCAPE_QUOTES)
- add_test(CTestTestNoExe ${CMAKE_CTEST_COMMAND}
- -S "${CMake_BINARY_DIR}/Tests/CTestTestFailure/testNoExe.cmake" -V
- --output-log "${CMake_BINARY_DIR}/Tests/CTestTestFailure/testOut2.log"
- )
- set_tests_properties(CTestTestNoExe PROPERTIES DEPENDS CTestTestNoBuild
- PASS_REGULAR_EXPRESSION "Could not find executable"
- FAIL_REGULAR_EXPRESSION "SegFault")
-
if(NOT CMake_TEST_NO_NETWORK)
configure_file(
"${CMake_SOURCE_DIR}/Tests/CTestTestUpload/test.cmake.in"
diff --git a/Tests/CTestTestFailure/CMakeLists.txt b/Tests/CTestTestFailure/CMakeLists.txt
deleted file mode 100644
index b6c1e7a..0000000
--- a/Tests/CTestTestFailure/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-cmake_minimum_required (VERSION 3.5)
-project(CTestTestFailure)
-include(CTest)
-
-add_executable (NoBuild badCode.cxx)
-target_link_libraries (NoBuild ${EXTRA_LIBS})
-
-add_test (TestNoExe NoBuild)
diff --git a/Tests/CTestTestFailure/CTestConfig.cmake b/Tests/CTestTestFailure/CTestConfig.cmake
deleted file mode 100644
index 5bc1e9e..0000000
--- a/Tests/CTestTestFailure/CTestConfig.cmake
+++ /dev/null
@@ -1,4 +0,0 @@
-set (CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
-set(CTEST_DROP_METHOD "http")
-set(CTEST_DROP_SITE "open.cdash.org")
-set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestFailure/testNoBuild.cmake.in b/Tests/CTestTestFailure/testNoBuild.cmake.in
deleted file mode 100644
index 505916e..0000000
--- a/Tests/CTestTestFailure/testNoBuild.cmake.in
+++ /dev/null
@@ -1,23 +0,0 @@
-cmake_minimum_required(VERSION 3.5)
-
-# Settings:
-set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
-set(CTEST_SITE "@SITE@")
-set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-NoBuild")
-
-set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestFailure")
-set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestFailure")
-set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
-set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
-set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
-set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
-set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
-set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
-set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
-
-#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
-
-CTEST_START(Experimental)
-#CTEST_UPDATE(SOURCE "${CTEST_SOURCE_DIRECTORY}" RETURN_VALUE res)
-CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
-CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
diff --git a/Tests/CTestTestFailure/testNoExe.cmake.in b/Tests/CTestTestFailure/testNoExe.cmake.in
deleted file mode 100644
index e3d7742..0000000
--- a/Tests/CTestTestFailure/testNoExe.cmake.in
+++ /dev/null
@@ -1,21 +0,0 @@
-cmake_minimum_required(VERSION 3.5)
-
-# Settings:
-set(CTEST_DASHBOARD_ROOT "@CMake_BINARY_DIR@/Tests/CTestTest")
-set(CTEST_SITE "@SITE@")
-set(CTEST_BUILD_NAME "CTestTest-@BUILDNAME@-NoExe")
-
-set(CTEST_SOURCE_DIRECTORY "@CMake_SOURCE_DIR@/Tests/CTestTestFailure")
-set(CTEST_BINARY_DIRECTORY "@CMake_BINARY_DIR@/Tests/CTestTestFailure")
-set(CTEST_CVS_COMMAND "@CVSCOMMAND@")
-set(CTEST_CMAKE_GENERATOR "@CMAKE_GENERATOR@")
-set(CTEST_CMAKE_GENERATOR_PLATFORM "@CMAKE_GENERATOR_PLATFORM@")
-set(CTEST_CMAKE_GENERATOR_TOOLSET "@CMAKE_GENERATOR_TOOLSET@")
-set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}")
-set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
-set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
-
-#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
-
-CTEST_START(Experimental)
-CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index a4f6141..5e212bd 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -466,6 +466,7 @@ add_RunCMake_test(build_command)
add_executable(exit_code exit_code.c)
set(execute_process_ARGS
-DEXIT_CODE_EXE=$<TARGET_FILE:exit_code>
+ -DPRINT_STDIN_EXE=$<TARGET_FILE:print_stdin>
-DPython_EXECUTABLE=${Python_EXECUTABLE}
)
if(NOT CMake_TEST_EXTERNAL_CMAKE)
diff --git a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
index c90d543..223a61c 100644
--- a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
@@ -472,7 +472,7 @@ add_test(test1 \"${CMAKE_COMMAND}\" -E false)
add_test(test2 \"${CMAKE_COMMAND}\" -E echo \"hello world\")
add_test(test3 \"${CMAKE_COMMAND}\" -E true)
set_tests_properties(test3 PROPERTIES DISABLED \"ON\")
-add_test(test4 \"${CMAKE_COMMAND}/doesnt_exist\")
+add_test(test4 \"${CMAKE_CURRENT_SOURCE_DIR}/does_not_exist\")
add_test(test5 \"${CMAKE_COMMAND}\" -E echo \"please skip\")
set_tests_properties(test5 PROPERTIES SKIP_REGULAR_EXPRESSION \"please skip\")
")
diff --git a/Tests/RunCMake/CTestCommandLine/output-junit-stderr.txt b/Tests/RunCMake/CTestCommandLine/output-junit-stderr.txt
index ce30dc8..c57c378 100644
--- a/Tests/RunCMake/CTestCommandLine/output-junit-stderr.txt
+++ b/Tests/RunCMake/CTestCommandLine/output-junit-stderr.txt
@@ -1 +1,2 @@
-Unable to find executable: .*doesnt_exist
+Unable to find executable:[^
+]*does_not_exist
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH-stdout.txt b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH-stdout.txt
deleted file mode 100644
index 539e5ef..0000000
--- a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH-stdout.txt
+++ /dev/null
@@ -1,3 +0,0 @@
--- ZOT_LIBRARIES='zot'
--- ZOT_LINK_LIBRARIES='[^']*/Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH-build/root/lib/prefix-zot-suffix'
--- ZOT_LDFLAGS='-L[^']*/Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH-build/root/lib;-lzot'
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_SYSTEM_PATH-stdout.txt b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_SYSTEM_PATH-stdout.txt
new file mode 100644
index 0000000..012458d
--- /dev/null
+++ b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_SYSTEM_PATH-stdout.txt
@@ -0,0 +1,4 @@
+-- ZOT_LIBRARIES='zot'
+-- ZOT_LINK_LIBRARIES='[^']*/Tests/RunCMake/FindPkgConfig/FindPkgConfig_SYSTEM_PATH-build/root/lib/prefix-zot-suffix'
+-- ZOT_LDFLAGS='-L[^']*/Tests/RunCMake/FindPkgConfig/FindPkgConfig_SYSTEM_PATH-build/root/lib;-lzot'
+-- ZOT_CFLAGS='-I[^']*/Tests/RunCMake/FindPkgConfig/FindPkgConfig_SYSTEM_PATH-build/root/include'
diff --git a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH.cmake b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_SYSTEM_PATH.cmake
index 1278c49..e58cefb 100644
--- a/Tests/RunCMake/FindPkgConfig/FindPkgConfig_LIBRARY_PATH.cmake
+++ b/Tests/RunCMake/FindPkgConfig/FindPkgConfig_SYSTEM_PATH.cmake
@@ -3,16 +3,19 @@ find_package(PkgConfig REQUIRED)
set(ROOT "${CMAKE_CURRENT_BINARY_DIR}/root")
string(REPLACE " " "\\ " ESCAPED_ROOT "${ROOT}")
set(LIB_DIR "${ROOT}/lib")
+set(INCLUDE_DIR "${ROOT}/include")
set(PKGCONFIG_DIR "${LIB_DIR}/pkgconfig")
file(WRITE "${PKGCONFIG_DIR}/zot.pc" "
prefix=${ESCAPED_ROOT}
libdir=\${prefix}/lib
+includedir=\${prefix}/include
Name: Zot
Description: Dummy package to test LIBRARY_DIR support
Version: 1.0
Libs: -L\${libdir} -lzot
+Cflags: -I\${includedir}
")
# Create a "library" file to find in libdir.
@@ -22,9 +25,13 @@ file(WRITE "${LIB_DIR}/prefix-zot-suffix")
# 'pkg-config --libs' drops -L flags in PKG_CONFIG_SYSTEM_LIBRARY_PATH by default.
set(ENV{PKG_CONFIG_SYSTEM_LIBRARY_PATH} "${LIB_DIR}")
+# 'pkg-config --cflags' drops -I flags in PKG_CONFIG_SYSTEM_INCLUDE_PATH by default.
+set(ENV{PKG_CONFIG_SYSTEM_INCLUDE_PATH} "${INCLUDE_DIR}")
# 'pkgconf --libs' also drops -L flags in LIBRARY_PATH by default.
set(ENV{LIBRARY_PATH} "${LIB_DIR}")
+# 'pkgconf --cflags' also drops -I flags in CPATH by default.
+set(ENV{CPATH} "${INCLUDE_DIR}")
set(ENV{PKG_CONFIG_PATH} "${PKGCONFIG_DIR}")
pkg_check_modules(ZOT REQUIRED zot)
@@ -32,3 +39,4 @@ pkg_check_modules(ZOT REQUIRED zot)
message(STATUS "ZOT_LIBRARIES='${ZOT_LIBRARIES}'")
message(STATUS "ZOT_LINK_LIBRARIES='${ZOT_LINK_LIBRARIES}'")
message(STATUS "ZOT_LDFLAGS='${ZOT_LDFLAGS}'")
+message(STATUS "ZOT_CFLAGS='${ZOT_CFLAGS}'")
diff --git a/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
index 6b8e884..2bfe028 100644
--- a/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake
@@ -59,6 +59,6 @@ Libs: -L\${libdir}
run_cmake(FindPkgConfig_GET_MATCHING_MODULE_NAME)
run_cmake(FindPkgConfig_empty_target)
if(NOT PKG_CONFIG_DONT_SUPPORT_SPACES_IN_PATH)
- run_cmake(FindPkgConfig_LIBRARY_PATH)
+ run_cmake(FindPkgConfig_SYSTEM_PATH)
endif()
endif ()
diff --git a/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem1-result.txt b/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem1-stderr.txt b/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem1-stderr.txt
new file mode 100644
index 0000000..61188b6
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem1-stderr.txt
@@ -0,0 +1,10 @@
+CMake Error at CMakeLists.txt:[0-9]+ \(project\):
+ Generator
+
+ Xcode
+
+ toolset specification field
+
+ buildsystem=1
+
+ is not allowed with Xcode [0-9.]+\.$
diff --git a/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem1.cmake b/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem1.cmake
new file mode 100644
index 0000000..2fc38e5
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/BadToolsetXcodeBuildSystem1.cmake
@@ -0,0 +1 @@
+message(FATAL_ERROR "This should not be reached!")
diff --git a/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake
index a742391..71cc2d4 100644
--- a/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake
@@ -89,7 +89,11 @@ elseif("${RunCMake_GENERATOR}" STREQUAL "Xcode")
set(RunCMake_GENERATOR_TOOLSET "Test Toolset")
run_cmake(TestToolsetXcodeBuildSystemDefault12)
set(RunCMake_GENERATOR_TOOLSET "Test Toolset,buildsystem=1")
- run_cmake(TestToolsetXcodeBuildSystem1)
+ if(XCODE_VERSION VERSION_GREATER_EQUAL 14)
+ run_cmake(BadToolsetXcodeBuildSystem1)
+ else()
+ run_cmake(TestToolsetXcodeBuildSystem1)
+ endif()
set(RunCMake_GENERATOR_TOOLSET "Test Toolset,buildsystem=12")
run_cmake(TestToolsetXcodeBuildSystem12)
else()
diff --git a/Tests/RunCMake/XcodeProject-Device/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject-Device/RunCMakeTest.cmake
index b3ab624..abb357b 100644
--- a/Tests/RunCMake/XcodeProject-Device/RunCMakeTest.cmake
+++ b/Tests/RunCMake/XcodeProject-Device/RunCMakeTest.cmake
@@ -311,9 +311,11 @@ if (XCODE_VERSION VERSION_GREATER_EQUAL 7.3)
endfunction()
if(XCODE_VERSION VERSION_GREATER_EQUAL 12)
- xctest_add_bundle_test(Darwin macosx "1" "$<TARGET_BUNDLE_CONTENT_DIR:TestedApp>/PlugIns")
xctest_add_bundle_test(Darwin macosx "12" "$<TARGET_BUNDLE_CONTENT_DIR:TestedApp>/PlugIns")
- xctest_add_bundle_test(iOS iphonesimulator "1" "$<TARGET_BUNDLE_CONTENT_DIR:TestedApp>/PlugIns")
+ if(XCODE_VERSION VERSION_LESS 14)
+ xctest_add_bundle_test(Darwin macosx "1" "$<TARGET_BUNDLE_CONTENT_DIR:TestedApp>/PlugIns")
+ xctest_add_bundle_test(iOS iphonesimulator "1" "$<TARGET_BUNDLE_CONTENT_DIR:TestedApp>/PlugIns")
+ endif()
if (XCODE_VERSION VERSION_LESS 12.5)
xctest_add_bundle_test(iOS iphonesimulator "12" "$<TARGET_BUNDLE_CONTENT_DIR:TestedApp>")
else()
diff --git a/Tests/CTestTestFailure/badCode.cxx b/Tests/RunCMake/ctest_build/BuildFailure.cxx
index 8102883..8102883 100644
--- a/Tests/CTestTestFailure/badCode.cxx
+++ b/Tests/RunCMake/ctest_build/BuildFailure.cxx
diff --git a/Tests/RunCMake/ctest_build/RunCMakeTest.cmake b/Tests/RunCMake/ctest_build/RunCMakeTest.cmake
index 12525f2..af56ead 100644
--- a/Tests/RunCMake/ctest_build/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ctest_build/RunCMakeTest.cmake
@@ -13,18 +13,18 @@ endfunction()
run_ctest_build(BuildQuiet QUIET)
run_ctest_build(ParallelLevel PARALLEL_LEVEL 1)
-function(run_BuildFailure)
- set(CASE_CMAKELISTS_SUFFIX_CODE [[
-add_custom_target(BuildFailure ALL COMMAND command-does-not-exist)
-]])
+block()
+ set(LANG CXX)
+ configure_file("${RunCMake_SOURCE_DIR}/BuildFailure.cxx" "${RunCMake_BINARY_DIR}/BuildFailure/BuildFailure.cxx" COPYONLY)
+ set(CASE_CMAKELISTS_SUFFIX_CODE [=[
+ add_executable(BuildFailure BuildFailure.cxx)
+ ]=])
set(CASE_CMAKELISTS_PREFIX_CODE [[
if(NOT CTEST_USE_LAUNCHERS)
message(FATAL_ERROR "CTEST_USE_LAUNCHERS not set")
endif()
]])
- set(CASE_TEST_PREFIX_CODE [[
-cmake_policy(SET CMP0061 NEW)
-]])
+ set(CASE_TEST_PREFIX_CODE "")
set(CASE_TEST_SUFFIX_CODE [[
if (ctest_build_return_value)
message("ctest_build returned non-zero")
@@ -35,13 +35,16 @@ endif()
run_ctest(BuildFailure)
if (RunCMake_GENERATOR MATCHES "Makefiles")
+ set(LANG NONE)
set(CASE_TEST_PREFIX_CODE [[
cmake_policy(VERSION 3.2)
]])
+ set(CASE_CMAKELISTS_SUFFIX_CODE [[
+add_custom_target(BuildFailure ALL COMMAND command-does-not-exist)
+]])
run_ctest(BuildFailure-CMP0061-OLD)
endif()
-endfunction()
-run_BuildFailure()
+endblock()
function(run_BuildChangeId)
set(CASE_TEST_PREFIX_CODE [[
diff --git a/Tests/RunCMake/ctest_test/NotRun-result.txt b/Tests/RunCMake/ctest_test/NotRun-result.txt
new file mode 100644
index 0000000..b57e2de
--- /dev/null
+++ b/Tests/RunCMake/ctest_test/NotRun-result.txt
@@ -0,0 +1 @@
+(-1|255)
diff --git a/Tests/RunCMake/ctest_test/NotRun-stderr.txt b/Tests/RunCMake/ctest_test/NotRun-stderr.txt
new file mode 100644
index 0000000..85907f3
--- /dev/null
+++ b/Tests/RunCMake/ctest_test/NotRun-stderr.txt
@@ -0,0 +1,2 @@
+.*Unable to find executable[^
+]*does_not_exist
diff --git a/Tests/RunCMake/ctest_test/NotRun-stdout.txt b/Tests/RunCMake/ctest_test/NotRun-stdout.txt
new file mode 100644
index 0000000..8d60833
--- /dev/null
+++ b/Tests/RunCMake/ctest_test/NotRun-stdout.txt
@@ -0,0 +1,7 @@
+.*Could not find executable[^
+]*does_not_exist
+.*
+50% tests passed, 1 tests failed out of 2
+.*
+The following tests FAILED:
+.*testNotRun \(Not Run\)
diff --git a/Tests/RunCMake/ctest_test/RunCMakeTest.cmake b/Tests/RunCMake/ctest_test/RunCMakeTest.cmake
index 242a059..d2f3da3 100644
--- a/Tests/RunCMake/ctest_test/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ctest_test/RunCMakeTest.cmake
@@ -53,6 +53,13 @@ unset(ENV{__CTEST_FAKE_LOAD_AVERAGE_FOR_TESTING})
unset(CASE_CTEST_TEST_LOAD)
unset(RunCTest_VERBOSE_FLAG)
+block()
+ set(CASE_CMAKELISTS_SUFFIX_CODE [[
+ add_test(NAME testNotRun COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/does_not_exist)
+ ]])
+ run_ctest_test(NotRun)
+endblock()
+
function(run_TestChangeId)
set(CASE_TEST_PREFIX_CODE [[
set(CTEST_CHANGE_ID "<>1")
@@ -131,8 +138,7 @@ run_TestRepeat(AfterTimeout RETURN_VALUE:0 REPEAT AFTER_TIMEOUT:3)
# test repeat and not run tests interact correctly
set(CASE_CMAKELISTS_SUFFIX_CODE [[
-add_test(NAME testNotRun
- COMMAND ${CMAKE_COMMAND}/doesnt_exist)
+ add_test(NAME testNotRun COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/does_not_exist)
set_property(TEST testNotRun PROPERTY TIMEOUT 5)
]])
run_TestRepeat(NotRun RETURN_VALUE:1 REPEAT UNTIL_PASS:3)
diff --git a/Tests/RunCMake/ctest_test/TestRepeatNotRun-stderr.txt b/Tests/RunCMake/ctest_test/TestRepeatNotRun-stderr.txt
index a69932d..85907f3 100644
--- a/Tests/RunCMake/ctest_test/TestRepeatNotRun-stderr.txt
+++ b/Tests/RunCMake/ctest_test/TestRepeatNotRun-stderr.txt
@@ -1 +1,2 @@
-.*Unable to find executable.*
+.*Unable to find executable[^
+]*does_not_exist
diff --git a/Tests/RunCMake/ctest_test/TestRepeatNotRun-stdout.txt b/Tests/RunCMake/ctest_test/TestRepeatNotRun-stdout.txt
index 72c98bc..8d60833 100644
--- a/Tests/RunCMake/ctest_test/TestRepeatNotRun-stdout.txt
+++ b/Tests/RunCMake/ctest_test/TestRepeatNotRun-stdout.txt
@@ -1,5 +1,7 @@
+.*Could not find executable[^
+]*does_not_exist
.*
50% tests passed, 1 tests failed out of 2
.*
The following tests FAILED:
-.*testNotRun.*Not Run.*
+.*testNotRun \(Not Run\)
diff --git a/Tests/RunCMake/execute_process/RunCMakeTest.cmake b/Tests/RunCMake/execute_process/RunCMakeTest.cmake
index c2f9144..1f89829 100644
--- a/Tests/RunCMake/execute_process/RunCMakeTest.cmake
+++ b/Tests/RunCMake/execute_process/RunCMakeTest.cmake
@@ -34,6 +34,7 @@ run_cmake_command(AnyCommandGood ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/AnyC
run_cmake_command(LastCommandError ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/LastCommandError.cmake)
run_cmake_command(LastCommandTimeout ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/LastCommandTimeout.cmake)
run_cmake_command(LastCommandGood ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/LastCommandGood.cmake)
+run_cmake_command(Stdin ${CMAKE_COMMAND} -DPRINT_STDIN_EXE=${PRINT_STDIN_EXE} -P ${RunCMake_SOURCE_DIR}/Stdin.cmake)
if(UNIX AND Python_EXECUTABLE)
run_cmake_command(AnyCommandAbnormalExit ${CMAKE_COMMAND} -DPython_EXECUTABLE=${Python_EXECUTABLE} -P ${RunCMake_SOURCE_DIR}/AnyCommandAbnormalExit.cmake)
diff --git a/Tests/RunCMake/execute_process/Stdin-stdin.txt b/Tests/RunCMake/execute_process/Stdin-stdin.txt
new file mode 100644
index 0000000..cd08755
--- /dev/null
+++ b/Tests/RunCMake/execute_process/Stdin-stdin.txt
@@ -0,0 +1 @@
+Hello world!
diff --git a/Tests/RunCMake/execute_process/Stdin-stdout.txt b/Tests/RunCMake/execute_process/Stdin-stdout.txt
new file mode 100644
index 0000000..04bd136
--- /dev/null
+++ b/Tests/RunCMake/execute_process/Stdin-stdout.txt
@@ -0,0 +1 @@
+^Hello world!$
diff --git a/Tests/RunCMake/execute_process/Stdin.cmake b/Tests/RunCMake/execute_process/Stdin.cmake
new file mode 100644
index 0000000..e8a2098
--- /dev/null
+++ b/Tests/RunCMake/execute_process/Stdin.cmake
@@ -0,0 +1 @@
+execute_process(COMMAND ${PRINT_STDIN_EXE})
diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp
index e45970d..6056030 100644
--- a/Utilities/IWYU/mapping.imp
+++ b/Utilities/IWYU/mapping.imp
@@ -75,6 +75,10 @@
{ include: [ "<ostream>", public, "\"cmsys/FStream.hxx\"", public ] },
{ include: [ "<fstream>", public, "\"cmsys/FStream.hxx\"", public ] },
+ { symbol: [ "mode_t", private, "\"cm_sys_stat.h\"", public ] },
+ { symbol: [ "S_IWUSR", private, "\"cm_sys_stat.h\"", public ] },
+ { symbol: [ "S_IWGRP", private, "\"cm_sys_stat.h\"", public ] },
+
{ include: [ "<filesystem>", public, "<cm/filesystem>", public ] },
{ include: [ "<optional>", public, "<cm/optional>", public ] },
{ include: [ "<shared_mutex>", public, "<cm/shared_mutex>", public ] },
diff --git a/bootstrap b/bootstrap
index afb03f3..2b7ddfe 100755
--- a/bootstrap
+++ b/bootstrap
@@ -508,6 +508,7 @@ CMAKE_CXX_SOURCES="\
cmake \
cmakemain \
cmcmd \
+ cm_fileno \
"
if ${cmake_system_mingw}; then