This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "CMake".
The branch, next has been updated via 140be4fd07c907c814ea0161db3c593463b53d74 (commit) via 9076e98ee35f88862e122aab970cbb5eb51b6653 (commit) from 3989553aae0bf67901dd141d7ebc86fa97dfe027 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=140be4fd07c907c814ea0161db3c593463b53d74 commit 140be4fd07c907c814ea0161db3c593463b53d74 Merge: 3989553 9076e98 Author: Stephen Kelly <steve...@gmail.com> AuthorDate: Tue Sep 23 16:33:48 2014 -0400 Commit: CMake Topic Stage <kwro...@kitware.com> CommitDate: Tue Sep 23 16:33:48 2014 -0400 Merge topic 'autorcc-depends' into next 9076e98e QtAutogen: Regenerate qrc files if their input changes (#15074) http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=9076e98ee35f88862e122aab970cbb5eb51b6653 commit 9076e98ee35f88862e122aab970cbb5eb51b6653 Author: Stephen Kelly <steve...@gmail.com> AuthorDate: Wed Sep 17 02:42:30 2014 +0200 Commit: Stephen Kelly <steve...@gmail.com> CommitDate: Tue Sep 23 22:32:26 2014 +0200 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. diff --git a/Modules/AutogenInfo.cmake.in b/Modules/AutogenInfo.cmake.in index 602b065..7d89420 100644 --- a/Modules/AutogenInfo.cmake.in +++ b/Modules/AutogenInfo.cmake.in @@ -1,5 +1,6 @@ set(AM_SOURCES @_cpp_files@ ) set(AM_RCC_SOURCES @_rcc_files@ ) +set(AM_RCC_INPUTS @_qt_rcc_inputs@) set(AM_SKIP_MOC @_skip_moc@ ) set(AM_SKIP_UIC @_skip_uic@ ) set(AM_HEADERS @_moc_headers@ ) diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 4e40fc7..8f1a52f 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* 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(); @@ -229,6 +335,46 @@ bool cmQtAutoGenerators::InitializeAutogenTarget(cmTarget* target) if (target->GetPropertyAsBool("AUTORCC")) { toolNames.push_back("rcc"); + + std::vector<cmSourceFile*> srcFiles; + target->GetConfigCommonSourceFiles(srcFiles); + + std::string qrcInputs; + const char* qrcInputsSep = ""; + + for(std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); + fileIt != srcFiles.end(); + ++fileIt) + { + cmSourceFile* sf = *fileIt; + std::string fileFullPath = sf->GetFullPath(); + std::string ext = sf->GetExtension(); + + if (ext == "qrc" + && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) + { + + std::string entriesList; + if (qtMajorVersion == "5") + { + entriesList = this->ListQt5RccInputs(sf, target, depends); + } + else + { + entriesList = this->ListQt4RccInputs(sf, depends); + } + if (entriesList.empty()) + { + return false; + } + + qrcInputs += qrcInputsSep; + qrcInputs += entriesList; + qrcInputsSep = ";"; + } + } + makefile->AddDefinition("_qt_rcc_inputs_" + target->GetName(), + cmLocalGenerator::EscapeForCMake(qrcInputs).c_str()); } std::string tools = toolNames[0]; @@ -418,6 +564,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); @@ -1153,6 +1301,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 +2245,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 +2286,14 @@ bool cmQtAutoGenerators::GenerateQrc() + ".dir/qrc_" + basename + ".cpp"; int sourceNewerThanQrc = 0; - bool success = cmsys::SystemTools::FileTimeCompare(si->c_str(), + bool generateQrc = !cmsys::SystemTools::FileTimeCompare(si->c_str(), 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); diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index ce27852..ba03999 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -88,6 +88,15 @@ private: std::string GetRccExecutable(cmTarget const* target); + std::string ListQt5RccInputs(cmSourceFile* sf, cmTarget* target, + std::vector<std::string>& depends); + + std::string ListQt4RccInputs(cmSourceFile* sf, + std::vector<std::string>& depends); + + bool InputFilesNewerThanQrc(const std::string& qrcFile, + const std::string& rccOutput); + std::string QtMajorVersion; std::string Sources; std::vector<std::string> RccSources; @@ -118,6 +127,7 @@ private: std::vector<std::string> UicTargetOptions; std::map<std::string, std::string> UicOptions; std::map<std::string, std::string> RccOptions; + std::map<std::string, std::vector<std::string> > RccInputs; bool Verbose; bool ColorOutput; diff --git a/Tests/QtAutogen/CMakeLists.txt b/Tests/QtAutogen/CMakeLists.txt index 3fd00b8..ff58bf9 100644 --- a/Tests/QtAutogen/CMakeLists.txt +++ b/Tests/QtAutogen/CMakeLists.txt @@ -113,3 +113,70 @@ set_target_properties(no_link_language PROPERTIES AUTOMOC TRUE) qtx_wrap_cpp(uicOnlyMoc sub/uiconly.h) add_executable(uiconly sub/uiconly.cpp ${uicOnlyMoc}) target_link_libraries(uiconly ${QT_LIBRARIES}) + +try_compile(RCC_DEPENDS + "${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends" + "${CMAKE_CURRENT_SOURCE_DIR}/autorcc_depends" + autorcc_depends + CMAKE_FLAGS "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}" "-DQT_TEST_VERSION=${QT_TEST_VERSION}" + OUTPUT_VARIABLE output +) + +set(info_file "${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends/info_file.txt") +if (NOT EXISTS ${info_file}) + unset(info_file) + foreach(_config ${CMAKE_CONFIGURATION_TYPES}) + set(_info_file "${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends/info_file_${config}.txt") + if (EXISTS ${_info_file}) + set(info_file ${_info_file}) + break() + endif() + endforeach() + if (NOT info_file) + message(SEND_ERROR "No valid info_file found!") + endif() +endif() + +file(STRINGS "${info_file}" qrc_files) + +list(GET qrc_files 0 qrc_file1) +list(GET qrc_files 1 qrc_file2) + +set(timeformat "%Y%j%H%M%S") + +file(TIMESTAMP "${qrc_file1}" file1_before "${timeformat}") +file(TIMESTAMP "${qrc_file2}" file2_before "${timeformat}") + +execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_SOURCE_DIR}/autorcc_depends/res1_input.txt") +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. + +execute_process(COMMAND "${CMAKE_COMMAND}" --build . + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends" +) + +file(TIMESTAMP "${qrc_file1}" file1_step1 "${timeformat}") +file(TIMESTAMP "${qrc_file2}" file2_step1 "${timeformat}") + +if (NOT file2_step1 STREQUAL file2_before) + message(SEND_ERROR "file2 (${qrc_file2}) should not have changed in the first step!") +endif() +if (NOT file1_step1 GREATER file1_before) + message(SEND_ERROR "file1 (${qrc_file1}) should have changed in the first step!") +endif() + +execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_SOURCE_DIR}/autorcc_depends/res2_input.txt") +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) + +execute_process(COMMAND "${CMAKE_COMMAND}" --build . + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends" +) + +file(TIMESTAMP "${qrc_file1}" file1_step2 "${timeformat}") +file(TIMESTAMP "${qrc_file2}" file2_step2 "${timeformat}") + +if (NOT file1_step2 STREQUAL file1_step1) + message(SEND_ERROR "file1 (${qrc_file1}) should not have changed in the second step!") +endif() +if (NOT file2_step2 GREATER file2_before) + message(SEND_ERROR "file2 (${qrc_file2}) should have changed in the second step!") +endif() diff --git a/Tests/QtAutogen/autorcc_depends/CMakeLists.txt b/Tests/QtAutogen/autorcc_depends/CMakeLists.txt new file mode 100644 index 0000000..5013739 --- /dev/null +++ b/Tests/QtAutogen/autorcc_depends/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 2.8) +project(autorcc_depends) + +set(CMAKE_AUTORCC ON) + +if (QT_TEST_VERSION STREQUAL 4) + find_package(Qt4 REQUIRED) + set(QT_CORE_TARGET Qt4::QtCore) +else() + if (NOT QT_TEST_VERSION STREQUAL 5) + message(SEND_ERROR "Invalid Qt version specified.") + endif() + + find_package(Qt5Core REQUIRED) + set(QT_CORE_TARGET Qt5::Core) +endif() + +add_custom_command(OUTPUT generated.txt + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/res1_input.txt" "${CMAKE_CURRENT_BINARY_DIR}/generated.txt" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/res1_input.txt" +) + +configure_file(res1.qrc.in res1_gen.qrc) + +add_executable(test_res1 + test_res1.cpp + ${CMAKE_CURRENT_BINARY_DIR}/res1_gen.qrc +) +target_link_libraries(test_res1 ${QT_CORE_TARGET}) + +add_executable(test_res2 + test_res2.cpp + res2_gen.qrc +) +target_link_libraries(test_res2 ${QT_CORE_TARGET}) + +file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/info_file$<$<BOOL:$<CONFIG>>:_$<CONFIG>>.txt" + CONTENT "$<TARGET_FILE:test_res1>\n$<TARGET_FILE:test_res2>\n" +) diff --git a/Tests/QtAutogen/autorcc_depends/res1.qrc.in b/Tests/QtAutogen/autorcc_depends/res1.qrc.in new file mode 100644 index 0000000..7c233cb --- /dev/null +++ b/Tests/QtAutogen/autorcc_depends/res1.qrc.in @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/"> + <file>@CMAKE_CURRENT_SOURCE_DIR@/src_file.txt</file> + <file>@CMAKE_CURRENT_BINARY_DIR@/generated.txt</file> + </qresource> +</RCC> diff --git a/Tests/QtAutogen/autorcc_depends/res1_input.txt b/Tests/QtAutogen/autorcc_depends/res1_input.txt new file mode 100644 index 0000000..da62762 --- /dev/null +++ b/Tests/QtAutogen/autorcc_depends/res1_input.txt @@ -0,0 +1 @@ +Res1 input. diff --git a/Tests/QtAutogen/autorcc_depends/res2_gen.qrc b/Tests/QtAutogen/autorcc_depends/res2_gen.qrc new file mode 100644 index 0000000..525a2fc --- /dev/null +++ b/Tests/QtAutogen/autorcc_depends/res2_gen.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>res2_input.txt</file> + </qresource> +</RCC> diff --git a/Tests/QtAutogen/autorcc_depends/res2_input.txt b/Tests/QtAutogen/autorcc_depends/res2_input.txt new file mode 100644 index 0000000..08e14b7 --- /dev/null +++ b/Tests/QtAutogen/autorcc_depends/res2_input.txt @@ -0,0 +1 @@ +Res2 input. diff --git a/Tests/QtAutogen/autorcc_depends/src_file.txt b/Tests/QtAutogen/autorcc_depends/src_file.txt new file mode 100644 index 0000000..3d54a31 --- /dev/null +++ b/Tests/QtAutogen/autorcc_depends/src_file.txt @@ -0,0 +1 @@ +src file. diff --git a/Tests/QtAutogen/autorcc_depends/test_res1.cpp b/Tests/QtAutogen/autorcc_depends/test_res1.cpp new file mode 100644 index 0000000..766b775 --- /dev/null +++ b/Tests/QtAutogen/autorcc_depends/test_res1.cpp @@ -0,0 +1,5 @@ + +int main() +{ + return 0; +} diff --git a/Tests/QtAutogen/autorcc_depends/test_res2.cpp b/Tests/QtAutogen/autorcc_depends/test_res2.cpp new file mode 100644 index 0000000..766b775 --- /dev/null +++ b/Tests/QtAutogen/autorcc_depends/test_res2.cpp @@ -0,0 +1,5 @@ + +int main() +{ + return 0; +} ----------------------------------------------------------------------- Summary of changes: hooks/post-receive -- CMake _______________________________________________ Cmake-commits mailing list Cmake-commits@cmake.org http://public.kitware.com/mailman/listinfo/cmake-commits