From 98fed0f1164349c3142f680e34c11b8312bd0e31 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 31 Jan 2025 10:50:09 -0500 Subject: cmSystemTools: Adopt MaybePrependCmdExe --- Source/cmQtAutoMocUic.cxx | 56 +++-------------------------------------------- Source/cmSystemTools.cxx | 30 +++++++++++++++++++++++++ Source/cmSystemTools.h | 19 ++++++++++++++++ 3 files changed, 52 insertions(+), 53 deletions(-) diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index 2a9937a..9ba48cc 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -344,8 +344,6 @@ public: void MaybeWriteResponseFile(std::string const& outputFile, std::vector& cmd) const; - static void MaybePrependCmdExe(std::vector& cmd); - /** @brief Run an external process. Use only during Process() call! */ bool RunProcess(GenT genType, cmWorkerPool::ProcessResultT& result, std::vector const& command, @@ -846,54 +844,6 @@ void cmQtAutoMocUicT::JobT::MaybeWriteResponseFile( #endif } -/* - * According to the CreateProcessW documentation which is the underlying - * function for all RunProcess calls: - * - * "To run a batch file, you must start the command interpreter; set" - * "lpApplicationName to cmd.exe and set lpCommandLine to the following" - * "arguments: /c plus the name of the batch file." - * - * we should to take care of the correctness of the command line when - * attempting to execute the batch files. - * - * Also cmd.exe is unable to parse batch file names correctly if they - * contain spaces. This function uses cmSystemTools::GetShortPath conversion - * to suppress this behavior. - * - * The function is noop on platforms different from the pure WIN32 one. - */ -void cmQtAutoMocUicT::JobT::MaybePrependCmdExe( - std::vector& cmdLine) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - if (!cmdLine.empty()) { - auto const& applicationName = cmdLine.at(0); - if (cmSystemTools::StringEndsWith(applicationName, ".bat") || - cmSystemTools::StringEndsWith(applicationName, ".cmd")) { - std::vector output; - output.reserve(cmdLine.size() + 2); - output.emplace_back(cmSystemTools::GetComspec()); - output.emplace_back("/c"); - std::string tmpShortPath; - if (applicationName.find(' ') != std::string::npos && - cmSystemTools::GetShortPath(applicationName, tmpShortPath)) { - // If the batch file name contains spaces convert it to the windows - // short path. Otherwise it might cause issue when running cmd.exe. - output.emplace_back(tmpShortPath); - } else { - output.push_back(applicationName); - } - std::move(cmdLine.begin() + 1, cmdLine.end(), - std::back_inserter(output)); - cmdLine = std::move(output); - } - } -#else - static_cast(cmdLine); -#endif -} - bool cmQtAutoMocUicT::JobT::RunProcess(GenT genType, cmWorkerPool::ProcessResultT& result, std::vector const& command, @@ -938,7 +888,7 @@ void cmQtAutoMocUicT::JobMocPredefsT::Process() // Check if response file is necessary MaybeWriteResponseFile(this->MocConst().PredefsFileAbs, cmd); - MaybePrependCmdExe(cmd); + cmSystemTools::MaybePrependCmdExe(cmd); // Execute command if (!this->RunProcess(GenT::MOC, result, cmd, reason.get())) { @@ -2141,7 +2091,7 @@ void cmQtAutoMocUicT::JobCompileMocT::Process() cmd.push_back(sourceFile); MaybeWriteResponseFile(outputFile, cmd); - MaybePrependCmdExe(cmd); + cmSystemTools::MaybePrependCmdExe(cmd); } // Execute moc command @@ -2208,7 +2158,7 @@ void cmQtAutoMocUicT::JobCompileUicT::Process() cmd.emplace_back(outputFile); cmd.emplace_back(sourceFile); - MaybePrependCmdExe(cmd); + cmSystemTools::MaybePrependCmdExe(cmd); cmWorkerPool::ProcessResultT result; if (this->RunProcess(GenT::UIC, result, cmd, this->Reason.get())) { diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 28db59b..0e6041f 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -787,6 +787,36 @@ std::size_t cmSystemTools::CalculateCommandLineLengthLimit() return sz; } +void cmSystemTools::MaybePrependCmdExe(std::vector& cmdLine) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + if (!cmdLine.empty()) { + auto const& applicationName = cmdLine.at(0); + if (cmSystemTools::StringEndsWith(applicationName, ".bat") || + cmSystemTools::StringEndsWith(applicationName, ".cmd")) { + std::vector output; + output.reserve(cmdLine.size() + 2); + output.emplace_back(cmSystemTools::GetComspec()); + output.emplace_back("/c"); + std::string tmpShortPath; + if (applicationName.find(' ') != std::string::npos && + cmSystemTools::GetShortPath(applicationName, tmpShortPath)) { + // If the batch file name contains spaces convert it to the windows + // short path. Otherwise it might cause issue when running cmd.exe. + output.emplace_back(tmpShortPath); + } else { + output.push_back(applicationName); + } + std::move(cmdLine.begin() + 1, cmdLine.end(), + std::back_inserter(output)); + cmdLine = std::move(output); + } + } +#else + static_cast(cmdLine); +#endif +} + bool cmSystemTools::RunSingleCommand(std::vector const& command, std::string* captureStdOut, std::string* captureStdErr, int* retVal, diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index efb073e..052c917 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -235,6 +235,25 @@ public: std::string const& destination); /** + * According to the CreateProcessW documentation which is the underlying + * function for all RunProcess calls: + * + * "To run a batch file, you must start the command interpreter; set" + * "lpApplicationName to cmd.exe and set lpCommandLine to the following" + * "arguments: /c plus the name of the batch file." + * + * we should to take care of the correctness of the command line when + * attempting to execute the batch files. + * + * Also cmd.exe is unable to parse batch file names correctly if they + * contain spaces. This function uses cmSystemTools::GetShortPath conversion + * to suppress this behavior. + * + * The function is noop on platforms different from the pure WIN32 one. + */ + static void MaybePrependCmdExe(std::vector& cmdLine); + + /** * Run a single executable command * * Output is controlled with outputflag. If outputflag is OUTPUT_NONE, no -- cgit v0.12 From 611a3000f7542499f6f3b654ad303fc6c5f85882 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 31 Jan 2025 12:27:29 -0500 Subject: cmSystemTools: Make MaybePrependCmdExe case-insensitive --- Source/cmSystemTools.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 0e6041f..54104db 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -792,8 +792,10 @@ void cmSystemTools::MaybePrependCmdExe(std::vector& cmdLine) #if defined(_WIN32) && !defined(__CYGWIN__) if (!cmdLine.empty()) { auto const& applicationName = cmdLine.at(0); - if (cmSystemTools::StringEndsWith(applicationName, ".bat") || - cmSystemTools::StringEndsWith(applicationName, ".cmd")) { + static cmsys::RegularExpression const winCmdRegex( + "\\.([Bb][Aa][Tt]|[Cc][Mm][Dd])$"); + cmsys::RegularExpressionMatch winCmdMatch; + if (winCmdRegex.find(applicationName.c_str(), winCmdMatch)) { std::vector output; output.reserve(cmdLine.size() + 2); output.emplace_back(cmSystemTools::GetComspec()); -- cgit v0.12 From 817b3967f875944d4514b876bee0a56c0c9f8dea Mon Sep 17 00:00:00 2001 From: Brad King Date: Sun, 2 Feb 2025 07:35:50 -0500 Subject: cmSystemTools: Teach MaybePrependCmdExe to return GetShortPathNameW failure --- Source/cmSystemTools.cxx | 21 +++++++++++---------- Source/cmSystemTools.h | 6 +++--- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 54104db..13e3245 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -787,11 +787,13 @@ std::size_t cmSystemTools::CalculateCommandLineLengthLimit() return sz; } -void cmSystemTools::MaybePrependCmdExe(std::vector& cmdLine) +cmsys::Status cmSystemTools::MaybePrependCmdExe( + std::vector& cmdLine) { #if defined(_WIN32) && !defined(__CYGWIN__) + cmsys::Status status; if (!cmdLine.empty()) { - auto const& applicationName = cmdLine.at(0); + std::string& applicationName = cmdLine.at(0); static cmsys::RegularExpression const winCmdRegex( "\\.([Bb][Aa][Tt]|[Cc][Mm][Dd])$"); cmsys::RegularExpressionMatch winCmdMatch; @@ -800,22 +802,21 @@ void cmSystemTools::MaybePrependCmdExe(std::vector& cmdLine) output.reserve(cmdLine.size() + 2); output.emplace_back(cmSystemTools::GetComspec()); output.emplace_back("/c"); - std::string tmpShortPath; - if (applicationName.find(' ') != std::string::npos && - cmSystemTools::GetShortPath(applicationName, tmpShortPath)) { - // If the batch file name contains spaces convert it to the windows - // short path. Otherwise it might cause issue when running cmd.exe. - output.emplace_back(tmpShortPath); - } else { - output.push_back(applicationName); + if (applicationName.find(' ') != std::string::npos) { + // Convert the batch file path to a short path to avoid spaces. + // Otherwise, cmd.exe may not handle arguments with spaces. + status = cmSystemTools::GetShortPath(applicationName, applicationName); } + output.push_back(applicationName); std::move(cmdLine.begin() + 1, cmdLine.end(), std::back_inserter(output)); cmdLine = std::move(output); } } + return status; #else static_cast(cmdLine); + return cmsys::Status::Success(); #endif } diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 052c917..60a7095 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -246,12 +246,12 @@ public: * attempting to execute the batch files. * * Also cmd.exe is unable to parse batch file names correctly if they - * contain spaces. This function uses cmSystemTools::GetShortPath conversion - * to suppress this behavior. + * contain spaces. This function uses cmSystemTools::GetShortPath + * conversion to suppress this behavior, and returns its status. * * The function is noop on platforms different from the pure WIN32 one. */ - static void MaybePrependCmdExe(std::vector& cmdLine); + static cmsys::Status MaybePrependCmdExe(std::vector& cmdLine); /** * Run a single executable command -- cgit v0.12 From c1f6b041761935b95f61020a0853c76a1b4eda50 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 3 Feb 2025 09:08:08 -0500 Subject: cmSystemTools: Teach MaybePrependCmdExe to always use backslashes --- Source/cmSystemTools.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 13e3245..065c4e7 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -802,6 +802,8 @@ cmsys::Status cmSystemTools::MaybePrependCmdExe( output.reserve(cmdLine.size() + 2); output.emplace_back(cmSystemTools::GetComspec()); output.emplace_back("/c"); + // Convert the batch file path to use backslashes for cmd.exe to parse. + std::replace(applicationName.begin(), applicationName.end(), '/', '\\'); if (applicationName.find(' ') != std::string::npos) { // Convert the batch file path to a short path to avoid spaces. // Otherwise, cmd.exe may not handle arguments with spaces. -- cgit v0.12 From c091fd1420aa2f4491d708362a5a2480cd814d56 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 31 Jan 2025 10:43:38 -0500 Subject: cmUVProcessChain: Convert AddCommand signature to move semantics --- Source/cmUVProcessChain.cxx | 4 ++-- Source/cmUVProcessChain.h | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx index c64d9a4..89743e4 100644 --- a/Source/cmUVProcessChain.cxx +++ b/Source/cmUVProcessChain.cxx @@ -63,11 +63,11 @@ struct cmUVProcessChain::InternalData cmUVProcessChainBuilder::cmUVProcessChainBuilder() = default; cmUVProcessChainBuilder& cmUVProcessChainBuilder::AddCommand( - std::vector const& arguments) + std::vector arguments) { if (!arguments.empty()) { this->Processes.emplace_back(); - this->Processes.back().Arguments = arguments; + this->Processes.back().Arguments = std::move(arguments); } return *this; } diff --git a/Source/cmUVProcessChain.h b/Source/cmUVProcessChain.h index b28a876..a717e3b 100644 --- a/Source/cmUVProcessChain.h +++ b/Source/cmUVProcessChain.h @@ -29,8 +29,7 @@ public: cmUVProcessChainBuilder(); - cmUVProcessChainBuilder& AddCommand( - std::vector const& arguments); + cmUVProcessChainBuilder& AddCommand(std::vector arguments); cmUVProcessChainBuilder& SetBuiltinLoop(); cmUVProcessChainBuilder& SetExternalLoop(uv_loop_t& loop); cmUVProcessChainBuilder& SetNoStream(Stream stdio); -- cgit v0.12 From cf7ba6d43d3096665885e6183595216ffcf93e38 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 31 Jan 2025 11:48:05 -0500 Subject: cmWorkerPool: Convert RunCommand signature to move semantics --- Source/cmWorkerPool.cxx | 17 +++++++++-------- Source/cmWorkerPool.h | 3 +-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Source/cmWorkerPool.cxx b/Source/cmWorkerPool.cxx index 716499c..c057ed1 100644 --- a/Source/cmWorkerPool.cxx +++ b/Source/cmWorkerPool.cxx @@ -159,7 +159,7 @@ public: // -- Runtime void setup(cmWorkerPool::ProcessResultT* result, bool mergedOutput, - std::vector const& command, + std::vector command, std::string const& workingDirectory = std::string()); bool start(uv_loop_t* uv_loop, std::function finishedCallback); @@ -188,11 +188,11 @@ private: void cmUVReadOnlyProcess::setup(cmWorkerPool::ProcessResultT* result, bool mergedOutput, - std::vector const& command, + std::vector command, std::string const& workingDirectory) { this->Setup_.WorkingDirectory = workingDirectory; - this->Setup_.Command = command; + this->Setup_.Command = std::move(command); this->Setup_.Result = result; this->Setup_.MergedOutput = mergedOutput; } @@ -396,7 +396,7 @@ public: * Run an external process */ bool RunProcess(cmWorkerPool::ProcessResultT& result, - std::vector const& command, + std::vector command, std::string const& workingDirectory); private: @@ -429,7 +429,7 @@ cmWorkerPoolWorker::~cmWorkerPoolWorker() } bool cmWorkerPoolWorker::RunProcess(cmWorkerPool::ProcessResultT& result, - std::vector const& command, + std::vector command, std::string const& workingDirectory) { if (command.empty()) { @@ -439,7 +439,8 @@ bool cmWorkerPoolWorker::RunProcess(cmWorkerPool::ProcessResultT& result, { std::lock_guard lock(this->Proc_.Mutex); this->Proc_.ROP = cm::make_unique(); - this->Proc_.ROP->setup(&result, true, command, workingDirectory); + this->Proc_.ROP->setup(&result, true, std::move(command), + workingDirectory); } // Send asynchronous process start request to libuv loop this->Proc_.Request.send(); @@ -731,12 +732,12 @@ void cmWorkerPoolInternal::Work(unsigned int workerIndex) cmWorkerPool::JobT::~JobT() = default; bool cmWorkerPool::JobT::RunProcess(ProcessResultT& result, - std::vector const& command, + std::vector command, std::string const& workingDirectory) { // Get worker by index auto* worker = this->Pool_->Int_->Workers.at(this->WorkerIndex_).get(); - return worker->RunProcess(result, command, workingDirectory); + return worker->RunProcess(result, std::move(command), workingDirectory); } cmWorkerPool::cmWorkerPool() diff --git a/Source/cmWorkerPool.h b/Source/cmWorkerPool.h index 4035650..4e7223b 100644 --- a/Source/cmWorkerPool.h +++ b/Source/cmWorkerPool.h @@ -102,8 +102,7 @@ public: * Run an external read only process. * Use only during JobT::Process() call! */ - bool RunProcess(ProcessResultT& result, - std::vector const& command, + bool RunProcess(ProcessResultT& result, std::vector command, std::string const& workingDirectory); private: -- cgit v0.12 From 104ca10208401c37fbf6002d937f89d201a80f41 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 31 Jan 2025 11:49:21 -0500 Subject: cmWorkerPool: Adopt MaybePrependCmdExe calls to reduce duplication --- Source/cmQtAutoMocUic.cxx | 5 ----- Source/cmWorkerPool.cxx | 2 ++ 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index 9ba48cc..653dc86 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -888,8 +888,6 @@ void cmQtAutoMocUicT::JobMocPredefsT::Process() // Check if response file is necessary MaybeWriteResponseFile(this->MocConst().PredefsFileAbs, cmd); - cmSystemTools::MaybePrependCmdExe(cmd); - // Execute command if (!this->RunProcess(GenT::MOC, result, cmd, reason.get())) { this->LogCommandError(GenT::MOC, @@ -2091,7 +2089,6 @@ void cmQtAutoMocUicT::JobCompileMocT::Process() cmd.push_back(sourceFile); MaybeWriteResponseFile(outputFile, cmd); - cmSystemTools::MaybePrependCmdExe(cmd); } // Execute moc command @@ -2158,8 +2155,6 @@ void cmQtAutoMocUicT::JobCompileUicT::Process() cmd.emplace_back(outputFile); cmd.emplace_back(sourceFile); - cmSystemTools::MaybePrependCmdExe(cmd); - cmWorkerPool::ProcessResultT result; if (this->RunProcess(GenT::UIC, result, cmd, this->Reason.get())) { // Uic command success diff --git a/Source/cmWorkerPool.cxx b/Source/cmWorkerPool.cxx index c057ed1..4a04e33 100644 --- a/Source/cmWorkerPool.cxx +++ b/Source/cmWorkerPool.cxx @@ -17,6 +17,7 @@ #include "cmRange.h" #include "cmStringAlgorithms.h" +#include "cmSystemTools.h" #include "cmUVHandlePtr.h" /** @@ -191,6 +192,7 @@ void cmUVReadOnlyProcess::setup(cmWorkerPool::ProcessResultT* result, std::vector command, std::string const& workingDirectory) { + cmSystemTools::MaybePrependCmdExe(command); this->Setup_.WorkingDirectory = workingDirectory; this->Setup_.Command = std::move(command); this->Setup_.Result = result; -- cgit v0.12 From 74c9d40876c955d5aca8824bfbdf78f79ca238a1 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 31 Jan 2025 11:51:01 -0500 Subject: 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 --- .gitattributes | 1 + Help/command/execute_process.rst | 12 ++++++++++-- Source/cmExecuteProcessCommand.cxx | 14 ++++++++++++-- Tests/RunCMake/execute_process/RunCMakeTest.cmake | 8 ++++++++ Tests/RunCMake/execute_process/WindowsBatch-stdout.txt | 8 ++++++++ Tests/RunCMake/execute_process/WindowsBatch.cmake | 8 ++++++++ Tests/RunCMake/execute_process/with space.bat | 1 + Tests/RunCMake/execute_process/with space.cmd | 1 + 8 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 Tests/RunCMake/execute_process/WindowsBatch-stdout.txt create mode 100644 Tests/RunCMake/execute_process/WindowsBatch.cmake create mode 100755 Tests/RunCMake/execute_process/with space.bat create mode 100755 Tests/RunCMake/execute_process/with space.cmd diff --git a/.gitattributes b/.gitattributes index 39ee3fb..8151ec8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -25,6 +25,7 @@ configure eol=lf *.bat eol=crlf *.bat.in eol=crlf +*.cmd eol=crlf *.sln eol=crlf *.vcproj eol=crlf diff --git a/Help/command/execute_process.rst b/Help/command/execute_process.rst index ed440b5..64ca24d 100644 --- a/Help/command/execute_process.rst +++ b/Help/command/execute_process.rst @@ -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 diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index 20a54b3..750c09d 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -120,7 +120,7 @@ bool cmExecuteProcessCommand(std::vector const& args, .Bind("COMMAND_ERROR_IS_FATAL"_s, &Arguments::CommandErrorIsFatal); std::vector 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 const& args, status.SetError(" called with no COMMAND argument."); return false; } - for (std::vector const& cmd : arguments.Commands) { + for (std::vector& 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. diff --git a/Tests/RunCMake/execute_process/RunCMakeTest.cmake b/Tests/RunCMake/execute_process/RunCMakeTest.cmake index e9b18a5..be2c652 100644 --- a/Tests/RunCMake/execute_process/RunCMakeTest.cmake +++ b/Tests/RunCMake/execute_process/RunCMakeTest.cmake @@ -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() diff --git a/Tests/RunCMake/execute_process/WindowsBatch-stdout.txt b/Tests/RunCMake/execute_process/WindowsBatch-stdout.txt new file mode 100644 index 0000000..58ced7e --- /dev/null +++ b/Tests/RunCMake/execute_process/WindowsBatch-stdout.txt @@ -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" -$ diff --git a/Tests/RunCMake/execute_process/WindowsBatch.cmake b/Tests/RunCMake/execute_process/WindowsBatch.cmake new file mode 100644 index 0000000..9ab9cb8 --- /dev/null +++ b/Tests/RunCMake/execute_process/WindowsBatch.cmake @@ -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") diff --git a/Tests/RunCMake/execute_process/with space.bat b/Tests/RunCMake/execute_process/with space.bat new file mode 100755 index 0000000..9712938 --- /dev/null +++ b/Tests/RunCMake/execute_process/with space.bat @@ -0,0 +1 @@ +@echo bat %1 - %2 - diff --git a/Tests/RunCMake/execute_process/with space.cmd b/Tests/RunCMake/execute_process/with space.cmd new file mode 100755 index 0000000..e3a64cf --- /dev/null +++ b/Tests/RunCMake/execute_process/with space.cmd @@ -0,0 +1 @@ +@echo cmd %1 - %2 - -- cgit v0.12