diff options
author | Stephen Kelly <steveire@gmail.com> | 2014-09-17 00:42:30 (GMT) |
---|---|---|
committer | Stephen Kelly <steveire@gmail.com> | 2014-10-24 17:45:27 (GMT) |
commit | 6e1c359fe9bee71c421a671108176d47fb415d93 (patch) | |
tree | 7672d870bac30b8ede0e201558155e5107cdb9b9 /Source/cmQtAutoGenerators.cxx | |
parent | a29953180c21ba0d56fb236eb58bafd40ae68961 (diff) | |
download | CMake-6e1c359fe9bee71c421a671108176d47fb415d93.zip CMake-6e1c359fe9bee71c421a671108176d47fb415d93.tar.gz CMake-6e1c359fe9bee71c421a671108176d47fb415d93.tar.bz2 |
QtAutogen: Regenerate qrc files if their input changes (#15074)
Get dependencies from the output of ``rcc --list`` if using
Qt 5. Otherwise process the file in the same way as the
qt4_add_resources macro.
This does not work for RCC files which are generated.
The cmake_autogen build step is implemented as a PRE_BUILD step
of the target currently if possible, rather than a standalone
custom target. This is to keep the number of (synthesized)
custom targets that appear in the UI low, but in some cases
it is necessary to fall back to a full custom target.
Fall back to a full custom target for the VS builds if autorcc
is used.
Diffstat (limited to 'Source/cmQtAutoGenerators.cxx')
-rw-r--r-- | Source/cmQtAutoGenerators.cxx | 275 |
1 files changed, 267 insertions, 8 deletions
diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 7b81f4f..929cbc0 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -166,6 +166,112 @@ static std::string getAutogenTargetDir(cmTarget const* target) return targetDir; } +std::string cmQtAutoGenerators::ListQt5RccInputs(cmSourceFile* sf, + cmTarget const* target, + std::vector<std::string>& depends) +{ + std::string rccCommand = this->GetRccExecutable(target); + std::vector<std::string> qrcEntries; + + std::vector<std::string> command; + command.push_back(rccCommand); + command.push_back("--list"); + + std::string absFile = cmsys::SystemTools::GetRealPath( + sf->GetFullPath().c_str()); + + command.push_back(absFile); + + std::string output; + int retVal = 0; + bool result = cmSystemTools::RunSingleCommand(command, &output, + &retVal, 0, + cmSystemTools::OUTPUT_NONE); + if (!result || retVal) + { + std::cerr << "AUTOGEN: error: Rcc list process for " << sf->GetFullPath() + << " failed:\n" << output << std::endl; + return std::string(); + } + + std::istringstream ostr(output); + std::string oline; + while(std::getline(ostr, oline)) + { + if (oline.empty()) + { + // The output of rcc --list contains many empty lines. + continue; + } + if (cmHasLiteralPrefix(oline, "RCC: Error in")) + { + static std::string searchString = "Cannot find file '"; + + std::string::size_type pos = oline.find(searchString); + if (pos == std::string::npos) + { + std::cerr << "AUTOGEN: error: Rcc lists unparsable output " + << oline << std::endl; + return std::string(); + } + pos += searchString.length(); + std::string::size_type sz = oline.size() - pos - 1; + qrcEntries.push_back(oline.substr(pos, sz)); + } + else + { + qrcEntries.push_back(oline); + } + } + depends.insert(depends.end(), qrcEntries.begin(), qrcEntries.end()); + std::string entriesList; + const char* sep = ""; + for(std::vector<std::string>::const_iterator it = qrcEntries.begin(); + it != qrcEntries.end(); ++it) + { + entriesList += sep; + entriesList += *it; + sep = "@list_sep@"; + } + return entriesList; +} + +std::string cmQtAutoGenerators::ListQt4RccInputs(cmSourceFile* sf, + std::vector<std::string>& depends) +{ + const std::string qrcContents = ReadAll(sf->GetFullPath()); + + cmsys::RegularExpression fileMatchRegex("(<file[^<]+)"); + + std::string entriesList; + const char* sep = ""; + + size_t offset = 0; + while (fileMatchRegex.find(qrcContents.c_str() + offset)) + { + std::string qrcEntry = fileMatchRegex.match(1); + + offset += qrcEntry.size(); + + cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)"); + fileReplaceRegex.find(qrcEntry); + std::string tag = fileReplaceRegex.match(1); + + qrcEntry = qrcEntry.substr(tag.size()); + + if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str())) + { + qrcEntry = sf->GetLocation().GetDirectory() + "/" + qrcEntry; + } + + entriesList += sep; + entriesList += qrcEntry; + sep = "@list_sep@"; + depends.push_back(qrcEntry); + } + return entriesList; +} + bool cmQtAutoGenerators::InitializeAutogenTarget(cmTarget* target) { cmMakefile* makefile = target->GetMakefile(); @@ -271,6 +377,61 @@ bool cmQtAutoGenerators::InitializeAutogenTarget(cmTarget* target) } } } +#endif + + std::vector<std::string> rcc_output; + if(makefile->GetLocalGenerator()->GetGlobalGenerator()->GetName() == "Ninja" +#if defined(_WIN32) && !defined(__CYGWIN__) + || usePRE_BUILD +#endif + ) + { + std::vector<cmSourceFile*> srcFiles; + target->GetConfigCommonSourceFiles(srcFiles); + for(std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); + fileIt != srcFiles.end(); + ++fileIt) + { + cmSourceFile* sf = *fileIt; + std::string absFile = cmsys::SystemTools::GetRealPath( + sf->GetFullPath().c_str()); + + std::string ext = sf->GetExtension(); + + if (target->GetPropertyAsBool("AUTORCC")) + { + if (ext == "qrc" + && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) + { + std::string basename = cmsys::SystemTools:: + GetFilenameWithoutLastExtension(absFile); + + std::string rcc_output_dir = target->GetSupportDirectory(); + cmSystemTools::MakeDirectory(rcc_output_dir.c_str()); + std::string rcc_output_file = rcc_output_dir; + rcc_output_file += "/qrc_" + basename + ".cpp"; + rcc_output.push_back(rcc_output_file); + + if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) + { + if (qtMajorVersion == "5") + { + this->ListQt5RccInputs(sf, target, depends); + } + else + { + this->ListQt4RccInputs(sf, depends); + } +#if defined(_WIN32) && !defined(__CYGWIN__) + usePRE_BUILD = false; +#endif + } + } + } + } + } + +#if defined(_WIN32) && !defined(__CYGWIN__) if(usePRE_BUILD) { // Add the pre-build command directly to bypass the OBJECT_LIBRARY @@ -287,10 +448,29 @@ bool cmQtAutoGenerators::InitializeAutogenTarget(cmTarget* target) else #endif { - cmTarget* autogenTarget = makefile->AddUtilityCommand( + cmTarget* autogenTarget = 0; + if (!rcc_output.empty()) + { + makefile->AddCustomCommandToOutput(rcc_output, depends, "", + commandLines, 0, + workingDirectory.c_str(), + false, false); + + cmCustomCommandLines no_commands; + autogenTarget = makefile->AddUtilityCommand( + autogenTargetName, true, + workingDirectory.c_str(), rcc_output, + no_commands, false, autogenComment.c_str()); + + } + else + { + autogenTarget = makefile->AddUtilityCommand( autogenTargetName, true, workingDirectory.c_str(), depends, commandLines, false, autogenComment.c_str()); + } + // Set target folder const char* autogenFolder = makefile->GetCMakeInstance()->GetProperty( "AUTOMOC_TARGETS_FOLDER"); @@ -418,6 +598,8 @@ void cmQtAutoGenerators::SetupAutoGenerateTarget(cmTarget const* target) inputFile += "/Modules/AutogenInfo.cmake.in"; std::string outputFile = targetDir; outputFile += "/AutogenInfo.cmake"; + makefile->AddDefinition("_qt_rcc_inputs", + makefile->GetDefinition("_qt_rcc_inputs_" + target->GetName())); makefile->ConfigureFile(inputFile.c_str(), outputFile.c_str(), false, true, false); @@ -869,9 +1051,12 @@ void cmQtAutoGenerators::SetupAutoRccTarget(cmTarget const* target) std::vector<cmSourceFile*> srcFiles; target->GetConfigCommonSourceFiles(srcFiles); + std::string qrcInputs; + const char* qrcInputsSep = ""; + std::string rccFileFiles; std::string rccFileOptions; - const char *sep = ""; + const char *optionSep = ""; const char *qtVersion = makefile->GetDefinition("_target_qt_version"); @@ -880,6 +1065,11 @@ void cmQtAutoGenerators::SetupAutoRccTarget(cmTarget const* target) { cmSystemTools::ExpandListArgument(opts, rccOptions); } + std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); + if (qtMajorVersion == "") + { + qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR"); + } for(std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); @@ -909,9 +1099,9 @@ void cmQtAutoGenerators::SetupAutoRccTarget(cmTarget const* target) if (!rccOptions.empty()) { - rccFileFiles += sep; + rccFileFiles += optionSep; rccFileFiles += absFile; - rccFileOptions += sep; + rccFileOptions += optionSep; } const char *listSep = ""; for(std::vector<std::string>::const_iterator it = rccOptions.begin(); @@ -922,10 +1112,34 @@ void cmQtAutoGenerators::SetupAutoRccTarget(cmTarget const* target) rccFileOptions += *it; listSep = "@list_sep@"; } - sep = ";"; + optionSep = ";"; + + std::vector<std::string> depends; + + std::string entriesList; + if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) + { + if (qtMajorVersion == "5") + { + entriesList = this->ListQt5RccInputs(sf, target, depends); + } + else + { + entriesList = this->ListQt4RccInputs(sf, depends); + } + if (entriesList.empty()) + { + return; + } + } + qrcInputs += qrcInputsSep; + qrcInputs += entriesList; + qrcInputsSep = ";"; } } } + makefile->AddDefinition("_qt_rcc_inputs_" + target->GetName(), + cmLocalGenerator::EscapeForCMake(qrcInputs).c_str()); makefile->AddDefinition("_rcc_files", cmLocalGenerator::EscapeForCMake(_rcc_files).c_str()); @@ -1153,6 +1367,28 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(cmMakefile* makefile, cmSystemTools::ReplaceString(*optionIt, "@list_sep@", ";"); this->RccOptions[*fileIt] = *optionIt; } + + const char *rccInputs = makefile->GetSafeDefinition("AM_RCC_INPUTS"); + std::vector<std::string> rccInputLists; + cmSystemTools::ExpandListArgument(rccInputs, rccInputLists); + + if (this->RccSources.size() != rccInputLists.size()) + { + cmSystemTools::Error("Error processing file: ", filename.c_str()); + return false; + } + + for (std::vector<std::string>::iterator fileIt = this->RccSources.begin(), + inputIt = rccInputLists.begin(); + fileIt != this->RccSources.end(); + ++fileIt, ++inputIt) + { + cmSystemTools::ReplaceString(*inputIt, "@list_sep@", ";"); + std::vector<std::string> rccInputFiles; + cmSystemTools::ExpandListArgument(*inputIt, rccInputFiles); + + this->RccInputs[*fileIt] = rccInputFiles; + } } this->CurrentCompileSettingsStr = this->MakeCompileSettingsString(makefile); @@ -2075,6 +2311,25 @@ bool cmQtAutoGenerators::GenerateUi(const std::string& realName, return false; } +bool cmQtAutoGenerators::InputFilesNewerThanQrc(const std::string& qrcFile, + const std::string& rccOutput) +{ + std::vector<std::string> const& files = this->RccInputs[qrcFile]; + for (std::vector<std::string>::const_iterator it = files.begin(); + it != files.end(); ++it) + { + int inputNewerThanQrc = 0; + bool success = cmsys::SystemTools::FileTimeCompare(it->c_str(), + rccOutput.c_str(), + &inputNewerThanQrc); + if (!success || inputNewerThanQrc >= 0) + { + return true; + } + } + return false; +} + bool cmQtAutoGenerators::GenerateQrc() { for(std::vector<std::string>::const_iterator si = this->RccSources.begin(); @@ -2097,10 +2352,14 @@ bool cmQtAutoGenerators::GenerateQrc() + ".dir/qrc_" + basename + ".cpp"; int sourceNewerThanQrc = 0; - bool success = cmsys::SystemTools::FileTimeCompare(*si, - rcc_output_file, + bool generateQrc = !cmsys::SystemTools::FileTimeCompare(*si, + rcc_output_file.c_str(), &sourceNewerThanQrc); - if (this->GenerateAll || !success || sourceNewerThanQrc >= 0) + generateQrc = generateQrc || (sourceNewerThanQrc >= 0); + generateQrc = generateQrc || this->InputFilesNewerThanQrc(*si, + rcc_output_file); + + if (this->GenerateAll || generateQrc) { std::map<std::string, std::string>::const_iterator optionIt = this->RccOptions.find(*si); |