[Cmake-commits] CMake branch, next, updated. v3.0.2-5521-g5748a42

Stephen Kelly steveire at gmail.com
Mon Sep 29 17:34:20 EDT 2014


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  5748a42d9a903ec8bc1acfd8160dc2bb5e923a5f (commit)
       via  8e23f21b2da0b9d4c0fdc7f2d9023459060033c4 (commit)
      from  40229e8a58c0b34706e0ae8b7bfc58a4d4fce853 (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=5748a42d9a903ec8bc1acfd8160dc2bb5e923a5f
commit 5748a42d9a903ec8bc1acfd8160dc2bb5e923a5f
Merge: 40229e8 8e23f21
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Mon Sep 29 17:34:19 2014 -0400
Commit:     CMake Topic Stage <kwrobot at kitware.com>
CommitDate: Mon Sep 29 17:34:19 2014 -0400

    Merge topic 'autorcc-depends' into next
    
    8e23f21b QtAutogen: Regenerate qrc files if their input changes (#15074)


http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8e23f21b2da0b9d4c0fdc7f2d9023459060033c4
commit 8e23f21b2da0b9d4c0fdc7f2d9023459060033c4
Author:     Stephen Kelly <steveire at gmail.com>
AuthorDate: Wed Sep 17 02:42:30 2014 +0200
Commit:     Stephen Kelly <steveire at gmail.com>
CommitDate: Mon Sep 29 23:34:13 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.
    
    This does not work with the Ninja generator, and it does not
    work for RCC files which are generated.

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..8054527 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,49 @@ 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 (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED")))
+          {
+          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 +567,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 +1304,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 +2248,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 +2289,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..c7815f6 100644
--- a/Tests/QtAutogen/CMakeLists.txt
+++ b/Tests/QtAutogen/CMakeLists.txt
@@ -113,3 +113,57 @@ 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})
+
+if (NOT CMAKE_GENERATOR STREQUAL Ninja)
+
+  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
+  )
+  if (NOT RCC_DEPENDS)
+    message(SEND_ERROR "Initial build of autorcc_depends failed. Output: ${output}")
+  endif()
+
+  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()
+      else()
+        message("Does not exist: ${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends/info_file_${_config}.txt")
+      endif()
+    endforeach()
+    if (NOT info_file)
+      file(GLOB info_files "${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends/info_file*" )
+      message("info_files glob: ${info_files}")
+      message(SEND_ERROR "No valid info_file found!")
+    endif()
+  endif()
+
+  file(STRINGS "${info_file}" qrc_files)
+
+  list(GET qrc_files 0 qrc_file1)
+
+  set(timeformat "%Y%j%H%M%S")
+
+  file(TIMESTAMP "${qrc_file1}" file1_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}")
+
+  if (NOT file1_step1 GREATER file1_before)
+    message(SEND_ERROR "file1 (${qrc_file1}) should have changed in the first step!")
+  endif()
+endif()
diff --git a/Tests/QtAutogen/autorcc_depends/CMakeLists.txt b/Tests/QtAutogen/autorcc_depends/CMakeLists.txt
new file mode 100644
index 0000000..590271f
--- /dev/null
+++ b/Tests/QtAutogen/autorcc_depends/CMakeLists.txt
@@ -0,0 +1,27 @@
+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_executable(test_res1
+  test_res1.cpp
+  res1.qrc
+)
+target_link_libraries(test_res1 ${QT_CORE_TARGET})
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/info_file$<$<BOOL:$<CONFIG>>:_$<CONFIG>>.txt"
+  CONTENT "$<TARGET_FILE:test_res1>\n"
+)
diff --git a/Tests/QtAutogen/autorcc_depends/res1.qrc b/Tests/QtAutogen/autorcc_depends/res1.qrc
new file mode 100644
index 0000000..cfea618
--- /dev/null
+++ b/Tests/QtAutogen/autorcc_depends/res1.qrc
@@ -0,0 +1,5 @@
+<RCC>
+    <qresource prefix="/">
+        <file>res1_input.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/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;
+}

-----------------------------------------------------------------------

Summary of changes:


hooks/post-receive
-- 
CMake


More information about the Cmake-commits mailing list