summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Edelev <alexey.edelev@qt.io>2024-08-19 19:12:03 (GMT)
committerAlexey Edelev <alexey.edelev@qt.io>2024-08-21 09:05:19 (GMT)
commit8d1803d463adac8ebc63bb0d1a9ef55b6c56472a (patch)
treef5deb9b7126b04cbb875553080ebbeaa6fe36520
parent9ab270f47d68198dee29780a346294a728087105 (diff)
downloadCMake-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.cxx56
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