From 7cbde5c503f15bcc568a64239977b8e1f6f501cb Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Fri, 5 Apr 2019 21:10:53 +0200 Subject: AutoRcc: Add cmQtAutoGen::RccLister class The new `cmQtAutoGen::RccLister` class provides a simple interface to list files in a `.qrc` resources file by either calling `rcc` with list options or by parsing the resources file content. --- Source/cmQtAutoGen.cxx | 108 +++++++++++++++++++++++++++++++++++++++++++++++-- Source/cmQtAutoGen.h | 39 ++++++++++++++++++ 2 files changed, 144 insertions(+), 3 deletions(-) diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx index d71d82f..9880c02 100644 --- a/Source/cmQtAutoGen.cxx +++ b/Source/cmQtAutoGen.cxx @@ -1,9 +1,12 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoGen.h" + #include "cmAlgorithms.h" +#include "cmDuration.h" +#include "cmProcessOutput.h" #include "cmSystemTools.h" - +#include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" #include @@ -309,7 +312,106 @@ void cmQtAutoGen::RccListConvertFullPath(std::string const& qrcFileDir, std::vector& files) { for (std::string& entry : files) { - std::string tmp = cmSystemTools::CollapseFullPath(entry, qrcFileDir); - entry = std::move(tmp); + entry = cmSystemTools::CollapseFullPath(entry, qrcFileDir); + } +} + +cmQtAutoGen::RccLister::RccLister() = default; + +cmQtAutoGen::RccLister::RccLister(std::string rccExecutable, + std::vector listOptions) + : RccExcutable_(std::move(rccExecutable)) + , ListOptions_(std::move(listOptions)) +{ +} + +bool cmQtAutoGen::RccLister::list(std::string const& qrcFile, + std::vector& files, + std::string& error, bool verbose) const +{ + error.clear(); + + if (!cmSystemTools::FileExists(qrcFile, true)) { + error = "The resource file "; + error += Quoted(qrcFile); + error += " does not exist."; + return false; + } + + // Run rcc list command in the directory of the qrc file with the pathless + // qrc file name argument. This way rcc prints relative paths. + // This avoids issues on Windows when the qrc file is in a path that + // contains non-ASCII characters. + std::string const fileDir = cmSystemTools::GetFilenamePath(qrcFile); + + if (!this->RccExcutable_.empty() && + cmSystemTools::FileExists(this->RccExcutable_, true) && + !this->ListOptions_.empty()) { + + bool result = false; + int retVal = 0; + std::string rccStdOut; + std::string rccStdErr; + { + std::vector cmd; + cmd.emplace_back(this->RccExcutable_); + cmd.insert(cmd.end(), this->ListOptions_.begin(), + this->ListOptions_.end()); + cmd.emplace_back(cmSystemTools::GetFilenameName(qrcFile)); + + // Log command + if (verbose) { + std::string msg = "Running command:\n"; + msg += QuotedCommand(cmd); + msg += '\n'; + cmSystemTools::Stdout(msg); + } + + result = cmSystemTools::RunSingleCommand( + cmd, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(), + cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto); + } + if (!result || retVal) { + error = "The rcc list process failed for "; + error += Quoted(qrcFile); + error += "\n"; + if (!rccStdOut.empty()) { + error += rccStdOut; + error += "\n"; + } + if (!rccStdErr.empty()) { + error += rccStdErr; + error += "\n"; + } + return false; + } + if (!RccListParseOutput(rccStdOut, rccStdErr, files, error)) { + return false; + } + } else { + // We can't use rcc for the file listing. + // Read the qrc file content into string and parse it. + { + std::string qrcContents; + { + cmsys::ifstream ifs(qrcFile.c_str()); + if (ifs) { + std::ostringstream osst; + osst << ifs.rdbuf(); + qrcContents = osst.str(); + } else { + error = "The resource file "; + error += Quoted(qrcFile); + error += " is not readable\n"; + return false; + } + } + // Parse string content + RccListParseContent(qrcContents, files); + } } + + // Convert relative paths to absolute paths + RccListConvertFullPath(fileDir, files); + return true; } diff --git a/Source/cmQtAutoGen.h b/Source/cmQtAutoGen.h index d127a71..0faf6b3 100644 --- a/Source/cmQtAutoGen.h +++ b/Source/cmQtAutoGen.h @@ -100,6 +100,45 @@ public: /// @brief Converts relative qrc entry paths to full paths static void RccListConvertFullPath(std::string const& qrcFileDir, std::vector& files); + + /** @class RccLister + * @brief Lists files in qrc resource files + */ + class RccLister + { + public: + RccLister(); + RccLister(std::string rccExecutable, std::vector listOptions); + + //! The rcc executable + std::string const& RccExcutable() const { return RccExcutable_; } + void SetRccExecutable(std::string const& rccExecutable) + { + RccExcutable_ = rccExecutable; + } + + //! The rcc executable list options + std::vector const& ListOptions() const + { + return ListOptions_; + } + void SetListOptions(std::vector const& listOptions) + { + ListOptions_ = listOptions; + } + + /** + * @brief Lists a files in the qrcFile + * @arg files The file names are appended to this list + * @arg error contains the error message when the function fails + */ + bool list(std::string const& qrcFile, std::vector& files, + std::string& error, bool verbose = false) const; + + private: + std::string RccExcutable_; + std::vector ListOptions_; + }; }; #endif -- cgit v0.12 From 521475b41b06d6f99edeeb9a36edb2bde8b55579 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Fri, 5 Apr 2019 21:31:27 +0200 Subject: AutoRcc: Use cmQtAutoGen::RccLister in initializer and generator Both classes `cmQtAutoGenInitializer` and `cmQtAutoGeneratorRcc` had different implementations for reading the files list from a `.qrc` resources file. This patch replaces both implementations with the common simple `cmQtAutoGen::RccLister` implementation. --- Source/cmQtAutoGenInitializer.cxx | 90 +-------------------------------------- Source/cmQtAutoGenInitializer.h | 4 -- Source/cmQtAutoGeneratorRcc.cxx | 57 +++---------------------- 3 files changed, 7 insertions(+), 144 deletions(-) diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index d80aaa2..be96f1a 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -7,7 +7,6 @@ #include "cmAlgorithms.h" #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" -#include "cmDuration.h" #include "cmFilePathChecksum.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" @@ -19,7 +18,6 @@ #include "cmMessageType.h" #include "cmOutputConverter.h" #include "cmPolicies.h" -#include "cmProcessOutput.h" #include "cmSourceFile.h" #include "cmSourceFileLocationKind.h" #include "cmSourceGroup.h" @@ -28,7 +26,6 @@ #include "cmSystemTools.h" #include "cmTarget.h" #include "cmake.h" -#include "cmsys/FStream.hxx" #include "cmsys/SystemInformation.hxx" #include @@ -36,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -935,7 +931,8 @@ bool cmQtAutoGenInitializer::InitScanFiles() for (Qrc& qrc : this->Rcc.Qrcs) { if (!qrc.Generated) { std::string error; - if (!RccListInputs(qrc.QrcFile, qrc.Resources, error)) { + RccLister const lister(this->Rcc.Executable, this->Rcc.ListOptions); + if (!lister.list(qrc.QrcFile, qrc.Resources, error)) { cmSystemTools::Error(error); return false; } @@ -1630,86 +1627,3 @@ bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars, return true; } - -/// @brief Reads the resource files list from from a .qrc file -/// @arg fileName Must be the absolute path of the .qrc file -/// @return True if the rcc file was successfully read -bool cmQtAutoGenInitializer::RccListInputs(std::string const& fileName, - std::vector& files, - std::string& error) -{ - if (!cmSystemTools::FileExists(fileName)) { - error = "rcc resource file does not exist:\n "; - error += Quoted(fileName); - error += "\n"; - return false; - } - if (this->Rcc.ExecutableExists && !this->Rcc.ListOptions.empty()) { - // Use rcc for file listing - if (this->Rcc.Executable.empty()) { - error = "rcc executable not available"; - return false; - } - - // Run rcc list command in the directory of the qrc file with the - // pathless - // qrc file name argument. This way rcc prints relative paths. - // This avoids issues on Windows when the qrc file is in a path that - // contains non-ASCII characters. - std::string const fileDir = cmSystemTools::GetFilenamePath(fileName); - std::string const fileNameName = cmSystemTools::GetFilenameName(fileName); - - bool result = false; - int retVal = 0; - std::string rccStdOut; - std::string rccStdErr; - { - std::vector cmd; - cmd.push_back(this->Rcc.Executable); - cmd.insert(cmd.end(), this->Rcc.ListOptions.begin(), - this->Rcc.ListOptions.end()); - cmd.push_back(fileNameName); - result = cmSystemTools::RunSingleCommand( - cmd, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(), - cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto); - } - if (!result || retVal) { - error = "rcc list process failed for:\n "; - error += Quoted(fileName); - error += "\n"; - error += rccStdOut; - error += "\n"; - error += rccStdErr; - error += "\n"; - return false; - } - if (!RccListParseOutput(rccStdOut, rccStdErr, files, error)) { - return false; - } - } else { - // We can't use rcc for the file listing. - // Read the qrc file content into string and parse it. - { - std::string qrcContents; - { - cmsys::ifstream ifs(fileName.c_str()); - if (ifs) { - std::ostringstream osst; - osst << ifs.rdbuf(); - qrcContents = osst.str(); - } else { - error = "rcc file not readable:\n "; - error += Quoted(fileName); - error += "\n"; - return false; - } - } - // Parse string content - RccListParseContent(qrcContents, files); - } - } - - // Convert relative paths to absolute paths - RccListConvertFullPath(cmSystemTools::GetFilenamePath(fileName), files); - return true; -} diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h index e7e5db2..7ff33c3 100644 --- a/Source/cmQtAutoGenInitializer.h +++ b/Source/cmQtAutoGenInitializer.h @@ -149,10 +149,6 @@ private: bool GetQtExecutable(GenVarsT& genVars, const std::string& executable, bool ignoreMissingTarget, std::string* output) const; - bool RccListInputs(std::string const& fileName, - std::vector& files, - std::string& errorMessage); - private: cmQtAutoGenGlobalInitializer* GlobalInitializer; cmGeneratorTarget* Target; diff --git a/Source/cmQtAutoGeneratorRcc.cxx b/Source/cmQtAutoGeneratorRcc.cxx index 5deb532..309d0e5 100644 --- a/Source/cmQtAutoGeneratorRcc.cxx +++ b/Source/cmQtAutoGeneratorRcc.cxx @@ -410,59 +410,12 @@ bool cmQtAutoGeneratorRcc::TestResourcesRead() return true; } - if (!RccListOptions_.empty()) { - // Start a rcc list process and parse the output - if (Process_) { - // Process is running already - if (Process_->IsFinished()) { - // Process is finished - if (!ProcessResult_.error()) { - // Process success - std::string parseError; - if (!RccListParseOutput(ProcessResult_.StdOut, ProcessResult_.StdErr, - Inputs_, parseError)) { - Log().ErrorFile(GenT::RCC, QrcFile_, parseError); - Error_ = true; - } - } else { - Log().ErrorFile(GenT::RCC, QrcFile_, ProcessResult_.ErrorMessage); - Error_ = true; - } - // Clean up - Process_.reset(); - ProcessResult_.reset(); - } else { - // Process is not finished, yet. - return false; - } - } else { - // Start a new process - // rcc prints relative entry paths when started in the directory of the - // qrc file with a pathless qrc file name argument. - // This is important because on Windows absolute paths returned by rcc - // might contain bad multibyte characters when the qrc file path - // contains non-ASCII pcharacters. - std::vector cmd; - cmd.push_back(RccExecutable_); - cmd.insert(cmd.end(), RccListOptions_.begin(), RccListOptions_.end()); - cmd.push_back(QrcFileName_); - // We're done here if the process fails to start - return !StartProcess(QrcFileDir_, cmd, false); - } - } else { - // rcc does not support the --list command. - // Read the qrc file content and parse it. - std::string qrcContent; - if (FileSys().FileRead(GenT::RCC, qrcContent, QrcFile_)) { - RccListParseContent(qrcContent, Inputs_); - } - } - - if (!Inputs_.empty()) { - // Convert relative paths to absolute paths - RccListConvertFullPath(QrcFileDir_, Inputs_); + std::string error; + RccLister lister(RccExecutable_, RccListOptions_); + if (!lister.list(QrcFile_, Inputs_, error)) { + Log().ErrorFile(GenT::RCC, QrcFile_, error); + Error_ = true; } - return true; } -- cgit v0.12 From 95de172b68b23124d8dfa3fb238876b8f2ecd3e7 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Fri, 5 Apr 2019 21:34:42 +0200 Subject: AutoRcc: Make rcc parsing function private The `.qrc` parsing functions in `cmQtAutoGen` are no longer needed outside the private implementation of `cmQtAutoGen::RccLister`. This makes them private, too. --- Source/cmQtAutoGen.cxx | 24 +++++++++--------------- Source/cmQtAutoGen.h | 16 ---------------- 2 files changed, 9 insertions(+), 31 deletions(-) diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx index 9880c02..9918c35 100644 --- a/Source/cmQtAutoGen.cxx +++ b/Source/cmQtAutoGen.cxx @@ -240,8 +240,8 @@ void cmQtAutoGen::RccMergeOptions(std::vector& baseOpts, MergeOptions(baseOpts, newOpts, valueOpts, isQt5); } -void cmQtAutoGen::RccListParseContent(std::string const& content, - std::vector& files) +static void RccListParseContent(std::string const& content, + std::vector& files) { cmsys::RegularExpression fileMatchRegex("(]*>)"); @@ -258,10 +258,10 @@ void cmQtAutoGen::RccListParseContent(std::string const& content, } } -bool cmQtAutoGen::RccListParseOutput(std::string const& rccStdOut, - std::string const& rccStdErr, - std::vector& files, - std::string& error) +static bool RccListParseOutput(std::string const& rccStdOut, + std::string const& rccStdErr, + std::vector& files, + std::string& error) { // Lambda to strip CR characters auto StripCR = [](std::string& line) { @@ -308,14 +308,6 @@ bool cmQtAutoGen::RccListParseOutput(std::string const& rccStdOut, return true; } -void cmQtAutoGen::RccListConvertFullPath(std::string const& qrcFileDir, - std::vector& files) -{ - for (std::string& entry : files) { - entry = cmSystemTools::CollapseFullPath(entry, qrcFileDir); - } -} - cmQtAutoGen::RccLister::RccLister() = default; cmQtAutoGen::RccLister::RccLister(std::string rccExecutable, @@ -412,6 +404,8 @@ bool cmQtAutoGen::RccLister::list(std::string const& qrcFile, } // Convert relative paths to absolute paths - RccListConvertFullPath(fileDir, files); + for (std::string& entry : files) { + entry = cmSystemTools::CollapseFullPath(entry, fileDir); + } return true; } diff --git a/Source/cmQtAutoGen.h b/Source/cmQtAutoGen.h index 0faf6b3..3a346b5 100644 --- a/Source/cmQtAutoGen.h +++ b/Source/cmQtAutoGen.h @@ -85,22 +85,6 @@ public: std::vector const& newOpts, bool isQt5); - /// @brief Parses the content of a qrc file - /// - /// Use when rcc does not support the "--list" option - static void RccListParseContent(std::string const& content, - std::vector& files); - - /// @brief Parses the output of the "rcc --list ..." command - static bool RccListParseOutput(std::string const& rccStdOut, - std::string const& rccStdErr, - std::vector& files, - std::string& error); - - /// @brief Converts relative qrc entry paths to full paths - static void RccListConvertFullPath(std::string const& qrcFileDir, - std::vector& files); - /** @class RccLister * @brief Lists files in qrc resource files */ -- cgit v0.12 From 191269d247827a4c1de739165c0555b4c9ea9d79 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Fri, 5 Apr 2019 21:54:53 +0200 Subject: AutoRcc: Remove libuv event loop from cmQtAutoGeneratorRcc Using a libuv event loop in AUTORCC is unnecessary and over complicated. This patch removes the loop and makes `cmQtAutoGeneratorRcc::Process` a regular serial processing method. --- Source/cmQtAutoGeneratorRcc.cxx | 424 ++++++++++++++-------------------------- Source/cmQtAutoGeneratorRcc.h | 49 +---- 2 files changed, 158 insertions(+), 315 deletions(-) diff --git a/Source/cmQtAutoGeneratorRcc.cxx b/Source/cmQtAutoGeneratorRcc.cxx index 309d0e5..792e6fd 100644 --- a/Source/cmQtAutoGeneratorRcc.cxx +++ b/Source/cmQtAutoGeneratorRcc.cxx @@ -5,18 +5,15 @@ #include "cmAlgorithms.h" #include "cmCryptoHash.h" +#include "cmDuration.h" #include "cmFileLockResult.h" #include "cmMakefile.h" +#include "cmProcessOutput.h" #include "cmSystemTools.h" -#include "cmUVHandlePtr.h" // -- Class methods -cmQtAutoGeneratorRcc::cmQtAutoGeneratorRcc() -{ - // Initialize libuv asynchronous iteration request - UVRequest().init(*UVLoop(), &cmQtAutoGeneratorRcc::UVPollStage, this); -} +cmQtAutoGeneratorRcc::cmQtAutoGeneratorRcc() = default; cmQtAutoGeneratorRcc::~cmQtAutoGeneratorRcc() = default; @@ -142,101 +139,38 @@ bool cmQtAutoGeneratorRcc::Init(cmMakefile* makefile) bool cmQtAutoGeneratorRcc::Process() { - // Run libuv event loop - UVRequest().send(); - if (uv_run(UVLoop(), UV_RUN_DEFAULT) == 0) { - if (Error_) { + if (!SettingsFileRead()) { + return false; + } + + // Test if the rcc output needs to be regenerated + bool generate = false; + if (!TestQrcRccFiles(generate)) { + return false; + } + if (!generate && !TestResources(generate)) { + return false; + } + // Generate on demand + if (generate) { + if (!GenerateParentDir()) { + return false; + } + if (!GenerateRcc()) { return false; } } else { - return false; + // Test if the info file is newer than the output file + if (!TestInfoFile()) { + return false; + } } - return true; -} - -void cmQtAutoGeneratorRcc::UVPollStage(uv_async_t* handle) -{ - reinterpret_cast(handle->data)->PollStage(); -} - -void cmQtAutoGeneratorRcc::PollStage() -{ - switch (Stage_) { - // -- Initialize - case StageT::SETTINGS_READ: - if (SettingsFileRead()) { - SetStage(StageT::TEST_QRC_RCC_FILES); - } else { - SetStage(StageT::FINISH); - } - break; - - // -- Change detection - case StageT::TEST_QRC_RCC_FILES: - if (TestQrcRccFiles()) { - SetStage(StageT::GENERATE); - } else { - SetStage(StageT::TEST_RESOURCES_READ); - } - break; - case StageT::TEST_RESOURCES_READ: - if (TestResourcesRead()) { - SetStage(StageT::TEST_RESOURCES); - } - break; - case StageT::TEST_RESOURCES: - if (TestResources()) { - SetStage(StageT::GENERATE); - } else { - SetStage(StageT::TEST_INFO_FILE); - } - break; - case StageT::TEST_INFO_FILE: - TestInfoFile(); - SetStage(StageT::GENERATE_WRAPPER); - break; - - // -- Generation - case StageT::GENERATE: - GenerateParentDir(); - SetStage(StageT::GENERATE_RCC); - break; - case StageT::GENERATE_RCC: - if (GenerateRcc()) { - SetStage(StageT::GENERATE_WRAPPER); - } - break; - case StageT::GENERATE_WRAPPER: - GenerateWrapper(); - SetStage(StageT::SETTINGS_WRITE); - break; - // -- Finalize - case StageT::SETTINGS_WRITE: - SettingsFileWrite(); - SetStage(StageT::FINISH); - break; - case StageT::FINISH: - // Clear all libuv handles - UVRequest().reset(); - // Set highest END stage manually - Stage_ = StageT::END; - break; - case StageT::END: - break; + if (!GenerateWrapper()) { + return false; } -} -void cmQtAutoGeneratorRcc::SetStage(StageT stage) -{ - if (Error_) { - stage = StageT::FINISH; - } - // Only allow to increase the stage - if (Stage_ < stage) { - Stage_ = stage; - UVRequest().send(); - } + return SettingsFileWrite(); } std::string cmQtAutoGeneratorRcc::MultiConfigOutput() const @@ -287,7 +221,6 @@ bool cmQtAutoGeneratorRcc::SettingsFileRead() if (!FileSys().FileExists(LockFile_, true)) { if (!FileSys().Touch(LockFile_, true)) { Log().ErrorFile(GenT::RCC, LockFile_, "Lock file creation failed"); - Error_ = true; return false; } } @@ -297,7 +230,6 @@ bool cmQtAutoGeneratorRcc::SettingsFileRead() if (!lockResult.IsOk()) { Log().ErrorFile(GenT::RCC, LockFile_, "File lock failed: " + lockResult.GetOutputMessage()); - Error_ = true; return false; } } @@ -321,7 +253,7 @@ bool cmQtAutoGeneratorRcc::SettingsFileRead() return true; } -void cmQtAutoGeneratorRcc::SettingsFileWrite() +bool cmQtAutoGeneratorRcc::SettingsFileWrite() { // Only write if any setting changed if (SettingsChanged_) { @@ -337,20 +269,30 @@ void cmQtAutoGeneratorRcc::SettingsFileWrite() "Settings file writing failed"); // Remove old settings file to trigger a full rebuild on the next run FileSys().FileRemove(SettingsFile_); - Error_ = true; + return false; } } // Unlock the lock file LockFileLock_.Release(); + return true; } -bool cmQtAutoGeneratorRcc::TestQrcRccFiles() +/// Do basic checks if rcc generation is required +bool cmQtAutoGeneratorRcc::TestQrcRccFiles(bool& generate) { - // Do basic checks if rcc generation is required + // Test if the rcc input file exists + if (!QrcFileTime_.Load(QrcFile_)) { + std::string error; + error = "The resources file "; + error += Quoted(QrcFile_); + error += " does not exist"; + Log().ErrorFile(GenT::RCC, QrcFile_, error); + return false; + } // Test if the rcc output file exists - if (!FileSys().FileExists(RccFileOutput_)) { + if (!RccFileTime_.Load(RccFileOutput_)) { if (Log().Verbose()) { std::string reason = "Generating "; reason += Quoted(RccFileOutput_); @@ -359,8 +301,8 @@ bool cmQtAutoGeneratorRcc::TestQrcRccFiles() reason += " because it doesn't exist"; Log().Info(GenT::RCC, reason); } - Generate_ = true; - return Generate_; + generate = true; + return true; } // Test if the settings changed @@ -373,192 +315,150 @@ bool cmQtAutoGeneratorRcc::TestQrcRccFiles() reason += " because the RCC settings changed"; Log().Info(GenT::RCC, reason); } - Generate_ = true; - return Generate_; + generate = true; + return true; } // Test if the rcc output file is older than the .qrc file - { - bool isOlder = false; - { - std::string error; - isOlder = FileSys().FileIsOlderThan(RccFileOutput_, QrcFile_, &error); - if (!error.empty()) { - Log().ErrorFile(GenT::RCC, QrcFile_, error); - Error_ = true; - } - } - if (isOlder) { - if (Log().Verbose()) { - std::string reason = "Generating "; - reason += Quoted(RccFileOutput_); - reason += " because it is older than "; - reason += Quoted(QrcFile_); - Log().Info(GenT::RCC, reason); - } - Generate_ = true; + if (RccFileTime_.Older(QrcFileTime_)) { + if (Log().Verbose()) { + std::string reason = "Generating "; + reason += Quoted(RccFileOutput_); + reason += " because it is older than "; + reason += Quoted(QrcFile_); + Log().Info(GenT::RCC, reason); } - } - - return Generate_; -} - -bool cmQtAutoGeneratorRcc::TestResourcesRead() -{ - if (!Inputs_.empty()) { - // Inputs are known already + generate = true; return true; } - std::string error; - RccLister lister(RccExecutable_, RccListOptions_); - if (!lister.list(QrcFile_, Inputs_, error)) { - Log().ErrorFile(GenT::RCC, QrcFile_, error); - Error_ = true; - } return true; } -bool cmQtAutoGeneratorRcc::TestResources() +bool cmQtAutoGeneratorRcc::TestResources(bool& generate) { + // Read resource files list if (Inputs_.empty()) { - return true; - } - { std::string error; - for (std::string const& resFile : Inputs_) { - // Check if the resource file exists - if (!FileSys().FileExists(resFile)) { - error = "Could not find the resource file\n "; - error += Quoted(resFile); - error += '\n'; - Log().ErrorFile(GenT::RCC, QrcFile_, error); - Error_ = true; - break; - } - // Check if the resource file is newer than the build file - if (FileSys().FileIsOlderThan(RccFileOutput_, resFile, &error)) { - if (Log().Verbose()) { - std::string reason = "Generating "; - reason += Quoted(RccFileOutput_); - reason += " from "; - reason += Quoted(QrcFile_); - reason += " because it is older than "; - reason += Quoted(resFile); - Log().Info(GenT::RCC, reason); - } - Generate_ = true; - break; - } - // Print error and break on demand - if (!error.empty()) { - Log().ErrorFile(GenT::RCC, QrcFile_, error); - Error_ = true; - break; - } + RccLister const lister(RccExecutable_, RccListOptions_); + if (!lister.list(QrcFile_, Inputs_, error, Log().Verbose())) { + Log().ErrorFile(GenT::RCC, QrcFile_, error); + return false; } } - return Generate_; -} - -void cmQtAutoGeneratorRcc::TestInfoFile() -{ - // Test if the rcc output file is older than the info file - { - bool isOlder = false; - { + for (std::string const& resFile : Inputs_) { + // Check if the resource file exists + cmFileTime fileTime; + if (!fileTime.Load(resFile)) { std::string error; - isOlder = FileSys().FileIsOlderThan(RccFileOutput_, InfoFile(), &error); - if (!error.empty()) { - Log().ErrorFile(GenT::RCC, QrcFile_, error); - Error_ = true; - } + error = "Could not find the resource file\n "; + error += Quoted(resFile); + error += '\n'; + Log().ErrorFile(GenT::RCC, QrcFile_, error); + return false; } - if (isOlder) { + // Check if the resource file is newer than the build file + if (RccFileTime_.Older(fileTime)) { if (Log().Verbose()) { - std::string reason = "Touching "; + std::string reason = "Generating "; reason += Quoted(RccFileOutput_); + reason += " from "; + reason += Quoted(QrcFile_); reason += " because it is older than "; - reason += Quoted(InfoFile()); + reason += Quoted(resFile); Log().Info(GenT::RCC, reason); } - // Touch build file - FileSys().Touch(RccFileOutput_); - BuildFileChanged_ = true; + generate = true; + break; } } + return true; } -void cmQtAutoGeneratorRcc::GenerateParentDir() +bool cmQtAutoGeneratorRcc::TestInfoFile() { - // Make sure the parent directory exists - if (!FileSys().MakeParentDirectory(GenT::RCC, RccFileOutput_)) { - Error_ = true; + // Test if the rcc output file is older than the info file + + cmFileTime infoFileTime; + if (!infoFileTime.Load(InfoFile())) { + std::string error; + error = "Could not find the info file "; + error += Quoted(InfoFile()); + error += '\n'; + Log().ErrorFile(GenT::RCC, QrcFile_, error); + return false; + } + if (RccFileTime_.Older(infoFileTime)) { + if (Log().Verbose()) { + std::string reason = "Touching "; + reason += Quoted(RccFileOutput_); + reason += " because it is older than "; + reason += Quoted(InfoFile()); + Log().Info(GenT::RCC, reason); + } + // Touch build file + FileSys().Touch(RccFileOutput_); + BuildFileChanged_ = true; } + + return true; +} + +bool cmQtAutoGeneratorRcc::GenerateParentDir() +{ + // Make sure the parent directory exists + return FileSys().MakeParentDirectory(GenT::RCC, RccFileOutput_); } -/** - * @return True when finished - */ bool cmQtAutoGeneratorRcc::GenerateRcc() { - if (!Generate_) { - // Nothing to do - return true; + // Start a rcc process + std::vector cmd; + cmd.push_back(RccExecutable_); + cmd.insert(cmd.end(), Options_.begin(), Options_.end()); + cmd.emplace_back("-o"); + cmd.push_back(RccFileOutput_); + cmd.push_back(QrcFile_); + + // Log command + if (Log().Verbose()) { + std::string msg = "Running command:\n"; + msg += QuotedCommand(cmd); + msg += '\n'; + cmSystemTools::Stdout(msg); } - if (Process_) { - // Process is running already - if (Process_->IsFinished()) { - // Process is finished - if (!ProcessResult_.error()) { - // Rcc process success - // Print rcc output - if (!ProcessResult_.StdOut.empty()) { - Log().Info(GenT::RCC, ProcessResult_.StdOut); - } - BuildFileChanged_ = true; - } else { - // Rcc process failed - { - std::string emsg = "The rcc process failed to compile\n "; - emsg += Quoted(QrcFile_); - emsg += "\ninto\n "; - emsg += Quoted(RccFileOutput_); - if (ProcessResult_.error()) { - emsg += "\n"; - emsg += ProcessResult_.ErrorMessage; - } - Log().ErrorCommand(GenT::RCC, emsg, Process_->Setup().Command, - ProcessResult_.StdOut); - } - FileSys().FileRemove(RccFileOutput_); - Error_ = true; - } - // Clean up - Process_.reset(); - ProcessResult_.reset(); - } else { - // Process is not finished, yet. - return false; + std::string rccStdOut; + std::string rccStdErr; + int retVal = 0; + bool result = cmSystemTools::RunSingleCommand( + cmd, &rccStdOut, &rccStdErr, &retVal, AutogenBuildDir_.c_str(), + cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto); + if (!result || (retVal != 0)) { + // rcc process failed + { + std::string err = "The rcc process failed to compile\n "; + err += Quoted(QrcFile_); + err += "\ninto\n "; + err += Quoted(RccFileOutput_); + Log().ErrorCommand(GenT::RCC, err, cmd, rccStdOut + rccStdErr); } - } else { - // Start a rcc process - std::vector cmd; - cmd.push_back(RccExecutable_); - cmd.insert(cmd.end(), Options_.begin(), Options_.end()); - cmd.emplace_back("-o"); - cmd.push_back(RccFileOutput_); - cmd.push_back(QrcFile_); - // We're done here if the process fails to start - return !StartProcess(AutogenBuildDir_, cmd, true); + FileSys().FileRemove(RccFileOutput_); + return false; } + // rcc process success + // Print rcc output + if (!rccStdOut.empty()) { + Log().Info(GenT::RCC, rccStdOut); + } + BuildFileChanged_ = true; + return true; } -void cmQtAutoGeneratorRcc::GenerateWrapper() +bool cmQtAutoGeneratorRcc::GenerateWrapper() { // Generate a wrapper source file on demand if (IsMultiConfig()) { @@ -579,7 +479,7 @@ void cmQtAutoGeneratorRcc::GenerateWrapper() if (!FileSys().FileWrite(GenT::RCC, RccFilePublic_, content)) { Log().ErrorFile(GenT::RCC, RccFilePublic_, "RCC wrapper file writing failed"); - Error_ = true; + return false; } } else if (BuildFileChanged_) { // Just touch the wrapper file @@ -589,31 +489,5 @@ void cmQtAutoGeneratorRcc::GenerateWrapper() FileSys().Touch(RccFilePublic_); } } -} - -bool cmQtAutoGeneratorRcc::StartProcess( - std::string const& workingDirectory, std::vector const& command, - bool mergedOutput) -{ - // Log command - if (Log().Verbose()) { - std::string msg = "Running command:\n"; - msg += QuotedCommand(command); - msg += '\n'; - Log().Info(GenT::RCC, msg); - } - - // Create process handler - Process_ = cm::make_unique(); - Process_->setup(&ProcessResult_, mergedOutput, command, workingDirectory); - // Start process - if (!Process_->start(UVLoop(), [this] { UVRequest().send(); })) { - Log().ErrorFile(GenT::RCC, QrcFile_, ProcessResult_.ErrorMessage); - Error_ = true; - // Clean up - Process_.reset(); - ProcessResult_.reset(); - return false; - } return true; } diff --git a/Source/cmQtAutoGeneratorRcc.h b/Source/cmQtAutoGeneratorRcc.h index 1ec1c4a..baa560c 100644 --- a/Source/cmQtAutoGeneratorRcc.h +++ b/Source/cmQtAutoGeneratorRcc.h @@ -6,8 +6,8 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmFileLock.h" +#include "cmFileTime.h" #include "cmQtAutoGenerator.h" -#include "cm_uv.h" #include #include @@ -25,50 +25,24 @@ public: cmQtAutoGeneratorRcc& operator=(cmQtAutoGeneratorRcc const&) = delete; private: - // -- Types - - /// @brief Processing stage - enum class StageT : unsigned char - { - SETTINGS_READ, - TEST_QRC_RCC_FILES, - TEST_RESOURCES_READ, - TEST_RESOURCES, - TEST_INFO_FILE, - GENERATE, - GENERATE_RCC, - GENERATE_WRAPPER, - SETTINGS_WRITE, - FINISH, - END - }; - // -- Abstract processing interface bool Init(cmMakefile* makefile) override; bool Process() override; - // -- Process stage - static void UVPollStage(uv_async_t* handle); - void PollStage(); - void SetStage(StageT stage); // -- Settings file bool SettingsFileRead(); - void SettingsFileWrite(); + bool SettingsFileWrite(); // -- Tests - bool TestQrcRccFiles(); - bool TestResourcesRead(); - bool TestResources(); - void TestInfoFile(); + bool TestQrcRccFiles(bool& generate); + bool TestResources(bool& generate); + bool TestInfoFile(); // -- Generation - void GenerateParentDir(); + bool GenerateParentDir(); bool GenerateRcc(); - void GenerateWrapper(); + bool GenerateWrapper(); // -- Utility bool IsMultiConfig() const { return MultiConfig_; } std::string MultiConfigOutput() const; - bool StartProcess(std::string const& workingDirectory, - std::vector const& command, - bool mergedOutput); private: // -- Config settings @@ -85,23 +59,18 @@ private: std::string QrcFile_; std::string QrcFileName_; std::string QrcFileDir_; + cmFileTime QrcFileTime_; std::string RccPathChecksum_; std::string RccFileName_; std::string RccFileOutput_; std::string RccFilePublic_; + cmFileTime RccFileTime_; std::vector Options_; std::vector Inputs_; - // -- Subprocess - ProcessResultT ProcessResult_; - std::unique_ptr Process_; // -- Settings file std::string SettingsFile_; std::string SettingsString_; bool SettingsChanged_ = false; - // -- libuv loop - StageT Stage_ = StageT::SETTINGS_READ; - bool Error_ = false; - bool Generate_ = false; bool BuildFileChanged_ = false; }; -- cgit v0.12 From 7baec5e94b372cfc21e777488ecf993e4bce368e Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Fri, 5 Apr 2019 23:43:19 +0200 Subject: AutoRcc: Don't use cmQtAutoGenerator::FileSystem methods `cmQtAutoGenerator::FileSystem` is only required for concurrent file system access, but `cmQtAutoGeneratorRcc` isn't concurrent. Therefore this patch replaces all `cmQtAutoGenerator::FileSystem` uses in `cmQtAutoGeneratorRcc`. --- Source/cmQtAutoGenerator.cxx | 148 +++++++++++++++++++++++----------------- Source/cmQtAutoGenerator.h | 8 +++ Source/cmQtAutoGeneratorRcc.cxx | 93 +++++++++++++++---------- Source/cmQtAutoGeneratorRcc.h | 1 - 4 files changed, 153 insertions(+), 97 deletions(-) diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx index 27afe48..f56f7c9 100644 --- a/Source/cmQtAutoGenerator.cxx +++ b/Source/cmQtAutoGenerator.cxx @@ -152,6 +152,87 @@ void cmQtAutoGenerator::Logger::ErrorCommand( } } +bool cmQtAutoGenerator::MakeParentDirectory(std::string const& filename) +{ + bool success = true; + std::string const dirName = cmSystemTools::GetFilenamePath(filename); + if (!dirName.empty()) { + success = cmSystemTools::MakeDirectory(dirName); + } + return success; +} + +bool cmQtAutoGenerator::FileRead(std::string& content, + std::string const& filename, + std::string* error) +{ + content.clear(); + if (!cmSystemTools::FileExists(filename, true)) { + if (error != nullptr) { + error->append("Not a file."); + } + return false; + } + + unsigned long const length = cmSystemTools::FileLength(filename); + cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary)); + + // Use lambda to save destructor calls of ifs + return [&ifs, length, &content, error]() -> bool { + if (!ifs) { + if (error != nullptr) { + error->append("Opening the file for reading failed."); + } + return false; + } + content.reserve(length); + typedef std::istreambuf_iterator IsIt; + content.assign(IsIt{ ifs }, IsIt{}); + if (!ifs) { + content.clear(); + if (error != nullptr) { + error->append("Reading from the file failed."); + } + return false; + } + return true; + }(); +} + +bool cmQtAutoGenerator::FileWrite(std::string const& filename, + std::string const& content, + std::string* error) +{ + // Make sure the parent directory exists + if (!cmQtAutoGenerator::MakeParentDirectory(filename)) { + if (error != nullptr) { + error->assign("Could not create parent directory."); + } + return false; + } + cmsys::ofstream ofs; + ofs.open(filename.c_str(), + (std::ios::out | std::ios::binary | std::ios::trunc)); + + // Use lambda to save destructor calls of ofs + return [&ofs, &content, error]() -> bool { + if (!ofs) { + if (error != nullptr) { + error->assign("Opening file for writing failed."); + } + return false; + } + ofs << content; + if (!ofs.good()) { + if (error != nullptr) { + error->assign("File writing failed."); + } + return false; + } + return true; + }(); +} + std::string cmQtAutoGenerator::FileSystem::GetRealPath( std::string const& filename) { @@ -267,33 +348,8 @@ bool cmQtAutoGenerator::FileSystem::FileRead(std::string& content, std::string const& filename, std::string* error) { - bool success = false; - if (FileExists(filename, true)) { - unsigned long const length = FileLength(filename); - { - std::lock_guard lock(Mutex_); - cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary)); - if (ifs) { - content.reserve(length); - content.assign(std::istreambuf_iterator{ ifs }, - std::istreambuf_iterator{}); - if (ifs) { - success = true; - } else { - content.clear(); - if (error != nullptr) { - error->append("Reading from the file failed."); - } - } - } else if (error != nullptr) { - error->append("Opening the file for reading failed."); - } - } - } else if (error != nullptr) { - error->append( - "The file does not exist, is not readable or is a directory."); - } - return success; + std::lock_guard lock(Mutex_); + return cmQtAutoGenerator::FileRead(content, filename, error); } bool cmQtAutoGenerator::FileSystem::FileRead(GenT genType, @@ -312,34 +368,8 @@ bool cmQtAutoGenerator::FileSystem::FileWrite(std::string const& filename, std::string const& content, std::string* error) { - bool success = false; - // Make sure the parent directory exists - if (MakeParentDirectory(filename)) { - std::lock_guard lock(Mutex_); - cmsys::ofstream outfile; - outfile.open(filename.c_str(), - (std::ios::out | std::ios::binary | std::ios::trunc)); - if (outfile) { - outfile << content; - // Check for write errors - if (outfile.good()) { - success = true; - } else { - if (error != nullptr) { - error->assign("File writing failed"); - } - } - } else { - if (error != nullptr) { - error->assign("Opening file for writing failed"); - } - } - } else { - if (error != nullptr) { - error->assign("Could not create parent directory"); - } - } - return success; + std::lock_guard lock(Mutex_); + return cmQtAutoGenerator::FileWrite(filename, content, error); } bool cmQtAutoGenerator::FileSystem::FileWrite(GenT genType, @@ -399,12 +429,8 @@ bool cmQtAutoGenerator::FileSystem::MakeDirectory(GenT genType, bool cmQtAutoGenerator::FileSystem::MakeParentDirectory( std::string const& filename) { - bool success = true; - std::string const dirName = cmSystemTools::GetFilenamePath(filename); - if (!dirName.empty()) { - success = MakeDirectory(dirName); - } - return success; + std::lock_guard lock(Mutex_); + return cmQtAutoGenerator::MakeParentDirectory(filename); } bool cmQtAutoGenerator::FileSystem::MakeParentDirectory( diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h index b55bebc..17170d7 100644 --- a/Source/cmQtAutoGenerator.h +++ b/Source/cmQtAutoGenerator.h @@ -62,6 +62,14 @@ public: bool ColorOutput_ = false; }; + // -- File system methods + static bool MakeParentDirectory(std::string const& filename); + static bool FileRead(std::string& content, std::string const& filename, + std::string* error = nullptr); + static bool FileWrite(std::string const& filename, + std::string const& content, + std::string* error = nullptr); + /// @brief Thread safe file system interface class FileSystem { diff --git a/Source/cmQtAutoGeneratorRcc.cxx b/Source/cmQtAutoGeneratorRcc.cxx index 792e6fd..add84de 100644 --- a/Source/cmQtAutoGeneratorRcc.cxx +++ b/Source/cmQtAutoGeneratorRcc.cxx @@ -52,7 +52,7 @@ bool cmQtAutoGeneratorRcc::Init(cmMakefile* makefile) // -- Read info file if (!makefile->ReadListFile(InfoFile())) { - Log().ErrorFile(GenT::RCC, InfoFile(), "File processing failed"); + Log().ErrorFile(GenT::RCC, InfoFile(), "File processing failed."); return false; } @@ -63,13 +63,13 @@ bool cmQtAutoGeneratorRcc::Init(cmMakefile* makefile) // - Directories AutogenBuildDir_ = InfoGet("ARCC_BUILD_DIR"); if (AutogenBuildDir_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "Build directory empty"); + Log().ErrorFile(GenT::RCC, InfoFile(), "Build directory empty."); return false; } IncludeDir_ = InfoGetConfig("ARCC_INCLUDE_DIR"); if (IncludeDir_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "Include directory empty"); + Log().ErrorFile(GenT::RCC, InfoFile(), "Include directory empty."); return false; } @@ -92,27 +92,27 @@ bool cmQtAutoGeneratorRcc::Init(cmMakefile* makefile) // - Validity checks if (LockFile_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "Lock file name missing"); + Log().ErrorFile(GenT::RCC, InfoFile(), "Lock file name missing."); return false; } if (SettingsFile_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "Settings file name missing"); + Log().ErrorFile(GenT::RCC, InfoFile(), "Settings file name missing."); return false; } if (AutogenBuildDir_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "Autogen build directory missing"); + Log().ErrorFile(GenT::RCC, InfoFile(), "Autogen build directory missing."); return false; } if (RccExecutable_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "rcc executable missing"); + Log().ErrorFile(GenT::RCC, InfoFile(), "rcc executable missing."); return false; } if (QrcFile_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "rcc input file missing"); + Log().ErrorFile(GenT::RCC, InfoFile(), "rcc input file missing."); return false; } if (RccFileName_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "rcc output file missing"); + Log().ErrorFile(GenT::RCC, InfoFile(), "rcc output file missing."); return false; } @@ -153,9 +153,6 @@ bool cmQtAutoGeneratorRcc::Process() } // Generate on demand if (generate) { - if (!GenerateParentDir()) { - return false; - } if (!GenerateRcc()) { return false; } @@ -210,17 +207,21 @@ bool cmQtAutoGeneratorRcc::SettingsFileRead() } // Make sure the settings file exists - if (!FileSys().FileExists(SettingsFile_, true)) { + if (!cmSystemTools::FileExists(SettingsFile_, true)) { // Touch the settings file to make sure it exists - FileSys().Touch(SettingsFile_, true); + if (!cmSystemTools::Touch(SettingsFile_, true)) { + Log().ErrorFile(GenT::RCC, SettingsFile_, + "Settings file creation failed."); + return false; + } } // Lock the lock file { // Make sure the lock file exists - if (!FileSys().FileExists(LockFile_, true)) { - if (!FileSys().Touch(LockFile_, true)) { - Log().ErrorFile(GenT::RCC, LockFile_, "Lock file creation failed"); + if (!cmSystemTools::FileExists(LockFile_, true)) { + if (!cmSystemTools::Touch(LockFile_, true)) { + Log().ErrorFile(GenT::RCC, LockFile_, "Lock file creation failed."); return false; } } @@ -237,13 +238,18 @@ bool cmQtAutoGeneratorRcc::SettingsFileRead() // Read old settings { std::string content; - if (FileSys().FileRead(content, SettingsFile_)) { + if (FileRead(content, SettingsFile_)) { SettingsChanged_ = (SettingsString_ != SettingsFind(content, "rcc")); // In case any setting changed clear the old settings file. // This triggers a full rebuild on the next run if the current // build is aborted before writing the current settings in the end. if (SettingsChanged_) { - FileSys().FileWrite(GenT::RCC, SettingsFile_, ""); + std::string error; + if (!FileWrite(SettingsFile_, "", &error)) { + Log().ErrorFile(GenT::RCC, SettingsFile_, + "Settings file clearing failed. " + error); + return false; + } } } else { SettingsChanged_ = true; @@ -264,11 +270,12 @@ bool cmQtAutoGeneratorRcc::SettingsFileWrite() std::string content = "rcc:"; content += SettingsString_; content += '\n'; - if (!FileSys().FileWrite(GenT::RCC, SettingsFile_, content)) { + std::string error; + if (!FileWrite(SettingsFile_, content, &error)) { Log().ErrorFile(GenT::RCC, SettingsFile_, - "Settings file writing failed"); + "Settings file writing failed. " + error); // Remove old settings file to trigger a full rebuild on the next run - FileSys().FileRemove(SettingsFile_); + cmSystemTools::RemoveFile(SettingsFile_); return false; } } @@ -398,21 +405,25 @@ bool cmQtAutoGeneratorRcc::TestInfoFile() Log().Info(GenT::RCC, reason); } // Touch build file - FileSys().Touch(RccFileOutput_); + if (!cmSystemTools::Touch(RccFileOutput_, false)) { + Log().ErrorFile(GenT::RCC, RccFileOutput_, "Build file touch failed"); + return false; + } BuildFileChanged_ = true; } return true; } -bool cmQtAutoGeneratorRcc::GenerateParentDir() -{ - // Make sure the parent directory exists - return FileSys().MakeParentDirectory(GenT::RCC, RccFileOutput_); -} - bool cmQtAutoGeneratorRcc::GenerateRcc() { + // Make parent directory + if (!MakeParentDirectory(RccFileOutput_)) { + Log().ErrorFile(GenT::RCC, RccFileOutput_, + "Could not create parent directory"); + return false; + } + // Start a rcc process std::vector cmd; cmd.push_back(RccExecutable_); @@ -444,7 +455,7 @@ bool cmQtAutoGeneratorRcc::GenerateRcc() err += Quoted(RccFileOutput_); Log().ErrorCommand(GenT::RCC, err, cmd, rccStdOut + rccStdErr); } - FileSys().FileRemove(RccFileOutput_); + cmSystemTools::RemoveFile(RccFileOutput_); return false; } @@ -470,15 +481,23 @@ bool cmQtAutoGeneratorRcc::GenerateWrapper() content += MultiConfigOutput(); content += ">\n"; - // Write content to file - if (FileSys().FileDiffers(RccFilePublic_, content)) { + // Compare with existing file content + bool fileDiffers = true; + { + std::string oldContents; + if (FileRead(oldContents, RccFilePublic_)) { + fileDiffers = (oldContents != content); + } + } + if (fileDiffers) { // Write new wrapper file if (Log().Verbose()) { Log().Info(GenT::RCC, "Generating RCC wrapper file " + RccFilePublic_); } - if (!FileSys().FileWrite(GenT::RCC, RccFilePublic_, content)) { + std::string error; + if (!FileWrite(RccFilePublic_, content, &error)) { Log().ErrorFile(GenT::RCC, RccFilePublic_, - "RCC wrapper file writing failed"); + "RCC wrapper file writing failed. " + error); return false; } } else if (BuildFileChanged_) { @@ -486,7 +505,11 @@ bool cmQtAutoGeneratorRcc::GenerateWrapper() if (Log().Verbose()) { Log().Info(GenT::RCC, "Touching RCC wrapper file " + RccFilePublic_); } - FileSys().Touch(RccFilePublic_); + if (!cmSystemTools::Touch(RccFilePublic_, false)) { + Log().ErrorFile(GenT::RCC, RccFilePublic_, + "RCC wrapper file touch failed."); + return false; + } } } return true; diff --git a/Source/cmQtAutoGeneratorRcc.h b/Source/cmQtAutoGeneratorRcc.h index baa560c..d831f1f 100644 --- a/Source/cmQtAutoGeneratorRcc.h +++ b/Source/cmQtAutoGeneratorRcc.h @@ -36,7 +36,6 @@ private: bool TestResources(bool& generate); bool TestInfoFile(); // -- Generation - bool GenerateParentDir(); bool GenerateRcc(); bool GenerateWrapper(); -- cgit v0.12 From f161cfe5a8fa00d6d203885e9c1985ec53d7d625 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Sat, 6 Apr 2019 11:43:21 +0200 Subject: Autogen: Move Logger and FileSystem member variables to generator classes `cmQtAutoGenerator` automatically added `cmQtAutoGenerator::Logger` and `cmQtAutoGenerator::FileSystem` member variables to all inherited classes. This patch moves these members variable declarations to the inherited classes, where needed. --- Source/cmQtAutoGenerator.cxx | 52 ++++++++++++++++++++------------------ Source/cmQtAutoGenerator.h | 12 +++------ Source/cmQtAutoGeneratorMocUic.cxx | 3 ++- Source/cmQtAutoGeneratorMocUic.h | 6 +++++ Source/cmQtAutoGeneratorRcc.h | 11 +++++--- 5 files changed, 47 insertions(+), 37 deletions(-) diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx index f56f7c9..c1e6aab 100644 --- a/Source/cmQtAutoGenerator.cxx +++ b/Source/cmQtAutoGenerator.cxx @@ -20,6 +20,34 @@ // -- Class methods +cmQtAutoGenerator::Logger::Logger() +{ + // Initialize logger + { + std::string verbose; + if (cmSystemTools::GetEnv("VERBOSE", verbose) && !verbose.empty()) { + unsigned long iVerbose = 0; + if (cmSystemTools::StringToULong(verbose.c_str(), &iVerbose)) { + SetVerbosity(static_cast(iVerbose)); + } else { + // Non numeric verbosity + SetVerbose(cmSystemTools::IsOn(verbose)); + } + } + } + { + std::string colorEnv; + cmSystemTools::GetEnv("COLOR", colorEnv); + if (!colorEnv.empty()) { + SetColorOutput(cmSystemTools::IsOn(colorEnv)); + } else { + SetColorOutput(true); + } + } +} + +cmQtAutoGenerator::Logger::~Logger() = default; + void cmQtAutoGenerator::Logger::RaiseVerbosity(std::string const& value) { unsigned long verbosity = 0; @@ -670,31 +698,7 @@ void cmQtAutoGenerator::ReadOnlyProcessT::UVTryFinish() } cmQtAutoGenerator::cmQtAutoGenerator() - : FileSys_(&Logger_) { - // Initialize logger - { - std::string verbose; - if (cmSystemTools::GetEnv("VERBOSE", verbose) && !verbose.empty()) { - unsigned long iVerbose = 0; - if (cmSystemTools::StringToULong(verbose.c_str(), &iVerbose)) { - Logger_.SetVerbosity(static_cast(iVerbose)); - } else { - // Non numeric verbosity - Logger_.SetVerbose(cmSystemTools::IsOn(verbose)); - } - } - } - { - std::string colorEnv; - cmSystemTools::GetEnv("COLOR", colorEnv); - if (!colorEnv.empty()) { - Logger_.SetColorOutput(cmSystemTools::IsOn(colorEnv)); - } else { - Logger_.SetColorOutput(true); - } - } - // Initialize libuv loop uv_disable_stdio_inheritance(); #ifdef CMAKE_UV_SIGNAL_HACK diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h index 17170d7..2993946 100644 --- a/Source/cmQtAutoGenerator.h +++ b/Source/cmQtAutoGenerator.h @@ -31,12 +31,16 @@ public: class Logger { public: + // -- Construction + Logger(); + ~Logger(); // -- Verbosity unsigned int Verbosity() const { return this->Verbosity_; } void SetVerbosity(unsigned int value) { this->Verbosity_ = value; } void RaiseVerbosity(std::string const& value); bool Verbose() const { return (this->Verbosity_ != 0); } void SetVerbose(bool value) { this->Verbosity_ = value ? 1 : 0; } + // -- Color output bool ColorOutput() const { return this->ColorOutput_; } void SetColorOutput(bool value); // -- Log info @@ -258,11 +262,6 @@ public: // -- Run bool Run(std::string const& infoFile, std::string const& config); - // -- Accessors - // Logging - Logger& Log() { return Logger_; } - // File System - FileSystem& FileSys() { return FileSys_; } // InfoFile std::string const& InfoFile() const { return InfoFile_; } std::string const& InfoDir() const { return InfoDir_; } @@ -280,9 +279,6 @@ protected: virtual bool Process() = 0; private: - // -- Logging - Logger Logger_; - FileSystem FileSys_; // -- Info settings std::string InfoFile_; std::string InfoDir_; diff --git a/Source/cmQtAutoGeneratorMocUic.cxx b/Source/cmQtAutoGeneratorMocUic.cxx index 0982473..607576f 100644 --- a/Source/cmQtAutoGeneratorMocUic.cxx +++ b/Source/cmQtAutoGeneratorMocUic.cxx @@ -1126,7 +1126,8 @@ void cmQtAutoGeneratorMocUic::WorkerT::UVProcessFinished() } cmQtAutoGeneratorMocUic::cmQtAutoGeneratorMocUic() - : Base_(&FileSys()) + : FileSys_(&Logger_) + , Base_(&FileSys()) , Moc_(&FileSys()) { // Precompile regular expressions diff --git a/Source/cmQtAutoGeneratorMocUic.h b/Source/cmQtAutoGeneratorMocUic.h index e48d7f3..cc785a7 100644 --- a/Source/cmQtAutoGeneratorMocUic.h +++ b/Source/cmQtAutoGeneratorMocUic.h @@ -387,6 +387,9 @@ public: void ParallelMocAutoUpdated(); private: + // -- Utility accessors + Logger& Log() { return Logger_; } + FileSystem& FileSys() { return FileSys_; } // -- Abstract processing interface bool Init(cmMakefile* makefile) override; bool Process() override; @@ -407,6 +410,9 @@ private: void MocGenerateCompilation(); private: + // -- Utility + Logger Logger_; + FileSystem FileSys_; // -- Settings BaseSettingsT Base_; MocSettingsT Moc_; diff --git a/Source/cmQtAutoGeneratorRcc.h b/Source/cmQtAutoGeneratorRcc.h index d831f1f..ff7a02a 100644 --- a/Source/cmQtAutoGeneratorRcc.h +++ b/Source/cmQtAutoGeneratorRcc.h @@ -25,6 +25,11 @@ public: cmQtAutoGeneratorRcc& operator=(cmQtAutoGeneratorRcc const&) = delete; private: + // -- Utility + Logger& Log() { return Logger_; } + bool IsMultiConfig() const { return MultiConfig_; } + std::string MultiConfigOutput() const; + // -- Abstract processing interface bool Init(cmMakefile* makefile) override; bool Process() override; @@ -39,11 +44,9 @@ private: bool GenerateRcc(); bool GenerateWrapper(); - // -- Utility - bool IsMultiConfig() const { return MultiConfig_; } - std::string MultiConfigOutput() const; - private: + // -- Logging + Logger Logger_; // -- Config settings bool MultiConfig_ = false; // -- Directories -- cgit v0.12 From 95e72c0157ecd9c603fc541fa7e9fa246b777969 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Sat, 6 Apr 2019 12:27:08 +0200 Subject: Autogen: Make cmQtAutoGenerator::FileSystem Logger free `cmQtAutoGenerator::FileSystem` used to have a reference to a `cmQtAutoGenerator::Logger` instances. This was used for utility methods that automatically generated an error message on demand. Unfortunately this resulted in double error messages in some places. To fix these and with the additional purpose of removing the dependency of `cmQtAutoGenerator::FileSystem` to `cmQtAutoGenerator::Logger`, this patch removes the `Logger` reference in `cmQtAutoGenerator::FileSystem`. In the process some silent error conditions gained error messages and some existing error messages were extended. --- Source/cmQtAutoGenerator.cxx | 48 ++++---------------------------------- Source/cmQtAutoGenerator.h | 21 ++--------------- Source/cmQtAutoGeneratorMocUic.cxx | 39 +++++++++++++++++++++---------- 3 files changed, 33 insertions(+), 75 deletions(-) diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx index c1e6aab..83a00cf 100644 --- a/Source/cmQtAutoGenerator.cxx +++ b/Source/cmQtAutoGenerator.cxx @@ -261,6 +261,10 @@ bool cmQtAutoGenerator::FileWrite(std::string const& filename, }(); } +cmQtAutoGenerator::FileSystem::FileSystem() = default; + +cmQtAutoGenerator::FileSystem::~FileSystem() = default; + std::string cmQtAutoGenerator::FileSystem::GetRealPath( std::string const& filename) { @@ -380,18 +384,6 @@ bool cmQtAutoGenerator::FileSystem::FileRead(std::string& content, return cmQtAutoGenerator::FileRead(content, filename, error); } -bool cmQtAutoGenerator::FileSystem::FileRead(GenT genType, - std::string& content, - std::string const& filename) -{ - std::string error; - if (!FileRead(content, filename, &error)) { - Log()->ErrorFile(genType, filename, error); - return false; - } - return true; -} - bool cmQtAutoGenerator::FileSystem::FileWrite(std::string const& filename, std::string const& content, std::string* error) @@ -400,18 +392,6 @@ bool cmQtAutoGenerator::FileSystem::FileWrite(std::string const& filename, return cmQtAutoGenerator::FileWrite(filename, content, error); } -bool cmQtAutoGenerator::FileSystem::FileWrite(GenT genType, - std::string const& filename, - std::string const& content) -{ - std::string error; - if (!FileWrite(filename, content, &error)) { - Log()->ErrorFile(genType, filename, error); - return false; - } - return true; -} - bool cmQtAutoGenerator::FileSystem::FileDiffers(std::string const& filename, std::string const& content) { @@ -444,16 +424,6 @@ bool cmQtAutoGenerator::FileSystem::MakeDirectory(std::string const& dirname) return cmSystemTools::MakeDirectory(dirname); } -bool cmQtAutoGenerator::FileSystem::MakeDirectory(GenT genType, - std::string const& dirname) -{ - if (!MakeDirectory(dirname)) { - Log()->ErrorFile(genType, dirname, "Could not create directory"); - return false; - } - return true; -} - bool cmQtAutoGenerator::FileSystem::MakeParentDirectory( std::string const& filename) { @@ -461,16 +431,6 @@ bool cmQtAutoGenerator::FileSystem::MakeParentDirectory( return cmQtAutoGenerator::MakeParentDirectory(filename); } -bool cmQtAutoGenerator::FileSystem::MakeParentDirectory( - GenT genType, std::string const& filename) -{ - if (!MakeParentDirectory(filename)) { - Log()->ErrorFile(genType, filename, "Could not create parent directory"); - return false; - } - return true; -} - int cmQtAutoGenerator::ReadOnlyProcessT::PipeT::init(uv_loop_t* uv_loop, ReadOnlyProcessT* process) { diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h index 2993946..862b18d 100644 --- a/Source/cmQtAutoGenerator.h +++ b/Source/cmQtAutoGenerator.h @@ -78,13 +78,8 @@ public: class FileSystem { public: - FileSystem(Logger* log) - : Log_(log) - { - } - - /// @brief Logger - Logger* Log() const { return Log_; } + FileSystem(); + ~FileSystem(); // -- Paths /// @brief Wrapper for cmSystemTools::GetRealPath @@ -125,15 +120,9 @@ public: bool FileRead(std::string& content, std::string const& filename, std::string* error = nullptr); - /// @brief Error logging version - bool FileRead(GenT genType, std::string& content, - std::string const& filename); bool FileWrite(std::string const& filename, std::string const& content, std::string* error = nullptr); - /// @brief Error logging version - bool FileWrite(GenT genType, std::string const& filename, - std::string const& content); bool FileDiffers(std::string const& filename, std::string const& content); @@ -142,17 +131,11 @@ public: // -- Directory access bool MakeDirectory(std::string const& dirname); - /// @brief Error logging version - bool MakeDirectory(GenT genType, std::string const& dirname); - bool MakeParentDirectory(std::string const& filename); - /// @brief Error logging version - bool MakeParentDirectory(GenT genType, std::string const& filename); private: std::mutex Mutex_; cmFilePathChecksum FilePathChecksum_; - Logger* Log_; }; /// @brief Return value and output of an external process diff --git a/Source/cmQtAutoGeneratorMocUic.cxx b/Source/cmQtAutoGeneratorMocUic.cxx index 607576f..32e5067 100644 --- a/Source/cmQtAutoGeneratorMocUic.cxx +++ b/Source/cmQtAutoGeneratorMocUic.cxx @@ -638,13 +638,15 @@ void cmQtAutoGeneratorMocUic::JobMocPredefsT::Process(WorkerT& wrk) if (!result.error()) { if (!fileExists || wrk.FileSys().FileDiffers(wrk.Moc().PredefsFileAbs, result.StdOut)) { - if (wrk.FileSys().FileWrite(GenT::MOC, wrk.Moc().PredefsFileAbs, - result.StdOut)) { + std::string error; + if (wrk.FileSys().FileWrite(wrk.Moc().PredefsFileAbs, result.StdOut, + &error)) { // Success } else { std::string emsg = "Writing "; emsg += Quoted(wrk.Moc().PredefsFileRel); - emsg += " failed."; + emsg += " failed. "; + emsg += error; wrk.LogFileError(GenT::MOC, wrk.Moc().PredefsFileAbs, emsg); } } else { @@ -835,7 +837,12 @@ bool cmQtAutoGeneratorMocUic::JobMocT::UpdateRequired(WorkerT& wrk) void cmQtAutoGeneratorMocUic::JobMocT::GenerateMoc(WorkerT& wrk) { // Make sure the parent directory exists - if (wrk.FileSys().MakeParentDirectory(GenT::MOC, BuildFile)) { + if (!wrk.FileSys().MakeParentDirectory(BuildFile)) { + wrk.LogFileError(GenT::MOC, BuildFile, + "Could not create parent directory."); + return; + } + { // Compose moc command std::vector cmd; cmd.push_back(wrk.Moc().Executable); @@ -950,7 +957,12 @@ bool cmQtAutoGeneratorMocUic::JobUicT::UpdateRequired(WorkerT& wrk) void cmQtAutoGeneratorMocUic::JobUicT::GenerateUic(WorkerT& wrk) { // Make sure the parent directory exists - if (wrk.FileSys().MakeParentDirectory(GenT::UIC, BuildFile)) { + if (!wrk.FileSys().MakeParentDirectory(BuildFile)) { + wrk.LogFileError(GenT::UIC, BuildFile, + "Could not create parent directory."); + return; + } + { // Compose uic command std::vector cmd; cmd.push_back(wrk.Uic().Executable); @@ -1126,8 +1138,7 @@ void cmQtAutoGeneratorMocUic::WorkerT::UVProcessFinished() } cmQtAutoGeneratorMocUic::cmQtAutoGeneratorMocUic() - : FileSys_(&Logger_) - , Base_(&FileSys()) + : Base_(&FileSys()) , Moc_(&FileSys()) { // Precompile regular expressions @@ -1692,9 +1703,10 @@ void cmQtAutoGeneratorMocUic::SettingsFileWrite() SettingAppend("uic", SettingsStringUic_); } // Write settings file - if (!FileSys().FileWrite(GenT::GEN, SettingsFile_, content)) { + std::string error; + if (!FileSys().FileWrite(SettingsFile_, content, &error)) { Log().ErrorFile(GenT::GEN, SettingsFile_, - "Settings file writing failed"); + "Settings file writing failed. " + error); // Remove old settings file to trigger a full rebuild on the next run FileSys().FileRemove(SettingsFile_); RegisterJobError(); @@ -1705,7 +1717,9 @@ void cmQtAutoGeneratorMocUic::SettingsFileWrite() void cmQtAutoGeneratorMocUic::CreateDirectories() { // Create AUTOGEN include directory - if (!FileSys().MakeDirectory(GenT::GEN, Base().AutogenIncludeDir)) { + if (!FileSys().MakeDirectory(Base().AutogenIncludeDir)) { + Log().ErrorFile(GenT::GEN, Base().AutogenIncludeDir, + "Could not create directory."); RegisterJobError(); } } @@ -2004,9 +2018,10 @@ void cmQtAutoGeneratorMocUic::MocGenerateCompilation() if (Log().Verbose()) { Log().Info(GenT::MOC, "Generating MOC compilation " + compAbs); } - if (!FileSys().FileWrite(GenT::MOC, compAbs, content)) { + std::string error; + if (!FileSys().FileWrite(compAbs, content, &error)) { Log().ErrorFile(GenT::MOC, compAbs, - "mocs compilation file writing failed"); + "mocs compilation file writing failed. " + error); RegisterJobError(); return; } -- cgit v0.12 From 9710d4aacf801d3dc7ab243bc2c8e051a65871a6 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Sat, 6 Apr 2019 12:39:33 +0200 Subject: Autogen: Move libuv loop from cmQtAutoGenerator to cmQtAutoGeneratorMocUic `cmQtAutoGenerator` automatically started a libuv loop in the constructor. The loop is needed in `cmQtAutoGeneratorMocUic`, but not in `cmQtAutoGeneratorRcc` (anymore). To avoid starting the loop in `cmQtAutoGeneratorRcc`, this patch moves the loop variables and startup code from `cmQtAutoGenerator` to `cmQtAutoGeneratorMocUic`. --- Source/cmQtAutoGenerator.cxx | 17 ++--------------- Source/cmQtAutoGenerator.h | 10 ---------- Source/cmQtAutoGeneratorMocUic.cxx | 14 +++++++++++++- Source/cmQtAutoGeneratorMocUic.h | 11 ++++++++++- 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx index 83a00cf..f115016 100644 --- a/Source/cmQtAutoGenerator.cxx +++ b/Source/cmQtAutoGenerator.cxx @@ -657,22 +657,9 @@ void cmQtAutoGenerator::ReadOnlyProcessT::UVTryFinish() } } -cmQtAutoGenerator::cmQtAutoGenerator() -{ - // Initialize libuv loop - uv_disable_stdio_inheritance(); -#ifdef CMAKE_UV_SIGNAL_HACK - UVHackRAII_ = cm::make_unique(); -#endif - UVLoop_ = cm::make_unique(); - uv_loop_init(UVLoop()); -} +cmQtAutoGenerator::cmQtAutoGenerator() = default; -cmQtAutoGenerator::~cmQtAutoGenerator() -{ - // Close libuv loop - uv_loop_close(UVLoop()); -} +cmQtAutoGenerator::~cmQtAutoGenerator() = default; bool cmQtAutoGenerator::Run(std::string const& infoFile, std::string const& config) diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h index 862b18d..479d357 100644 --- a/Source/cmQtAutoGenerator.h +++ b/Source/cmQtAutoGenerator.h @@ -8,7 +8,6 @@ #include "cmFilePathChecksum.h" #include "cmQtAutoGen.h" #include "cmUVHandlePtr.h" -#include "cmUVSignalHackRAII.h" // IWYU pragma: keep #include "cm_uv.h" #include @@ -249,9 +248,6 @@ public: std::string const& InfoFile() const { return InfoFile_; } std::string const& InfoDir() const { return InfoDir_; } std::string const& InfoConfig() const { return InfoConfig_; } - // libuv loop - uv_loop_t* UVLoop() { return UVLoop_.get(); } - cm::uv_async_ptr& UVRequest() { return UVRequest_; } // -- Utility static std::string SettingsFind(std::string const& content, const char* key); @@ -266,12 +262,6 @@ private: std::string InfoFile_; std::string InfoDir_; std::string InfoConfig_; -// -- libuv loop -#ifdef CMAKE_UV_SIGNAL_HACK - std::unique_ptr UVHackRAII_; -#endif - std::unique_ptr UVLoop_; - cm::uv_async_ptr UVRequest_; }; #endif diff --git a/Source/cmQtAutoGeneratorMocUic.cxx b/Source/cmQtAutoGeneratorMocUic.cxx index 32e5067..ec1a1aa 100644 --- a/Source/cmQtAutoGeneratorMocUic.cxx +++ b/Source/cmQtAutoGeneratorMocUic.cxx @@ -1148,11 +1148,23 @@ cmQtAutoGeneratorMocUic::cmQtAutoGeneratorMocUic() Uic_.RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+" "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]"); + // Initialize libuv loop + uv_disable_stdio_inheritance(); +#ifdef CMAKE_UV_SIGNAL_HACK + UVHackRAII_ = cm::make_unique(); +#endif + UVLoop_ = cm::make_unique(); + uv_loop_init(UVLoop()); + // Initialize libuv asynchronous iteration request UVRequest().init(*UVLoop(), &cmQtAutoGeneratorMocUic::UVPollStage, this); } -cmQtAutoGeneratorMocUic::~cmQtAutoGeneratorMocUic() = default; +cmQtAutoGeneratorMocUic::~cmQtAutoGeneratorMocUic() +{ + // Close libuv loop + uv_loop_close(UVLoop()); +} bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile) { diff --git a/Source/cmQtAutoGeneratorMocUic.h b/Source/cmQtAutoGeneratorMocUic.h index cc785a7..27d73a7 100644 --- a/Source/cmQtAutoGeneratorMocUic.h +++ b/Source/cmQtAutoGeneratorMocUic.h @@ -8,6 +8,7 @@ #include "cmQtAutoGen.h" #include "cmQtAutoGenerator.h" #include "cmUVHandlePtr.h" +#include "cmUVSignalHackRAII.h" // IWYU pragma: keep #include "cm_uv.h" #include "cmsys/RegularExpression.hxx" @@ -390,6 +391,9 @@ private: // -- Utility accessors Logger& Log() { return Logger_; } FileSystem& FileSys() { return FileSys_; } + // -- libuv loop accessors + uv_loop_t* UVLoop() { return UVLoop_.get(); } + cm::uv_async_ptr& UVRequest() { return UVRequest_; } // -- Abstract processing interface bool Init(cmMakefile* makefile) override; bool Process() override; @@ -417,7 +421,12 @@ private: BaseSettingsT Base_; MocSettingsT Moc_; UicSettingsT Uic_; - // -- Progress + // -- libuv loop +#ifdef CMAKE_UV_SIGNAL_HACK + std::unique_ptr UVHackRAII_; +#endif + std::unique_ptr UVLoop_; + cm::uv_async_ptr UVRequest_; StageT Stage_ = StageT::SETTINGS_READ; // -- Job queues std::mutex JobsMutex_; -- cgit v0.12 From 7b98a6eb68e6a2c9a422e42c8eeb78dfa4038364 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Sat, 6 Apr 2019 12:42:56 +0200 Subject: Autogen: Rename cmQtAutoGeneratorRcc to cmQtAutoRcc The class name `cmQtAutoGeneratorRcc` is long and cumbersome. This shortens it to `cmQtAutoRcc`. --- Source/CMakeLists.txt | 4 +- Source/cmQtAutoGeneratorRcc.cxx | 516 ---------------------------------------- Source/cmQtAutoGeneratorRcc.h | 79 ------ Source/cmQtAutoRcc.cxx | 516 ++++++++++++++++++++++++++++++++++++++++ Source/cmQtAutoRcc.h | 79 ++++++ Source/cmcmd.cxx | 4 +- 6 files changed, 599 insertions(+), 599 deletions(-) delete mode 100644 Source/cmQtAutoGeneratorRcc.cxx delete mode 100644 Source/cmQtAutoGeneratorRcc.h create mode 100644 Source/cmQtAutoRcc.cxx create mode 100644 Source/cmQtAutoRcc.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 52f6742..3a12120 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -350,8 +350,8 @@ set(SRCS cmQtAutoGenInitializer.h cmQtAutoGeneratorMocUic.cxx cmQtAutoGeneratorMocUic.h - cmQtAutoGeneratorRcc.cxx - cmQtAutoGeneratorRcc.h + cmQtAutoRcc.cxx + cmQtAutoRcc.h cmRST.cxx cmRST.h cmScriptGenerator.h diff --git a/Source/cmQtAutoGeneratorRcc.cxx b/Source/cmQtAutoGeneratorRcc.cxx deleted file mode 100644 index add84de..0000000 --- a/Source/cmQtAutoGeneratorRcc.cxx +++ /dev/null @@ -1,516 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmQtAutoGeneratorRcc.h" -#include "cmQtAutoGen.h" - -#include "cmAlgorithms.h" -#include "cmCryptoHash.h" -#include "cmDuration.h" -#include "cmFileLockResult.h" -#include "cmMakefile.h" -#include "cmProcessOutput.h" -#include "cmSystemTools.h" - -// -- Class methods - -cmQtAutoGeneratorRcc::cmQtAutoGeneratorRcc() = default; - -cmQtAutoGeneratorRcc::~cmQtAutoGeneratorRcc() = default; - -bool cmQtAutoGeneratorRcc::Init(cmMakefile* makefile) -{ - // -- Utility lambdas - auto InfoGet = [makefile](std::string const& key) { - return makefile->GetSafeDefinition(key); - }; - auto InfoGetList = - [makefile](std::string const& key) -> std::vector { - std::vector list; - cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list); - return list; - }; - auto InfoGetConfig = [makefile, - this](std::string const& key) -> std::string { - const char* valueConf = nullptr; - { - std::string keyConf = key; - keyConf += '_'; - keyConf += InfoConfig(); - valueConf = makefile->GetDefinition(keyConf); - } - if (valueConf == nullptr) { - return makefile->GetSafeDefinition(key); - } - return std::string(valueConf); - }; - auto InfoGetConfigList = - [&InfoGetConfig](std::string const& key) -> std::vector { - std::vector list; - cmSystemTools::ExpandListArgument(InfoGetConfig(key), list); - return list; - }; - - // -- Read info file - if (!makefile->ReadListFile(InfoFile())) { - Log().ErrorFile(GenT::RCC, InfoFile(), "File processing failed."); - return false; - } - - // - Configurations - Log().RaiseVerbosity(InfoGet("ARCC_VERBOSITY")); - MultiConfig_ = makefile->IsOn("ARCC_MULTI_CONFIG"); - - // - Directories - AutogenBuildDir_ = InfoGet("ARCC_BUILD_DIR"); - if (AutogenBuildDir_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "Build directory empty."); - return false; - } - - IncludeDir_ = InfoGetConfig("ARCC_INCLUDE_DIR"); - if (IncludeDir_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "Include directory empty."); - return false; - } - - // - Rcc executable - RccExecutable_ = InfoGet("ARCC_RCC_EXECUTABLE"); - RccListOptions_ = InfoGetList("ARCC_RCC_LIST_OPTIONS"); - - // - Job - LockFile_ = InfoGet("ARCC_LOCK_FILE"); - QrcFile_ = InfoGet("ARCC_SOURCE"); - QrcFileName_ = cmSystemTools::GetFilenameName(QrcFile_); - QrcFileDir_ = cmSystemTools::GetFilenamePath(QrcFile_); - RccPathChecksum_ = InfoGet("ARCC_OUTPUT_CHECKSUM"); - RccFileName_ = InfoGet("ARCC_OUTPUT_NAME"); - Options_ = InfoGetConfigList("ARCC_OPTIONS"); - Inputs_ = InfoGetList("ARCC_INPUTS"); - - // - Settings file - SettingsFile_ = InfoGetConfig("ARCC_SETTINGS_FILE"); - - // - Validity checks - if (LockFile_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "Lock file name missing."); - return false; - } - if (SettingsFile_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "Settings file name missing."); - return false; - } - if (AutogenBuildDir_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "Autogen build directory missing."); - return false; - } - if (RccExecutable_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "rcc executable missing."); - return false; - } - if (QrcFile_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "rcc input file missing."); - return false; - } - if (RccFileName_.empty()) { - Log().ErrorFile(GenT::RCC, InfoFile(), "rcc output file missing."); - return false; - } - - // Init derived information - // ------------------------ - - RccFilePublic_ = AutogenBuildDir_; - RccFilePublic_ += '/'; - RccFilePublic_ += RccPathChecksum_; - RccFilePublic_ += '/'; - RccFilePublic_ += RccFileName_; - - // Compute rcc output file name - if (IsMultiConfig()) { - RccFileOutput_ = IncludeDir_; - RccFileOutput_ += '/'; - RccFileOutput_ += MultiConfigOutput(); - } else { - RccFileOutput_ = RccFilePublic_; - } - - return true; -} - -bool cmQtAutoGeneratorRcc::Process() -{ - if (!SettingsFileRead()) { - return false; - } - - // Test if the rcc output needs to be regenerated - bool generate = false; - if (!TestQrcRccFiles(generate)) { - return false; - } - if (!generate && !TestResources(generate)) { - return false; - } - // Generate on demand - if (generate) { - if (!GenerateRcc()) { - return false; - } - } else { - // Test if the info file is newer than the output file - if (!TestInfoFile()) { - return false; - } - } - - if (!GenerateWrapper()) { - return false; - } - - return SettingsFileWrite(); -} - -std::string cmQtAutoGeneratorRcc::MultiConfigOutput() const -{ - static std::string const suffix = "_CMAKE_"; - std::string res; - res += RccPathChecksum_; - res += '/'; - res += AppendFilenameSuffix(RccFileName_, suffix); - return res; -} - -bool cmQtAutoGeneratorRcc::SettingsFileRead() -{ - // Compose current settings strings - { - cmCryptoHash crypt(cmCryptoHash::AlgoSHA256); - std::string const sep(" ~~~ "); - { - std::string str; - str += RccExecutable_; - str += sep; - str += cmJoin(RccListOptions_, ";"); - str += sep; - str += QrcFile_; - str += sep; - str += RccPathChecksum_; - str += sep; - str += RccFileName_; - str += sep; - str += cmJoin(Options_, ";"); - str += sep; - str += cmJoin(Inputs_, ";"); - str += sep; - SettingsString_ = crypt.HashString(str); - } - } - - // Make sure the settings file exists - if (!cmSystemTools::FileExists(SettingsFile_, true)) { - // Touch the settings file to make sure it exists - if (!cmSystemTools::Touch(SettingsFile_, true)) { - Log().ErrorFile(GenT::RCC, SettingsFile_, - "Settings file creation failed."); - return false; - } - } - - // Lock the lock file - { - // Make sure the lock file exists - if (!cmSystemTools::FileExists(LockFile_, true)) { - if (!cmSystemTools::Touch(LockFile_, true)) { - Log().ErrorFile(GenT::RCC, LockFile_, "Lock file creation failed."); - return false; - } - } - // Lock the lock file - cmFileLockResult lockResult = - LockFileLock_.Lock(LockFile_, static_cast(-1)); - if (!lockResult.IsOk()) { - Log().ErrorFile(GenT::RCC, LockFile_, - "File lock failed: " + lockResult.GetOutputMessage()); - return false; - } - } - - // Read old settings - { - std::string content; - if (FileRead(content, SettingsFile_)) { - SettingsChanged_ = (SettingsString_ != SettingsFind(content, "rcc")); - // In case any setting changed clear the old settings file. - // This triggers a full rebuild on the next run if the current - // build is aborted before writing the current settings in the end. - if (SettingsChanged_) { - std::string error; - if (!FileWrite(SettingsFile_, "", &error)) { - Log().ErrorFile(GenT::RCC, SettingsFile_, - "Settings file clearing failed. " + error); - return false; - } - } - } else { - SettingsChanged_ = true; - } - } - - return true; -} - -bool cmQtAutoGeneratorRcc::SettingsFileWrite() -{ - // Only write if any setting changed - if (SettingsChanged_) { - if (Log().Verbose()) { - Log().Info(GenT::RCC, "Writing settings file " + Quoted(SettingsFile_)); - } - // Write settings file - std::string content = "rcc:"; - content += SettingsString_; - content += '\n'; - std::string error; - if (!FileWrite(SettingsFile_, content, &error)) { - Log().ErrorFile(GenT::RCC, SettingsFile_, - "Settings file writing failed. " + error); - // Remove old settings file to trigger a full rebuild on the next run - cmSystemTools::RemoveFile(SettingsFile_); - return false; - } - } - - // Unlock the lock file - LockFileLock_.Release(); - return true; -} - -/// Do basic checks if rcc generation is required -bool cmQtAutoGeneratorRcc::TestQrcRccFiles(bool& generate) -{ - // Test if the rcc input file exists - if (!QrcFileTime_.Load(QrcFile_)) { - std::string error; - error = "The resources file "; - error += Quoted(QrcFile_); - error += " does not exist"; - Log().ErrorFile(GenT::RCC, QrcFile_, error); - return false; - } - - // Test if the rcc output file exists - if (!RccFileTime_.Load(RccFileOutput_)) { - if (Log().Verbose()) { - std::string reason = "Generating "; - reason += Quoted(RccFileOutput_); - reason += " from its source file "; - reason += Quoted(QrcFile_); - reason += " because it doesn't exist"; - Log().Info(GenT::RCC, reason); - } - generate = true; - return true; - } - - // Test if the settings changed - if (SettingsChanged_) { - if (Log().Verbose()) { - std::string reason = "Generating "; - reason += Quoted(RccFileOutput_); - reason += " from "; - reason += Quoted(QrcFile_); - reason += " because the RCC settings changed"; - Log().Info(GenT::RCC, reason); - } - generate = true; - return true; - } - - // Test if the rcc output file is older than the .qrc file - if (RccFileTime_.Older(QrcFileTime_)) { - if (Log().Verbose()) { - std::string reason = "Generating "; - reason += Quoted(RccFileOutput_); - reason += " because it is older than "; - reason += Quoted(QrcFile_); - Log().Info(GenT::RCC, reason); - } - generate = true; - return true; - } - - return true; -} - -bool cmQtAutoGeneratorRcc::TestResources(bool& generate) -{ - // Read resource files list - if (Inputs_.empty()) { - std::string error; - RccLister const lister(RccExecutable_, RccListOptions_); - if (!lister.list(QrcFile_, Inputs_, error, Log().Verbose())) { - Log().ErrorFile(GenT::RCC, QrcFile_, error); - return false; - } - } - - for (std::string const& resFile : Inputs_) { - // Check if the resource file exists - cmFileTime fileTime; - if (!fileTime.Load(resFile)) { - std::string error; - error = "Could not find the resource file\n "; - error += Quoted(resFile); - error += '\n'; - Log().ErrorFile(GenT::RCC, QrcFile_, error); - return false; - } - // Check if the resource file is newer than the build file - if (RccFileTime_.Older(fileTime)) { - if (Log().Verbose()) { - std::string reason = "Generating "; - reason += Quoted(RccFileOutput_); - reason += " from "; - reason += Quoted(QrcFile_); - reason += " because it is older than "; - reason += Quoted(resFile); - Log().Info(GenT::RCC, reason); - } - generate = true; - break; - } - } - return true; -} - -bool cmQtAutoGeneratorRcc::TestInfoFile() -{ - // Test if the rcc output file is older than the info file - - cmFileTime infoFileTime; - if (!infoFileTime.Load(InfoFile())) { - std::string error; - error = "Could not find the info file "; - error += Quoted(InfoFile()); - error += '\n'; - Log().ErrorFile(GenT::RCC, QrcFile_, error); - return false; - } - if (RccFileTime_.Older(infoFileTime)) { - if (Log().Verbose()) { - std::string reason = "Touching "; - reason += Quoted(RccFileOutput_); - reason += " because it is older than "; - reason += Quoted(InfoFile()); - Log().Info(GenT::RCC, reason); - } - // Touch build file - if (!cmSystemTools::Touch(RccFileOutput_, false)) { - Log().ErrorFile(GenT::RCC, RccFileOutput_, "Build file touch failed"); - return false; - } - BuildFileChanged_ = true; - } - - return true; -} - -bool cmQtAutoGeneratorRcc::GenerateRcc() -{ - // Make parent directory - if (!MakeParentDirectory(RccFileOutput_)) { - Log().ErrorFile(GenT::RCC, RccFileOutput_, - "Could not create parent directory"); - return false; - } - - // Start a rcc process - std::vector cmd; - cmd.push_back(RccExecutable_); - cmd.insert(cmd.end(), Options_.begin(), Options_.end()); - cmd.emplace_back("-o"); - cmd.push_back(RccFileOutput_); - cmd.push_back(QrcFile_); - - // Log command - if (Log().Verbose()) { - std::string msg = "Running command:\n"; - msg += QuotedCommand(cmd); - msg += '\n'; - cmSystemTools::Stdout(msg); - } - - std::string rccStdOut; - std::string rccStdErr; - int retVal = 0; - bool result = cmSystemTools::RunSingleCommand( - cmd, &rccStdOut, &rccStdErr, &retVal, AutogenBuildDir_.c_str(), - cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto); - if (!result || (retVal != 0)) { - // rcc process failed - { - std::string err = "The rcc process failed to compile\n "; - err += Quoted(QrcFile_); - err += "\ninto\n "; - err += Quoted(RccFileOutput_); - Log().ErrorCommand(GenT::RCC, err, cmd, rccStdOut + rccStdErr); - } - cmSystemTools::RemoveFile(RccFileOutput_); - return false; - } - - // rcc process success - // Print rcc output - if (!rccStdOut.empty()) { - Log().Info(GenT::RCC, rccStdOut); - } - BuildFileChanged_ = true; - - return true; -} - -bool cmQtAutoGeneratorRcc::GenerateWrapper() -{ - // Generate a wrapper source file on demand - if (IsMultiConfig()) { - // Wrapper file content - std::string content; - content += "// This is an autogenerated configuration wrapper file.\n"; - content += "// Changes will be overwritten.\n"; - content += "#include <"; - content += MultiConfigOutput(); - content += ">\n"; - - // Compare with existing file content - bool fileDiffers = true; - { - std::string oldContents; - if (FileRead(oldContents, RccFilePublic_)) { - fileDiffers = (oldContents != content); - } - } - if (fileDiffers) { - // Write new wrapper file - if (Log().Verbose()) { - Log().Info(GenT::RCC, "Generating RCC wrapper file " + RccFilePublic_); - } - std::string error; - if (!FileWrite(RccFilePublic_, content, &error)) { - Log().ErrorFile(GenT::RCC, RccFilePublic_, - "RCC wrapper file writing failed. " + error); - return false; - } - } else if (BuildFileChanged_) { - // Just touch the wrapper file - if (Log().Verbose()) { - Log().Info(GenT::RCC, "Touching RCC wrapper file " + RccFilePublic_); - } - if (!cmSystemTools::Touch(RccFilePublic_, false)) { - Log().ErrorFile(GenT::RCC, RccFilePublic_, - "RCC wrapper file touch failed."); - return false; - } - } - } - return true; -} diff --git a/Source/cmQtAutoGeneratorRcc.h b/Source/cmQtAutoGeneratorRcc.h deleted file mode 100644 index ff7a02a..0000000 --- a/Source/cmQtAutoGeneratorRcc.h +++ /dev/null @@ -1,79 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cmQtAutoGeneratorRcc_h -#define cmQtAutoGeneratorRcc_h - -#include "cmConfigure.h" // IWYU pragma: keep - -#include "cmFileLock.h" -#include "cmFileTime.h" -#include "cmQtAutoGenerator.h" - -#include -#include - -class cmMakefile; - -// @brief AUTORCC generator -class cmQtAutoGeneratorRcc : public cmQtAutoGenerator -{ -public: - cmQtAutoGeneratorRcc(); - ~cmQtAutoGeneratorRcc() override; - - cmQtAutoGeneratorRcc(cmQtAutoGeneratorRcc const&) = delete; - cmQtAutoGeneratorRcc& operator=(cmQtAutoGeneratorRcc const&) = delete; - -private: - // -- Utility - Logger& Log() { return Logger_; } - bool IsMultiConfig() const { return MultiConfig_; } - std::string MultiConfigOutput() const; - - // -- Abstract processing interface - bool Init(cmMakefile* makefile) override; - bool Process() override; - // -- Settings file - bool SettingsFileRead(); - bool SettingsFileWrite(); - // -- Tests - bool TestQrcRccFiles(bool& generate); - bool TestResources(bool& generate); - bool TestInfoFile(); - // -- Generation - bool GenerateRcc(); - bool GenerateWrapper(); - -private: - // -- Logging - Logger Logger_; - // -- Config settings - bool MultiConfig_ = false; - // -- Directories - std::string AutogenBuildDir_; - std::string IncludeDir_; - // -- Qt environment - std::string RccExecutable_; - std::vector RccListOptions_; - // -- Job - std::string LockFile_; - cmFileLock LockFileLock_; - std::string QrcFile_; - std::string QrcFileName_; - std::string QrcFileDir_; - cmFileTime QrcFileTime_; - std::string RccPathChecksum_; - std::string RccFileName_; - std::string RccFileOutput_; - std::string RccFilePublic_; - cmFileTime RccFileTime_; - std::vector Options_; - std::vector Inputs_; - // -- Settings file - std::string SettingsFile_; - std::string SettingsString_; - bool SettingsChanged_ = false; - bool BuildFileChanged_ = false; -}; - -#endif diff --git a/Source/cmQtAutoRcc.cxx b/Source/cmQtAutoRcc.cxx new file mode 100644 index 0000000..e58324d --- /dev/null +++ b/Source/cmQtAutoRcc.cxx @@ -0,0 +1,516 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmQtAutoRcc.h" +#include "cmQtAutoGen.h" + +#include "cmAlgorithms.h" +#include "cmCryptoHash.h" +#include "cmDuration.h" +#include "cmFileLockResult.h" +#include "cmMakefile.h" +#include "cmProcessOutput.h" +#include "cmSystemTools.h" + +// -- Class methods + +cmQtAutoRcc::cmQtAutoRcc() = default; + +cmQtAutoRcc::~cmQtAutoRcc() = default; + +bool cmQtAutoRcc::Init(cmMakefile* makefile) +{ + // -- Utility lambdas + auto InfoGet = [makefile](std::string const& key) { + return makefile->GetSafeDefinition(key); + }; + auto InfoGetList = + [makefile](std::string const& key) -> std::vector { + std::vector list; + cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list); + return list; + }; + auto InfoGetConfig = [makefile, + this](std::string const& key) -> std::string { + const char* valueConf = nullptr; + { + std::string keyConf = key; + keyConf += '_'; + keyConf += InfoConfig(); + valueConf = makefile->GetDefinition(keyConf); + } + if (valueConf == nullptr) { + return makefile->GetSafeDefinition(key); + } + return std::string(valueConf); + }; + auto InfoGetConfigList = + [&InfoGetConfig](std::string const& key) -> std::vector { + std::vector list; + cmSystemTools::ExpandListArgument(InfoGetConfig(key), list); + return list; + }; + + // -- Read info file + if (!makefile->ReadListFile(InfoFile())) { + Log().ErrorFile(GenT::RCC, InfoFile(), "File processing failed."); + return false; + } + + // - Configurations + Log().RaiseVerbosity(InfoGet("ARCC_VERBOSITY")); + MultiConfig_ = makefile->IsOn("ARCC_MULTI_CONFIG"); + + // - Directories + AutogenBuildDir_ = InfoGet("ARCC_BUILD_DIR"); + if (AutogenBuildDir_.empty()) { + Log().ErrorFile(GenT::RCC, InfoFile(), "Build directory empty."); + return false; + } + + IncludeDir_ = InfoGetConfig("ARCC_INCLUDE_DIR"); + if (IncludeDir_.empty()) { + Log().ErrorFile(GenT::RCC, InfoFile(), "Include directory empty."); + return false; + } + + // - Rcc executable + RccExecutable_ = InfoGet("ARCC_RCC_EXECUTABLE"); + RccListOptions_ = InfoGetList("ARCC_RCC_LIST_OPTIONS"); + + // - Job + LockFile_ = InfoGet("ARCC_LOCK_FILE"); + QrcFile_ = InfoGet("ARCC_SOURCE"); + QrcFileName_ = cmSystemTools::GetFilenameName(QrcFile_); + QrcFileDir_ = cmSystemTools::GetFilenamePath(QrcFile_); + RccPathChecksum_ = InfoGet("ARCC_OUTPUT_CHECKSUM"); + RccFileName_ = InfoGet("ARCC_OUTPUT_NAME"); + Options_ = InfoGetConfigList("ARCC_OPTIONS"); + Inputs_ = InfoGetList("ARCC_INPUTS"); + + // - Settings file + SettingsFile_ = InfoGetConfig("ARCC_SETTINGS_FILE"); + + // - Validity checks + if (LockFile_.empty()) { + Log().ErrorFile(GenT::RCC, InfoFile(), "Lock file name missing."); + return false; + } + if (SettingsFile_.empty()) { + Log().ErrorFile(GenT::RCC, InfoFile(), "Settings file name missing."); + return false; + } + if (AutogenBuildDir_.empty()) { + Log().ErrorFile(GenT::RCC, InfoFile(), "Autogen build directory missing."); + return false; + } + if (RccExecutable_.empty()) { + Log().ErrorFile(GenT::RCC, InfoFile(), "rcc executable missing."); + return false; + } + if (QrcFile_.empty()) { + Log().ErrorFile(GenT::RCC, InfoFile(), "rcc input file missing."); + return false; + } + if (RccFileName_.empty()) { + Log().ErrorFile(GenT::RCC, InfoFile(), "rcc output file missing."); + return false; + } + + // Init derived information + // ------------------------ + + RccFilePublic_ = AutogenBuildDir_; + RccFilePublic_ += '/'; + RccFilePublic_ += RccPathChecksum_; + RccFilePublic_ += '/'; + RccFilePublic_ += RccFileName_; + + // Compute rcc output file name + if (IsMultiConfig()) { + RccFileOutput_ = IncludeDir_; + RccFileOutput_ += '/'; + RccFileOutput_ += MultiConfigOutput(); + } else { + RccFileOutput_ = RccFilePublic_; + } + + return true; +} + +bool cmQtAutoRcc::Process() +{ + if (!SettingsFileRead()) { + return false; + } + + // Test if the rcc output needs to be regenerated + bool generate = false; + if (!TestQrcRccFiles(generate)) { + return false; + } + if (!generate && !TestResources(generate)) { + return false; + } + // Generate on demand + if (generate) { + if (!GenerateRcc()) { + return false; + } + } else { + // Test if the info file is newer than the output file + if (!TestInfoFile()) { + return false; + } + } + + if (!GenerateWrapper()) { + return false; + } + + return SettingsFileWrite(); +} + +std::string cmQtAutoRcc::MultiConfigOutput() const +{ + static std::string const suffix = "_CMAKE_"; + std::string res; + res += RccPathChecksum_; + res += '/'; + res += AppendFilenameSuffix(RccFileName_, suffix); + return res; +} + +bool cmQtAutoRcc::SettingsFileRead() +{ + // Compose current settings strings + { + cmCryptoHash crypt(cmCryptoHash::AlgoSHA256); + std::string const sep(" ~~~ "); + { + std::string str; + str += RccExecutable_; + str += sep; + str += cmJoin(RccListOptions_, ";"); + str += sep; + str += QrcFile_; + str += sep; + str += RccPathChecksum_; + str += sep; + str += RccFileName_; + str += sep; + str += cmJoin(Options_, ";"); + str += sep; + str += cmJoin(Inputs_, ";"); + str += sep; + SettingsString_ = crypt.HashString(str); + } + } + + // Make sure the settings file exists + if (!cmSystemTools::FileExists(SettingsFile_, true)) { + // Touch the settings file to make sure it exists + if (!cmSystemTools::Touch(SettingsFile_, true)) { + Log().ErrorFile(GenT::RCC, SettingsFile_, + "Settings file creation failed."); + return false; + } + } + + // Lock the lock file + { + // Make sure the lock file exists + if (!cmSystemTools::FileExists(LockFile_, true)) { + if (!cmSystemTools::Touch(LockFile_, true)) { + Log().ErrorFile(GenT::RCC, LockFile_, "Lock file creation failed."); + return false; + } + } + // Lock the lock file + cmFileLockResult lockResult = + LockFileLock_.Lock(LockFile_, static_cast(-1)); + if (!lockResult.IsOk()) { + Log().ErrorFile(GenT::RCC, LockFile_, + "File lock failed: " + lockResult.GetOutputMessage()); + return false; + } + } + + // Read old settings + { + std::string content; + if (FileRead(content, SettingsFile_)) { + SettingsChanged_ = (SettingsString_ != SettingsFind(content, "rcc")); + // In case any setting changed clear the old settings file. + // This triggers a full rebuild on the next run if the current + // build is aborted before writing the current settings in the end. + if (SettingsChanged_) { + std::string error; + if (!FileWrite(SettingsFile_, "", &error)) { + Log().ErrorFile(GenT::RCC, SettingsFile_, + "Settings file clearing failed. " + error); + return false; + } + } + } else { + SettingsChanged_ = true; + } + } + + return true; +} + +bool cmQtAutoRcc::SettingsFileWrite() +{ + // Only write if any setting changed + if (SettingsChanged_) { + if (Log().Verbose()) { + Log().Info(GenT::RCC, "Writing settings file " + Quoted(SettingsFile_)); + } + // Write settings file + std::string content = "rcc:"; + content += SettingsString_; + content += '\n'; + std::string error; + if (!FileWrite(SettingsFile_, content, &error)) { + Log().ErrorFile(GenT::RCC, SettingsFile_, + "Settings file writing failed. " + error); + // Remove old settings file to trigger a full rebuild on the next run + cmSystemTools::RemoveFile(SettingsFile_); + return false; + } + } + + // Unlock the lock file + LockFileLock_.Release(); + return true; +} + +/// Do basic checks if rcc generation is required +bool cmQtAutoRcc::TestQrcRccFiles(bool& generate) +{ + // Test if the rcc input file exists + if (!QrcFileTime_.Load(QrcFile_)) { + std::string error; + error = "The resources file "; + error += Quoted(QrcFile_); + error += " does not exist"; + Log().ErrorFile(GenT::RCC, QrcFile_, error); + return false; + } + + // Test if the rcc output file exists + if (!RccFileTime_.Load(RccFileOutput_)) { + if (Log().Verbose()) { + std::string reason = "Generating "; + reason += Quoted(RccFileOutput_); + reason += " from its source file "; + reason += Quoted(QrcFile_); + reason += " because it doesn't exist"; + Log().Info(GenT::RCC, reason); + } + generate = true; + return true; + } + + // Test if the settings changed + if (SettingsChanged_) { + if (Log().Verbose()) { + std::string reason = "Generating "; + reason += Quoted(RccFileOutput_); + reason += " from "; + reason += Quoted(QrcFile_); + reason += " because the RCC settings changed"; + Log().Info(GenT::RCC, reason); + } + generate = true; + return true; + } + + // Test if the rcc output file is older than the .qrc file + if (RccFileTime_.Older(QrcFileTime_)) { + if (Log().Verbose()) { + std::string reason = "Generating "; + reason += Quoted(RccFileOutput_); + reason += " because it is older than "; + reason += Quoted(QrcFile_); + Log().Info(GenT::RCC, reason); + } + generate = true; + return true; + } + + return true; +} + +bool cmQtAutoRcc::TestResources(bool& generate) +{ + // Read resource files list + if (Inputs_.empty()) { + std::string error; + RccLister const lister(RccExecutable_, RccListOptions_); + if (!lister.list(QrcFile_, Inputs_, error, Log().Verbose())) { + Log().ErrorFile(GenT::RCC, QrcFile_, error); + return false; + } + } + + for (std::string const& resFile : Inputs_) { + // Check if the resource file exists + cmFileTime fileTime; + if (!fileTime.Load(resFile)) { + std::string error; + error = "Could not find the resource file\n "; + error += Quoted(resFile); + error += '\n'; + Log().ErrorFile(GenT::RCC, QrcFile_, error); + return false; + } + // Check if the resource file is newer than the build file + if (RccFileTime_.Older(fileTime)) { + if (Log().Verbose()) { + std::string reason = "Generating "; + reason += Quoted(RccFileOutput_); + reason += " from "; + reason += Quoted(QrcFile_); + reason += " because it is older than "; + reason += Quoted(resFile); + Log().Info(GenT::RCC, reason); + } + generate = true; + break; + } + } + return true; +} + +bool cmQtAutoRcc::TestInfoFile() +{ + // Test if the rcc output file is older than the info file + + cmFileTime infoFileTime; + if (!infoFileTime.Load(InfoFile())) { + std::string error; + error = "Could not find the info file "; + error += Quoted(InfoFile()); + error += '\n'; + Log().ErrorFile(GenT::RCC, QrcFile_, error); + return false; + } + if (RccFileTime_.Older(infoFileTime)) { + if (Log().Verbose()) { + std::string reason = "Touching "; + reason += Quoted(RccFileOutput_); + reason += " because it is older than "; + reason += Quoted(InfoFile()); + Log().Info(GenT::RCC, reason); + } + // Touch build file + if (!cmSystemTools::Touch(RccFileOutput_, false)) { + Log().ErrorFile(GenT::RCC, RccFileOutput_, "Build file touch failed"); + return false; + } + BuildFileChanged_ = true; + } + + return true; +} + +bool cmQtAutoRcc::GenerateRcc() +{ + // Make parent directory + if (!MakeParentDirectory(RccFileOutput_)) { + Log().ErrorFile(GenT::RCC, RccFileOutput_, + "Could not create parent directory"); + return false; + } + + // Start a rcc process + std::vector cmd; + cmd.push_back(RccExecutable_); + cmd.insert(cmd.end(), Options_.begin(), Options_.end()); + cmd.emplace_back("-o"); + cmd.push_back(RccFileOutput_); + cmd.push_back(QrcFile_); + + // Log command + if (Log().Verbose()) { + std::string msg = "Running command:\n"; + msg += QuotedCommand(cmd); + msg += '\n'; + cmSystemTools::Stdout(msg); + } + + std::string rccStdOut; + std::string rccStdErr; + int retVal = 0; + bool result = cmSystemTools::RunSingleCommand( + cmd, &rccStdOut, &rccStdErr, &retVal, AutogenBuildDir_.c_str(), + cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto); + if (!result || (retVal != 0)) { + // rcc process failed + { + std::string err = "The rcc process failed to compile\n "; + err += Quoted(QrcFile_); + err += "\ninto\n "; + err += Quoted(RccFileOutput_); + Log().ErrorCommand(GenT::RCC, err, cmd, rccStdOut + rccStdErr); + } + cmSystemTools::RemoveFile(RccFileOutput_); + return false; + } + + // rcc process success + // Print rcc output + if (!rccStdOut.empty()) { + Log().Info(GenT::RCC, rccStdOut); + } + BuildFileChanged_ = true; + + return true; +} + +bool cmQtAutoRcc::GenerateWrapper() +{ + // Generate a wrapper source file on demand + if (IsMultiConfig()) { + // Wrapper file content + std::string content; + content += "// This is an autogenerated configuration wrapper file.\n"; + content += "// Changes will be overwritten.\n"; + content += "#include <"; + content += MultiConfigOutput(); + content += ">\n"; + + // Compare with existing file content + bool fileDiffers = true; + { + std::string oldContents; + if (FileRead(oldContents, RccFilePublic_)) { + fileDiffers = (oldContents != content); + } + } + if (fileDiffers) { + // Write new wrapper file + if (Log().Verbose()) { + Log().Info(GenT::RCC, "Generating RCC wrapper file " + RccFilePublic_); + } + std::string error; + if (!FileWrite(RccFilePublic_, content, &error)) { + Log().ErrorFile(GenT::RCC, RccFilePublic_, + "RCC wrapper file writing failed. " + error); + return false; + } + } else if (BuildFileChanged_) { + // Just touch the wrapper file + if (Log().Verbose()) { + Log().Info(GenT::RCC, "Touching RCC wrapper file " + RccFilePublic_); + } + if (!cmSystemTools::Touch(RccFilePublic_, false)) { + Log().ErrorFile(GenT::RCC, RccFilePublic_, + "RCC wrapper file touch failed."); + return false; + } + } + } + return true; +} diff --git a/Source/cmQtAutoRcc.h b/Source/cmQtAutoRcc.h new file mode 100644 index 0000000..8dc9179 --- /dev/null +++ b/Source/cmQtAutoRcc.h @@ -0,0 +1,79 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmQtAutoRcc_h +#define cmQtAutoRcc_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include "cmFileLock.h" +#include "cmFileTime.h" +#include "cmQtAutoGenerator.h" + +#include +#include + +class cmMakefile; + +// @brief AUTORCC generator +class cmQtAutoRcc : public cmQtAutoGenerator +{ +public: + cmQtAutoRcc(); + ~cmQtAutoRcc() override; + + cmQtAutoRcc(cmQtAutoRcc const&) = delete; + cmQtAutoRcc& operator=(cmQtAutoRcc const&) = delete; + +private: + // -- Utility + Logger& Log() { return Logger_; } + bool IsMultiConfig() const { return MultiConfig_; } + std::string MultiConfigOutput() const; + + // -- Abstract processing interface + bool Init(cmMakefile* makefile) override; + bool Process() override; + // -- Settings file + bool SettingsFileRead(); + bool SettingsFileWrite(); + // -- Tests + bool TestQrcRccFiles(bool& generate); + bool TestResources(bool& generate); + bool TestInfoFile(); + // -- Generation + bool GenerateRcc(); + bool GenerateWrapper(); + +private: + // -- Logging + Logger Logger_; + // -- Config settings + bool MultiConfig_ = false; + // -- Directories + std::string AutogenBuildDir_; + std::string IncludeDir_; + // -- Qt environment + std::string RccExecutable_; + std::vector RccListOptions_; + // -- Job + std::string LockFile_; + cmFileLock LockFileLock_; + std::string QrcFile_; + std::string QrcFileName_; + std::string QrcFileDir_; + cmFileTime QrcFileTime_; + std::string RccPathChecksum_; + std::string RccFileName_; + std::string RccFileOutput_; + std::string RccFilePublic_; + cmFileTime RccFileTime_; + std::vector Options_; + std::vector Inputs_; + // -- Settings file + std::string SettingsFile_; + std::string SettingsString_; + bool SettingsChanged_ = false; + bool BuildFileChanged_ = false; +}; + +#endif diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index cf9f064..c18c256 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -8,7 +8,7 @@ #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmQtAutoGeneratorMocUic.h" -#include "cmQtAutoGeneratorRcc.h" +#include "cmQtAutoRcc.h" #include "cmRange.h" #include "cmState.h" #include "cmStateDirectory.h" @@ -1024,7 +1024,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector const& args) return autoGen.Run(infoDir, config) ? 0 : 1; } if ((args[1] == "cmake_autorcc") && (args.size() >= 3)) { - cmQtAutoGeneratorRcc autoGen; + cmQtAutoRcc autoGen; std::string const& infoFile = args[2]; std::string config; if (args.size() > 3) { -- cgit v0.12