diff options
author | Brad King <brad.king@kitware.com> | 2017-03-07 13:22:55 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2017-03-07 13:23:00 (GMT) |
commit | 696c75e99124728d35339d1465e3e8edbed7fd04 (patch) | |
tree | 56394cbc361afafec4987330c5cbfea6fbc0659b | |
parent | 1e1cb41c46d5247c437b384fa702cfe774aaf501 (diff) | |
parent | ef3c319b971de36eabdc4180243a07e3581f84b7 (diff) | |
download | CMake-696c75e99124728d35339d1465e3e8edbed7fd04.zip CMake-696c75e99124728d35339d1465e3e8edbed7fd04.tar.gz CMake-696c75e99124728d35339d1465e3e8edbed7fd04.tar.bz2 |
Merge topic 'autogen_common'
ef3c319b Autogen: Test: Add mocDepends test
7f9baf57 Autogen: Test: Add generated qrc file to rccDepends test
81656b92 Autogen: Test: Add generated file to moc rerun test
d9a7ef80 Autogen: Test: Add timestamp comparison to moc rerun test
89780663 Autogen: Test: Rename automoc_rerun test to mocRerun
9cad44dc Autogen: Test: Rename autorcc_depends test to rccDepends
60274e1d Autogen: Add RunCommand method with built in logging
8f2ad9c4 Autogen: Error return when a scan file is not readable
...
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !543
32 files changed, 920 insertions, 548 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 76b98fc..5f2cbc3 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -344,6 +344,8 @@ set(SRCS cmPropertyDefinitionMap.h cmPropertyMap.cxx cmPropertyMap.h + cmQtAutoGeneratorCommon.cxx + cmQtAutoGeneratorCommon.h cmQtAutoGeneratorInitializer.cxx cmQtAutoGeneratorInitializer.h cmQtAutoGenerators.cxx diff --git a/Source/cmQtAutoGeneratorCommon.cxx b/Source/cmQtAutoGeneratorCommon.cxx new file mode 100644 index 0000000..dcd61a3 --- /dev/null +++ b/Source/cmQtAutoGeneratorCommon.cxx @@ -0,0 +1,215 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmQtAutoGeneratorCommon.h" +#include "cmAlgorithms.h" +#include "cmSystemTools.h" + +#include <cmsys/FStream.hxx> +#include <cmsys/RegularExpression.hxx> + +#include <sstream> + +// - Static functions + +static std::string utilStripCR(std::string const& line) +{ + // Strip CR characters rcc may have printed (possibly more than one!). + std::string::size_type cr = line.find('\r'); + if (cr != line.npos) { + return line.substr(0, cr); + } + return line; +} + +/// @brief Reads the resource files list from from a .qrc file - Qt4 version +/// @return True if the .qrc file was successfully parsed +static bool RccListInputsQt4(const std::string& fileName, + std::vector<std::string>& files, + std::string* errorMessage) +{ + bool allGood = true; + // Read qrc file content into string + std::string qrcContents; + { + cmsys::ifstream ifs(fileName.c_str()); + if (ifs) { + std::ostringstream osst; + osst << ifs.rdbuf(); + qrcContents = osst.str(); + } else { + if (errorMessage != CM_NULLPTR) { + std::ostringstream ost; + ost << "AutoRcc: Error: Rcc file not readable:\n" + << cmQtAutoGeneratorCommon::Quoted(fileName) << "\n"; + *errorMessage = ost.str(); + } + allGood = false; + } + } + if (allGood) { + // qrc file directory + std::string qrcDir(cmsys::SystemTools::GetFilenamePath(fileName)); + if (!qrcDir.empty()) { + qrcDir += '/'; + } + + cmsys::RegularExpression fileMatchRegex("(<file[^<]+)"); + cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)"); + + size_t offset = 0; + while (fileMatchRegex.find(qrcContents.c_str() + offset)) { + std::string qrcEntry = fileMatchRegex.match(1); + offset += qrcEntry.size(); + { + fileReplaceRegex.find(qrcEntry); + std::string tag = fileReplaceRegex.match(1); + qrcEntry = qrcEntry.substr(tag.size()); + } + if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str())) { + qrcEntry = qrcDir + qrcEntry; + } + files.push_back(qrcEntry); + } + } + return allGood; +} + +/// @brief Reads the resource files list from from a .qrc file - Qt5 version +/// @return True if the .qrc file was successfully parsed +static bool RccListInputsQt5(const std::string& rccCommand, + const std::string& fileName, + std::vector<std::string>& files, + std::string* errorMessage) +{ + if (rccCommand.empty()) { + cmSystemTools::Error("AutoRcc: Error: rcc executable not available\n"); + return false; + } + + // Read rcc features + bool hasDashDashList = false; + { + std::vector<std::string> command; + command.push_back(rccCommand); + command.push_back("--help"); + std::string rccStdOut; + std::string rccStdErr; + int retVal = 0; + bool result = + cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal, + CM_NULLPTR, cmSystemTools::OUTPUT_NONE); + if (result && retVal == 0 && + rccStdOut.find("--list") != std::string::npos) { + hasDashDashList = true; + } + } + + // Run rcc list command + bool result = false; + int retVal = 0; + std::string rccStdOut; + std::string rccStdErr; + { + std::vector<std::string> command; + command.push_back(rccCommand); + command.push_back(hasDashDashList ? "--list" : "-list"); + command.push_back(fileName); + result = + cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal, + CM_NULLPTR, cmSystemTools::OUTPUT_NONE); + } + if (!result || retVal) { + if (errorMessage != CM_NULLPTR) { + std::ostringstream ost; + ost << "AutoRcc: Error: Rcc list process for " << fileName + << " failed:\n" + << rccStdOut << "\n" + << rccStdErr << "\n"; + *errorMessage = ost.str(); + } + return false; + } + + // Parse rcc std output + { + std::istringstream ostr(rccStdOut); + std::string oline; + while (std::getline(ostr, oline)) { + oline = utilStripCR(oline); + if (!oline.empty()) { + files.push_back(oline); + } + } + } + // Parse rcc error output + { + std::istringstream estr(rccStdErr); + std::string eline; + while (std::getline(estr, eline)) { + eline = utilStripCR(eline); + if (cmHasLiteralPrefix(eline, "RCC: Error in")) { + static std::string searchString = "Cannot find file '"; + + std::string::size_type pos = eline.find(searchString); + if (pos == std::string::npos) { + if (errorMessage != CM_NULLPTR) { + std::ostringstream ost; + ost << "AutoRcc: Error: Rcc lists unparsable output:\n" + << cmQtAutoGeneratorCommon::Quoted(eline) << "\n"; + *errorMessage = ost.str(); + } + return false; + } + pos += searchString.length(); + std::string::size_type sz = eline.size() - pos - 1; + files.push_back(eline.substr(pos, sz)); + } + } + } + + return true; +} + +// - Class definitions + +const char* cmQtAutoGeneratorCommon::listSep = "@LSEP@"; + +std::string cmQtAutoGeneratorCommon::Quoted(const std::string& text) +{ + static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a", + "\b", "\\b", "\f", "\\f", "\n", "\\n", + "\r", "\\r", "\t", "\\t", "\v", "\\v" }; + + std::string res = text; + for (const char* const* it = cmArrayBegin(rep); it != cmArrayEnd(rep); + it += 2) { + cmSystemTools::ReplaceString(res, *it, *(it + 1)); + } + res = '"' + res; + res += '"'; + return res; +} + +bool cmQtAutoGeneratorCommon::RccListInputs(const std::string& qtMajorVersion, + const std::string& rccCommand, + const std::string& fileName, + std::vector<std::string>& files, + std::string* errorMessage) +{ + bool allGood = false; + if (cmsys::SystemTools::FileExists(fileName.c_str())) { + if (qtMajorVersion == "4") { + allGood = RccListInputsQt4(fileName, files, errorMessage); + } else { + allGood = RccListInputsQt5(rccCommand, fileName, files, errorMessage); + } + } else { + if (errorMessage != CM_NULLPTR) { + std::ostringstream ost; + ost << "AutoRcc: Error: Rcc file does not exist:\n" + << cmQtAutoGeneratorCommon::Quoted(fileName) << "\n"; + *errorMessage = ost.str(); + } + } + return allGood; +} diff --git a/Source/cmQtAutoGeneratorCommon.h b/Source/cmQtAutoGeneratorCommon.h new file mode 100644 index 0000000..ee97b71 --- /dev/null +++ b/Source/cmQtAutoGeneratorCommon.h @@ -0,0 +1,34 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmQtAutoGeneratorCommon_h +#define cmQtAutoGeneratorCommon_h + +#include <cmConfigure.h> // IWYU pragma: keep +#include <string> +#include <vector> + +class cmGeneratorTarget; +class cmLocalGenerator; + +class cmQtAutoGeneratorCommon +{ + // - Types and statics +public: + static const char* listSep; + +public: + /// @brief Returns a the string escaped and enclosed in quotes + /// + static std::string Quoted(const std::string& text); + + /// @brief Reads the resource files list from from a .qrc file + /// @arg fileName Must be the absolute path of the .qrc file + /// @return True if the rcc file was successfully parsed + static bool RccListInputs(const std::string& qtMajorVersion, + const std::string& rccCommand, + const std::string& fileName, + std::vector<std::string>& files, + std::string* errorMessage = CM_NULLPTR); +}; + +#endif diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index a45b3d5..94cc981 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -1,6 +1,7 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoGeneratorInitializer.h" +#include "cmQtAutoGeneratorCommon.h" #include "cmAlgorithms.h" #include "cmCustomCommandLines.h" @@ -44,14 +45,9 @@ static void utilCopyTargetProperty(cmTarget* destinationTarget, } } -static std::string utilStripCR(std::string const& line) +inline static bool PropertyEnabled(cmSourceFile* sourceFile, const char* key) { - // Strip CR characters rcc may have printed (possibly more than one!). - std::string::size_type cr = line.find('\r'); - if (cr != line.npos) { - return line.substr(0, cr); - } - return line; + return cmSystemTools::IsOn(sourceFile->GetPropertyForUser(key)); } static std::string GetSafeProperty(cmGeneratorTarget const* target, @@ -138,21 +134,17 @@ static void AddDefinitionEscaped(cmMakefile* makefile, const char* key, key, cmOutputConverter::EscapeForCMake(cmJoin(values, ";")).c_str()); } -static void SetupSourceFiles(cmGeneratorTarget const* target, +static void AcquireScanFiles(cmGeneratorTarget const* target, std::vector<std::string>& mocUicSources, std::vector<std::string>& mocUicHeaders, std::vector<std::string>& mocSkipList, std::vector<std::string>& uicSkipList) { - cmMakefile* makefile = target->Target->GetMakefile(); - - std::vector<cmSourceFile*> srcFiles; - target->GetConfigCommonSourceFiles(srcFiles); - const bool mocTarget = target->GetPropertyAsBool("AUTOMOC"); const bool uicTarget = target->GetPropertyAsBool("AUTOUIC"); - cmFilePathChecksum fpathCheckSum(makefile); + std::vector<cmSourceFile*> srcFiles; + target->GetConfigCommonSourceFiles(srcFiles); for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; @@ -163,18 +155,12 @@ static void SetupSourceFiles(cmGeneratorTarget const* target, !(fileType == cmSystemTools::HEADER_FILE_FORMAT)) { continue; } - if (cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { - continue; - } const std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); // Skip flags - const bool skipAll = - cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOGEN")); - const bool mocSkip = - skipAll || cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC")); - const bool uicSkip = - skipAll || cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOUIC")); + const bool skipAll = PropertyEnabled(sf, "SKIP_AUTOGEN"); + const bool mocSkip = skipAll || PropertyEnabled(sf, "SKIP_AUTOMOC"); + const bool uicSkip = skipAll || PropertyEnabled(sf, "SKIP_AUTOUIC"); // Add file name to skip lists. // Do this even when the file is not added to the sources/headers lists // because the file name may be extracted from an other file when @@ -361,7 +347,8 @@ static void UicSetupAutoTarget( uiFileFiles.push_back(absFile); { std::string opts = sf->GetProperty("AUTOUIC_OPTIONS"); - cmSystemTools::ReplaceString(opts, ";", "@list_sep@"); + cmSystemTools::ReplaceString(opts, ";", + cmQtAutoGeneratorCommon::listSep); uiFileOptions.push_back(opts); } } @@ -469,146 +456,12 @@ static void RccMergeOptions(std::vector<std::string>& opts, opts.insert(opts.end(), extraOpts.begin(), extraOpts.end()); } -/// @brief Reads the resource files list from from a .qrc file - Qt5 version -/// @return True if the .qrc file was successfully parsed -static bool RccListInputsQt5(cmSourceFile* sf, cmGeneratorTarget const* target, - std::vector<std::string>& depends) -{ - const std::string rccCommand = RccGetExecutable(target, "5"); - if (rccCommand.empty()) { - cmSystemTools::Error("AUTOGEN: error: rcc executable not available\n"); - return false; - } - - bool hasDashDashList = false; - // Read rcc features - { - std::vector<std::string> command; - command.push_back(rccCommand); - command.push_back("--help"); - std::string rccStdOut; - std::string rccStdErr; - int retVal = 0; - bool result = - cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal, - CM_NULLPTR, cmSystemTools::OUTPUT_NONE); - if (result && retVal == 0 && - rccStdOut.find("--list") != std::string::npos) { - hasDashDashList = true; - } - } - // Run rcc list command - std::vector<std::string> command; - command.push_back(rccCommand); - command.push_back(hasDashDashList ? "--list" : "-list"); - - std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); - command.push_back(absFile); - - std::string rccStdOut; - std::string rccStdErr; - int retVal = 0; - bool result = - cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal, - CM_NULLPTR, cmSystemTools::OUTPUT_NONE); - if (!result || retVal) { - std::ostringstream err; - err << "AUTOGEN: error: Rcc list process for " << sf->GetFullPath() - << " failed:\n" - << rccStdOut << "\n" - << rccStdErr << std::endl; - cmSystemTools::Error(err.str().c_str()); - return false; - } - - // Parse rcc list output - { - std::istringstream ostr(rccStdOut); - std::string oline; - while (std::getline(ostr, oline)) { - oline = utilStripCR(oline); - if (!oline.empty()) { - depends.push_back(oline); - } - } - } - - { - std::istringstream estr(rccStdErr); - std::string eline; - while (std::getline(estr, eline)) { - eline = utilStripCR(eline); - if (cmHasLiteralPrefix(eline, "RCC: Error in")) { - static std::string searchString = "Cannot find file '"; - - std::string::size_type pos = eline.find(searchString); - if (pos == std::string::npos) { - std::ostringstream err; - err << "AUTOGEN: error: Rcc lists unparsable output " << eline - << std::endl; - cmSystemTools::Error(err.str().c_str()); - return false; - } - pos += searchString.length(); - std::string::size_type sz = eline.size() - pos - 1; - depends.push_back(eline.substr(pos, sz)); - } - } - } - - return true; -} - -/// @brief Reads the resource files list from from a .qrc file - Qt4 version -/// @return True if the .qrc file was successfully parsed -static bool RccListInputsQt4(cmSourceFile* sf, - std::vector<std::string>& depends) -{ - // Read file into string - std::string qrcContents; - { - std::ostringstream stream; - stream << cmsys::ifstream(sf->GetFullPath().c_str()).rdbuf(); - qrcContents = stream.str(); - } - - cmsys::RegularExpression fileMatchRegex("(<file[^<]+)"); - cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)"); - - size_t offset = 0; - while (fileMatchRegex.find(qrcContents.c_str() + offset)) { - std::string qrcEntry = fileMatchRegex.match(1); - offset += qrcEntry.size(); - { - 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; - } - depends.push_back(qrcEntry); - } - return true; -} - -/// @brief Reads the resource files list from from a .qrc file -/// @return True if the rcc file was successfully parsed -static bool RccListInputs(const std::string& qtMajorVersion, cmSourceFile* sf, - cmGeneratorTarget const* target, - std::vector<std::string>& depends) -{ - if (qtMajorVersion == "5") { - return RccListInputsQt5(sf, target, depends); - } - return RccListInputsQt4(sf, depends); -} - static void RccSetupAutoTarget(cmGeneratorTarget const* target, const std::string& qtMajorVersion) { cmMakefile* makefile = target->Target->GetMakefile(); const bool qtMajorVersion5 = (qtMajorVersion == "5"); + const std::string rccCommand = RccGetExecutable(target, qtMajorVersion); std::vector<std::string> _rcc_files; std::vector<std::string> _rcc_inputs; std::vector<std::string> rccFileFiles; @@ -623,53 +476,54 @@ static void RccSetupAutoTarget(cmGeneratorTarget const* target, for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; - if (sf->GetExtension() == "qrc") { - const bool skip = - cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOGEN")) || - cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC")); - if (!skip) { - const std::string absFile = - cmsys::SystemTools::GetRealPath(sf->GetFullPath()); - // qrc file - _rcc_files.push_back(absFile); - // qrc file entries - { - std::string entriesList; - if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { - std::vector<std::string> depends; - if (RccListInputs(qtMajorVersion, sf, target, depends)) { - entriesList = cmJoin(depends, "@list_sep@"); - } else { - return; - } + if ((sf->GetExtension() == "qrc") && + !PropertyEnabled(sf, "SKIP_AUTOGEN") && + !PropertyEnabled(sf, "SKIP_AUTORCC")) { + const std::string absFile = + cmsys::SystemTools::GetRealPath(sf->GetFullPath()); + // qrc file + _rcc_files.push_back(absFile); + // qrc file entries + { + std::string entriesList = "{"; + // Read input file list only for non generated .qrc files. + if (!PropertyEnabled(sf, "GENERATED")) { + std::string error; + std::vector<std::string> files; + if (cmQtAutoGeneratorCommon::RccListInputs( + qtMajorVersion, rccCommand, absFile, files, &error)) { + entriesList += cmJoin(files, cmQtAutoGeneratorCommon::listSep); + } else { + cmSystemTools::Error(error.c_str()); } - _rcc_inputs.push_back(entriesList); } - // rcc options for this qrc file - { - // Merged target and file options - std::vector<std::string> rccOptions(rccOptionsTarget); - if (const char* prop = sf->GetProperty("AUTORCC_OPTIONS")) { - std::vector<std::string> optsVec; - cmSystemTools::ExpandListArgument(prop, optsVec); - RccMergeOptions(rccOptions, optsVec, qtMajorVersion5); - } - // Only store non empty options lists - if (!rccOptions.empty()) { - rccFileFiles.push_back(absFile); - rccFileOptions.push_back(cmJoin(rccOptions, "@list_sep@")); - } + entriesList += "}"; + _rcc_inputs.push_back(entriesList); + } + // rcc options for this qrc file + { + // Merged target and file options + std::vector<std::string> rccOptions(rccOptionsTarget); + if (const char* prop = sf->GetProperty("AUTORCC_OPTIONS")) { + std::vector<std::string> optsVec; + cmSystemTools::ExpandListArgument(prop, optsVec); + RccMergeOptions(rccOptions, optsVec, qtMajorVersion5); + } + // Only store non empty options lists + if (!rccOptions.empty()) { + rccFileFiles.push_back(absFile); + rccFileOptions.push_back( + cmJoin(rccOptions, cmQtAutoGeneratorCommon::listSep)); } } } } + AddDefinitionEscaped(makefile, "_qt_rcc_executable", rccCommand); AddDefinitionEscaped(makefile, "_rcc_files", _rcc_files); AddDefinitionEscaped(makefile, "_rcc_inputs", _rcc_inputs); AddDefinitionEscaped(makefile, "_rcc_options_files", rccFileFiles); AddDefinitionEscaped(makefile, "_rcc_options_options", rccFileOptions); - AddDefinitionEscaped(makefile, "_qt_rcc_executable", - RccGetExecutable(target, qtMajorVersion)); } void cmQtAutoGeneratorInitializer::InitializeAutogenSources( @@ -691,12 +545,17 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( cmMakefile* makefile = target->Target->GetMakefile(); // Create a custom target for running generators at buildtime + const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC"); + const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC"); + const bool rccEnabled = target->GetPropertyAsBool("AUTORCC"); const std::string autogenTargetName = GetAutogenTargetName(target); const std::string autogenBuildDir = GetAutogenTargetBuildDir(target); const std::string workingDirectory = cmSystemTools::CollapseFullPath("", makefile->GetCurrentBinaryDirectory()); const std::string qtMajorVersion = GetQtMajorVersion(target); - std::vector<std::string> autogenOutputFiles; + const std::string rccCommand = RccGetExecutable(target, qtMajorVersion); + std::vector<std::string> autogenDepends; + std::vector<std::string> autogenProvides; // Remove old settings on cleanup { @@ -706,32 +565,6 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( false); } - // Create autogen target build directory and add it to the clean files - cmSystemTools::MakeDirectory(autogenBuildDir); - makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", - autogenBuildDir.c_str(), false); - - if (target->GetPropertyAsBool("AUTOMOC") || - target->GetPropertyAsBool("AUTOUIC")) { - // Create autogen target includes directory and - // add it to the origin target INCLUDE_DIRECTORIES - const std::string incsDir = autogenBuildDir + "include"; - cmSystemTools::MakeDirectory(incsDir); - target->AddIncludeDirectory(incsDir, true); - } - - if (target->GetPropertyAsBool("AUTOMOC")) { - // Register moc compilation file as generated - autogenOutputFiles.push_back(autogenBuildDir + "moc_compilation.cpp"); - } - - // Initialize autogen target dependencies - std::vector<std::string> depends; - if (const char* autogenDepends = - target->GetProperty("AUTOGEN_TARGET_DEPENDS")) { - cmSystemTools::ExpandListArgument(autogenDepends, depends); - } - // Compose command lines cmCustomCommandLines commandLines; { @@ -748,13 +581,13 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( std::string autogenComment; { std::vector<std::string> toolNames; - if (target->GetPropertyAsBool("AUTOMOC")) { + if (mocEnabled) { toolNames.push_back("MOC"); } - if (target->GetPropertyAsBool("AUTOUIC")) { + if (uicEnabled) { toolNames.push_back("UIC"); } - if (target->GetPropertyAsBool("AUTORCC")) { + if (rccEnabled) { toolNames.push_back("RCC"); } @@ -770,6 +603,24 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( autogenComment = "Automatic " + tools + " for target " + target->GetName(); } + // Create autogen target build directory and add it to the clean files + cmSystemTools::MakeDirectory(autogenBuildDir); + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", + autogenBuildDir.c_str(), false); + + // Create autogen target includes directory and + // add it to the origin target INCLUDE_DIRECTORIES + if (mocEnabled || uicEnabled) { + const std::string incsDir = autogenBuildDir + "include"; + cmSystemTools::MakeDirectory(incsDir); + target->AddIncludeDirectory(incsDir, true); + } + + // Register moc compilation file as generated + if (mocEnabled) { + autogenProvides.push_back(autogenBuildDir + "moc_compilation.cpp"); + } + #if defined(_WIN32) && !defined(__CYGWIN__) bool usePRE_BUILD = false; cmGlobalGenerator* gg = lg->GetGlobalGenerator(); @@ -781,65 +632,100 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( // This also works around a VS 11 bug that may skip updating the target: // https://connect.microsoft.com/VisualStudio/feedback/details/769495 usePRE_BUILD = vsgg->GetVersion() >= cmGlobalVisualStudioGenerator::VS7; - if (usePRE_BUILD) { - // If the autogen target depends on an other target - // don't use PRE_BUILD - for (std::vector<std::string>::iterator it = depends.begin(); - it != depends.end(); ++it) { - if (!makefile->FindTargetToUse(it->c_str())) { - usePRE_BUILD = false; - break; - } - } - } } #endif - if (target->GetPropertyAsBool("AUTORCC")) { + // Initialize autogen target dependencies + if (const char* deps = target->GetProperty("AUTOGEN_TARGET_DEPENDS")) { + cmSystemTools::ExpandListArgument(deps, autogenDepends); + } + // Add link library targets to the autogen dependencies + { + const cmTarget::LinkLibraryVectorType& libVec = + target->Target->GetOriginalLinkLibraries(); + for (cmTarget::LinkLibraryVectorType::const_iterator it = libVec.begin(); + it != libVec.end(); ++it) { + const std::string& libName = it->first; + if (makefile->FindTargetToUse(libName) != CM_NULLPTR) { + autogenDepends.push_back(libName); + } + } + } + { cmFilePathChecksum fpathCheckSum(makefile); + // Iterate over all source files std::vector<cmSourceFile*> srcFiles; target->GetConfigCommonSourceFiles(srcFiles); for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; - if (sf->GetExtension() == "qrc" && - !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOGEN")) && - !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { - { + if (!PropertyEnabled(sf, "SKIP_AUTOGEN")) { + const std::string ext = sf->GetExtension(); + // Add generated file that will be scanned by moc or uic to + // the dependencies + if (mocEnabled || uicEnabled) { + const cmSystemTools::FileFormat fileType = + cmSystemTools::GetFileFormat(ext.c_str()); + if ((fileType == cmSystemTools::CXX_FILE_FORMAT) || + (fileType == cmSystemTools::HEADER_FILE_FORMAT)) { + if (PropertyEnabled(sf, "GENERATED")) { + if ((mocEnabled && !PropertyEnabled(sf, "SKIP_AUTOMOC")) || + (uicEnabled && !PropertyEnabled(sf, "SKIP_AUTOUIC"))) { + autogenDepends.push_back( + cmsys::SystemTools::GetRealPath(sf->GetFullPath())); +#if defined(_WIN32) && !defined(__CYGWIN__) + // Cannot use PRE_BUILD with generated files + usePRE_BUILD = false; +#endif + } + } + } + } + // Process rcc enabled files + if (rccEnabled && (ext == "qrc") && + !PropertyEnabled(sf, "SKIP_AUTORCC")) { const std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); - // Run cmake again when .qrc file changes - makefile->AddCMakeDependFile(absFile); - - std::string rccOutputFile = autogenBuildDir; - rccOutputFile += fpathCheckSum.getPart(absFile); - rccOutputFile += "/qrc_"; - rccOutputFile += - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); - rccOutputFile += ".cpp"; - - // Add rcc output file to origin target sources - cmSourceFile* gf = makefile->GetOrCreateSource(rccOutputFile, true); - gf->SetProperty("SKIP_AUTOGEN", "On"); - target->AddSource(rccOutputFile); - // Register rcc output file as generated - autogenOutputFiles.push_back(rccOutputFile); - } - if (lg->GetGlobalGenerator()->GetName() == "Ninja" -#if defined(_WIN32) && !defined(__CYGWIN__) - || usePRE_BUILD -#endif - ) { - if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { - RccListInputs(qtMajorVersion, sf, target, depends); + // Compose rcc output file name + { + std::string rccOut = autogenBuildDir; + rccOut += fpathCheckSum.getPart(absFile); + rccOut += "/qrc_"; + rccOut += + cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); + rccOut += ".cpp"; + + // Register rcc output file as generated + autogenProvides.push_back(rccOut); + + // Add rcc output file to origin target sources + cmSourceFile* gf = makefile->GetOrCreateSource(rccOut, true); + gf->SetProperty("SKIP_AUTOGEN", "On"); + target->AddSource(rccOut); + } + + if (PropertyEnabled(sf, "GENERATED")) { + // Add generated qrc file to the dependencies + autogenDepends.push_back(absFile); + } else { + // Run cmake again when .qrc file changes + makefile->AddCMakeDependFile(absFile); + + // Add the qrc input files to the dependencies + std::string error; + if (!cmQtAutoGeneratorCommon::RccListInputs( + qtMajorVersion, rccCommand, absFile, autogenDepends, + &error)) { + cmSystemTools::Error(error.c_str()); + } + } #if defined(_WIN32) && !defined(__CYGWIN__) - // Cannot use PRE_BUILD because the resource files themselves - // may not be sources within the target so VS may not know the - // target needs to re-build at all. - usePRE_BUILD = false; + // Cannot use PRE_BUILD because the resource files themselves + // may not be sources within the target so VS may not know the + // target needs to re-build at all. + usePRE_BUILD = false; #endif - } } } } @@ -847,12 +733,21 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( #if defined(_WIN32) && !defined(__CYGWIN__) if (usePRE_BUILD) { + // If the autogen target depends on an other target don't use PRE_BUILD + for (std::vector<std::string>::iterator it = autogenDepends.begin(); + it != autogenDepends.end(); ++it) { + if (makefile->FindTargetToUse(*it) != CM_NULLPTR) { + usePRE_BUILD = false; + break; + } + } + } + if (usePRE_BUILD) { // Add the pre-build command directly to bypass the OBJECT_LIBRARY // rejection in cmMakefile::AddCustomCommandToTarget because we know // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case. std::vector<std::string> no_output; - std::vector<std::string> no_byproducts; - cmCustomCommand cc(makefile, no_output, no_byproducts, depends, + cmCustomCommand cc(makefile, no_output, autogenProvides, autogenDepends, commandLines, autogenComment.c_str(), workingDirectory.c_str()); cc.SetEscapeOldStyle(false); @@ -863,7 +758,7 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( { cmTarget* autogenTarget = makefile->AddUtilityCommand( autogenTargetName, true, workingDirectory.c_str(), - /*byproducts=*/autogenOutputFiles, depends, commandLines, false, + /*byproducts=*/autogenProvides, autogenDepends, commandLines, false, autogenComment.c_str()); cmGeneratorTarget* gt = new cmGeneratorTarget(autogenTarget, lg); @@ -900,38 +795,37 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( std::map<std::string, std::string> configMocDefines; std::map<std::string, std::string> configUicOptions; { - // create a custom target for running generators at buildtime: + const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC"); + const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC"); + const bool rccEnabled = target->GetPropertyAsBool("AUTORCC"); const std::string autogenTargetName = GetAutogenTargetName(target); const std::string qtMajorVersion = GetQtMajorVersion(target); - AddDefinitionEscaped(makefile, "_autogen_target_name", autogenTargetName); - AddDefinitionEscaped(makefile, "_origin_target_name", target->GetName()); - AddDefinitionEscaped(makefile, "_qt_version_major", qtMajorVersion); - std::vector<std::string> _sources; std::vector<std::string> _headers; - std::vector<std::string> mocSkipList; - std::vector<std::string> uicSkipList; - if (target->GetPropertyAsBool("AUTOMOC") || - target->GetPropertyAsBool("AUTOUIC") || - target->GetPropertyAsBool("AUTORCC")) { - SetupSourceFiles(target, _sources, _headers, mocSkipList, uicSkipList); + if (mocEnabled || uicEnabled || rccEnabled) { + std::vector<std::string> mocSkipList; + std::vector<std::string> uicSkipList; + AcquireScanFiles(target, _sources, _headers, mocSkipList, uicSkipList); + if (mocEnabled) { + MocSetupAutoTarget(target, autogenTargetName, qtMajorVersion, + mocSkipList, configMocIncludes, configMocDefines); + } + if (uicEnabled) { + UicSetupAutoTarget(target, qtMajorVersion, uicSkipList, + configUicOptions); + } + if (rccEnabled) { + RccSetupAutoTarget(target, qtMajorVersion); + } } + + AddDefinitionEscaped(makefile, "_autogen_target_name", autogenTargetName); + AddDefinitionEscaped(makefile, "_origin_target_name", target->GetName()); + AddDefinitionEscaped(makefile, "_qt_version_major", qtMajorVersion); AddDefinitionEscaped(makefile, "_sources", _sources); AddDefinitionEscaped(makefile, "_headers", _headers); - - if (target->GetPropertyAsBool("AUTOMOC")) { - MocSetupAutoTarget(target, autogenTargetName, qtMajorVersion, - mocSkipList, configMocIncludes, configMocDefines); - } - if (target->GetPropertyAsBool("AUTOUIC")) { - UicSetupAutoTarget(target, qtMajorVersion, uicSkipList, - configUicOptions); - } - if (target->GetPropertyAsBool("AUTORCC")) { - RccSetupAutoTarget(target, qtMajorVersion); - } } // Generate config file diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index c83f9a9..246dd8d 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -1,6 +1,7 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoGenerators.h" +#include "cmQtAutoGeneratorCommon.h" #include <algorithm> #include <assert.h> @@ -36,23 +37,9 @@ static const char* SettingsKeyRcc = "AM_RCC_OLD_SETTINGS"; // -- Static functions -/** - * @brief Returns a the string escaped and enclosed in quotes - */ -static std::string Quoted(const std::string& text) +inline static std::string Quoted(const std::string& text) { - static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a", - "\b", "\\b", "\f", "\\f", "\n", "\\n", - "\r", "\\r", "\t", "\\t", "\v", "\\v" }; - - std::string res = text; - for (const char* const* it = cmArrayBegin(rep); it != cmArrayEnd(rep); - it += 2) { - cmSystemTools::ReplaceString(res, *it, *(it + 1)); - } - res = '"' + res; - res += '"'; - return res; + return cmQtAutoGeneratorCommon::Quoted(text); } static void InfoGet(cmMakefile* makefile, const char* key, std::string& value) @@ -138,13 +125,19 @@ static bool FileNameIsUnique(const std::string& filePath, return true; } -static std::string ReadAll(const std::string& filename) +static bool ReadAll(std::string& content, const std::string& filename) { - cmsys::ifstream file(filename.c_str()); - std::ostringstream stream; - stream << file.rdbuf(); - file.close(); - return stream.str(); + bool success = false; + { + cmsys::ifstream ifs(filename.c_str()); + if (ifs) { + std::ostringstream osst; + osst << ifs.rdbuf(); + content = osst.str(); + success = true; + } + } + return success; } /** @@ -178,7 +171,7 @@ static std::string JoinOptionsMap( for (std::map<std::string, std::string>::const_iterator it = opts.begin(); it != opts.end(); ++it) { if (it != opts.begin()) { - result += "@list_sep@"; + result += cmQtAutoGeneratorCommon::listSep; } result += it->first; result += "==="; @@ -402,7 +395,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( } else { this->LogError( "AutoMoc: Error: AUTOMOC_DEPEND_FILTERS list size is not " - "a multiple of 2"); + "a multiple of 2 in:\n" + + Quoted(filename)); return false; } } @@ -424,13 +418,14 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( fileIt = uicFilesVec.begin(), optionIt = uicOptionsVec.begin(); fileIt != uicFilesVec.end(); ++fileIt, ++optionIt) { - cmSystemTools::ReplaceString(*optionIt, "@list_sep@", ";"); + cmSystemTools::ReplaceString(*optionIt, + cmQtAutoGeneratorCommon::listSep, ";"); this->UicOptions[*fileIt] = *optionIt; } } else { this->LogError( - "AutoGen: Error: Uic files/options lists size missmatch in: " + - filename); + "AutoGen: Error: Uic files/options lists size missmatch in:\n" + + Quoted(filename)); return false; } } @@ -439,47 +434,53 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( // - Rcc if (this->RccEnabled()) { InfoGet(makefile, "AM_RCC_SOURCES", this->RccSources); + // File options { std::vector<std::string> rccFilesVec; std::vector<std::string> rccOptionsVec; InfoGet(makefile, "AM_RCC_OPTIONS_FILES", rccFilesVec); InfoGet(makefile, "AM_RCC_OPTIONS_OPTIONS", rccOptionsVec); - if (rccFilesVec.size() != rccOptionsVec.size()) { + if (rccFilesVec.size() == rccOptionsVec.size()) { + for (std::vector<std::string>::iterator + fileIt = rccFilesVec.begin(), + optionIt = rccOptionsVec.begin(); + fileIt != rccFilesVec.end(); ++fileIt, ++optionIt) { + // Replace item separator + cmSystemTools::ReplaceString(*optionIt, + cmQtAutoGeneratorCommon::listSep, ";"); + this->RccOptions[*fileIt] = *optionIt; + } + } else { this->LogError( - "AutoGen: Error: RCC files/options lists size missmatch in: " + - filename); + "AutoGen: Error: RCC files/options lists size missmatch in:\n" + + Quoted(filename)); return false; } - for (std::vector<std::string>::iterator fileIt = rccFilesVec.begin(), - optionIt = rccOptionsVec.begin(); - fileIt != rccFilesVec.end(); ++fileIt, ++optionIt) { - cmSystemTools::ReplaceString(*optionIt, "@list_sep@", ";"); - this->RccOptions[*fileIt] = *optionIt; - } } + // File lists { std::vector<std::string> rccInputLists; InfoGet(makefile, "AM_RCC_INPUTS", rccInputLists); - - // qrc files in the end of the list may have been empty - if (rccInputLists.size() < this->RccSources.size()) { - rccInputLists.resize(this->RccSources.size()); - } - if (this->RccSources.size() != rccInputLists.size()) { + if (this->RccSources.size() == rccInputLists.size()) { + for (std::vector<std::string>::iterator + fileIt = this->RccSources.begin(), + inputIt = rccInputLists.begin(); + fileIt != this->RccSources.end(); ++fileIt, ++inputIt) { + // Remove braces + *inputIt = inputIt->substr(1, inputIt->size() - 2); + // Replace item separator + cmSystemTools::ReplaceString(*inputIt, + cmQtAutoGeneratorCommon::listSep, ";"); + std::vector<std::string> rccInputFiles; + cmSystemTools::ExpandListArgument(*inputIt, rccInputFiles); + this->RccInputs[*fileIt] = rccInputFiles; + } + } else { this->LogError( - "AutoGen: Error: RCC sources/inputs lists size missmatch in: " + - filename); + "AutoGen: Error: RCC sources/inputs lists size missmatch in:\n" + + Quoted(filename)); 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; - } } } @@ -687,8 +688,10 @@ bool cmQtAutoGenerators::RunAutogen() uicHeaderFiles.insert(headerName); } } - this->ParseHeaders(mocHeaderFiles, uicHeaderFiles, mocsIncluded, - mocsNotIncluded, mocDepends, uisIncluded); + if (!this->ParseHeaders(mocHeaderFiles, uicHeaderFiles, mocsIncluded, + mocsNotIncluded, mocDepends, uisIncluded)) { + return false; + }; // Generate files if (!this->MocGenerateAll(mocsIncluded, mocsNotIncluded, mocDepends)) { @@ -804,23 +807,29 @@ bool cmQtAutoGenerators::ParseSourceFile( std::map<std::string, std::set<std::string> >& mocDepends, std::map<std::string, std::vector<std::string> >& uisIncluded, bool relaxed) { - bool success = true; - const std::string contentText = ReadAll(absFilename); - if (contentText.empty()) { - std::ostringstream ost; - ost << "AutoGen: Warning: " << absFilename << "\n" - << "The file is empty\n"; - this->LogWarning(ost.str()); - } else { - // Parse source contents for MOC - if (success && !this->MocSkip(absFilename)) { - success = this->MocParseSourceContent(absFilename, contentText, - mocsIncluded, mocDepends, relaxed); - } - // Parse source contents for UIC - if (success && !this->UicSkip(absFilename)) { - this->UicParseContent(absFilename, contentText, uisIncluded); + std::string contentText; + bool success = ReadAll(contentText, absFilename); + if (success) { + if (!contentText.empty()) { + // Parse source contents for MOC + if (success && !this->MocSkip(absFilename)) { + success = this->MocParseSourceContent( + absFilename, contentText, mocsIncluded, mocDepends, relaxed); + } + // Parse source contents for UIC + if (success && !this->UicSkip(absFilename)) { + this->UicParseContent(absFilename, contentText, uisIncluded); + } + } else { + std::ostringstream ost; + ost << "AutoGen: Warning: The file is empty:\n" + << Quoted(absFilename) << "\n"; + this->LogWarning(ost.str()); } + } else { + std::ostringstream ost; + ost << "AutoGen: Error: Could not read file:\n" << Quoted(absFilename); + this->LogError(ost.str()); } return success; } @@ -1083,7 +1092,7 @@ void cmQtAutoGenerators::SearchHeadersForSourceFile( } } -void cmQtAutoGenerators::ParseHeaders( +bool cmQtAutoGenerators::ParseHeaders( const std::set<std::string>& mocHeaderFiles, const std::set<std::string>& uicHeaderFiles, const std::map<std::string, std::string>& mocsIncluded, @@ -1091,6 +1100,7 @@ void cmQtAutoGenerators::ParseHeaders( std::map<std::string, std::set<std::string> >& mocDepends, std::map<std::string, std::vector<std::string> >& uisIncluded) { + bool success = true; // Merged header files list to read files only once std::set<std::string> headerFiles; headerFiles.insert(mocHeaderFiles.begin(), mocHeaderFiles.end()); @@ -1099,20 +1109,28 @@ void cmQtAutoGenerators::ParseHeaders( for (std::set<std::string>::const_iterator hIt = headerFiles.begin(); hIt != headerFiles.end(); ++hIt) { const std::string& headerName = *hIt; - const std::string contentText = ReadAll(headerName); - - // Parse header content for MOC - if ((mocHeaderFiles.find(headerName) != mocHeaderFiles.end()) && - (mocsIncluded.find(headerName) == mocsIncluded.end())) { - this->MocParseHeaderContent(headerName, contentText, mocsNotIncluded, - mocDepends); - } - - // Parse header content for UIC - if (uicHeaderFiles.find(headerName) != uicHeaderFiles.end()) { - this->UicParseContent(headerName, contentText, uisIncluded); + std::string contentText; + if (ReadAll(contentText, headerName)) { + // Parse header content for MOC + if ((mocHeaderFiles.find(headerName) != mocHeaderFiles.end()) && + (mocsIncluded.find(headerName) == mocsIncluded.end())) { + this->MocParseHeaderContent(headerName, contentText, mocsNotIncluded, + mocDepends); + } + // Parse header content for UIC + if (uicHeaderFiles.find(headerName) != uicHeaderFiles.end()) { + this->UicParseContent(headerName, contentText, uisIncluded); + } + } else { + std::ostringstream ost; + ost << "AutoGen: Error: Could not read header file:\n" + << Quoted(headerName); + this->LogError(ost.str()); + success = false; + break; } } + return success; } bool cmQtAutoGenerators::MocGenerateAll( @@ -1195,8 +1213,12 @@ bool cmQtAutoGenerators::MocGenerateAll( // Check if the content of moc_compilation.cpp changed { - const std::string oldContents = ReadAll(this->MocCppFilenameAbs); - mocCompChanged = (oldContents != automocSource); + std::string oldContents; + if (ReadAll(oldContents, this->MocCppFilenameAbs)) { + mocCompChanged = (oldContents != automocSource); + } else { + mocCompChanged = true; + } } bool success = true; @@ -1290,18 +1312,12 @@ bool cmQtAutoGenerators::MocGenerateFile( cmd.push_back(mocFileAbs); cmd.push_back(sourceFile); - // Log moc command - if (this->Verbose) { - this->LogCommand(cmd); - } - // Execute moc command - bool res = false; - int retVal = 0; std::string output; - res = cmSystemTools::RunSingleCommand(cmd, &output, &output, &retVal); - - if (!res || (retVal != 0)) { + if (this->RunCommand(cmd, output)) { + // Success + mocGenerated = true; + } else { // Command failed { std::ostringstream ost; @@ -1313,9 +1329,6 @@ bool cmQtAutoGenerators::MocGenerateFile( } cmSystemTools::RemoveFile(mocFileAbs); this->RunMocFailed = true; - } else { - // Success - mocGenerated = true; } } else { // Parent directory creation failed @@ -1470,18 +1483,11 @@ bool cmQtAutoGenerators::UicGenerateFile(const std::string& realName, cmd.push_back(uicFileAbs); cmd.push_back(uiInputFile); - // Log command - if (this->Verbose) { - this->LogCommand(cmd); - } - - // Execute command - bool res = false; - int retVal = 0; std::string output; - res = cmSystemTools::RunSingleCommand(cmd, &output, &output, &retVal); - - if (!res || (retVal != 0)) { + if (this->RunCommand(cmd, output)) { + // Success + uicGenerated = true; + } else { // Command failed { std::ostringstream ost; @@ -1494,9 +1500,6 @@ bool cmQtAutoGenerators::UicGenerateFile(const std::string& realName, } cmSystemTools::RemoveFile(uicFileAbs); this->RunUicFailed = true; - } else { - // Success - uicGenerated = true; } } else { // Parent directory creation failed @@ -1566,13 +1569,30 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile, // Test if the resources list file is newer than build file generateRcc = FileAbsentOrOlder(rccBuildFile, rccInputFile); if (!generateRcc) { - // Test if any resource file is newer than the build file - const std::vector<std::string>& files = this->RccInputs[rccInputFile]; - for (std::vector<std::string>::const_iterator it = files.begin(); - it != files.end(); ++it) { - if (FileAbsentOrOlder(rccBuildFile, *it)) { - generateRcc = true; - break; + // Acquire input file list + std::vector<std::string> readFiles; + const std::vector<std::string>* files = &this->RccInputs[rccInputFile]; + if (files->empty()) { + // Read input file list from qrc file + std::string error; + if (cmQtAutoGeneratorCommon::RccListInputs( + this->QtMajorVersion, this->RccExecutable, rccInputFile, + readFiles, &error)) { + files = &readFiles; + } else { + files = CM_NULLPTR; + this->LogError(error); + this->RunRccFailed = true; + } + } + // Test if any input file is newer than the build file + if (files != CM_NULLPTR) { + for (std::vector<std::string>::const_iterator it = files->begin(); + it != files->end(); ++it) { + if (FileAbsentOrOlder(rccBuildFile, *it)) { + generateRcc = true; + break; + } } } } @@ -1610,17 +1630,11 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile, cmd.push_back(rccBuildFile); cmd.push_back(rccInputFile); - // Log command - if (this->Verbose) { - this->LogCommand(cmd); - } - - // Execute command - bool res = false; - int retVal = 0; std::string output; - res = cmSystemTools::RunSingleCommand(cmd, &output, &output, &retVal); - if (!res || (retVal != 0)) { + if (this->RunCommand(cmd, output)) { + // Success + rccGenerated = true; + } else { // Command failed { std::ostringstream ost; @@ -1632,9 +1646,6 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile, } cmSystemTools::RemoveFile(rccBuildFile); this->RunRccFailed = true; - } else { - // Success - rccGenerated = true; } } else { // Parent directory creation failed @@ -1712,7 +1723,18 @@ void cmQtAutoGenerators::LogError(const std::string& message) const void cmQtAutoGenerators::LogCommand( const std::vector<std::string>& command) const { - this->LogInfo(cmJoin(command, " ")); + std::vector<std::string> cmdEscaped; + typedef std::vector<std::string>::const_iterator Iter; + for (Iter cit = command.begin(); cit != command.end(); ++cit) { + const std::string cesc = Quoted(*cit); + if ((cesc.size() > (cit->size() + 2)) || + (cesc.find(' ') != std::string::npos)) { + cmdEscaped.push_back(cesc); + } else { + cmdEscaped.push_back(*cit); + } + } + this->LogInfo(cmJoin(cmdEscaped, " ")); } /** @@ -1762,6 +1784,41 @@ std::string cmQtAutoGenerators::ChecksumedPath(const std::string& sourceFile, } /** + * @brief Generates the parent directory of the given file on demand + * @return True on success + */ +bool cmQtAutoGenerators::MakeParentDirectory(const std::string& filename) const +{ + bool success = true; + const std::string dirName = cmSystemTools::GetFilenamePath(filename); + if (!dirName.empty()) { + success = cmsys::SystemTools::MakeDirectory(dirName); + if (!success) { + this->LogError("AutoGen: Error: Directory creation failed: " + dirName); + } + } + return success; +} + +/** + * @brief Runs a command and returns true on success + * @return True on success + */ +bool cmQtAutoGenerators::RunCommand(const std::vector<std::string>& command, + std::string& output) const +{ + // Log command + if (this->Verbose) { + this->LogCommand(command); + } + // Execute command + int retVal = 0; + bool res = + cmSystemTools::RunSingleCommand(command, &output, &output, &retVal); + return (res && (retVal == 0)); +} + +/** * @brief Tries to find the header file to the given file base path by * appending different header extensions * @return True on success @@ -1835,20 +1892,3 @@ bool cmQtAutoGenerators::MocFindIncludedFile( } return success; } - -/** - * @brief Generates the parent directory of the given file on demand - * @return True on success - */ -bool cmQtAutoGenerators::MakeParentDirectory(const std::string& filename) const -{ - bool success = true; - const std::string dirName = cmSystemTools::GetFilenamePath(filename); - if (!dirName.empty()) { - success = cmsys::SystemTools::MakeDirectory(dirName); - if (!success) { - this->LogError("AutoGen: Error: Directory creation failed: " + dirName); - } - } - return success; -} diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 3bff2b2..ee046de 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -78,7 +78,7 @@ private: std::set<std::string>& mocHeaderFiles, std::set<std::string>& uicHeaderFiles) const; - void ParseHeaders( + bool ParseHeaders( const std::set<std::string>& mocHeaderFiles, const std::set<std::string>& uicHeaderFiles, const std::map<std::string, std::string>& mocsIncluded, @@ -142,6 +142,8 @@ private: const char* basePrefix, const char* baseSuffix) const; bool MakeParentDirectory(const std::string& filename) const; + bool RunCommand(const std::vector<std::string>& command, + std::string& output) const; bool FindHeader(std::string& header, const std::string& testBasePath) const; diff --git a/Tests/QtAutogen/CMakeLists.txt b/Tests/QtAutogen/CMakeLists.txt index 4960472..86af746 100644 --- a/Tests/QtAutogen/CMakeLists.txt +++ b/Tests/QtAutogen/CMakeLists.txt @@ -83,62 +83,92 @@ target_compile_features(empty PRIVATE ${QT_COMPILE_FEATURES}) # -- Test # When a file listed in a .qrc file changes the target must be rebuilt try_compile(RCC_DEPENDS - "${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends" - "${CMAKE_CURRENT_SOURCE_DIR}/autorcc_depends" - autorcc_depends + "${CMAKE_CURRENT_BINARY_DIR}/rccDepends" + "${CMAKE_CURRENT_SOURCE_DIR}/rccDepends" + rccDepends CMAKE_FLAGS "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}" "-DQT_TEST_VERSION=${QT_TEST_VERSION}" "-DCMAKE_PREFIX_PATH=${Qt_PREFIX_DIR}" OUTPUT_VARIABLE output ) if (NOT RCC_DEPENDS) - message(SEND_ERROR "Initial build of autorcc_depends failed. Output: ${output}") + message(SEND_ERROR "Initial build of rccDepends failed. Output: ${output}") endif() -file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends/info_file.txt" qrc_files) - -list(GET qrc_files 0 qrc_file1) - +# Get name and timestamp of the output binary +file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/rccDepends/target1.txt" target1List) +list(GET target1List 0 binFile) set(timeformat "%Y%j%H%M%S") +file(TIMESTAMP "${binFile}" timeBegin "${timeformat}") -file(TIMESTAMP "${qrc_file1}" file1_before "${timeformat}") - +# Touch first qrc input file and rebuild execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. -execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends/res1/input.txt") - +execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_BINARY_DIR}/rccDepends/res1/input.txt") execute_process(COMMAND "${CMAKE_COMMAND}" --build . - WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends" + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rccDepends" + RESULT_VARIABLE rccDepends_result ) +if (rccDepends_result) + message(SEND_ERROR "Second build of rccDepends failed.") +endif() +# Compare timestamps +file(TIMESTAMP "${binFile}" timeStep1 "${timeformat}") +if (NOT timeStep1 GREATER timeBegin) + message(SEND_ERROR "File (${binFile}) should have changed in the first step!") +endif() -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!") +# Touch second qrc input file and rebuild +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. +execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_BINARY_DIR}/rccDepends/res2/input.txt") +execute_process(COMMAND "${CMAKE_COMMAND}" --build . + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rccDepends" + RESULT_VARIABLE rccDepends_result +) +if (rccDepends_result) + message(SEND_ERROR "Third build of rccDepends failed.") +endif() +# Compare timestamps +file(TIMESTAMP "${binFile}" timeStep2 "${timeformat}") +if (NOT timeStep2 GREATER timeStep1) + message(SEND_ERROR "File (${binFile}) should have changed in the second step!") endif() # -- Test # Ensure a repeated build succeeds when a header containing a QObject changes try_compile(MOC_RERUN - "${CMAKE_CURRENT_BINARY_DIR}/automoc_rerun" - "${CMAKE_CURRENT_SOURCE_DIR}/automoc_rerun" - automoc_rerun + "${CMAKE_CURRENT_BINARY_DIR}/mocRerun" + "${CMAKE_CURRENT_SOURCE_DIR}/mocRerun" + mocRerun CMAKE_FLAGS "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}" "-DQT_TEST_VERSION=${QT_TEST_VERSION}" "-DCMAKE_PREFIX_PATH=${Qt_PREFIX_DIR}" OUTPUT_VARIABLE output ) if (NOT MOC_RERUN) - message(SEND_ERROR "Initial build of automoc_rerun failed. Output: ${output}") + message(SEND_ERROR "Initial build of mocRerun failed. Output: ${output}") endif() -configure_file(automoc_rerun/test1.h.in2 automoc_rerun/test1.h COPYONLY) +# Get name and timestamp of the output binary +file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/mocRerun/target1.txt" target1List) +list(GET target1List 0 binFile) +set(timeformat "%Y%j%H%M%S") +file(TIMESTAMP "${binFile}" timeBegin "${timeformat}") +# Change file content and rebuild +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) +configure_file(mocRerun/test1b.h.in mocRerun/test1.h COPYONLY) execute_process(COMMAND "${CMAKE_COMMAND}" --build . - WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/automoc_rerun" - RESULT_VARIABLE automoc_rerun_result + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/mocRerun" + RESULT_VARIABLE mocRerun_result ) -if (automoc_rerun_result) - message(SEND_ERROR "Second build of automoc_rerun failed.") +if (mocRerun_result) + message(SEND_ERROR "Second build of mocRerun failed.") +endif() + +# Compare timestamps +file(TIMESTAMP "${binFile}" timeStep1 "${timeformat}") +if (NOT timeStep1 GREATER timeBegin) + message(SEND_ERROR "File (${binFile}) should have changed in the first step!") endif() # -- Test @@ -209,6 +239,10 @@ target_link_libraries(skipRccB ${QT_LIBRARIES}) add_subdirectory(sameName) # -- Test +# Tests AUTOMOC with generated sources +add_subdirectory(mocDepends) + +# -- Test # Tests various include moc patterns add_subdirectory(mocIncludeStrict) diff --git a/Tests/QtAutogen/automoc_rerun/CMakeLists.txt b/Tests/QtAutogen/automoc_rerun/CMakeLists.txt deleted file mode 100644 index 92a682b..0000000 --- a/Tests/QtAutogen/automoc_rerun/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 3.7) -project(automoc_rerun CXX) - -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() - -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) - -configure_file(test1.h.in1 test1.h COPYONLY) - -add_executable(test1 - ${CMAKE_CURRENT_BINARY_DIR}/test1.h - test1.cpp - res1.qrc - ) -target_include_directories(test1 PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) -target_link_libraries(test1 ${QT_CORE_TARGET}) diff --git a/Tests/QtAutogen/automoc_rerun/test1.cpp b/Tests/QtAutogen/automoc_rerun/test1.cpp deleted file mode 100644 index 4316a91..0000000 --- a/Tests/QtAutogen/automoc_rerun/test1.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "test1.h" -int main() -{ - return 0; -} diff --git a/Tests/QtAutogen/automoc_rerun/test1.h.in1 b/Tests/QtAutogen/automoc_rerun/test1.h.in1 deleted file mode 100644 index fee2c09..0000000 --- a/Tests/QtAutogen/automoc_rerun/test1.h.in1 +++ /dev/null @@ -1,8 +0,0 @@ -#include <QObject> -class test1 : public QObject -{ - Q_OBJECT - public slots: - void onTst1() {} - void onTst2() {} -}; diff --git a/Tests/QtAutogen/automoc_rerun/test1.h.in2 b/Tests/QtAutogen/automoc_rerun/test1.h.in2 deleted file mode 100644 index 6531d10..0000000 --- a/Tests/QtAutogen/automoc_rerun/test1.h.in2 +++ /dev/null @@ -1,7 +0,0 @@ -#include <QObject> -class test1 : public QObject -{ - Q_OBJECT - public slots: - void onTst1() {} -}; diff --git a/Tests/QtAutogen/autorcc_depends/CMakeLists.txt b/Tests/QtAutogen/autorcc_depends/CMakeLists.txt deleted file mode 100644 index 7b51e11..0000000 --- a/Tests/QtAutogen/autorcc_depends/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 3.7) -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() - -configure_file(res1.qrc.in res1.qrc @ONLY) -configure_file(res1/input.txt.in res1/input.txt @ONLY) - -add_executable(test_res1 - test_res1.cpp - ${CMAKE_CURRENT_BINARY_DIR}/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/mocDepends/CMakeLists.txt b/Tests/QtAutogen/mocDepends/CMakeLists.txt new file mode 100644 index 0000000..8bd72eb --- /dev/null +++ b/Tests/QtAutogen/mocDepends/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.7) +project(mocDepends) + +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() + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +# -- Test 1 using generated header +# This tests the dependency of AUTOMOC of mocDepends1 to the generated object.hpp +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/object.hpp + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/invalid.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/object.hpp + COMMAND ${CMAKE_COMMAND} -E sleep 3 + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/object.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/object.hpp + ) + +add_executable(mocDepends1 test1.cpp + ${CMAKE_CURRENT_BINARY_DIR}/object.hpp +) +target_link_libraries(mocDepends1 ${QT_CORE_TARGET}) +set_target_properties(mocDepends1 PROPERTIES AUTOMOC TRUE) + +# -- Test 2 using generated library +# This tests the dependency of AUTOMOC of mocDepends2 to the +# generated simpleLib.hpp which belongs to a linked library of mocDepends2 +add_custom_command(OUTPUT simpleLib.hpp simpleLib.cpp + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/invalid.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/simpleLib.hpp + COMMAND ${CMAKE_COMMAND} -E sleep 3 + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/simpleLib.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/simpleLib.hpp + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/simpleLib.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/simpleLib.cpp + ) +add_library(SimpleLib STATIC simpleLib.hpp simpleLib.cpp) + +add_executable(mocDepends2 test2.cpp ) +target_link_libraries(mocDepends2 SimpleLib ${QT_CORE_TARGET}) +set_target_properties(mocDepends2 PROPERTIES AUTOMOC TRUE) diff --git a/Tests/QtAutogen/mocDepends/invalid.hpp.in b/Tests/QtAutogen/mocDepends/invalid.hpp.in new file mode 100644 index 0000000..854d9a1 --- /dev/null +++ b/Tests/QtAutogen/mocDepends/invalid.hpp.in @@ -0,0 +1 @@ +#ifndef diff --git a/Tests/QtAutogen/mocDepends/object.hpp.in b/Tests/QtAutogen/mocDepends/object.hpp.in new file mode 100644 index 0000000..f364f7c --- /dev/null +++ b/Tests/QtAutogen/mocDepends/object.hpp.in @@ -0,0 +1,14 @@ +#ifndef OBJECT_HPP +#define OBJECT_HPP + +#include <QObject> + +class Object : public QObject +{ + Q_OBJECT +public: + Q_SLOT + void aSlot(){}; +}; + +#endif diff --git a/Tests/QtAutogen/mocDepends/simpleLib.cpp.in b/Tests/QtAutogen/mocDepends/simpleLib.cpp.in new file mode 100644 index 0000000..fa33bd3 --- /dev/null +++ b/Tests/QtAutogen/mocDepends/simpleLib.cpp.in @@ -0,0 +1,9 @@ +#include "simpleLib.hpp" + +SimpleLib::SimpleLib() +{ +} + +SimpleLib::~SimpleLib() +{ +} diff --git a/Tests/QtAutogen/mocDepends/simpleLib.hpp.in b/Tests/QtAutogen/mocDepends/simpleLib.hpp.in new file mode 100644 index 0000000..758f1f6 --- /dev/null +++ b/Tests/QtAutogen/mocDepends/simpleLib.hpp.in @@ -0,0 +1,11 @@ +#ifndef SIMPLE_LIB_H +#define SIMPLE_LIB_H + +class SimpleLib +{ +public: + SimpleLib(); + ~SimpleLib(); +}; + +#endif diff --git a/Tests/QtAutogen/mocDepends/test1.cpp b/Tests/QtAutogen/mocDepends/test1.cpp new file mode 100644 index 0000000..92c259c --- /dev/null +++ b/Tests/QtAutogen/mocDepends/test1.cpp @@ -0,0 +1,9 @@ + +#include "object.hpp" + +int main() +{ + Object obj; + + return 0; +} diff --git a/Tests/QtAutogen/mocDepends/test2.cpp b/Tests/QtAutogen/mocDepends/test2.cpp new file mode 100644 index 0000000..155b19b --- /dev/null +++ b/Tests/QtAutogen/mocDepends/test2.cpp @@ -0,0 +1,10 @@ + +#include "test2.hpp" + +int main() +{ + SimpleLib obj; + LObject lobject; + + return 0; +} diff --git a/Tests/QtAutogen/mocDepends/test2.hpp b/Tests/QtAutogen/mocDepends/test2.hpp new file mode 100644 index 0000000..0125f07 --- /dev/null +++ b/Tests/QtAutogen/mocDepends/test2.hpp @@ -0,0 +1,16 @@ +#ifndef TEST2_HPP +#define TEST2_HPP + +#include "simpleLib.hpp" +#include <QObject> + +// This object triggers the AUTOMOC on this file +class LObject : public QObject +{ + Q_OBJECT +public: + Q_SLOT + void aSlot(){}; +}; + +#endif diff --git a/Tests/QtAutogen/mocRerun/CMakeLists.txt b/Tests/QtAutogen/mocRerun/CMakeLists.txt new file mode 100644 index 0000000..6689f50 --- /dev/null +++ b/Tests/QtAutogen/mocRerun/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.7) +project(mocRerun CXX) + +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() + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +configure_file(test1a.h.in test1.h COPYONLY) +# Generated source file +add_custom_command(OUTPUT main.cpp + COMMAND ${CMAKE_COMMAND} -E sleep 3 + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + ) + +add_executable(mocRerun + ${CMAKE_CURRENT_BINARY_DIR}/test1.h + ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + res1.qrc + ) +target_include_directories(mocRerun PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_link_libraries(mocRerun ${QT_CORE_TARGET}) +# Write target name to text file +add_custom_command(TARGET mocRerun POST_BUILD COMMAND + ${CMAKE_COMMAND} -E echo "$<TARGET_FILE:mocRerun>" > target1.txt) diff --git a/Tests/QtAutogen/automoc_rerun/input.txt b/Tests/QtAutogen/mocRerun/input.txt index da62762..da62762 100644 --- a/Tests/QtAutogen/automoc_rerun/input.txt +++ b/Tests/QtAutogen/mocRerun/input.txt diff --git a/Tests/QtAutogen/mocRerun/main.cpp.in b/Tests/QtAutogen/mocRerun/main.cpp.in new file mode 100644 index 0000000..b37ff61 --- /dev/null +++ b/Tests/QtAutogen/mocRerun/main.cpp.in @@ -0,0 +1,18 @@ +#include "test1.h" + +class Test2 : public QObject +{ + Q_OBJECT +public slots: + void onTst1() {} +}; + +int main() +{ + Test1 test1; + Test2 test2; + + return 0; +} + +#include "main.moc" diff --git a/Tests/QtAutogen/automoc_rerun/res1.qrc b/Tests/QtAutogen/mocRerun/res1.qrc index fb804b5..fb804b5 100644 --- a/Tests/QtAutogen/automoc_rerun/res1.qrc +++ b/Tests/QtAutogen/mocRerun/res1.qrc diff --git a/Tests/QtAutogen/mocRerun/test1a.h.in b/Tests/QtAutogen/mocRerun/test1a.h.in new file mode 100644 index 0000000..a335046 --- /dev/null +++ b/Tests/QtAutogen/mocRerun/test1a.h.in @@ -0,0 +1,8 @@ +#include <QObject> +class Test1 : public QObject +{ + Q_OBJECT +public slots: + void onTst1() {} + void onTst2() {} +}; diff --git a/Tests/QtAutogen/mocRerun/test1b.h.in b/Tests/QtAutogen/mocRerun/test1b.h.in new file mode 100644 index 0000000..6128eeb --- /dev/null +++ b/Tests/QtAutogen/mocRerun/test1b.h.in @@ -0,0 +1,7 @@ +#include <QObject> +class Test1 : public QObject +{ + Q_OBJECT +public slots: + void onTst1() {} +}; diff --git a/Tests/QtAutogen/rccDepends/CMakeLists.txt b/Tests/QtAutogen/rccDepends/CMakeLists.txt new file mode 100644 index 0000000..de98573 --- /dev/null +++ b/Tests/QtAutogen/rccDepends/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.7) +project(rccDepends) + +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() + +configure_file(res/input1.txt.in res1/input.txt @ONLY) +configure_file(res/input2.txt.in res2/input.txt @ONLY) +# Configure time generated qrc file +configure_file(res1.qrc.in res1.qrc @ONLY) +# Dependency generated qrc file +add_custom_command(OUTPUT res2.qrc + COMMAND ${CMAKE_COMMAND} -E sleep 3 + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/res2.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/res2.qrc + ) + + +add_executable(rccDepends + main.cpp + ${CMAKE_CURRENT_BINARY_DIR}/res1.qrc + ${CMAKE_CURRENT_BINARY_DIR}/res2.qrc +) +target_link_libraries(rccDepends ${QT_CORE_TARGET}) +add_custom_command(TARGET rccDepends POST_BUILD COMMAND + ${CMAKE_COMMAND} -E echo "$<TARGET_FILE:rccDepends>" > target1.txt) diff --git a/Tests/QtAutogen/autorcc_depends/test_res1.cpp b/Tests/QtAutogen/rccDepends/main.cpp index 766b775..766b775 100644 --- a/Tests/QtAutogen/autorcc_depends/test_res1.cpp +++ b/Tests/QtAutogen/rccDepends/main.cpp diff --git a/Tests/QtAutogen/autorcc_depends/res1/input.txt.in b/Tests/QtAutogen/rccDepends/res/input1.txt.in index da62762..da62762 100644 --- a/Tests/QtAutogen/autorcc_depends/res1/input.txt.in +++ b/Tests/QtAutogen/rccDepends/res/input1.txt.in diff --git a/Tests/QtAutogen/rccDepends/res/input2.txt.in b/Tests/QtAutogen/rccDepends/res/input2.txt.in new file mode 100644 index 0000000..08e14b7 --- /dev/null +++ b/Tests/QtAutogen/rccDepends/res/input2.txt.in @@ -0,0 +1 @@ +Res2 input. diff --git a/Tests/QtAutogen/autorcc_depends/res1.qrc.in b/Tests/QtAutogen/rccDepends/res1.qrc.in index 2a5417b..2a5417b 100644 --- a/Tests/QtAutogen/autorcc_depends/res1.qrc.in +++ b/Tests/QtAutogen/rccDepends/res1.qrc.in diff --git a/Tests/QtAutogen/rccDepends/res2.qrc.in b/Tests/QtAutogen/rccDepends/res2.qrc.in new file mode 100644 index 0000000..18b916a --- /dev/null +++ b/Tests/QtAutogen/rccDepends/res2.qrc.in @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>res2/input.txt</file> + </qresource> +</RCC> |