diff options
author | Alexey Edelev <alexey.edelev@qt.io> | 2024-08-19 19:12:03 (GMT) |
---|---|---|
committer | Alexey Edelev <alexey.edelev@qt.io> | 2024-08-21 09:05:19 (GMT) |
commit | 8d1803d463adac8ebc63bb0d1a9ef55b6c56472a (patch) | |
tree | f5deb9b7126b04cbb875553080ebbeaa6fe36520 | |
parent | 9ab270f47d68198dee29780a346294a728087105 (diff) | |
download | CMake-8d1803d463adac8ebc63bb0d1a9ef55b6c56472a.zip CMake-8d1803d463adac8ebc63bb0d1a9ef55b6c56472a.tar.gz CMake-8d1803d463adac8ebc63bb0d1a9ef55b6c56472a.tar.bz2 |
AutoGen: Run batch scripts using cmd.exe on windows platforms explicitly
The CreateProcessW function requires to use the cmd.exe when
attempting to execute batch scripts. AutoMoc RunProcess relies on
CreateProcessW in it's internals. Currently the cmd.exe run happens
implicitly for batch files(perhaps by luck), but this is not
documented anywhere.
This replaces the .bat files in the AutoGen related command lines with
explicit 'cmd.exe /c' call. Also 'cmd.exe /c' has own limitation
related to the arguments. The very first argument shouldn't be quoted
otherwise this lead to the parsing issues. So for the .bat files that
contain spaces in their paths use short name conversion.
Fixes #26208
-rw-r--r-- | Source/cmQtAutoMocUic.cxx | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index 408a22c..c07f361 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -345,6 +345,8 @@ public: void MaybeWriteResponseFile(std::string const& outputFile, std::vector<std::string>& cmd) const; + static void MaybePrependCmdExe(std::vector<std::string>& cmd); + /** @brief Run an external process. Use only during Process() call! */ bool RunProcess(GenT genType, cmWorkerPool::ProcessResultT& result, std::vector<std::string> const& command, @@ -848,6 +850,54 @@ 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<std::string>& cmdLine) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + if (!cmdLine.empty()) { + const auto& applicationName = cmdLine.at(0); + if (cmSystemTools::StringEndsWith(applicationName, ".bat") || + cmSystemTools::StringEndsWith(applicationName, ".cmd")) { + std::vector<std::string> 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<void>(cmdLine); +#endif +} + bool cmQtAutoMocUicT::JobT::RunProcess(GenT genType, cmWorkerPool::ProcessResultT& result, std::vector<std::string> const& command, @@ -891,6 +941,9 @@ void cmQtAutoMocUicT::JobMocPredefsT::Process() cm::append(cmd, this->MocConst().OptionsIncludes); // Check if response file is necessary MaybeWriteResponseFile(this->MocConst().PredefsFileAbs, cmd); + + MaybePrependCmdExe(cmd); + // Execute command if (!this->RunProcess(GenT::MOC, result, cmd, reason.get())) { this->LogCommandError(GenT::MOC, @@ -2090,6 +2143,7 @@ void cmQtAutoMocUicT::JobCompileMocT::Process() cmd.push_back(sourceFile); MaybeWriteResponseFile(outputFile, cmd); + MaybePrependCmdExe(cmd); } // Execute moc command @@ -2156,6 +2210,8 @@ void cmQtAutoMocUicT::JobCompileUicT::Process() cmd.emplace_back(outputFile); cmd.emplace_back(sourceFile); + MaybePrependCmdExe(cmd); + cmWorkerPool::ProcessResultT result; if (this->RunProcess(GenT::UIC, result, cmd, this->Reason.get())) { // Uic command success |