diff options
author | Sebastian Holtermann <sebholt@xwmw.org> | 2018-01-03 15:59:40 (GMT) |
---|---|---|
committer | Sebastian Holtermann <sebholt@xwmw.org> | 2018-01-17 16:23:49 (GMT) |
commit | a008578deebfa71b38786281450e3d9cf84f5847 (patch) | |
tree | 70173006b0adc6a62626e59d9cc653826f950336 /Source/cmQtAutoGeneratorRcc.cxx | |
parent | 488baaf0d6144cd7cedfbbd3bb6eadcc72257fc4 (diff) | |
download | CMake-a008578deebfa71b38786281450e3d9cf84f5847.zip CMake-a008578deebfa71b38786281450e3d9cf84f5847.tar.gz CMake-a008578deebfa71b38786281450e3d9cf84f5847.tar.bz2 |
Autogen: Process files concurrently in AUTOMOC and AUTOUIC
This introduces concurrent thread processing in the `_autogen`
target wich processes AUTOMOC and AUTOUIC.
Source file parsing is distributed among the threads by
using a job queue from which the threads pull new parse jobs.
Each thread might start an independent ``moc`` or ``uic`` process.
Altogether this roughly speeds up the AUTOMOC and AUTOUIC build
process by the number of physical CPUs on the host system.
The exact number of threads to start in the `_autogen` target
is controlled by the new AUTOGEN_PARALLEL target property which
is initialized by the new CMAKE_AUTOGEN_PARALLEL variable.
If AUTOGEN_PARALLEL is empty or unset (which is the default)
the thread count is set to the number of physical CPUs on
the host system.
The AUTOMOC/AUTOUIC generator and the AUTORCC generator are
refactored to use a libuv loop internally.
Closes #17422.
Diffstat (limited to 'Source/cmQtAutoGeneratorRcc.cxx')
-rw-r--r-- | Source/cmQtAutoGeneratorRcc.cxx | 719 |
1 files changed, 455 insertions, 264 deletions
diff --git a/Source/cmQtAutoGeneratorRcc.cxx b/Source/cmQtAutoGeneratorRcc.cxx index 3c9f1a8..e8ff75a 100644 --- a/Source/cmQtAutoGeneratorRcc.cxx +++ b/Source/cmQtAutoGeneratorRcc.cxx @@ -6,22 +6,30 @@ #include "cmAlgorithms.h" #include "cmCryptoHash.h" #include "cmMakefile.h" -#include "cmOutputConverter.h" #include "cmSystemTools.h" +#include "cmUVHandlePtr.h" -// -- Static variables - -static const char* SettingsKeyRcc = "ARCC_SETTINGS_HASH"; +#include <functional> // -- Class methods cmQtAutoGeneratorRcc::cmQtAutoGeneratorRcc() - : MultiConfig(cmQtAutoGen::WRAP) - , SettingsChanged(false) + : SettingsChanged_(false) + , MultiConfig_(MultiConfigT::WRAPPER) + , Stage_(StageT::SETTINGS_READ) + , Error_(false) + , Generate_(false) + , BuildFileChanged_(false) { + // Initialize libuv asynchronous iteration request + UVRequest().init(*UVLoop(), &cmQtAutoGeneratorRcc::UVPollStage, this); } -bool cmQtAutoGeneratorRcc::InfoFileRead(cmMakefile* makefile) +cmQtAutoGeneratorRcc::~cmQtAutoGeneratorRcc() +{ +} + +bool cmQtAutoGeneratorRcc::Init(cmMakefile* makefile) { // Utility lambdas auto InfoGet = [makefile](const char* key) { @@ -37,7 +45,7 @@ bool cmQtAutoGeneratorRcc::InfoFileRead(cmMakefile* makefile) { std::string keyConf = key; keyConf += '_'; - keyConf += this->GetInfoConfig(); + keyConf += InfoConfig(); valueConf = makefile->GetDefinition(keyConf); } if (valueConf == nullptr) { @@ -53,79 +61,180 @@ bool cmQtAutoGeneratorRcc::InfoFileRead(cmMakefile* makefile) }; // -- Read info file - if (!makefile->ReadListFile(this->GetInfoFile().c_str())) { - this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(), - "File processing failed"); + if (!makefile->ReadListFile(InfoFile().c_str())) { + Log().ErrorFile(GeneratorT::RCC, InfoFile(), "File processing failed"); return false; } // -- Meta - this->MultiConfig = - cmQtAutoGen::MultiConfigType(InfoGet("ARCC_MULTI_CONFIG")); - this->ConfigSuffix = InfoGetConfig("ARCC_CONFIG_SUFFIX"); - if (this->ConfigSuffix.empty()) { - this->ConfigSuffix = "_"; - this->ConfigSuffix += this->GetInfoConfig(); + MultiConfig_ = MultiConfigType(InfoGet("ARCC_MULTI_CONFIG")); + ConfigSuffix_ = InfoGetConfig("ARCC_CONFIG_SUFFIX"); + if (ConfigSuffix_.empty()) { + ConfigSuffix_ = "_"; + ConfigSuffix_ += InfoConfig(); } - this->SettingsFile = InfoGetConfig("ARCC_SETTINGS_FILE"); + SettingsFile_ = InfoGetConfig("ARCC_SETTINGS_FILE"); // - Files and directories - this->ProjectSourceDir = InfoGet("ARCC_CMAKE_SOURCE_DIR"); - this->ProjectBinaryDir = InfoGet("ARCC_CMAKE_BINARY_DIR"); - this->CurrentSourceDir = InfoGet("ARCC_CMAKE_CURRENT_SOURCE_DIR"); - this->CurrentBinaryDir = InfoGet("ARCC_CMAKE_CURRENT_BINARY_DIR"); - this->AutogenBuildDir = InfoGet("ARCC_BUILD_DIR"); + AutogenBuildDir_ = InfoGet("ARCC_BUILD_DIR"); // - Qt environment - this->RccExecutable = InfoGet("ARCC_RCC_EXECUTABLE"); - this->RccListOptions = InfoGetList("ARCC_RCC_LIST_OPTIONS"); + RccExecutable_ = InfoGet("ARCC_RCC_EXECUTABLE"); + RccListOptions_ = InfoGetList("ARCC_RCC_LIST_OPTIONS"); // - Job - this->QrcFile = InfoGet("ARCC_SOURCE"); - this->RccFile = InfoGet("ARCC_OUTPUT"); - this->Options = InfoGetConfigList("ARCC_OPTIONS"); - this->Inputs = InfoGetList("ARCC_INPUTS"); + QrcFile_ = InfoGet("ARCC_SOURCE"); + QrcFileName_ = cmSystemTools::GetFilenameName(QrcFile_); + QrcFileDir_ = cmSystemTools::GetFilenamePath(QrcFile_); + RccFile_ = InfoGet("ARCC_OUTPUT"); + Options_ = InfoGetConfigList("ARCC_OPTIONS"); + Inputs_ = InfoGetList("ARCC_INPUTS"); // - Validity checks - if (this->SettingsFile.empty()) { - this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(), - "Settings file name missing"); + if (SettingsFile_.empty()) { + Log().ErrorFile(GeneratorT::RCC, InfoFile(), "Settings file name missing"); return false; } - if (this->AutogenBuildDir.empty()) { - this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(), - "Autogen build directory missing"); + if (AutogenBuildDir_.empty()) { + Log().ErrorFile(GeneratorT::RCC, InfoFile(), + "Autogen build directory missing"); return false; } - if (this->RccExecutable.empty()) { - this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(), - "rcc executable missing"); + if (RccExecutable_.empty()) { + Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc executable missing"); return false; } - if (this->QrcFile.empty()) { - this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(), - "rcc input file missing"); + if (QrcFile_.empty()) { + Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc input file missing"); return false; } - if (this->RccFile.empty()) { - this->LogFileError(cmQtAutoGen::RCC, this->GetInfoFile(), - "rcc output file missing"); + if (RccFile_.empty()) { + Log().ErrorFile(GeneratorT::RCC, InfoFile(), "rcc output file missing"); return false; } // Init derived information // ------------------------ - // Init file path checksum generator - this->FilePathChecksum.setupParentDirs( - this->CurrentSourceDir, this->CurrentBinaryDir, this->ProjectSourceDir, - this->ProjectBinaryDir); + // Compute rcc output file name + { + std::string suffix; + switch (MultiConfig_) { + case MultiConfigT::SINGLE: + break; + case MultiConfigT::WRAPPER: + suffix = "_CMAKE"; + suffix += ConfigSuffix_; + suffix += "_"; + break; + case MultiConfigT::MULTI: + suffix = ConfigSuffix_; + break; + } + RccFileBuild_ = AppendFilenameSuffix(RccFile_, suffix); + } + + return true; +} +bool cmQtAutoGeneratorRcc::Process() +{ + // Run libuv event loop + UVRequest().send(); + if (uv_run(UVLoop(), UV_RUN_DEFAULT) == 0) { + if (Error_) { + return false; + } + } else { + return false; + } return true; } -void cmQtAutoGeneratorRcc::SettingsFileRead(cmMakefile* makefile) +void cmQtAutoGeneratorRcc::UVPollStage(uv_async_t* handle) +{ + reinterpret_cast<cmQtAutoGeneratorRcc*>(handle->data)->PollStage(); +} + +void cmQtAutoGeneratorRcc::PollStage() +{ + switch (Stage_) { + // -- Initialize + case StageT::SETTINGS_READ: + SettingsFileRead(); + SetStage(StageT::TEST_QRC_RCC_FILES); + 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; + } +} + +void cmQtAutoGeneratorRcc::SetStage(StageT stage) +{ + if (Error_) { + stage = StageT::FINISH; + } + // Only allow to increase the stage + if (Stage_ < stage) { + Stage_ = stage; + UVRequest().send(); + } +} + +void cmQtAutoGeneratorRcc::SettingsFileRead() { // Compose current settings strings { @@ -133,293 +242,375 @@ void cmQtAutoGeneratorRcc::SettingsFileRead(cmMakefile* makefile) std::string const sep(" ~~~ "); { std::string str; - str += this->RccExecutable; + str += RccExecutable_; str += sep; - str += cmJoin(this->RccListOptions, ";"); + str += cmJoin(RccListOptions_, ";"); str += sep; - str += this->QrcFile; + str += QrcFile_; str += sep; - str += this->RccFile; + str += RccFile_; str += sep; - str += cmJoin(this->Options, ";"); + str += cmJoin(Options_, ";"); str += sep; - str += cmJoin(this->Inputs, ";"); + str += cmJoin(Inputs_, ";"); str += sep; - this->SettingsString = crypt.HashString(str); + SettingsString_ = crypt.HashString(str); } } // Read old settings - if (makefile->ReadListFile(this->SettingsFile.c_str())) { - { - auto SMatch = [makefile](const char* key, std::string const& value) { - return (value == makefile->GetSafeDefinition(key)); - }; - if (!SMatch(SettingsKeyRcc, this->SettingsString)) { - this->SettingsChanged = true; + { + std::string content; + if (FileSys().FileRead(content, SettingsFile_)) { + SettingsChanged_ = (SettingsString_ != SettingsFind(content, "rcc")); + // In case any setting changed remove 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().FileRemove(SettingsFile_); } + } else { + SettingsChanged_ = true; } - // In case any setting changed remove 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 (this->SettingsChanged) { - cmSystemTools::RemoveFile(this->SettingsFile); - } - } else { - // If the file could not be read re-generate everythiung. - this->SettingsChanged = true; } } -bool cmQtAutoGeneratorRcc::SettingsFileWrite() +void cmQtAutoGeneratorRcc::SettingsFileWrite() { - bool success = true; // Only write if any setting changed - if (this->SettingsChanged) { - if (this->GetVerbose()) { - this->LogInfo(cmQtAutoGen::RCC, "Writing settings file " + - cmQtAutoGen::Quoted(this->SettingsFile)); - } - // Compose settings file content - std::string settings; - { - auto SettingAppend = [&settings](const char* key, - std::string const& value) { - settings += "set("; - settings += key; - settings += " "; - settings += cmOutputConverter::EscapeForCMake(value); - settings += ")\n"; - }; - SettingAppend(SettingsKeyRcc, this->SettingsString); + if (SettingsChanged_) { + if (Log().Verbose()) { + Log().Info(GeneratorT::RCC, + "Writing settings file " + Quoted(SettingsFile_)); } // Write settings file - if (!this->FileWrite(cmQtAutoGen::RCC, this->SettingsFile, settings)) { - this->LogFileError(cmQtAutoGen::RCC, this->SettingsFile, - "Settings file writing failed"); + std::string content = "rcc:"; + content += SettingsString_; + content += '\n'; + if (!FileSys().FileWrite(GeneratorT::RCC, SettingsFile_, content)) { + Log().ErrorFile(GeneratorT::RCC, SettingsFile_, + "Settings file writing failed"); // Remove old settings file to trigger a full rebuild on the next run - cmSystemTools::RemoveFile(this->SettingsFile); - success = false; + FileSys().FileRemove(SettingsFile_); + Error_ = true; } } - return success; } -bool cmQtAutoGeneratorRcc::Process(cmMakefile* makefile) +bool cmQtAutoGeneratorRcc::TestQrcRccFiles() { - // Read info file - if (!this->InfoFileRead(makefile)) { - return false; + // Do basic checks if rcc generation is required + + // Test if the rcc output file exists + if (!FileSys().FileExists(RccFileBuild_)) { + if (Log().Verbose()) { + std::string reason = "Generating "; + reason += Quoted(RccFileBuild_); + reason += " from its source file "; + reason += Quoted(QrcFile_); + reason += " because it doesn't exist"; + Log().Info(GeneratorT::RCC, reason); + } + Generate_ = true; + return Generate_; } - // Read latest settings - this->SettingsFileRead(makefile); - // Generate rcc file - if (!this->RccGenerate()) { - return false; + + // Test if the settings changed + if (SettingsChanged_) { + if (Log().Verbose()) { + std::string reason = "Generating "; + reason += Quoted(RccFileBuild_); + reason += " from "; + reason += Quoted(QrcFile_); + reason += " because the RCC settings changed"; + Log().Info(GeneratorT::RCC, reason); + } + Generate_ = true; + return Generate_; } - // Write latest settings - if (!this->SettingsFileWrite()) { - return false; + + // Test if the rcc output file is older than the .qrc file + { + bool isOlder = false; + { + std::string error; + isOlder = FileSys().FileIsOlderThan(RccFileBuild_, QrcFile_, &error); + if (!error.empty()) { + Log().ErrorFile(GeneratorT::RCC, QrcFile_, error); + Error_ = true; + } + } + if (isOlder) { + if (Log().Verbose()) { + std::string reason = "Generating "; + reason += Quoted(RccFileBuild_); + reason += " because it is older than "; + reason += Quoted(QrcFile_); + Log().Info(GeneratorT::RCC, reason); + } + Generate_ = true; + } } - return true; + + return Generate_; } -/** - * @return True on success - */ -bool cmQtAutoGeneratorRcc::RccGenerate() +bool cmQtAutoGeneratorRcc::TestResourcesRead() { - bool success = true; - bool rccGenerated = false; - - std::string rccFileAbs; - { - std::string suffix; - switch (this->MultiConfig) { - case cmQtAutoGen::SINGLE: - break; - case cmQtAutoGen::WRAP: - suffix = "_CMAKE"; - suffix += this->ConfigSuffix; - suffix += "_"; - break; - case cmQtAutoGen::FULL: - suffix = this->ConfigSuffix; - break; - } - rccFileAbs = cmQtAutoGen::AppendFilenameSuffix(this->RccFile, suffix); + if (!Inputs_.empty()) { + // Inputs are known already + return true; } - std::string const rccFileRel = cmSystemTools::RelativePath( - this->AutogenBuildDir.c_str(), rccFileAbs.c_str()); - // Check if regeneration is required - bool generate = false; - std::string generateReason; - if (!cmSystemTools::FileExists(this->QrcFile)) { - { - std::string error = "Could not find the file\n "; - error += cmQtAutoGen::Quoted(this->QrcFile); - this->LogError(cmQtAutoGen::RCC, error); + 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(GeneratorT::RCC, QrcFile_, parseError); + Error_ = true; + } + } else { + Log().ErrorFile(GeneratorT::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<std::string> 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); } - success = false; - } - if (success && !generate && !cmSystemTools::FileExists(rccFileAbs.c_str())) { - if (this->GetVerbose()) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(rccFileAbs); - generateReason += " from its source file "; - generateReason += cmQtAutoGen::Quoted(this->QrcFile); - generateReason += " because it doesn't exist"; + } else { + // rcc does not support the --list command. + // Read the qrc file content and parse it. + std::string qrcContent; + if (FileSys().FileRead(GeneratorT::RCC, qrcContent, QrcFile_)) { + RccListParseContent(qrcContent, Inputs_); } - generate = true; } - if (success && !generate && this->SettingsChanged) { - if (this->GetVerbose()) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(rccFileAbs); - generateReason += " from "; - generateReason += cmQtAutoGen::Quoted(this->QrcFile); - generateReason += " because the RCC settings changed"; - } - generate = true; + + if (!Inputs_.empty()) { + // Convert relative paths to absolute paths + RccListConvertFullPath(QrcFileDir_, Inputs_); + } + + return true; +} + +bool cmQtAutoGeneratorRcc::TestResources() +{ + if (Inputs_.empty()) { + return true; } - if (success && !generate) { + { std::string error; - if (FileIsOlderThan(rccFileAbs, this->QrcFile, &error)) { - if (this->GetVerbose()) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(rccFileAbs); - generateReason += " because it is older than "; - generateReason += cmQtAutoGen::Quoted(this->QrcFile); + 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(GeneratorT::RCC, QrcFile_, error); + Error_ = true; + break; } - generate = true; - } else { + // Check if the resource file is newer than the build file + if (FileSys().FileIsOlderThan(RccFileBuild_, resFile, &error)) { + if (Log().Verbose()) { + std::string reason = "Generating "; + reason += Quoted(RccFileBuild_); + reason += " from "; + reason += Quoted(QrcFile_); + reason += " because it is older than "; + reason += Quoted(resFile); + Log().Info(GeneratorT::RCC, reason); + } + Generate_ = true; + break; + } + // Print error and break on demand if (!error.empty()) { - this->LogError(cmQtAutoGen::RCC, error); - success = false; + Log().ErrorFile(GeneratorT::RCC, QrcFile_, error); + Error_ = true; + break; } } } - if (success && !generate) { - // Acquire input file list - std::vector<std::string> readFiles; - std::vector<std::string> const* files = nullptr; - if (!this->Inputs.empty()) { - files = &this->Inputs; - } else { - // Read input file list from qrc file + + return Generate_; +} + +void cmQtAutoGeneratorRcc::TestInfoFile() +{ + // Test if the rcc output file is older than the info file + { + bool isOlder = false; + { std::string error; - if (cmQtAutoGen::RccListInputs(this->RccExecutable, this->RccListOptions, - this->QrcFile, readFiles, &error)) { - files = &readFiles; - } else { - this->LogFileError(cmQtAutoGen::RCC, this->QrcFile, error); - success = false; + isOlder = FileSys().FileIsOlderThan(RccFileBuild_, InfoFile(), &error); + if (!error.empty()) { + Log().ErrorFile(GeneratorT::RCC, QrcFile_, error); + Error_ = true; } } - // Test if any input file is newer than the build file - if (files != nullptr) { - std::string error; - for (std::string const& resFile : *files) { - if (!cmSystemTools::FileExists(resFile.c_str())) { - error = "Could not find the file\n "; - error += cmQtAutoGen::Quoted(resFile); - error += "\nwhich is listed in\n "; - error += cmQtAutoGen::Quoted(this->QrcFile); - break; - } - if (FileIsOlderThan(rccFileAbs, resFile, &error)) { - if (this->GetVerbose()) { - generateReason = "Generating "; - generateReason += cmQtAutoGen::Quoted(rccFileAbs); - generateReason += " from "; - generateReason += cmQtAutoGen::Quoted(this->QrcFile); - generateReason += " because it is older than "; - generateReason += cmQtAutoGen::Quoted(resFile); - } - generate = true; - break; - } - if (!error.empty()) { - break; - } - } - // Print error - if (!error.empty()) { - this->LogError(cmQtAutoGen::RCC, error); - success = false; + if (isOlder) { + if (Log().Verbose()) { + std::string reason = "Touching "; + reason += Quoted(RccFileBuild_); + reason += " because it is older than "; + reason += Quoted(InfoFile()); + Log().Info(GeneratorT::RCC, reason); } + // Touch build file + FileSys().Touch(RccFileBuild_); + BuildFileChanged_ = true; } } - // Regenerate on demand - if (generate) { - // Log - if (this->GetVerbose()) { - this->LogBold("Generating RCC source " + rccFileRel); - this->LogInfo(cmQtAutoGen::RCC, generateReason); - } +} - // Make sure the parent directory exists - if (this->MakeParentDirectory(cmQtAutoGen::RCC, rccFileAbs)) { - // Compose rcc command - std::vector<std::string> cmd; - cmd.push_back(this->RccExecutable); - cmd.insert(cmd.end(), this->Options.begin(), this->Options.end()); - cmd.push_back("-o"); - cmd.push_back(rccFileAbs); - cmd.push_back(this->QrcFile); - - std::string output; - if (this->RunCommand(cmd, output)) { - // Success - rccGenerated = true; +void cmQtAutoGeneratorRcc::GenerateParentDir() +{ + // Make sure the parent directory exists + if (!FileSys().MakeParentDirectory(GeneratorT::RCC, RccFileBuild_)) { + Error_ = true; + } +} + +/** + * @return True when finished + */ +bool cmQtAutoGeneratorRcc::GenerateRcc() +{ + if (!Generate_) { + // Nothing to do + return true; + } + + if (Process_) { + // Process is running already + if (Process_->IsFinished()) { + // Process is finished + if (!ProcessResult_.error()) { + // Process success + BuildFileChanged_ = true; } else { + // Process failed { - std::string emsg = "rcc failed for\n "; - emsg += cmQtAutoGen::Quoted(this->QrcFile); - this->LogCommandError(cmQtAutoGen::RCC, emsg, cmd, output); + std::string emsg = "The rcc process failed to compile\n "; + emsg += Quoted(QrcFile_); + emsg += "\ninto\n "; + emsg += Quoted(RccFileBuild_); + if (ProcessResult_.error()) { + emsg += "\n"; + emsg += ProcessResult_.ErrorMessage; + } + Log().ErrorCommand(GeneratorT::RCC, emsg, Process_->Setup().Command, + ProcessResult_.StdOut); } - cmSystemTools::RemoveFile(rccFileAbs); - success = false; + FileSys().FileRemove(RccFileBuild_); + Error_ = true; } + // Clean up + Process_.reset(); + ProcessResult_.reset(); } else { - // Parent directory creation failed - success = false; + // Process is not finished, yet. + return false; } + } else { + // Start a rcc process + std::vector<std::string> cmd; + cmd.push_back(RccExecutable_); + cmd.insert(cmd.end(), Options_.begin(), Options_.end()); + cmd.push_back("-o"); + cmd.push_back(RccFileBuild_); + cmd.push_back(QrcFile_); + // We're done here if the process fails to start + return !StartProcess(AutogenBuildDir_, cmd, true); } + return true; +} + +void cmQtAutoGeneratorRcc::GenerateWrapper() +{ // Generate a wrapper source file on demand - if (success && (this->MultiConfig == cmQtAutoGen::WRAP)) { + if (MultiConfig_ == MultiConfigT::WRAPPER) { // Wrapper file name - std::string const& wrapperFileAbs = this->RccFile; - std::string const wrapperFileRel = cmSystemTools::RelativePath( - this->AutogenBuildDir.c_str(), wrapperFileAbs.c_str()); + std::string const& wrapperAbs = RccFile_; // Wrapper file content std::string content = "// This is an autogenerated configuration " "wrapper file. Changes will be overwritten.\n" "#include \""; - content += cmSystemTools::GetFilenameName(rccFileRel); + content += cmSystemTools::GetFilenameName(RccFileBuild_); content += "\"\n"; // Write content to file - if (this->FileDiffers(wrapperFileAbs, content)) { + if (FileSys().FileDiffers(wrapperAbs, content)) { // Write new wrapper file - if (this->GetVerbose()) { - this->LogBold("Generating RCC wrapper " + wrapperFileRel); + if (Log().Verbose()) { + Log().Info(GeneratorT::RCC, "Generating RCC wrapper " + wrapperAbs); } - if (!this->FileWrite(cmQtAutoGen::RCC, wrapperFileAbs, content)) { - this->LogFileError(cmQtAutoGen::RCC, wrapperFileAbs, - "rcc wrapper file writing failed"); - success = false; + if (!FileSys().FileWrite(GeneratorT::RCC, wrapperAbs, content)) { + Log().ErrorFile(GeneratorT::RCC, wrapperAbs, + "RCC wrapper file writing failed"); + Error_ = true; } - } else if (rccGenerated) { + } else if (BuildFileChanged_) { // Just touch the wrapper file - if (this->GetVerbose()) { - this->LogInfo(cmQtAutoGen::RCC, - "Touching RCC wrapper " + wrapperFileRel); + if (Log().Verbose()) { + Log().Info(GeneratorT::RCC, "Touching RCC wrapper " + wrapperAbs); } - cmSystemTools::Touch(wrapperFileAbs, false); + FileSys().Touch(wrapperAbs); } } +} + +bool cmQtAutoGeneratorRcc::StartProcess( + std::string const& workingDirectory, std::vector<std::string> const& command, + bool mergedOutput) +{ + // Log command + if (Log().Verbose()) { + std::string msg = "Running command:\n"; + msg += QuotedCommand(command); + msg += '\n'; + Log().Info(GeneratorT::RCC, msg); + } - return success; + // Create process handler + Process_ = cm::make_unique<ReadOnlyProcessT>(); + Process_->setup(&ProcessResult_, mergedOutput, command, workingDirectory); + // Start process + if (!Process_->start(UVLoop(), + std::bind(&cm::uv_async_ptr::send, &UVRequest()))) { + Log().ErrorFile(GeneratorT::RCC, QrcFile_, ProcessResult_.ErrorMessage); + Error_ = true; + // Clean up + Process_.reset(); + ProcessResult_.reset(); + return false; + } + return true; } |