execute_process: Fix invocation of .cmd/.bat with spaces
The `CreateProcessW` documentation states "to run a batch file, you must start the command interpreter". Use `cmd /c the.bat` to run batch files. Also, use a "short path" to the `.bat` file if needed to avoid spaces. Previously this worked in some cases only due to undocumented behavior of `CreateProcessW` when given a `.bat` file. Fixes: #26655
This commit is contained in:
parent
104ca10208
commit
74c9d40876
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -25,6 +25,7 @@ configure eol=lf
|
||||
|
||||
*.bat eol=crlf
|
||||
*.bat.in eol=crlf
|
||||
*.cmd eol=crlf
|
||||
*.sln eol=crlf
|
||||
*.vcproj eol=crlf
|
||||
|
||||
|
@ -48,8 +48,14 @@ Options:
|
||||
child process in an ``argv[]`` style array.
|
||||
|
||||
* On Windows platforms, the command line is encoded as a string such
|
||||
that child processes using ``CommandLineToArgvW`` will decode the
|
||||
original arguments.
|
||||
that child processes using `CommandLineToArgvW`_ will decode the
|
||||
original arguments. If the command runs a ``.bat`` or ``.cmd``
|
||||
script, it may receive arguments with extra quoting.
|
||||
|
||||
* .. versionchanged:: 4.0
|
||||
On Windows platforms, if the command runs a ``.bat`` or ``.cmd`` script,
|
||||
it is automatically executed through the command interpreter, ``cmd /c``.
|
||||
However, paths with spaces may fail if a "short path" is not available.
|
||||
|
||||
No intermediate shell is used, so shell operators such as ``>``
|
||||
are treated as normal arguments.
|
||||
@ -197,3 +203,5 @@ Options:
|
||||
is checked. If the variable is not set, the default is ``NONE``.
|
||||
If ``RESULT_VARIABLE`` or ``RESULTS_VARIABLE`` is supplied,
|
||||
:variable:`CMAKE_EXECUTE_PROCESS_COMMAND_ERROR_IS_FATAL` is ignored.
|
||||
|
||||
.. _`CommandLineToArgvW`: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw
|
||||
|
@ -120,7 +120,7 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
|
||||
.Bind("COMMAND_ERROR_IS_FATAL"_s, &Arguments::CommandErrorIsFatal);
|
||||
|
||||
std::vector<std::string> unparsedArguments;
|
||||
Arguments const arguments = parser.Parse(args, &unparsedArguments);
|
||||
Arguments arguments = parser.Parse(args, &unparsedArguments);
|
||||
|
||||
if (arguments.MaybeReportError(status.GetMakefile())) {
|
||||
return true;
|
||||
@ -161,11 +161,21 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
|
||||
status.SetError(" called with no COMMAND argument.");
|
||||
return false;
|
||||
}
|
||||
for (std::vector<std::string> const& cmd : arguments.Commands) {
|
||||
for (std::vector<std::string>& cmd : arguments.Commands) {
|
||||
if (cmd.empty()) {
|
||||
status.SetError(" given COMMAND argument with no value.");
|
||||
return false;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
cmsys::Status shortPathRes = cmSystemTools::MaybePrependCmdExe(cmd);
|
||||
if (!shortPathRes) {
|
||||
status.GetMakefile().IssueMessage(
|
||||
MessageType::WARNING,
|
||||
cmStrCat("Conversion of COMMAND:\n ", cmd[2], '\n',
|
||||
"to a short path without spaces failed:\n ",
|
||||
shortPathRes.GetString()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Parse the timeout string.
|
||||
|
@ -63,6 +63,14 @@ if(WIN32 OR CYGWIN)
|
||||
run_cmake_command(WindowsNoExtension-build ${CMAKE_COMMAND} --build . --config Debug --target RunScript)
|
||||
endif()
|
||||
|
||||
if(CMAKE_HOST_WIN32
|
||||
# By default, only C: has short paths enabled.
|
||||
# Since querying with `fsutil 8dot3name query C:`
|
||||
# requires admin, just test the drive letter.
|
||||
AND RunCMake_SOURCE_DIR MATCHES "^[Cc]:")
|
||||
run_cmake_command(WindowsBatch ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/WindowsBatch.cmake)
|
||||
endif()
|
||||
|
||||
if(TEST_STARTUPINFO_EXE)
|
||||
run_cmake_script(StartupInfo -DTEST_STARTUPINFO_EXE=${TEST_STARTUPINFO_EXE})
|
||||
endif()
|
||||
|
8
Tests/RunCMake/execute_process/WindowsBatch-stdout.txt
Normal file
8
Tests/RunCMake/execute_process/WindowsBatch-stdout.txt
Normal file
@ -0,0 +1,8 @@
|
||||
^bat arg1 - arg2 -
|
||||
bat "arg1 space" - arg2 -
|
||||
bat arg1 - "arg2 space" -
|
||||
bat "arg1 space" - "arg2 space" -
|
||||
cmd arg1 - arg2 -
|
||||
cmd "arg1 space" - arg2 -
|
||||
cmd arg1 - "arg2 space" -
|
||||
cmd "arg1 space" - "arg2 space" -$
|
8
Tests/RunCMake/execute_process/WindowsBatch.cmake
Normal file
8
Tests/RunCMake/execute_process/WindowsBatch.cmake
Normal file
@ -0,0 +1,8 @@
|
||||
execute_process(COMMAND "${CMAKE_CURRENT_LIST_DIR}/with space.bat" arg1 arg2)
|
||||
execute_process(COMMAND "${CMAKE_CURRENT_LIST_DIR}/with space.Bat" "arg1 space" arg2)
|
||||
execute_process(COMMAND "${CMAKE_CURRENT_LIST_DIR}/with space.bAT" arg1 "arg2 space")
|
||||
execute_process(COMMAND "${CMAKE_CURRENT_LIST_DIR}/with space.BAT" "arg1 space" "arg2 space")
|
||||
execute_process(COMMAND "${CMAKE_CURRENT_LIST_DIR}/with space.cmd" arg1 arg2)
|
||||
execute_process(COMMAND "${CMAKE_CURRENT_LIST_DIR}/with space.Cmd" "arg1 space" arg2)
|
||||
execute_process(COMMAND "${CMAKE_CURRENT_LIST_DIR}/with space.cMD" arg1 "arg2 space")
|
||||
execute_process(COMMAND "${CMAKE_CURRENT_LIST_DIR}/with space.CMD" "arg1 space" "arg2 space")
|
1
Tests/RunCMake/execute_process/with space.bat
Executable file
1
Tests/RunCMake/execute_process/with space.bat
Executable file
@ -0,0 +1 @@
|
||||
@echo bat %1 - %2 -
|
1
Tests/RunCMake/execute_process/with space.cmd
Executable file
1
Tests/RunCMake/execute_process/with space.cmd
Executable file
@ -0,0 +1 @@
|
||||
@echo cmd %1 - %2 -
|
Loading…
Reference in New Issue
Block a user