summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Modules/AutogenInfo.cmake.in1
-rw-r--r--Source/cmQtAutoGenerators.cxx275
-rw-r--r--Source/cmQtAutoGenerators.h10
-rw-r--r--Tests/QtAutogen/CMakeLists.txt32
-rw-r--r--Tests/QtAutogen/autorcc_depends/CMakeLists.txt24
-rw-r--r--Tests/QtAutogen/autorcc_depends/res1.qrc5
-rw-r--r--Tests/QtAutogen/autorcc_depends/res1_input.txt1
-rw-r--r--Tests/QtAutogen/autorcc_depends/test_res1.cpp5
8 files changed, 345 insertions, 8 deletions
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 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);
diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h
index ce27852..79fa5df 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 const* 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..a60b556 100644
--- a/Tests/QtAutogen/CMakeLists.txt
+++ b/Tests/QtAutogen/CMakeLists.txt
@@ -113,3 +113,35 @@ 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
+)
+if (NOT RCC_DEPENDS)
+ message(SEND_ERROR "Initial build of autorcc_depends failed. Output: ${output}")
+endif()
+
+file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends/info_file.txt" 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 sleep 1) # Ensure that the timestamp will change.
+execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_SOURCE_DIR}/autorcc_depends/res1_input.txt")
+
+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()
diff --git a/Tests/QtAutogen/autorcc_depends/CMakeLists.txt b/Tests/QtAutogen/autorcc_depends/CMakeLists.txt
new file mode 100644
index 0000000..afd95bc
--- /dev/null
+++ b/Tests/QtAutogen/autorcc_depends/CMakeLists.txt
@@ -0,0 +1,24 @@
+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})
+add_custom_command(TARGET test_res1 POST_BUILD COMMAND
+ ${CMAKE_COMMAND} -E echo "$<TARGET_FILE:test_res1>" > info_file.txt)
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;
+}