From 15346bec1930437cf9eb4fd32b6733790be2cc58 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Sat, 2 Sep 2017 11:07:30 +0200 Subject: Autogen: Refactor cmQtAutoGenerators The refactoring of cmQtAutoGenerators serializes the program flow and makes it less jumpy in terms of function calling. Instead of keeping and passing multiple std::vectors and std::maps in function arguments, single lists with job descriptions are used, one job list for MOC, UIC, RCC respectively. Several utility functions and methods were replaced with scoped lambdas and the remaining methods were sorted by their scope (MOC, UIC, RCC). Error and warning messages were refactored to be more verbose about the problem at hand. The source parsing algorithms were rewritten in large parts. In the process a lack of functionality of CMAKE_AUTOMOC_DEPEND_FILTERS was discovered and fixed. CMAKE_AUTOMOC_DEPEND_FILTERS did not extract dependency file names from headers that were not in the target sources but were registered to AUTOMOC by a `#include "moc_.cpp"` statement. A test for this use case is provided in a follow up commit. --- Source/cmQtAutoGenerators.cxx | 2033 +++++++++++++++++++++-------------------- Source/cmQtAutoGenerators.h | 239 +++-- 2 files changed, 1164 insertions(+), 1108 deletions(-) diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 8c03045..8453198 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -35,14 +36,23 @@ static const char* SettingsKeyRcc = "AM_RCC_SETTINGS_HASH"; // -- Static functions -static std::string QuotedCommand(const std::vector& command) +static std::string HeadLine(std::string const& title) +{ + std::string head = title; + head += '\n'; + head.append(head.size() - 1, '-'); + head += '\n'; + return head; +} + +static std::string QuotedCommand(std::vector const& command) { std::string res; for (std::string const& item : command) { if (!res.empty()) { res.push_back(' '); } - const std::string cesc = cmQtAutoGen::Quoted(item); + std::string const cesc = cmQtAutoGen::Quoted(item); if (item.empty() || (cesc.size() > (item.size() + 2)) || (cesc.find(' ') != std::string::npos)) { res += cesc; @@ -53,7 +63,7 @@ static std::string QuotedCommand(const std::vector& command) return res; } -static std::string SubDirPrefix(const std::string& fileName) +static std::string SubDirPrefix(std::string const& fileName) { std::string res(cmSystemTools::GetFilenamePath(fileName)); if (!res.empty()) { @@ -62,17 +72,29 @@ static std::string SubDirPrefix(const std::string& fileName) return res; } -static bool ReadAll(std::string& content, const std::string& filename) +static bool ReadFile(std::string& content, std::string const& filename, + std::string* error = nullptr) { bool success = false; - { - cmsys::ifstream ifs(filename.c_str()); + if (cmSystemTools::FileExists(filename)) { + std::size_t const length = cmSystemTools::FileLength(filename); + cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary)); if (ifs) { - std::ostringstream osst; - osst << ifs.rdbuf(); - content = osst.str(); - success = true; + content.resize(length); + ifs.read(&content.front(), content.size()); + if (ifs) { + success = true; + } else { + content.clear(); + if (error != nullptr) { + error->append("Reading from the file failed."); + } + } + } else if (error != nullptr) { + error->append("Opening the file for reading failed."); } + } else if (error != nullptr) { + error->append("The file does not exist."); } return success; } @@ -81,17 +103,17 @@ static bool ReadAll(std::string& content, const std::string& filename) * @brief Tests if buildFile doesn't exist or is older than sourceFile * @return True if buildFile doesn't exist or is older than sourceFile */ -static bool FileAbsentOrOlder(const std::string& buildFile, - const std::string& sourceFile) +static bool FileAbsentOrOlder(std::string const& buildFile, + std::string const& sourceFile) { int result = 0; bool success = cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result); - return (!success || (result <= 0)); + return (!success || (result < 0)); } -static bool ListContains(const std::vector& list, - const std::string& entry) +static bool ListContains(std::vector const& list, + std::string const& entry) { return (std::find(list.begin(), list.end(), entry) != list.end()); } @@ -99,24 +121,20 @@ static bool ListContains(const std::vector& list, // -- Class methods cmQtAutoGenerators::cmQtAutoGenerators() - : Verbose(cmSystemTools::HasEnv("VERBOSE")) + : IncludeProjectDirsBefore(false) + , Verbose(cmSystemTools::HasEnv("VERBOSE")) , ColorOutput(true) , MocSettingsChanged(false) , MocPredefsChanged(false) - , MocRunFailed(false) + , MocRelaxedMode(false) , UicSettingsChanged(false) - , UicRunFailed(false) , RccSettingsChanged(false) - , RccRunFailed(false) { - - std::string colorEnv; - cmSystemTools::GetEnv("COLOR", colorEnv); - if (!colorEnv.empty()) { - if (cmSystemTools::IsOn(colorEnv.c_str())) { - this->ColorOutput = true; - } else { - this->ColorOutput = false; + { + std::string colorEnv; + cmSystemTools::GetEnv("COLOR", colorEnv); + if (!colorEnv.empty()) { + this->ColorOutput = cmSystemTools::IsOn(colorEnv.c_str()); } } @@ -134,8 +152,8 @@ cmQtAutoGenerators::cmQtAutoGenerators() "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]"); } -bool cmQtAutoGenerators::Run(const std::string& targetDirectory, - const std::string& config) +bool cmQtAutoGenerators::Run(std::string const& targetDirectory, + std::string const& config) { cmake cm(cmake::RoleScript); cm.SetHomeOutputDirectory(targetDirectory); @@ -147,16 +165,14 @@ bool cmQtAutoGenerators::Run(const std::string& targetDirectory, snapshot.GetDirectory().SetCurrentBinary(targetDirectory); snapshot.GetDirectory().SetCurrentSource(targetDirectory); - std::unique_ptr makefile(new cmMakefile(&gg, snapshot)); + auto makefile = cm::make_unique(&gg, snapshot); gg.SetCurrentMakefile(makefile.get()); bool success = false; - if (this->ReadAutogenInfoFile(makefile.get(), targetDirectory, config)) { - // Read old settings + if (this->InitInfoFile(makefile.get(), targetDirectory, config)) { + // Read latest settings this->SettingsFileRead(makefile.get()); - // Init and run - this->Init(makefile.get()); - if (this->RunAutogen()) { + if (this->Process()) { // Write current settings if (this->SettingsFileWrite()) { success = true; @@ -166,46 +182,11 @@ bool cmQtAutoGenerators::Run(const std::string& targetDirectory, return success; } -bool cmQtAutoGenerators::MocDependFilterPush(const std::string& key, - const std::string& regExp) -{ - std::string error; - if (!key.empty()) { - if (!regExp.empty()) { - KeyRegExp filter; - filter.Key = key; - if (filter.RegExp.compile(regExp)) { - this->MocDependFilters.push_back(std::move(filter)); - } else { - error = "Regular expression compiling failed"; - } - } else { - error = "Regular expression is empty"; - } - } else { - error = "Key is empty"; - } - if (!error.empty()) { - std::string emsg = "AUTOMOC_DEPEND_FILTERS: "; - emsg += error; - emsg += "\n"; - emsg += " Key: "; - emsg += cmQtAutoGen::Quoted(key); - emsg += "\n"; - emsg += " RegExp: "; - emsg += cmQtAutoGen::Quoted(regExp); - emsg += "\n"; - this->LogError(cmQtAutoGen::MOC, emsg); - return false; - } - return true; -} - -bool cmQtAutoGenerators::ReadAutogenInfoFile( - cmMakefile* makefile, const std::string& targetDirectory, - const std::string& config) +bool cmQtAutoGenerators::InitInfoFile(cmMakefile* makefile, + std::string const& targetDirectory, + std::string const& config) { - // Lambdas + // Utility lambdas auto InfoGet = [makefile](const char* key) { return makefile->GetSafeDefinition(key); }; @@ -221,7 +202,7 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( [makefile](const char* key) -> std::vector> { std::vector> lists; { - const std::string value = makefile->GetSafeDefinition(key); + std::string const value = makefile->GetSafeDefinition(key); std::string::size_type pos = 0; while (pos < value.size()) { std::string::size_type next = value.find(cmQtAutoGen::listSep, pos); @@ -266,16 +247,18 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( return list; }; - std::string filename(cmSystemTools::CollapseFullPath(targetDirectory)); - cmSystemTools::ConvertToUnixSlashes(filename); - filename += "/AutogenInfo.cmake"; + this->InfoFile = cmSystemTools::CollapseFullPath(targetDirectory); + cmSystemTools::ConvertToUnixSlashes(this->InfoFile); + this->InfoFile += "/AutogenInfo.cmake"; - if (!makefile->ReadListFile(filename.c_str())) { - this->LogFileError(cmQtAutoGen::GEN, filename, "File processing failed"); + if (!makefile->ReadListFile(this->InfoFile.c_str())) { + this->LogFileError(cmQtAutoGen::GEN, this->InfoFile, + "File processing failed"); return false; } // -- Meta + this->HeaderExtensions = makefile->GetCMakeInstance()->GetHeaderExtensions(); this->ConfigSuffix = InfoGetConfig("AM_CONFIG_SUFFIX"); // - Old settings file @@ -296,12 +279,10 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE"); this->AutogenBuildDir = InfoGet("AM_BUILD_DIR"); if (this->AutogenBuildDir.empty()) { - this->LogFileError(cmQtAutoGen::GEN, filename, + this->LogFileError(cmQtAutoGen::GEN, this->InfoFile, "Autogen build directory missing"); return false; } - this->Sources = InfoGetList("AM_SOURCES"); - this->Headers = InfoGetList("AM_HEADERS"); // - Qt environment this->QtMajorVersion = InfoGet("AM_QT_VERSION_MAJOR"); @@ -312,7 +293,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( // Check Qt version if ((this->QtMajorVersion != "4") && (this->QtMajorVersion != "5")) { - this->LogFileError(cmQtAutoGen::GEN, filename, "Unsupported Qt version: " + + this->LogFileError(cmQtAutoGen::GEN, this->InfoFile, + "Unsupported Qt version: " + cmQtAutoGen::Quoted(this->QtMajorVersion)); return false; } @@ -323,7 +305,7 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( this->MocDefinitions = InfoGetConfigList("AM_MOC_DEFINITIONS"); #ifdef _WIN32 { - const std::string win32("WIN32"); + std::string const win32("WIN32"); if (!ListContains(this->MocDefinitions, win32)) { this->MocDefinitions.push_back(win32); } @@ -333,7 +315,7 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( this->MocOptions = InfoGetList("AM_MOC_OPTIONS"); this->MocRelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE"); { - const std::vector MocMacroNames = + std::vector const MocMacroNames = InfoGetList("AM_MOC_MACRO_NAMES"); for (std::string const& item : MocMacroNames) { this->MocMacroFilters.emplace_back( @@ -341,7 +323,7 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( } } { - const std::vector mocDependFilters = + std::vector const mocDependFilters = InfoGetList("AM_MOC_DEPEND_FILTERS"); // Insert Q_PLUGIN_METADATA dependency filter if (this->QtMajorVersion != "4") { @@ -361,7 +343,7 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( } } else { this->LogFileError( - cmQtAutoGen::MOC, filename, + cmQtAutoGen::MOC, this->InfoFile, "AUTOMOC_DEPEND_FILTERS list size is not a multiple of 2"); return false; } @@ -378,22 +360,21 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( auto sources = InfoGetList("AM_UIC_OPTIONS_FILES"); auto options = InfoGetLists("AM_UIC_OPTIONS_OPTIONS"); // Compare list sizes - if (sources.size() == options.size()) { - auto fitEnd = sources.cend(); - auto fit = sources.begin(); - auto oit = options.begin(); - while (fit != fitEnd) { - this->UicOptions[*fit] = std::move(*oit); - ++fit; - ++oit; - } - } else { + if (sources.size() != options.size()) { std::ostringstream ost; ost << "files/options lists sizes missmatch (" << sources.size() << "/" << options.size() << ")"; - this->LogFileError(cmQtAutoGen::UIC, filename, ost.str()); + this->LogFileError(cmQtAutoGen::UIC, this->InfoFile, ost.str()); return false; } + auto fitEnd = sources.cend(); + auto fit = sources.begin(); + auto oit = options.begin(); + while (fit != fitEnd) { + this->UicOptions[*fit] = std::move(*oit); + ++fit; + ++oit; + } } } @@ -409,24 +390,23 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( std::ostringstream ost; ost << "sources, builds lists sizes missmatch (" << sources.size() << "/" << builds.size() << ")"; - this->LogFileError(cmQtAutoGen::RCC, filename, ost.str()); + this->LogFileError(cmQtAutoGen::RCC, this->InfoFile, ost.str()); return false; } if (sources.size() != options.size()) { std::ostringstream ost; ost << "sources, options lists sizes missmatch (" << sources.size() << "/" << options.size() << ")"; - this->LogFileError(cmQtAutoGen::RCC, filename, ost.str()); + this->LogFileError(cmQtAutoGen::RCC, this->InfoFile, ost.str()); return false; } if (sources.size() != inputs.size()) { std::ostringstream ost; ost << "sources, inputs lists sizes missmatch (" << sources.size() << "/" << inputs.size() << ")"; - this->LogFileError(cmQtAutoGen::RCC, filename, ost.str()); + this->LogFileError(cmQtAutoGen::RCC, this->InfoFile, ost.str()); return false; } - { auto srcItEnd = sources.end(); auto srcIt = sources.begin(); @@ -445,6 +425,156 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( } } + // Initialize source file jobs + { + // Utility lambdas + auto AddJob = [this](std::map& jobs, + std::string&& sourceFile) { + const bool moc = !this->MocSkip(sourceFile); + const bool uic = !this->UicSkip(sourceFile); + if (moc || uic) { + SourceJob& job = jobs[std::move(sourceFile)]; + job.Moc = moc; + job.Uic = uic; + } + }; + + // Add header jobs + for (std::string& hdr : InfoGetList("AM_HEADERS")) { + AddJob(this->HeaderJobs, std::move(hdr)); + } + // Add source jobs + { + std::vector sources = InfoGetList("AM_SOURCES"); + // Add header(s) for the source file + for (std::string const& src : sources) { + const bool srcMoc = !this->MocSkip(src); + const bool srcUic = !this->UicSkip(src); + if (!srcMoc && !srcUic) { + continue; + } + // Search for the default header file and a private header + std::array headerBases; + headerBases[0] = SubDirPrefix(src); + headerBases[0] += cmSystemTools::GetFilenameWithoutLastExtension(src); + headerBases[1] = headerBases[0]; + headerBases[1] += "_p"; + for (std::string const& headerBase : headerBases) { + std::string header; + if (this->FindHeader(header, headerBase)) { + const bool moc = srcMoc && !this->MocSkip(header); + const bool uic = srcUic && !this->UicSkip(header); + if (moc || uic) { + SourceJob& job = this->HeaderJobs[std::move(header)]; + job.Moc = moc; + job.Uic = uic; + } + } + } + } + // Add Source jobs + for (std::string& src : sources) { + AddJob(this->SourceJobs, std::move(src)); + } + } + } + + // Init derived information + // ------------------------ + + // Init file path checksum generator + this->FilePathChecksum.setupParentDirs( + this->CurrentSourceDir, this->CurrentBinaryDir, this->ProjectSourceDir, + this->ProjectBinaryDir); + + // include directory + this->AutogenIncludeDir = "include"; + this->AutogenIncludeDir += this->ConfigSuffix; + this->AutogenIncludeDir += "/"; + + if (this->MocEnabled()) { + // Mocs compilation file + this->MocCompFileRel = "mocs_compilation.cpp"; + this->MocCompFileAbs = cmSystemTools::CollapseCombinedPath( + this->AutogenBuildDir, this->MocCompFileRel); + + // Moc predefs file + if (!this->MocPredefsCmd.empty()) { + this->MocPredefsFileRel = "moc_predefs"; + this->MocPredefsFileRel += this->ConfigSuffix; + this->MocPredefsFileRel += ".h"; + this->MocPredefsFileAbs = cmSystemTools::CollapseCombinedPath( + this->AutogenBuildDir, this->MocPredefsFileRel); + } + + // Sort include directories on demand + if (this->IncludeProjectDirsBefore) { + // Move strings to temporary list + std::list includes; + includes.insert(includes.end(), this->MocIncludePaths.begin(), + this->MocIncludePaths.end()); + this->MocIncludePaths.clear(); + this->MocIncludePaths.reserve(includes.size()); + // Append project directories only + { + std::array const movePaths = { + { &this->ProjectBinaryDir, &this->ProjectSourceDir } + }; + for (std::string const* ppath : movePaths) { + std::list::iterator it = includes.begin(); + while (it != includes.end()) { + std::string const& path = *it; + if (cmSystemTools::StringStartsWith(path, ppath->c_str())) { + this->MocIncludePaths.push_back(path); + it = includes.erase(it); + } else { + ++it; + } + } + } + } + // Append remaining directories + this->MocIncludePaths.insert(this->MocIncludePaths.end(), + includes.begin(), includes.end()); + } + // Compose moc includes list + { + std::set frameworkPaths; + for (std::string const& path : this->MocIncludePaths) { + this->MocIncludes.push_back("-I" + path); + // Extract framework path + if (cmHasLiteralSuffix(path, ".framework/Headers")) { + // Go up twice to get to the framework root + std::vector pathComponents; + cmSystemTools::SplitPath(path, pathComponents); + std::string frameworkPath = cmSystemTools::JoinPath( + pathComponents.begin(), pathComponents.end() - 2); + frameworkPaths.insert(frameworkPath); + } + } + // Append framework includes + for (std::string const& path : frameworkPaths) { + this->MocIncludes.push_back("-F"); + this->MocIncludes.push_back(path); + } + } + // Setup single list with all options + { + // Add includes + this->MocAllOptions.insert(this->MocAllOptions.end(), + this->MocIncludes.begin(), + this->MocIncludes.end()); + // Add definitions + for (std::string const& def : this->MocDefinitions) { + this->MocAllOptions.push_back("-D" + def); + } + // Add options + this->MocAllOptions.insert(this->MocAllOptions.end(), + this->MocOptions.begin(), + this->MocOptions.end()); + } + } + return true; } @@ -453,16 +583,12 @@ void cmQtAutoGenerators::SettingsFileRead(cmMakefile* makefile) // Compose current settings strings { cmCryptoHash crypt(cmCryptoHash::AlgoSHA256); - const std::string sep(" ~~~ "); + std::string const sep(" ~~~ "); if (this->MocEnabled()) { std::string str; str += this->MocExecutable; str += sep; - str += cmJoin(this->MocDefinitions, ";"); - str += sep; - str += cmJoin(this->MocIncludePaths, ";"); - str += sep; - str += cmJoin(this->MocOptions, ";"); + str += cmJoin(this->MocAllOptions, ";"); str += sep; str += this->IncludeProjectDirsBefore ? "TRUE" : "FALSE"; str += sep; @@ -503,7 +629,7 @@ void cmQtAutoGenerators::SettingsFileRead(cmMakefile* makefile) // Read old settings if (makefile->ReadListFile(this->SettingsFile.c_str())) { { - auto SMatch = [makefile](const char* key, const std::string& value) { + auto SMatch = [makefile](const char* key, std::string const& value) { return (value == makefile->GetSafeDefinition(key)); }; if (!SMatch(SettingsKeyMoc, this->SettingsStringMoc)) { @@ -519,7 +645,7 @@ void cmQtAutoGenerators::SettingsFileRead(cmMakefile* makefile) // In case any setting changed remove the old settings file. // This triggers a full rebuild on the next run if the current // build is aborted before writing the current settings in the end. - if (this->AnySettingsChanged()) { + if (this->SettingsChanged()) { cmSystemTools::RemoveFile(this->SettingsFile); } } else { @@ -534,7 +660,7 @@ bool cmQtAutoGenerators::SettingsFileWrite() { bool success = true; // Only write if any setting changed - if (this->AnySettingsChanged()) { + if (this->SettingsChanged()) { if (this->Verbose) { this->LogInfo(cmQtAutoGen::GEN, "Writing settings file " + cmQtAutoGen::Quoted(this->SettingsFile)); @@ -543,7 +669,7 @@ bool cmQtAutoGenerators::SettingsFileWrite() std::string settings; { auto SettingAppend = [&settings](const char* key, - const std::string& value) { + std::string const& value) { settings += "set("; settings += key; settings += " "; @@ -557,7 +683,7 @@ bool cmQtAutoGenerators::SettingsFileWrite() // Write settings file if (!this->FileWrite(cmQtAutoGen::GEN, this->SettingsFile, settings)) { this->LogFileError(cmQtAutoGen::GEN, this->SettingsFile, - "File writing failed"); + "Settings file writing failed"); // Remove old settings file to trigger a full rebuild on the next run cmSystemTools::RemoveFile(this->SettingsFile); success = false; @@ -566,89 +692,7 @@ bool cmQtAutoGenerators::SettingsFileWrite() return success; } -void cmQtAutoGenerators::Init(cmMakefile* makefile) -{ - // Mocs compilation file - this->MocCompFileRel = "mocs_compilation.cpp"; - this->MocCompFileAbs = cmSystemTools::CollapseCombinedPath( - this->AutogenBuildDir, this->MocCompFileRel); - - // Mocs include directory - this->AutogenIncludeDir = "include"; - this->AutogenIncludeDir += this->ConfigSuffix; - this->AutogenIncludeDir += "/"; - - // Moc predefs file - if (!this->MocPredefsCmd.empty()) { - this->MocPredefsFileRel = "moc_predefs"; - this->MocPredefsFileRel += this->ConfigSuffix; - this->MocPredefsFileRel += ".h"; - this->MocPredefsFileAbs = cmSystemTools::CollapseCombinedPath( - this->AutogenBuildDir, this->MocPredefsFileRel); - } - - // Init file path checksum generator - FPathChecksum.setupParentDirs(this->CurrentSourceDir, this->CurrentBinaryDir, - this->ProjectSourceDir, - this->ProjectBinaryDir); - - // Acquire header extensions - this->HeaderExtensions = makefile->GetCMakeInstance()->GetHeaderExtensions(); - - // Sort include directories on demand - if (this->IncludeProjectDirsBefore) { - // Move strings to temporary list - std::list includes; - includes.insert(includes.end(), this->MocIncludePaths.begin(), - this->MocIncludePaths.end()); - this->MocIncludePaths.clear(); - this->MocIncludePaths.reserve(includes.size()); - // Append project directories only - { - const std::array movePaths = { - { &this->ProjectBinaryDir, &this->ProjectSourceDir } - }; - for (const std::string* ppath : movePaths) { - std::list::iterator it = includes.begin(); - while (it != includes.end()) { - const std::string& path = *it; - if (cmSystemTools::StringStartsWith(path, ppath->c_str())) { - this->MocIncludePaths.push_back(path); - it = includes.erase(it); - } else { - ++it; - } - } - } - } - // Append remaining directories - this->MocIncludePaths.insert(this->MocIncludePaths.end(), includes.begin(), - includes.end()); - } - // Compose moc includes list - { - std::set frameworkPaths; - for (std::string const& path : this->MocIncludePaths) { - this->MocIncludes.push_back("-I" + path); - // Extract framework path - if (cmHasLiteralSuffix(path, ".framework/Headers")) { - // Go up twice to get to the framework root - std::vector pathComponents; - cmSystemTools::SplitPath(path, pathComponents); - std::string frameworkPath = cmSystemTools::JoinPath( - pathComponents.begin(), pathComponents.end() - 2); - frameworkPaths.insert(frameworkPath); - } - } - // Append framework includes - for (std::string const& path : frameworkPaths) { - this->MocIncludes.push_back("-F"); - this->MocIncludes.push_back(path); - } - } -} - -bool cmQtAutoGenerators::RunAutogen() +bool cmQtAutoGenerators::Process() { // the program goes through all .cpp files to see which moc files are // included. It is not really interesting how the moc file is named, but @@ -660,7 +704,7 @@ bool cmQtAutoGenerators::RunAutogen() // Create AUTOGEN include directory { - const std::string incDirAbs = cmSystemTools::CollapseCombinedPath( + std::string const incDirAbs = cmSystemTools::CollapseCombinedPath( this->AutogenBuildDir, this->AutogenIncludeDir); if (!cmSystemTools::MakeDirectory(incDirAbs)) { this->LogFileError(cmQtAutoGen::GEN, incDirAbs, @@ -669,45 +713,28 @@ bool cmQtAutoGenerators::RunAutogen() } } - // key = moc source filepath, value = moc output filepath - std::map mocsIncluded; - std::map mocsNotIncluded; - std::map> mocDepends; - std::map> uisIncluded; - // collects all headers which may need to be mocced - std::set mocHeaderFiles; - std::set uicHeaderFiles; - - // Parse sources - for (std::string const& src : this->Sources) { - // Parse source file for MOC/UIC - if (!this->ParseSourceFile(src, mocsIncluded, mocDepends, uisIncluded, - this->MocRelaxedMode)) { + // Parse source files + for (const auto& item : this->SourceJobs) { + if (!this->ParseSourceFile(item.first, item.second)) { return false; } - // Find additional headers - this->SearchHeadersForSourceFile(src, mocHeaderFiles, uicHeaderFiles); } - - // Parse headers - for (std::string const& hdr : this->Headers) { - if (!this->MocSkip(hdr)) { - mocHeaderFiles.insert(hdr); - } - if (!this->UicSkip(hdr)) { - uicHeaderFiles.insert(hdr); + // Parse header files + for (const auto& item : this->HeaderJobs) { + if (!this->ParseHeaderFile(item.first, item.second)) { + return false; } } - if (!this->ParseHeaders(mocHeaderFiles, uicHeaderFiles, mocsIncluded, - mocsNotIncluded, mocDepends, uisIncluded)) { + // Read missing dependency information + if (!this->ParsePostprocess()) { return false; - }; + } // Generate files - if (!this->MocGenerateAll(mocsIncluded, mocsNotIncluded, mocDepends)) { + if (!this->MocGenerateAll()) { return false; } - if (!this->UicGenerateAll(uisIncluded)) { + if (!this->UicGenerateAll()) { return false; } if (!this->RccGenerateAll()) { @@ -718,87 +745,100 @@ bool cmQtAutoGenerators::RunAutogen() } /** - * @brief Tests if the C++ content requires moc processing - * @return True if moc is required + * @return True on success */ -bool cmQtAutoGenerators::MocRequired(const std::string& contentText, - std::string* macroName) +bool cmQtAutoGenerators::ParseSourceFile(std::string const& absFilename, + const SourceJob& job) { - for (KeyRegExp& filter : this->MocMacroFilters) { - // Run a simple find string operation before the expensive - // regular expression check - if (contentText.find(filter.Key) != std::string::npos) { - if (filter.RegExp.find(contentText)) { - // Return macro name on demand - if (macroName != nullptr) { - *macroName = filter.Key; - } - return true; + std::string contentText; + std::string error; + bool success = ReadFile(contentText, absFilename, &error); + if (success) { + if (!contentText.empty()) { + if (job.Moc) { + success = this->MocParseSourceContent(absFilename, contentText); + } + if (success && job.Uic) { + success = this->UicParseContent(absFilename, contentText); } + } else { + this->LogFileWarning(cmQtAutoGen::GEN, absFilename, + "The source file is empty"); } + } else { + this->LogFileError(cmQtAutoGen::GEN, absFilename, + "Could not read the source file: " + error); } - return false; + return success; } -void cmQtAutoGenerators::MocFindDepends( - const std::string& absFilename, const std::string& contentText, - std::map>& mocDepends) +/** + * @return True on success + */ +bool cmQtAutoGenerators::ParseHeaderFile(std::string const& absFilename, + const SourceJob& job) { - for (KeyRegExp& filter : this->MocDependFilters) { - // Run a simple find string operation before the expensive - // regular expression check - if (contentText.find(filter.Key) != std::string::npos) { - // Run regular expression check loop - const std::string sourcePath = SubDirPrefix(absFilename); - const char* contentChars = contentText.c_str(); - while (filter.RegExp.find(contentChars)) { - // Evaluate match - const std::string match = filter.RegExp.match(1); - if (!match.empty()) { - // Find the dependency file - std::string incFile; - if (this->MocFindIncludedFile(incFile, sourcePath, match)) { - mocDepends[absFilename].insert(incFile); - if (this->Verbose) { - this->LogInfo(cmQtAutoGen::MOC, "Found dependency:\n " + - cmQtAutoGen::Quoted(absFilename) + "\n " + - cmQtAutoGen::Quoted(incFile)); - } - } else { - this->LogFileWarning(cmQtAutoGen::MOC, absFilename, - "Could not find dependency file " + - cmQtAutoGen::Quoted(match)); - } - } - contentChars += filter.RegExp.end(); + std::string contentText; + std::string error; + bool success = ReadFile(contentText, absFilename, &error); + if (success) { + if (!contentText.empty()) { + if (job.Moc) { + this->MocParseHeaderContent(absFilename, contentText); } + if (job.Uic) { + success = this->UicParseContent(absFilename, contentText); + } + } else { + this->LogFileWarning(cmQtAutoGen::GEN, absFilename, + "The header file is empty"); } + } else { + this->LogFileError(cmQtAutoGen::GEN, absFilename, + "Could not read the header file: " + error); } + return success; } /** - * @brief Tests if the file should be ignored for moc scanning - * @return True if the file should be ignored + * @return True on success */ -bool cmQtAutoGenerators::MocSkip(const std::string& absFilename) const +bool cmQtAutoGenerators::ParsePostprocess() { - if (this->MocEnabled()) { - // Test if the file name is on the skip list - if (!ListContains(this->MocSkipList, absFilename)) { - return false; + bool success = true; + // Read missin dependecies + for (auto& item : this->MocJobsIncluded) { + if (!item->DependsValid) { + std::string content; + std::string error; + if (ReadFile(content, item->SourceFile, &error)) { + this->MocFindDepends(item->SourceFile, content, item->Depends); + item->DependsValid = true; + } else { + std::string emsg = "Could not read file\n "; + emsg += item->SourceFile; + emsg += "\nrequired by moc include \""; + emsg += item->IncludeString; + emsg += "\".\n"; + emsg += error; + this->LogFileError(cmQtAutoGen::MOC, item->Includer, emsg); + success = false; + break; + } } } - return true; + return success; } /** - * @brief Tests if the file name is in the skip list + * @brief Tests if the file should be ignored for moc scanning + * @return True if the file should be ignored */ -bool cmQtAutoGenerators::UicSkip(const std::string& absFilename) const +bool cmQtAutoGenerators::MocSkip(std::string const& absFilename) const { - if (this->UicEnabled()) { + if (this->MocEnabled()) { // Test if the file name is on the skip list - if (!ListContains(this->UicSkipList, absFilename)) { + if (!ListContains(this->MocSkipList, absFilename)) { return false; } } @@ -806,54 +846,29 @@ bool cmQtAutoGenerators::UicSkip(const std::string& absFilename) const } /** - * @return True on success + * @brief Tests if the C++ content requires moc processing + * @return True if moc is required */ -bool cmQtAutoGenerators::ParseSourceFile( - const std::string& absFilename, - std::map& mocsIncluded, - std::map>& mocDepends, - std::map>& uisIncluded, bool relaxed) +bool cmQtAutoGenerators::MocRequired(std::string const& contentText, + std::string* macroName) { - 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); + for (KeyRegExp& filter : this->MocMacroFilters) { + // Run a simple find string operation before the expensive + // regular expression check + if (contentText.find(filter.Key) != std::string::npos) { + if (filter.RegExp.find(contentText)) { + // Return macro name on demand + if (macroName != nullptr) { + *macroName = filter.Key; + } + return true; } - } else { - this->LogFileWarning(cmQtAutoGen::GEN, absFilename, "The file is empty"); - } - } else { - this->LogFileError(cmQtAutoGen::GEN, absFilename, "Could not read file"); - } - return success; -} - -void cmQtAutoGenerators::UicParseContent( - const std::string& absFilename, const std::string& contentText, - std::map>& uisIncluded) -{ - if (this->Verbose) { - this->LogInfo(cmQtAutoGen::UIC, "Checking " + absFilename); - } - - const char* contentChars = contentText.c_str(); - if (strstr(contentChars, "ui_") != nullptr) { - while (this->UicRegExpInclude.find(contentChars)) { - uisIncluded[absFilename].push_back(this->UicRegExpInclude.match(1)); - contentChars += this->UicRegExpInclude.end(); } } + return false; } -std::string cmQtAutoGenerators::MocMacroNamesString() const +std::string cmQtAutoGenerators::MocStringMacros() const { std::string res; const auto itB = this->MocMacroFilters.cbegin(); @@ -875,339 +890,479 @@ std::string cmQtAutoGenerators::MocMacroNamesString() const return res; } -std::string cmQtAutoGenerators::MocHeaderSuffixesString() const +std::string cmQtAutoGenerators::MocStringHeaders( + std::string const& fileBase) const { - std::string res = ".{"; + std::string res = fileBase; + res += ".{"; res += cmJoin(this->HeaderExtensions, ","); res += "}"; return res; } -/** - * @return True on success - */ -bool cmQtAutoGenerators::MocParseSourceContent( - const std::string& absFilename, const std::string& contentText, - std::map& mocsIncluded, - std::map>& mocDepends, bool relaxed) +std::string cmQtAutoGenerators::MocFindIncludedHeader( + std::string const& sourcePath, std::string const& includeBase) const { - if (this->Verbose) { - this->LogInfo(cmQtAutoGen::MOC, "Checking " + absFilename); + std::string header; + // Search in vicinity of the source + if (!this->FindHeader(header, sourcePath + includeBase)) { + // Search in include directories + for (std::string const& path : this->MocIncludePaths) { + std::string fullPath = path; + fullPath.push_back('/'); + fullPath += includeBase; + if (this->FindHeader(header, fullPath)) { + break; + } + } } + // Sanitize + if (!header.empty()) { + header = cmSystemTools::GetRealPath(header); + } + return header; +} - const std::string scanFileDir = SubDirPrefix(absFilename); - const std::string scanFileBase = - cmSystemTools::GetFilenameWithoutLastExtension(absFilename); - - std::string selfMacroName; - const bool selfRequiresMoc = this->MocRequired(contentText, &selfMacroName); - bool ownDotMocIncluded = false; - std::string ownMocUnderscoreInclude; - std::string ownMocUnderscoreHeader; - - // first a simple string check for "moc" is *much* faster than the regexp, - // and if the string search already fails, we don't have to try the - // expensive regexp - const char* contentChars = contentText.c_str(); - if (strstr(contentChars, "moc") != nullptr) { - // Iterate over all included moc files - while (this->MocRegExpInclude.find(contentChars)) { - const std::string incString = this->MocRegExpInclude.match(1); - // Basename of the moc include - const std::string incDir(SubDirPrefix(incString)); - const std::string incBase = - cmSystemTools::GetFilenameWithoutLastExtension(incString); - - // If the moc include is of the moc_foo.cpp style we expect - // the Q_OBJECT class declaration in a header file. - // If the moc include is of the foo.moc style we need to look for - // a Q_OBJECT macro in the current source file, if it contains the - // macro we generate the moc file from the source file. - if (cmHasLiteralPrefix(incBase, "moc_")) { - // Include: moc_FOO.cxx - // Remove the moc_ part - const std::string incRealBase = incBase.substr(4); - const std::string headerToMoc = - this->MocFindHeader(scanFileDir, incDir + incRealBase); - if (!headerToMoc.empty()) { - if (!this->MocSkip(headerToMoc)) { - // Register moc job - mocsIncluded[headerToMoc] = incString; - this->MocFindDepends(headerToMoc, contentText, mocDepends); - // Store meta information for relaxed mode - if (relaxed && (incRealBase == scanFileBase)) { - ownMocUnderscoreInclude = incString; - ownMocUnderscoreHeader = headerToMoc; - } - } - } else { - std::ostringstream ost; - ost << "The file includes the moc file " - << cmQtAutoGen::Quoted(incString) - << ", but could not find header "; - ost << cmQtAutoGen::Quoted(incRealBase + - this->MocHeaderSuffixesString()); - this->LogFileError(cmQtAutoGen::MOC, absFilename, ost.str()); - return false; - } - } else { - // Include: FOO.moc - bool ownDotMoc = (incBase == scanFileBase); - std::string fileToMoc; - if (relaxed) { - // Mode: Relaxed - if (selfRequiresMoc && ownDotMoc) { - // Include self - fileToMoc = absFilename; - ownDotMocIncluded = true; - } else { - // In relaxed mode try to find a header instead but issue a warning - const std::string headerToMoc = - this->MocFindHeader(scanFileDir, incDir + incBase); - if (!headerToMoc.empty()) { - if (!this->MocSkip(headerToMoc)) { - // This is for KDE4 compatibility: - fileToMoc = headerToMoc; - - auto quoted_inc = cmQtAutoGen::Quoted(incString); - auto quoted_header = cmQtAutoGen::Quoted(headerToMoc); - auto quoted_base = - cmQtAutoGen::Quoted("moc_" + incBase + ".cpp"); - if (!selfRequiresMoc) { - if (ownDotMoc) { - std::ostringstream ost; - ost << "The file includes the moc file " << quoted_inc - << ", but does not contain a " - << this->MocMacroNamesString() << " macro.\n" - << "Running moc on\n" - << " " << quoted_header << "!\n" - << "Better include " << quoted_base - << " for a compatibility with strict mode.\n" - "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n"; - this->LogFileWarning(cmQtAutoGen::MOC, absFilename, - ost.str()); - } else if (!ownDotMoc) { - std::ostringstream ost; - ost << "The file includes the moc file " << quoted_inc - << " instead of " << quoted_base << ".\n"; - ost << "Running moc on\n" - << " " << quoted_header << "!\n" - << "Better include " << quoted_base - << " for compatibility with strict mode.\n" - "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n"; - this->LogFileWarning(cmQtAutoGen::MOC, absFilename, - ost.str()); - } - } else { - if (!ownDotMoc) { - // Handled further down - } - } - } +bool cmQtAutoGenerators::MocFindIncludedFile( + std::string& absFile, std::string const& sourcePath, + std::string const& includeString) const +{ + bool success = false; + // Search in vicinity of the source + { + std::string testPath = sourcePath; + testPath += includeString; + if (cmSystemTools::FileExists(testPath.c_str())) { + absFile = cmSystemTools::GetRealPath(testPath); + success = true; + } + } + // Search in include directories + if (!success) { + for (std::string const& path : this->MocIncludePaths) { + std::string fullPath = path; + fullPath.push_back('/'); + fullPath += includeString; + if (cmSystemTools::FileExists(fullPath.c_str())) { + absFile = cmSystemTools::GetRealPath(fullPath); + success = true; + break; + } + } + } + return success; +} + +bool cmQtAutoGenerators::MocDependFilterPush(std::string const& key, + std::string const& regExp) +{ + std::string error; + if (!key.empty()) { + if (!regExp.empty()) { + KeyRegExp filter; + filter.Key = key; + if (filter.RegExp.compile(regExp)) { + this->MocDependFilters.push_back(std::move(filter)); + } else { + error = "Regular expression compiling failed"; + } + } else { + error = "Regular expression is empty"; + } + } else { + error = "Key is empty"; + } + if (!error.empty()) { + std::string emsg = "AUTOMOC_DEPEND_FILTERS: "; + emsg += error; + emsg += "\n"; + emsg += " Key: "; + emsg += cmQtAutoGen::Quoted(key); + emsg += "\n"; + emsg += " RegExp: "; + emsg += cmQtAutoGen::Quoted(regExp); + emsg += "\n"; + this->LogError(cmQtAutoGen::MOC, emsg); + return false; + } + return true; +} + +void cmQtAutoGenerators::MocFindDepends(std::string const& absFilename, + std::string const& contentText, + std::set& depends) +{ + if (this->MocDependFilters.empty() && contentText.empty()) { + return; + } + + std::vector matches; + for (KeyRegExp& filter : this->MocDependFilters) { + // Run a simple find string check + if (contentText.find(filter.Key) != std::string::npos) { + // Run the expensive regular expression check loop + const char* contentChars = contentText.c_str(); + while (filter.RegExp.find(contentChars)) { + std::string match = filter.RegExp.match(1); + if (!match.empty()) { + matches.emplace_back(std::move(match)); + } + contentChars += filter.RegExp.end(); + } + } + } + + if (!matches.empty()) { + std::string const sourcePath = SubDirPrefix(absFilename); + for (std::string const& match : matches) { + // Find the dependency file + std::string incFile; + if (this->MocFindIncludedFile(incFile, sourcePath, match)) { + depends.insert(incFile); + if (this->Verbose) { + this->LogInfo(cmQtAutoGen::MOC, "Found dependency:\n " + + cmQtAutoGen::Quoted(absFilename) + "\n " + + cmQtAutoGen::Quoted(incFile)); + } + } else { + this->LogFileWarning(cmQtAutoGen::MOC, absFilename, + "Could not find dependency file " + + cmQtAutoGen::Quoted(match)); + } + } + } +} + +/** + * @return True on success + */ +bool cmQtAutoGenerators::MocParseSourceContent(std::string const& absFilename, + std::string const& contentText) +{ + if (this->Verbose) { + this->LogInfo(cmQtAutoGen::MOC, "Checking: " + absFilename); + } + + auto AddJob = [this, &absFilename](std::string const& sourceFile, + std::string const& includeString, + std::string const* content) { + auto job = cm::make_unique(); + job->SourceFile = sourceFile; + job->BuildFileRel = this->AutogenIncludeDir; + job->BuildFileRel += includeString; + job->Includer = absFilename; + job->IncludeString = includeString; + job->DependsValid = (content != nullptr); + if (job->DependsValid) { + this->MocFindDepends(sourceFile, *content, job->Depends); + } + this->MocJobsIncluded.push_back(std::move(job)); + }; + + struct MocInc + { + std::string Inc; // full include string + std::string Dir; // include string directory + std::string Base; // include string file base + }; + + // Extract moc includes from file + std::vector mocIncsUsc; + std::vector mocIncsDot; + { + const char* contentChars = contentText.c_str(); + if (strstr(contentChars, "moc") != nullptr) { + while (this->MocRegExpInclude.find(contentChars)) { + std::string incString = this->MocRegExpInclude.match(1); + std::string incDir(SubDirPrefix(incString)); + std::string incBase = + cmSystemTools::GetFilenameWithoutLastExtension(incString); + if (cmHasLiteralPrefix(incBase, "moc_")) { + // moc_.cxx + // Remove the moc_ part from the base name + mocIncsUsc.push_back(MocInc{ std::move(incString), std::move(incDir), + incBase.substr(4) }); + } else { + // .moc + mocIncsDot.push_back(MocInc{ std::move(incString), std::move(incDir), + std::move(incBase) }); + } + // Forward content pointer + contentChars += this->MocRegExpInclude.end(); + } + } + } + + std::string selfMacroName; + const bool selfRequiresMoc = this->MocRequired(contentText, &selfMacroName); + + // Check if there is anything to do + if (!selfRequiresMoc && mocIncsUsc.empty() && mocIncsDot.empty()) { + return true; + } + + // Scan file variables + std::string const scanFileDir = SubDirPrefix(absFilename); + std::string const scanFileBase = + cmSystemTools::GetFilenameWithoutLastExtension(absFilename); + // Relaxed mode variables + bool ownDotMocIncluded = false; + std::string ownMocUscInclude; + std::string ownMocUscHeader; + + // Process moc_.cxx includes + for (const MocInc& mocInc : mocIncsUsc) { + std::string const header = + this->MocFindIncludedHeader(scanFileDir, mocInc.Dir + mocInc.Base); + if (!header.empty()) { + // Check if header is skipped + if (this->MocSkip(header)) { + continue; + } + // Register moc job + AddJob(header, mocInc.Inc, nullptr); + // Store meta information for relaxed mode + if (this->MocRelaxedMode && (mocInc.Base == scanFileBase)) { + ownMocUscInclude = mocInc.Inc; + ownMocUscHeader = header; + } + } else { + std::string emsg = "The file includes the moc file "; + emsg += cmQtAutoGen::Quoted(mocInc.Inc); + emsg += ", but could not find the header "; + emsg += cmQtAutoGen::Quoted(this->MocStringHeaders(mocInc.Base)); + this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg); + return false; + } + } + + // Process .moc includes + for (const MocInc& mocInc : mocIncsDot) { + const bool ownMoc = (mocInc.Base == scanFileBase); + if (this->MocRelaxedMode) { + // Relaxed mode + if (selfRequiresMoc && ownMoc) { + // Add self + AddJob(absFilename, mocInc.Inc, &contentText); + ownDotMocIncluded = true; + } else { + // In relaxed mode try to find a header instead but issue a warning. + // This is for KDE4 compatibility + std::string const header = + this->MocFindIncludedHeader(scanFileDir, mocInc.Dir + mocInc.Base); + if (!header.empty()) { + // Check if header is skipped + if (this->MocSkip(header)) { + continue; + } + // Register moc job + AddJob(header, mocInc.Inc, nullptr); + if (!selfRequiresMoc) { + if (ownMoc) { + std::string emsg = "The file includes the moc file "; + emsg += cmQtAutoGen::Quoted(mocInc.Inc); + emsg += ", but does not contain a "; + emsg += this->MocStringMacros(); + emsg += " macro.\nRunning moc on\n "; + emsg += cmQtAutoGen::Quoted(header); + emsg += "!\nBetter include "; + emsg += cmQtAutoGen::Quoted("moc_" + mocInc.Base + ".cpp"); + emsg += " for a compatibility with strict mode.\n" + "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n"; + this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg); } else { - std::ostringstream ost; - ost << "The file includes the moc file " - << cmQtAutoGen::Quoted(incString) - << ", which seems to be the moc file from a different " - "source file. CMake also could not find a matching " - "header."; - this->LogFileError(cmQtAutoGen::MOC, absFilename, ost.str()); - return false; + std::string emsg = "The file includes the moc file "; + emsg += cmQtAutoGen::Quoted(mocInc.Inc); + emsg += " instead of "; + emsg += cmQtAutoGen::Quoted("moc_" + mocInc.Base + ".cpp"); + emsg += ".\nRunning moc on\n "; + emsg += cmQtAutoGen::Quoted(header); + emsg += "!\nBetter include "; + emsg += cmQtAutoGen::Quoted("moc_" + mocInc.Base + ".cpp"); + emsg += " for compatibility with strict mode.\n" + "(CMAKE_AUTOMOC_RELAXED_MODE warning)\n"; + this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg); } } } else { - // Mode: Strict - if (ownDotMoc) { - // Include self - fileToMoc = absFilename; - ownDotMocIncluded = true; - // Accept but issue a warning if moc isn't required - if (!selfRequiresMoc) { - std::ostringstream ost; - ost << "The file includes the moc file " - << cmQtAutoGen::Quoted(incString) - << ", but does not contain a " << this->MocMacroNamesString() - << " macro."; - this->LogFileWarning(cmQtAutoGen::MOC, absFilename, ost.str()); - } - } else { - // Don't allow FOO.moc include other than self in strict mode - std::ostringstream ost; - ost << "The file includes the moc file " - << cmQtAutoGen::Quoted(incString) - << ", which seems to be the moc file from a different " - "source file. This is not supported. Include " - << cmQtAutoGen::Quoted(scanFileBase + ".moc") - << " to run moc on this source file."; - this->LogFileError(cmQtAutoGen::MOC, absFilename, ost.str()); - return false; - } + std::string emsg = "The file includes the moc file "; + emsg += cmQtAutoGen::Quoted(mocInc.Inc); + emsg += ", which seems to be the moc file from a different " + "source file. CMake also could not find a matching " + "header."; + this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg); + return false; } - if (!fileToMoc.empty()) { - mocsIncluded[fileToMoc] = incString; - this->MocFindDepends(fileToMoc, contentText, mocDepends); + } + } else { + // Strict mode + if (ownMoc) { + // Include self + AddJob(absFilename, mocInc.Inc, &contentText); + ownDotMocIncluded = true; + // Accept but issue a warning if moc isn't required + if (!selfRequiresMoc) { + std::string emsg = "The file includes the moc file "; + emsg += cmQtAutoGen::Quoted(mocInc.Inc); + emsg += ", but does not contain a "; + emsg += this->MocStringMacros(); + emsg += " macro."; + this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg); } + } else { + // Don't allow .moc include other than self in strict mode + std::string emsg = "The file includes the moc file "; + emsg += cmQtAutoGen::Quoted(mocInc.Inc); + emsg += ", which seems to be the moc file from a different " + "source file.\nThis is not supported. Include "; + emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc"); + emsg += " to run moc on this source file."; + this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg); + return false; } - // Forward content pointer - contentChars += this->MocRegExpInclude.end(); } } if (selfRequiresMoc && !ownDotMocIncluded) { - // In this case, check whether the scanned file itself contains a - // Q_OBJECT. + // In this case, check whether the scanned file itself contains a Q_OBJECT. // If this is the case, the moc_foo.cpp should probably be generated from // foo.cpp instead of foo.h, because otherwise it won't build. // But warn, since this is not how it is supposed to be used. - if (relaxed && !ownMocUnderscoreInclude.empty()) { + if (this->MocRelaxedMode && !ownMocUscInclude.empty()) { // This is for KDE4 compatibility: - std::ostringstream ost; - ost << "The file contains a " << selfMacroName - << " macro, but does not include " - << cmQtAutoGen::Quoted(scanFileBase + ".moc") - << ". Instead it includes " - << cmQtAutoGen::Quoted(ownMocUnderscoreInclude) << ".\n" - << "Running moc on\n" - << " " << cmQtAutoGen::Quoted(absFilename) << "!\n" - << "Better include " << cmQtAutoGen::Quoted(scanFileBase + ".moc") - << " for compatibility with strict mode.\n" - "(CMAKE_AUTOMOC_RELAXED_MODE warning)"; - this->LogFileWarning(cmQtAutoGen::MOC, absFilename, ost.str()); - - // Use scanned source file instead of scanned header file as moc source - mocsIncluded[absFilename] = ownMocUnderscoreInclude; - this->MocFindDepends(absFilename, contentText, mocDepends); - // Remove - mocsIncluded.erase(ownMocUnderscoreHeader); + std::string emsg = "The file contains a "; + emsg += selfMacroName; + emsg += " macro, but does not include "; + emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc"); + emsg += ". Instead it includes "; + emsg += cmQtAutoGen::Quoted(ownMocUscInclude); + emsg += ".\nRunning moc on\n "; + emsg += cmQtAutoGen::Quoted(absFilename); + emsg += "!\nBetter include "; + emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc"); + emsg += " for compatibility with strict mode.\n" + "(CMAKE_AUTOMOC_RELAXED_MODE warning)"; + this->LogFileWarning(cmQtAutoGen::MOC, absFilename, emsg); + + // Remove own header job + { + auto itC = this->MocJobsIncluded.begin(); + auto itE = this->MocJobsIncluded.end(); + for (; itC != itE; ++itC) { + if ((*itC)->SourceFile == ownMocUscHeader) { + if ((*itC)->IncludeString == ownMocUscInclude) { + this->MocJobsIncluded.erase(itC); + break; + } + } + } + } + // Add own source job + AddJob(absFilename, ownMocUscInclude, &contentText); } else { // Otherwise always error out since it will not compile: - std::ostringstream ost; - ost << "The file contains a " << selfMacroName - << " macro, but does not include " - << cmQtAutoGen::Quoted(scanFileBase + ".moc") << "!\n" - << "Consider adding the include or enabling SKIP_AUTOMOC for this " - "file."; - this->LogFileError(cmQtAutoGen::MOC, absFilename, ost.str()); + std::string emsg = "The file contains a "; + emsg += selfMacroName; + emsg += " macro, but does not include "; + emsg += cmQtAutoGen::Quoted(scanFileBase + ".moc"); + emsg += "!\nConsider to\n - add #include \""; + emsg += scanFileBase; + emsg += ".moc\"\n - enable SKIP_AUTOMOC for this file"; + this->LogFileError(cmQtAutoGen::MOC, absFilename, emsg); return false; } } - return true; } -void cmQtAutoGenerators::MocParseHeaderContent( - const std::string& absFilename, const std::string& contentText, - std::map& mocsNotIncluded, - std::map>& mocDepends) +void cmQtAutoGenerators::MocParseHeaderContent(std::string const& absFilename, + std::string const& contentText) { - // Log if (this->Verbose) { - this->LogInfo(cmQtAutoGen::MOC, "Checking " + absFilename); - } - if (this->MocRequired(contentText)) { - // Register moc job - mocsNotIncluded[absFilename] = - this->ChecksumedPath(absFilename, "moc_", this->ConfigSuffix + ".cpp"); - this->MocFindDepends(absFilename, contentText, mocDepends); + this->LogInfo(cmQtAutoGen::MOC, "Checking: " + absFilename); } -} -void cmQtAutoGenerators::SearchHeadersForSourceFile( - const std::string& absFilename, std::set& mocHeaderFiles, - std::set& uicHeaderFiles) const -{ - std::array basepaths; - { - std::string bpath = SubDirPrefix(absFilename); - bpath += cmSystemTools::GetFilenameWithoutLastExtension(absFilename); - // search for default header files and private header files - basepaths[0] = bpath; - basepaths[1] = bpath; - basepaths[1] += "_p"; - } + auto const fit = + std::find_if(this->MocJobsIncluded.cbegin(), this->MocJobsIncluded.cend(), + [&absFilename](std::unique_ptr const& job) { + return job->SourceFile == absFilename; + }); + if (fit == this->MocJobsIncluded.cend()) { + if (this->MocRequired(contentText)) { + static std::string const prefix = "moc_"; + static std::string const suffix = this->ConfigSuffix + ".cpp"; - for (const std::string& bPath : basepaths) { - std::string headerName; - if (this->FindHeader(headerName, bPath)) { - // Moc headers - if (!this->MocSkip(absFilename) && !this->MocSkip(headerName)) { - mocHeaderFiles.insert(headerName); - } - // Uic headers - if (!this->UicSkip(absFilename) && !this->UicSkip(headerName)) { - uicHeaderFiles.insert(headerName); - } - } - } -} - -bool cmQtAutoGenerators::ParseHeaders( - const std::set& mocHeaderFiles, - const std::set& uicHeaderFiles, - const std::map& mocsIncluded, - std::map& mocsNotIncluded, - std::map>& mocDepends, - std::map>& uisIncluded) -{ - bool success = true; - // Merged header files list to read files only once - std::set headerFiles; - headerFiles.insert(mocHeaderFiles.begin(), mocHeaderFiles.end()); - headerFiles.insert(uicHeaderFiles.begin(), uicHeaderFiles.end()); - - for (std::string const& headerName : headerFiles) { - 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); + auto job = cm::make_unique(); + job->SourceFile = absFilename; + { + std::string& bld = job->BuildFileRel; + bld = this->FilePathChecksum.getPart(absFilename); + bld += "/"; + bld += prefix; + bld += cmSystemTools::GetFilenameWithoutLastExtension(absFilename); + bld += suffix; } - } else { - this->LogFileError(cmQtAutoGen::GEN, headerName, - "Could not read header file"); - success = false; - break; + this->MocFindDepends(absFilename, contentText, job->Depends); + this->MocJobsAuto.push_back(std::move(job)); } } - return success; } -bool cmQtAutoGenerators::MocGenerateAll( - const std::map& mocsIncluded, - const std::map& mocsNotIncluded, - const std::map>& mocDepends) +bool cmQtAutoGenerators::MocGenerateAll() { if (!this->MocEnabled()) { return true; } - // Look for name collisions + // Look for name collisions in included moc files { - std::multimap collisions; - // Test merged map of included and notIncluded - std::map mergedMocs(mocsIncluded); - mergedMocs.insert(mocsNotIncluded.begin(), mocsNotIncluded.end()); - if (this->NameCollisionTest(mergedMocs, collisions)) { - std::string msg = "The same moc file will be generated " - "from different sources.\n" - "To avoid this error either\n" - " - rename the source files or\n" - " - do not include the (moc_NAME.cpp|NAME.moc) file"; - this->LogNameCollisionError(cmQtAutoGen::MOC, msg, collisions); + bool collision = false; + std::map> collisions; + for (auto const& job : this->MocJobsIncluded) { + auto& list = collisions[job->IncludeString]; + if (!list.empty()) { + collision = true; + } + list.push_back(job.get()); + } + if (collision) { + std::string emsg = + "Included moc files with the same name will be " + "generated from different sources.\n" + "Consider to\n" + " - not include the \"moc_.cpp\" file\n" + " - add a directory prefix to a \".moc\" include " + "(e.g \"sub/.moc\")\n" + " - rename the source file(s)\n" + "Include conflicts\n" + "-----------------\n"; + const auto& colls = collisions; + for (auto const& coll : colls) { + if (coll.second.size() > 1) { + emsg += cmQtAutoGen::Quoted(coll.first); + emsg += " included in\n"; + for (const MocJobIncluded* job : coll.second) { + emsg += " - "; + emsg += cmQtAutoGen::Quoted(job->Includer); + emsg += "\n"; + } + emsg += "would be generated from\n"; + for (const MocJobIncluded* job : coll.second) { + emsg += " - "; + emsg += cmQtAutoGen::Quoted(job->SourceFile); + emsg += "\n"; + } + } + } + this->LogError(cmQtAutoGen::MOC, emsg); return false; } } - // Generate moc_predefs + // (Re)generate moc_predefs.h on demand if (!this->MocPredefsCmd.empty()) { if (this->MocSettingsChanged || - FileAbsentOrOlder(this->MocPredefsFileAbs, this->SettingsFile)) { + !cmSystemTools::FileExists(this->MocPredefsFileAbs)) { if (this->Verbose) { this->LogBold("Generating MOC predefs " + this->MocPredefsFileRel); } @@ -1216,16 +1371,9 @@ bool cmQtAutoGenerators::MocGenerateAll( { // Compose command std::vector cmd = this->MocPredefsCmd; - // Add includes - cmd.insert(cmd.end(), this->MocIncludes.begin(), - this->MocIncludes.end()); - // Add definitions - for (std::string const& def : this->MocDefinitions) { - cmd.push_back("-D" + def); - } // Add options - cmd.insert(cmd.end(), this->MocOptions.begin(), - this->MocOptions.end()); + cmd.insert(cmd.end(), this->MocAllOptions.begin(), + this->MocAllOptions.end()); // Execute command if (!this->RunCommand(cmd, output)) { this->LogCommandError(cmQtAutoGen::MOC, @@ -1240,6 +1388,8 @@ bool cmQtAutoGenerators::MocGenerateAll( output)) { this->MocPredefsChanged = true; } else { + this->LogFileError(cmQtAutoGen::MOC, this->MocPredefsFileAbs, + "moc_predefs file writing failed"); return false; } } else { @@ -1254,101 +1404,90 @@ bool cmQtAutoGenerators::MocGenerateAll( } // Generate moc files that are included by source files. - for (auto const& it : mocsIncluded) { - if (!this->MocGenerateFile(it.first, it.second, mocDepends, true)) { - if (this->MocRunFailed) { - return false; - } + for (auto const& item : this->MocJobsIncluded) { + if (!this->MocGenerateFile(*item)) { + return false; } } - // Generate moc files that are _not_ included by source files. - bool mocCompFileGenerated = false; - for (auto const& it : mocsNotIncluded) { - if (this->MocGenerateFile(it.first, it.second, mocDepends, false)) { - mocCompFileGenerated = true; - } else { - if (this->MocRunFailed) { - return false; - } + bool autoNameGenerated = false; + for (auto const& item : this->MocJobsAuto) { + if (!this->MocGenerateFile(*item, &autoNameGenerated)) { + return false; } } // Compose mocs compilation file content - std::string automocSource; { - std::ostringstream ost; - ost << "/* This file is autogenerated, do not edit*/\n"; - if (mocsNotIncluded.empty()) { + std::string mocs = "/* This file is autogenerated, do not edit*/\n"; + if (this->MocJobsAuto.empty()) { // Dummy content - ost << "enum some_compilers { need_more_than_nothing };\n"; + mocs += "enum some_compilers { need_more_than_nothing };\n"; } else { // Valid content - for (auto const& it : mocsNotIncluded) { - ost << "#include \"" << it.second << "\"\n"; + for (const auto& item : this->MocJobsAuto) { + mocs += "#include \""; + mocs += item->BuildFileRel; + mocs += "\"\n"; } } - automocSource = ost.str(); - } - if (this->FileDiffers(this->MocCompFileAbs, automocSource)) { - // Actually write mocs compilation file - if (this->Verbose) { - this->LogBold("Generating MOC compilation " + this->MocCompFileRel); - } - if (!this->FileWrite(cmQtAutoGen::MOC, this->MocCompFileAbs, - automocSource)) { - return false; - } - } else if (mocCompFileGenerated) { - // Only touch mocs compilation file - if (this->Verbose) { - this->LogInfo(cmQtAutoGen::MOC, - "Touching mocs compilation " + this->MocCompFileRel); + if (this->FileDiffers(this->MocCompFileAbs, mocs)) { + // Actually write mocs compilation file + if (this->Verbose) { + this->LogBold("Generating MOC compilation " + this->MocCompFileRel); + } + if (!this->FileWrite(cmQtAutoGen::MOC, this->MocCompFileAbs, mocs)) { + this->LogFileError(cmQtAutoGen::MOC, this->MocCompFileAbs, + "mocs compilation file writing failed"); + return false; + } + } else if (autoNameGenerated) { + // Only touch mocs compilation file + if (this->Verbose) { + this->LogInfo(cmQtAutoGen::MOC, + "Touching mocs compilation " + this->MocCompFileRel); + } + cmSystemTools::Touch(this->MocCompFileAbs, false); } - cmSystemTools::Touch(this->MocCompFileAbs, false); } return true; } /** - * @return True if a moc file was created. False may indicate an error. + * @return True on success */ -bool cmQtAutoGenerators::MocGenerateFile( - const std::string& sourceFile, const std::string& mocFileName, - const std::map>& mocDepends, - bool included) +bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& job, + bool* generated) { - bool mocGenerated = false; - bool generateMoc = this->MocSettingsChanged || this->MocPredefsChanged; + bool success = true; - const std::string mocFileRel = - included ? (this->AutogenIncludeDir + mocFileName) : mocFileName; - const std::string mocFileAbs = - cmSystemTools::CollapseCombinedPath(this->AutogenBuildDir, mocFileRel); + std::string const mocFileAbs = cmSystemTools::CollapseCombinedPath( + this->AutogenBuildDir, job.BuildFileRel); + bool generateMoc = (this->MocSettingsChanged || this->MocPredefsChanged); if (!generateMoc) { // Test if the source file is newer that the build file - generateMoc = FileAbsentOrOlder(mocFileAbs, sourceFile); - if (!generateMoc) { - // Test if a dependency file changed - std::map>::const_iterator dit = - mocDepends.find(sourceFile); - if (dit != mocDepends.end()) { - for (std::string const& fit : dit->second) { - if (FileAbsentOrOlder(mocFileAbs, fit)) { - generateMoc = true; - break; - } - } + generateMoc = FileAbsentOrOlder(mocFileAbs, job.SourceFile); + } + if (!generateMoc && !this->MocPredefsFileAbs.empty()) { + // Check if moc_predefs is newer + generateMoc = FileAbsentOrOlder(mocFileAbs, this->MocPredefsFileAbs); + } + if (!generateMoc) { + // Test if a dependency file is newer + for (std::string const& depFile : job.Depends) { + if (FileAbsentOrOlder(mocFileAbs, depFile)) { + generateMoc = true; + break; } } } if (generateMoc) { // Log if (this->Verbose) { - this->LogBold("Generating MOC source " + mocFileRel); + this->LogBold("Generating MOC source " + job.BuildFileRel); } // Make sure the parent directory exists @@ -1356,15 +1495,9 @@ bool cmQtAutoGenerators::MocGenerateFile( // Compose moc command std::vector cmd; cmd.push_back(this->MocExecutable); - // Add includes - cmd.insert(cmd.end(), this->MocIncludes.begin(), - this->MocIncludes.end()); - // Add definitions - for (std::string const& def : this->MocDefinitions) { - cmd.push_back("-D" + def); - } // Add options - cmd.insert(cmd.end(), this->MocOptions.begin(), this->MocOptions.end()); + cmd.insert(cmd.end(), this->MocAllOptions.begin(), + this->MocAllOptions.end()); // Add predefs include if (!this->MocPredefsFileAbs.empty()) { cmd.push_back("--include"); @@ -1372,37 +1505,111 @@ bool cmQtAutoGenerators::MocGenerateFile( } cmd.push_back("-o"); cmd.push_back(mocFileAbs); - cmd.push_back(sourceFile); + cmd.push_back(job.SourceFile); // Execute moc command std::string output; if (this->RunCommand(cmd, output)) { // Success - mocGenerated = true; + if (generated != nullptr) { + *generated = true; + } } else { - this->LogCommandError(cmQtAutoGen::MOC, "moc failed for\n " + - cmQtAutoGen::Quoted(sourceFile), - cmd, output); + // Moc command failed + { + std::string emsg = "moc failed for\n "; + emsg += cmQtAutoGen::Quoted(job.SourceFile); + this->LogCommandError(cmQtAutoGen::MOC, emsg, cmd, output); + } cmSystemTools::RemoveFile(mocFileAbs); - this->MocRunFailed = true; + success = false; } } else { // Parent directory creation failed - this->MocRunFailed = true; + success = false; } } - return mocGenerated; + return success; +} + +/** + * @brief Tests if the file name is in the skip list + */ +bool cmQtAutoGenerators::UicSkip(std::string const& absFilename) const +{ + if (this->UicEnabled()) { + // Test if the file name is on the skip list + if (!ListContains(this->UicSkipList, absFilename)) { + return false; + } + } + return true; +} + +bool cmQtAutoGenerators::UicParseContent(std::string const& absFilename, + std::string const& contentText) +{ + if (this->Verbose) { + this->LogInfo(cmQtAutoGen::UIC, "Checking: " + absFilename); + } + + std::vector includes; + // Extracte includes + { + const char* contentChars = contentText.c_str(); + if (strstr(contentChars, "ui_") != nullptr) { + while (this->UicRegExpInclude.find(contentChars)) { + includes.push_back(this->UicRegExpInclude.match(1)); + contentChars += this->UicRegExpInclude.end(); + } + } + } + + for (std::string const& includeString : includes) { + std::string uiInputFile; + if (!UicFindIncludedFile(uiInputFile, absFilename, includeString)) { + return false; + } + // Check if this file should be skipped + if (this->UicSkip(uiInputFile)) { + continue; + } + // Check if the job already exists + bool jobExists = false; + for (const auto& job : this->UicJobs) { + if ((job->SourceFile == uiInputFile) && + (job->IncludeString == includeString)) { + jobExists = true; + break; + } + } + if (!jobExists) { + auto job = cm::make_unique(); + job->SourceFile = uiInputFile; + job->BuildFileRel = this->AutogenIncludeDir; + job->BuildFileRel += includeString; + job->Includer = absFilename; + job->IncludeString = includeString; + this->UicJobs.push_back(std::move(job)); + } + } + + return true; } bool cmQtAutoGenerators::UicFindIncludedFile(std::string& absFile, - const std::string& sourceFile, - const std::string& searchPath, - const std::string& searchFile) + std::string const& sourceFile, + std::string const& includeString) { bool success = false; - std::vector testFiles; + std::string searchFile = + cmSystemTools::GetFilenameWithoutLastExtension(includeString).substr(3); + searchFile += ".ui"; // Collect search paths list + std::vector testFiles; { + std::string const searchPath = SubDirPrefix(includeString); + std::string searchFileFull; if (!searchPath.empty()) { searchFileFull = searchPath; @@ -1410,7 +1617,7 @@ bool cmQtAutoGenerators::UicFindIncludedFile(std::string& absFile, } // Vicinity of the source { - const std::string sourcePath = SubDirPrefix(sourceFile); + std::string const sourcePath = SubDirPrefix(sourceFile); testFiles.push_back(sourcePath + searchFile); if (!searchPath.empty()) { testFiles.push_back(sourcePath + searchFileFull); @@ -1440,76 +1647,75 @@ bool cmQtAutoGenerators::UicFindIncludedFile(std::string& absFile, // Log error if (!success) { - std::ostringstream ost; - ost << "Could not find " << cmQtAutoGen::Quoted(searchFile) << " in\n"; + std::string emsg = "Could not find "; + emsg += cmQtAutoGen::Quoted(searchFile); + emsg += " in\n"; for (std::string const& testFile : testFiles) { - ost << " " << cmQtAutoGen::Quoted(testFile) << "\n"; + emsg += " "; + emsg += cmQtAutoGen::Quoted(testFile); + emsg += "\n"; } - this->LogFileError(cmQtAutoGen::UIC, sourceFile, ost.str()); + this->LogFileError(cmQtAutoGen::UIC, sourceFile, emsg); } return success; } -bool cmQtAutoGenerators::UicGenerateAll( - const std::map>& uisIncluded) +bool cmQtAutoGenerators::UicGenerateAll() { if (!this->UicEnabled()) { return true; } - // single map with input / output names - std::map> sourceGenMap; + // Look for name collisions in included uic files { - // Collision lookup map - std::map testMap; - // Compile maps - for (auto const& sit : uisIncluded) { - const std::string& source(sit.first); - const std::vector& sourceIncs(sit.second); - // insert new source/destination map - std::map& uiGenMap = sourceGenMap[source]; - for (std::string const& inc : sourceIncs) { - // Remove ui_ from the begin filename by substr() - const std::string uiBasePath = SubDirPrefix(inc); - const std::string uiBaseName = - cmSystemTools::GetFilenameWithoutLastExtension(inc).substr(3); - const std::string uiFileName = uiBaseName + ".ui"; - std::string uiInputFile; - if (UicFindIncludedFile(uiInputFile, source, uiBasePath, uiFileName)) { - std::string uiOutputFile = uiBasePath; - uiOutputFile += "ui_"; - uiOutputFile += uiBaseName; - uiOutputFile += ".h"; - cmSystemTools::ReplaceString(uiOutputFile, "..", "__"); - uiGenMap[uiInputFile] = uiOutputFile; - testMap[uiInputFile] = uiOutputFile; - } else { - return false; - } + bool collision = false; + std::map> collisions; + for (auto const& job : this->UicJobs) { + auto& list = collisions[job->IncludeString]; + if (!list.empty()) { + collision = true; } - } - // look for name collisions - { - std::multimap collisions; - if (this->NameCollisionTest(testMap, collisions)) { - std::string msg = "The same ui_NAME.h file will be generated " - "from different sources.\n" - "To avoid this error rename the source files.\n"; - this->LogNameCollisionError(cmQtAutoGen::UIC, msg, collisions); - return false; + list.push_back(job.get()); + } + if (collision) { + std::string emsg = + "Included uic files with the same name will be " + "generated from different sources.\n" + "Consider to\n" + " - add a directory prefix to a \"ui_.h\" include " + "(e.g \"sub/ui_.h\")\n" + " - rename the .ui file(s) and adjust the \"ui_.h\" " + "include(s)\n" + "Include conflicts\n" + "-----------------\n"; + const auto& colls = collisions; + for (auto const& coll : colls) { + if (coll.second.size() > 1) { + emsg += cmQtAutoGen::Quoted(coll.first); + emsg += " included in\n"; + for (const UicJob* job : coll.second) { + emsg += " - "; + emsg += cmQtAutoGen::Quoted(job->Includer); + emsg += "\n"; + } + emsg += "would be generated from\n"; + for (const UicJob* job : coll.second) { + emsg += " - "; + emsg += cmQtAutoGen::Quoted(job->SourceFile); + emsg += "\n"; + } + } } + this->LogError(cmQtAutoGen::UIC, emsg); + return false; } } - // generate ui files - for (auto const& srcItem : sourceGenMap) { - for (auto const& item : srcItem.second) { - if (!this->UicGenerateFile(srcItem.first, item.first, item.second)) { - if (this->UicRunFailed) { - return false; - } - } + // Generate ui header files + for (const auto& item : this->UicJobs) { + if (!this->UicGenerateFile(*item)) { + return false; } } @@ -1517,27 +1723,24 @@ bool cmQtAutoGenerators::UicGenerateAll( } /** - * @return True if a uic file was created. False may indicate an error. + * @return True on success */ -bool cmQtAutoGenerators::UicGenerateFile(const std::string& realName, - const std::string& uiInputFile, - const std::string& uiOutputFile) +bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob) { - bool uicGenerated = false; - bool generateUic = this->UicSettingsChanged; + bool success = true; - const std::string uicFileRel = this->AutogenIncludeDir + uiOutputFile; - const std::string uicFileAbs = - cmSystemTools::CollapseCombinedPath(this->AutogenBuildDir, uicFileRel); + std::string const uicFileAbs = cmSystemTools::CollapseCombinedPath( + this->AutogenBuildDir, uicJob.BuildFileRel); + bool generateUic = this->UicSettingsChanged; if (!generateUic) { // Test if the source file is newer that the build file - generateUic = FileAbsentOrOlder(uicFileAbs, uiInputFile); + generateUic = FileAbsentOrOlder(uicFileAbs, uicJob.SourceFile); } if (generateUic) { // Log if (this->Verbose) { - this->LogBold("Generating UIC header " + uicFileRel); + this->LogBold("Generating UIC header " + uicJob.BuildFileRel); } // Make sure the parent directory exists @@ -1547,7 +1750,7 @@ bool cmQtAutoGenerators::UicGenerateFile(const std::string& realName, cmd.push_back(this->UicExecutable); { std::vector allOpts = this->UicTargetOptions; - auto optionIt = this->UicOptions.find(uiInputFile); + auto optionIt = this->UicOptions.find(uicJob.SourceFile); if (optionIt != this->UicOptions.end()) { cmQtAutoGen::UicMergeOptions(allOpts, optionIt->second, (this->QtMajorVersion == "5")); @@ -1556,31 +1759,29 @@ bool cmQtAutoGenerators::UicGenerateFile(const std::string& realName, } cmd.push_back("-o"); cmd.push_back(uicFileAbs); - cmd.push_back(uiInputFile); + cmd.push_back(uicJob.SourceFile); std::string output; if (this->RunCommand(cmd, output)) { // Success - uicGenerated = true; } else { // Command failed { - std::ostringstream ost; - ost << "uic failed for\n" - << " " << cmQtAutoGen::Quoted(uiInputFile) << "\n" - << "needed by\n" - << " " << cmQtAutoGen::Quoted(realName); - this->LogCommandError(cmQtAutoGen::UIC, ost.str(), cmd, output); + std::string emsg = "uic failed for\n "; + emsg += cmQtAutoGen::Quoted(uicJob.SourceFile); + emsg += "\nincluded by\n "; + emsg += cmQtAutoGen::Quoted(uicJob.Includer); + this->LogCommandError(cmQtAutoGen::UIC, emsg, cmd, output); } cmSystemTools::RemoveFile(uicFileAbs); - this->UicRunFailed = true; + success = false; } } else { // Parent directory creation failed - this->UicRunFailed = true; + success = false; } } - return uicGenerated; + return success; } bool cmQtAutoGenerators::RccGenerateAll() @@ -1589,24 +1790,22 @@ bool cmQtAutoGenerators::RccGenerateAll() return true; } - // Generate qrc files - for (RccJob const& rccJob : this->RccJobs) { + // Generate rcc files + for (const RccJob& rccJob : this->RccJobs) { if (!this->RccGenerateFile(rccJob)) { - if (this->RccRunFailed) { - return false; - } + return false; } } return true; } /** - * @return True if a rcc file was created. False may indicate an error. + * @return True on success */ bool cmQtAutoGenerators::RccGenerateFile(const RccJob& rccJob) { + bool success = true; bool rccGenerated = false; - bool generateRcc = this->RccSettingsChanged; std::string rccFileAbs; if (this->ConfigSuffix.empty()) { @@ -1618,37 +1817,37 @@ bool cmQtAutoGenerators::RccGenerateFile(const RccJob& rccJob) rccFileAbs += this->ConfigSuffix; rccFileAbs += cmSystemTools::GetFilenameLastExtension(rccJob.RccFile); } - const std::string rccFileRel = cmSystemTools::RelativePath( + std::string const rccFileRel = cmSystemTools::RelativePath( this->AutogenBuildDir.c_str(), rccFileAbs.c_str()); // Check if regeneration is required + bool generateRcc = this->RccSettingsChanged; if (!generateRcc) { // Test if the resources list file is newer than build file generateRcc = FileAbsentOrOlder(rccFileAbs, rccJob.QrcFile); - if (!generateRcc) { - // Acquire input file list - std::vector readFiles; - const std::vector* files = &rccJob.Inputs; - if (files->empty()) { - // Read input file list from qrc file - std::string error; - if (cmQtAutoGen::RccListInputs(this->QtMajorVersion, - this->RccExecutable, rccJob.QrcFile, - readFiles, &error)) { - files = &readFiles; - } else { - files = nullptr; - this->LogFileError(cmQtAutoGen::RCC, rccJob.QrcFile, error); - this->RccRunFailed = true; - } + } + if (!generateRcc) { + // Acquire input file list + std::vector readFiles; + std::vector const* files = &rccJob.Inputs; + if (rccJob.Inputs.empty()) { + // Read input file list from qrc file + std::string error; + if (cmQtAutoGen::RccListInputs(this->QtMajorVersion, this->RccExecutable, + rccJob.QrcFile, readFiles, &error)) { + files = &readFiles; + } else { + files = nullptr; + this->LogFileError(cmQtAutoGen::RCC, rccJob.QrcFile, error); + success = false; } - // Test if any input file is newer than the build file - if (files != nullptr) { - for (std::string const& file : *files) { - if (FileAbsentOrOlder(rccFileAbs, file)) { - generateRcc = true; - break; - } + } + // Test if any input file is newer than the build file + if (files != nullptr) { + for (std::string const& file : *files) { + if (FileAbsentOrOlder(rccFileAbs, file)) { + generateRcc = true; + break; } } } @@ -1675,22 +1874,24 @@ bool cmQtAutoGenerators::RccGenerateFile(const RccJob& rccJob) // Success rccGenerated = true; } else { - this->LogCommandError(cmQtAutoGen::RCC, "rcc failed for\n " + - cmQtAutoGen::Quoted(rccJob.QrcFile), - cmd, output); + { + std::string emsg = "rcc failed for\n "; + emsg += cmQtAutoGen::Quoted(rccJob.QrcFile); + this->LogCommandError(cmQtAutoGen::RCC, emsg, cmd, output); + } cmSystemTools::RemoveFile(rccFileAbs); - this->RccRunFailed = true; + success = false; } } else { // Parent directory creation failed - this->RccRunFailed = true; + success = false; } } // For a multi configuration generator generate a wrapper file - if (!this->ConfigSuffix.empty() && !this->RccRunFailed) { + if (success && !this->ConfigSuffix.empty()) { // Wrapper file name - const std::string& wrapperFileAbs = rccJob.RccFile; - const std::string wrapperFileRel = cmSystemTools::RelativePath( + std::string const& wrapperFileAbs = rccJob.RccFile; + std::string const wrapperFileRel = cmSystemTools::RelativePath( this->AutogenBuildDir.c_str(), wrapperFileAbs.c_str()); // Wrapper file content std::string content = "// This is an autogenerated configuration " @@ -1705,9 +1906,9 @@ bool cmQtAutoGenerators::RccGenerateFile(const RccJob& rccJob) this->LogBold("Generating RCC wrapper " + wrapperFileRel); } if (!this->FileWrite(cmQtAutoGen::RCC, wrapperFileAbs, content)) { - // Error - rccGenerated = false; - this->RccRunFailed = true; + this->LogFileError(cmQtAutoGen::RCC, wrapperFileAbs, + "rcc wrapper file writing failed"); + success = false; } } else if (rccGenerated) { // Only touch wrapper file if the content matches @@ -1719,10 +1920,10 @@ bool cmQtAutoGenerators::RccGenerateFile(const RccJob& rccJob) } } - return rccGenerated; + return success; } -void cmQtAutoGenerators::LogBold(const std::string& message) const +void cmQtAutoGenerators::LogBold(std::string const& message) const { cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue | cmsysTerminal_Color_ForegroundBold, @@ -1730,7 +1931,7 @@ void cmQtAutoGenerators::LogBold(const std::string& message) const } void cmQtAutoGenerators::LogInfo(cmQtAutoGen::GeneratorType genType, - const std::string& message) const + std::string const& message) const { std::string msg = cmQtAutoGen::GeneratorName(genType); msg += ": "; @@ -1742,7 +1943,7 @@ void cmQtAutoGenerators::LogInfo(cmQtAutoGen::GeneratorType genType, } void cmQtAutoGenerators::LogWarning(cmQtAutoGen::GeneratorType genType, - const std::string& message) const + std::string const& message) const { std::string msg = cmQtAutoGen::GeneratorName(genType); msg += " warning:"; @@ -1758,182 +1959,102 @@ void cmQtAutoGenerators::LogWarning(cmQtAutoGen::GeneratorType genType, if (msg.back() != '\n') { msg.push_back('\n'); } - msg += "\n"; + msg.push_back('\n'); cmSystemTools::Stdout(msg.c_str(), msg.size()); } void cmQtAutoGenerators::LogFileWarning(cmQtAutoGen::GeneratorType genType, - const std::string& filename, - const std::string& message) const + std::string const& filename, + std::string const& message) const { - std::string emsg = " "; - emsg += cmQtAutoGen::Quoted(filename); - emsg += "\n"; + std::string msg = " "; + msg += cmQtAutoGen::Quoted(filename); + msg.push_back('\n'); // Message - emsg += message; - this->LogWarning(genType, emsg); + msg += message; + this->LogWarning(genType, msg); } void cmQtAutoGenerators::LogError(cmQtAutoGen::GeneratorType genType, - const std::string& message) const + std::string const& message) const { std::string msg; msg.push_back('\n'); - msg = cmQtAutoGen::GeneratorName(genType); - msg += " error:"; - if (message.find('\n') == std::string::npos) { - // Single line message - msg.push_back(' '); - } else { - // Multi line message - msg.push_back('\n'); - } + msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " error"); // Message msg += message; if (msg.back() != '\n') { msg.push_back('\n'); } - msg += "\n"; + msg.push_back('\n'); cmSystemTools::Stderr(msg.c_str(), msg.size()); } void cmQtAutoGenerators::LogFileError(cmQtAutoGen::GeneratorType genType, - const std::string& filename, - const std::string& message) const + std::string const& filename, + std::string const& message) const { std::string emsg = " "; emsg += cmQtAutoGen::Quoted(filename); - emsg += "\n"; + emsg += '\n'; // Message emsg += message; this->LogError(genType, emsg); } -void cmQtAutoGenerators::LogNameCollisionError( - cmQtAutoGen::GeneratorType genType, const std::string& message, - const std::multimap& collisions) const -{ - std::string emsg; - // Add message - if (!message.empty()) { - emsg += message; - if (emsg.back() != '\n') { - emsg.push_back('\n'); - } - } - // Append collision list - for (auto const& item : collisions) { - emsg += " "; - emsg += item.first; - emsg += " -> "; - emsg += item.second; - emsg += "\n"; - } - this->LogError(genType, emsg); -} - void cmQtAutoGenerators::LogCommandError( - cmQtAutoGen::GeneratorType genType, const std::string& message, - const std::vector& command, const std::string& output) const + cmQtAutoGen::GeneratorType genType, std::string const& message, + std::vector const& command, std::string const& output) const { std::string msg; msg.push_back('\n'); - msg += cmQtAutoGen::GeneratorName(genType); - msg += " subprocess error: "; + msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " subprocess error"); msg += message; if (msg.back() != '\n') { msg.push_back('\n'); } msg.push_back('\n'); - msg += "Command\n"; - msg += "-------\n"; + msg += HeadLine("Command"); msg += QuotedCommand(command); if (msg.back() != '\n') { msg.push_back('\n'); } msg.push_back('\n'); - msg += "Output\n"; - msg += "------\n"; + msg += HeadLine("Output"); msg += output; if (msg.back() != '\n') { msg.push_back('\n'); } - msg += "\n"; + msg.push_back('\n'); cmSystemTools::Stderr(msg.c_str(), msg.size()); } /** - * @brief Collects name collisions as output/input pairs - * @return True if there were collisions - */ -bool cmQtAutoGenerators::NameCollisionTest( - const std::map& genFiles, - std::multimap& collisions) const -{ - typedef std::map::const_iterator Iter; - typedef std::map::value_type VType; - for (Iter ait = genFiles.begin(); ait != genFiles.end(); ++ait) { - bool first_match(true); - for (Iter bit = (++Iter(ait)); bit != genFiles.end(); ++bit) { - if (ait->second == bit->second) { - if (first_match) { - if (collisions.find(ait->second) != collisions.end()) { - // We already know of this collision from before - break; - } - collisions.insert(VType(ait->second, ait->first)); - first_match = false; - } - collisions.insert(VType(bit->second, bit->first)); - } - } - } - - return !collisions.empty(); -} - -/** - * @brief Generates a file path based on the checksum of the source file path - * @return The path - */ -std::string cmQtAutoGenerators::ChecksumedPath( - const std::string& sourceFile, const std::string& basePrefix, - const std::string& baseSuffix) const -{ - std::string res = FPathChecksum.getPart(sourceFile); - res += "/"; - res += basePrefix; - res += cmSystemTools::GetFilenameWithoutLastExtension(sourceFile); - res += baseSuffix; - return res; -} - -/** * @brief Generates the parent directory of the given file on demand * @return True on success */ bool cmQtAutoGenerators::MakeParentDirectory( - cmQtAutoGen::GeneratorType genType, const std::string& filename) const + cmQtAutoGen::GeneratorType genType, std::string const& filename) const { bool success = true; - const std::string dirName = cmSystemTools::GetFilenamePath(filename); + std::string const dirName = cmSystemTools::GetFilenamePath(filename); if (!dirName.empty()) { - success = cmSystemTools::MakeDirectory(dirName); - if (!success) { + if (!cmSystemTools::MakeDirectory(dirName)) { this->LogFileError(genType, filename, "Could not create parent directory"); + success = false; } } return success; } -bool cmQtAutoGenerators::FileDiffers(const std::string& filename, - const std::string& content) +bool cmQtAutoGenerators::FileDiffers(std::string const& filename, + std::string const& content) { bool differs = true; { std::string oldContents; - if (ReadAll(oldContents, filename)) { + if (ReadFile(oldContents, filename)) { differs = (oldContents != content); } } @@ -1941,14 +2062,15 @@ bool cmQtAutoGenerators::FileDiffers(const std::string& filename, } bool cmQtAutoGenerators::FileWrite(cmQtAutoGen::GeneratorType genType, - const std::string& filename, - const std::string& content) + std::string const& filename, + std::string const& content) { std::string error; // Make sure the parent directory exists if (this->MakeParentDirectory(genType, filename)) { cmsys::ofstream outfile; - outfile.open(filename.c_str(), std::ios::trunc); + outfile.open(filename.c_str(), + (std::ios::out | std::ios::binary | std::ios::trunc)); if (outfile) { outfile << content; // Check for write errors @@ -1970,7 +2092,7 @@ bool cmQtAutoGenerators::FileWrite(cmQtAutoGen::GeneratorType genType, * @brief Runs a command and returns true on success * @return True on success */ -bool cmQtAutoGenerators::RunCommand(const std::vector& command, +bool cmQtAutoGenerators::RunCommand(std::vector const& command, std::string& output) const { // Log command @@ -1992,7 +2114,7 @@ bool cmQtAutoGenerators::RunCommand(const std::vector& command, * @return True on success */ bool cmQtAutoGenerators::FindHeader(std::string& header, - const std::string& testBasePath) const + std::string const& testBasePath) const { for (std::string const& ext : this->HeaderExtensions) { std::string testFilePath(testBasePath); @@ -2005,56 +2127,3 @@ bool cmQtAutoGenerators::FindHeader(std::string& header, } return false; } - -std::string cmQtAutoGenerators::MocFindHeader( - const std::string& sourcePath, const std::string& includeBase) const -{ - std::string header; - // Search in vicinity of the source - if (!this->FindHeader(header, sourcePath + includeBase)) { - // Search in include directories - for (std::string const& path : this->MocIncludePaths) { - std::string fullPath = path; - fullPath.push_back('/'); - fullPath += includeBase; - if (FindHeader(header, fullPath)) { - break; - } - } - } - // Sanitize - if (!header.empty()) { - header = cmSystemTools::GetRealPath(header); - } - return header; -} - -bool cmQtAutoGenerators::MocFindIncludedFile( - std::string& absFile, const std::string& sourcePath, - const std::string& includeString) const -{ - bool success = false; - // Search in vicinity of the source - { - std::string testPath = sourcePath; - testPath += includeString; - if (cmSystemTools::FileExists(testPath.c_str())) { - absFile = cmSystemTools::GetRealPath(testPath); - success = true; - } - } - // Search in include directories - if (!success) { - for (std::string const& path : this->MocIncludePaths) { - std::string fullPath = path; - fullPath.push_back('/'); - fullPath += includeString; - if (cmSystemTools::FileExists(fullPath.c_str())) { - absFile = cmSystemTools::GetRealPath(fullPath); - success = true; - break; - } - } - } - return success; -} diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 5d3ad74..aeffbb1 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -10,6 +10,7 @@ #include "cmsys/RegularExpression.hxx" #include +#include // IWYU pragma: keep #include #include #include @@ -21,7 +22,7 @@ class cmQtAutoGenerators CM_DISABLE_COPY(cmQtAutoGenerators) public: cmQtAutoGenerators(); - bool Run(const std::string& targetDirectory, const std::string& config); + bool Run(std::string const& targetDirectory, std::string const& config); private: // -- Types @@ -37,7 +38,7 @@ private: { } - KeyRegExp(const std::string& key, const std::string& regExp) + KeyRegExp(std::string const& key, std::string const& regExp) : Key(key) , RegExp(regExp) { @@ -47,6 +48,38 @@ private: cmsys::RegularExpression RegExp; }; + /// @brief Source file job + struct SourceJob + { + bool Moc = false; + bool Uic = false; + }; + + /// @brief MOC job + struct MocJobAuto + { + std::string SourceFile; + std::string BuildFileRel; + std::set Depends; + }; + + /// @brief MOC job + struct MocJobIncluded : MocJobAuto + { + bool DependsValid = false; + std::string Includer; + std::string IncludeString; + }; + + /// @brief UIC job + struct UicJob + { + std::string SourceFile; + std::string BuildFileRel; + std::string Includer; + std::string IncludeString; + }; + /// @brief RCC job struct RccJob { @@ -56,149 +89,110 @@ private: std::vector Inputs; }; - // -- Configuration - bool MocDependFilterPush(const std::string& key, const std::string& regExp); - bool ReadAutogenInfoFile(cmMakefile* makefile, - const std::string& targetDirectory, - const std::string& config); - - bool MocEnabled() const { return !this->MocExecutable.empty(); } - bool UicEnabled() const { return !this->UicExecutable.empty(); } - bool RccEnabled() const { return !this->RccExecutable.empty(); } + // -- Initialization + bool InitInfoFile(cmMakefile* makefile, std::string const& targetDirectory, + std::string const& config); // -- Settings file void SettingsFileRead(cmMakefile* makefile); bool SettingsFileWrite(); - - bool AnySettingsChanged() const + bool SettingsChanged() const { return (this->MocSettingsChanged || this->RccSettingsChanged || this->UicSettingsChanged); } - // -- Init and run - void Init(cmMakefile* makefile); - bool RunAutogen(); - - // -- Content analysis - bool MocRequired(const std::string& contentText, - std::string* macroName = nullptr); - void MocFindDepends( - const std::string& absFilename, const std::string& contentText, - std::map>& mocDepends); - - bool MocSkip(const std::string& absFilename) const; - bool UicSkip(const std::string& absFilename) const; - - bool ParseSourceFile( - const std::string& absFilename, - std::map& mocsIncluded, - std::map>& mocDepends, - std::map>& includedUis, - bool relaxed); - - void SearchHeadersForSourceFile(const std::string& absFilename, - std::set& mocHeaderFiles, - std::set& uicHeaderFiles) const; - - bool ParseHeaders( - const std::set& mocHeaderFiles, - const std::set& uicHeaderFiles, - const std::map& mocsIncluded, - std::map& mocsNotIncluded, - std::map>& mocDepends, - std::map>& includedUis); - - void UicParseContent( - const std::string& fileName, const std::string& contentText, - std::map>& includedUis); - - std::string MocMacroNamesString() const; - std::string MocHeaderSuffixesString() const; - - bool MocParseSourceContent( - const std::string& absFilename, const std::string& contentText, - std::map& mocsIncluded, - std::map>& mocDepends, bool relaxed); + // -- Central processing + bool Process(); - void MocParseHeaderContent( - const std::string& absFilename, const std::string& contentText, - std::map& mocsNotIncluded, - std::map>& mocDepends); + // -- Source parsing + bool ParseSourceFile(std::string const& absFilename, const SourceJob& job); + bool ParseHeaderFile(std::string const& absFilename, const SourceJob& job); + bool ParsePostprocess(); - // -- Moc file generation - bool MocGenerateAll( - const std::map& mocsIncluded, - const std::map& mocsNotIncluded, - const std::map>& mocDepends); - bool MocGenerateFile( - const std::string& sourceFile, const std::string& mocFileName, - const std::map>& mocDepends, - bool included); + // -- Moc + bool MocEnabled() const { return !this->MocExecutable.empty(); } + bool MocSkip(std::string const& absFilename) const; + bool MocRequired(std::string const& contentText, + std::string* macroName = nullptr); + // Moc strings + std::string MocStringMacros() const; + std::string MocStringHeaders(std::string const& fileBase) const; + std::string MocFindIncludedHeader(std::string const& sourcePath, + std::string const& includeBase) const; + bool MocFindIncludedFile(std::string& absFile, std::string const& sourceFile, + std::string const& includeString) const; + // Moc depends + bool MocDependFilterPush(std::string const& key, std::string const& regExp); + void MocFindDepends(std::string const& absFilename, + std::string const& contentText, + std::set& depends); + // Moc + bool MocParseSourceContent(std::string const& absFilename, + std::string const& contentText); + void MocParseHeaderContent(std::string const& absFilename, + std::string const& contentText); + + bool MocGenerateAll(); + bool MocGenerateFile(const MocJobAuto& job, bool* generated = nullptr); - // -- Uic file generation - bool UicFindIncludedFile(std::string& absFile, const std::string& sourceFile, - const std::string& searchPath, - const std::string& searchFile); - bool UicGenerateAll( - const std::map>& includedUis); - bool UicGenerateFile(const std::string& realName, - const std::string& uiInputFile, - const std::string& uiOutputFile); + // -- Uic + bool UicEnabled() const { return !this->UicExecutable.empty(); } + bool UicSkip(std::string const& absFilename) const; + bool UicParseContent(std::string const& fileName, + std::string const& contentText); + bool UicFindIncludedFile(std::string& absFile, std::string const& sourceFile, + std::string const& includeString); + bool UicGenerateAll(); + bool UicGenerateFile(const UicJob& uicJob); - // -- Rcc file generation + // -- Rcc + bool RccEnabled() const { return !this->RccExecutable.empty(); } bool RccGenerateAll(); bool RccGenerateFile(const RccJob& rccJob); // -- Log info - void LogBold(const std::string& message) const; + void LogBold(std::string const& message) const; void LogInfo(cmQtAutoGen::GeneratorType genType, - const std::string& message) const; + std::string const& message) const; // -- Log warning void LogWarning(cmQtAutoGen::GeneratorType genType, - const std::string& message) const; + std::string const& message) const; void LogFileWarning(cmQtAutoGen::GeneratorType genType, - const std::string& filename, - const std::string& message) const; + std::string const& filename, + std::string const& message) const; // -- Log error void LogError(cmQtAutoGen::GeneratorType genType, - const std::string& message) const; + std::string const& message) const; void LogFileError(cmQtAutoGen::GeneratorType genType, - const std::string& filename, - const std::string& message) const; + std::string const& filename, + std::string const& message) const; void LogCommandError(cmQtAutoGen::GeneratorType genType, - const std::string& message, - const std::vector& command, - const std::string& output) const; - void LogNameCollisionError( - cmQtAutoGen::GeneratorType genType, const std::string& message, - const std::multimap& collisions) const; + std::string const& message, + std::vector const& command, + std::string const& output) const; // -- Utility - bool NameCollisionTest( - const std::map& genFiles, - std::multimap& collisions) const; - std::string ChecksumedPath(const std::string& sourceFile, - const std::string& basePrefix, - const std::string& baseSuffix) const; bool MakeParentDirectory(cmQtAutoGen::GeneratorType genType, - const std::string& filename) const; - bool FileDiffers(const std::string& filename, const std::string& content); + std::string const& filename) const; + bool FileDiffers(std::string const& filename, std::string const& content); bool FileWrite(cmQtAutoGen::GeneratorType genType, - const std::string& filename, const std::string& content); - - bool RunCommand(const std::vector& command, + std::string const& filename, std::string const& content); + bool FindHeader(std::string& header, std::string const& testBasePath) const; + bool RunCommand(std::vector const& command, std::string& output) const; - bool FindHeader(std::string& header, const std::string& testBasePath) const; - - std::string MocFindHeader(const std::string& sourcePath, - const std::string& includeBase) const; - bool MocFindIncludedFile(std::string& absFile, const std::string& sourceFile, - const std::string& includeString) const; - // -- Meta std::string ConfigSuffix; + std::string InfoFile; + // -- Settings + bool IncludeProjectDirsBefore; + bool Verbose; + bool ColorOutput; + std::string SettingsFile; + std::string SettingsStringMoc; + std::string SettingsStringUic; + std::string SettingsStringRcc; // -- Directories std::string ProjectSourceDir; std::string ProjectBinaryDir; @@ -213,23 +207,14 @@ private: std::string UicExecutable; std::string RccExecutable; // -- File lists - std::vector Sources; - std::vector Headers; + std::map HeaderJobs; + std::map SourceJobs; std::vector HeaderExtensions; - cmFilePathChecksum FPathChecksum; - // -- Settings - bool IncludeProjectDirsBefore; - bool Verbose; - bool ColorOutput; - std::string SettingsFile; - std::string SettingsStringMoc; - std::string SettingsStringUic; - std::string SettingsStringRcc; + cmFilePathChecksum FilePathChecksum; // -- Moc bool MocSettingsChanged; bool MocPredefsChanged; bool MocRelaxedMode; - bool MocRunFailed; std::string MocCompFileRel; std::string MocCompFileAbs; std::string MocPredefsFileRel; @@ -239,21 +224,23 @@ private: std::vector MocIncludes; std::vector MocDefinitions; std::vector MocOptions; + std::vector MocAllOptions; std::vector MocPredefsCmd; std::vector MocDependFilters; std::vector MocMacroFilters; cmsys::RegularExpression MocRegExpInclude; + std::vector> MocJobsIncluded; + std::vector> MocJobsAuto; // -- Uic bool UicSettingsChanged; - bool UicRunFailed; std::vector UicSkipList; std::vector UicTargetOptions; std::map> UicOptions; std::vector UicSearchPaths; cmsys::RegularExpression UicRegExpInclude; + std::vector> UicJobs; // -- Rcc bool RccSettingsChanged; - bool RccRunFailed; std::vector RccJobs; }; -- cgit v0.12 From 8bee55bce1ea814ed598516eee7f4e0e2adf8747 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Thu, 14 Sep 2017 20:12:22 +0200 Subject: Autogen: In VERBOSE mode print why files are (re)generated --- Source/cmQtAutoGenerators.cxx | 263 +++++++++++++++++++++++++++++++++++------- Source/cmQtAutoGenerators.h | 2 +- 2 files changed, 221 insertions(+), 44 deletions(-) diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 8453198..e8a9006 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -100,16 +100,26 @@ static bool ReadFile(std::string& content, std::string const& filename, } /** - * @brief Tests if buildFile doesn't exist or is older than sourceFile - * @return True if buildFile doesn't exist or is older than sourceFile + * @brief Tests if buildFile is older than sourceFile + * @return True if buildFile is older than sourceFile. + * False may indicate an error. */ -static bool FileAbsentOrOlder(std::string const& buildFile, - std::string const& sourceFile) +static bool FileIsOlderThan(std::string const& buildFile, + std::string const& sourceFile, + std::string* error = nullptr) { int result = 0; - bool success = - cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result); - return (!success || (result < 0)); + if (cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result)) { + return (result < 0); + } + if (error != nullptr) { + error->append( + "File modification time comparison failed for the files\n "); + error->append(cmQtAutoGen::Quoted(buildFile)); + error->append("\nand\n "); + error->append(cmQtAutoGen::Quoted(sourceFile)); + } + return false; } static bool ListContains(std::vector const& list, @@ -1401,6 +1411,14 @@ bool cmQtAutoGenerators::MocGenerateAll() cmSystemTools::Touch(this->MocPredefsFileAbs, false); } } + + // Add moc_predefs.h to moc file dependecies + for (auto const& item : this->MocJobsIncluded) { + item->Depends.insert(this->MocPredefsFileAbs); + } + for (auto const& item : this->MocJobsAuto) { + item->Depends.insert(this->MocPredefsFileAbs); + } } // Generate moc files that are included by source files. @@ -1458,36 +1476,92 @@ bool cmQtAutoGenerators::MocGenerateAll() /** * @return True on success */ -bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& job, +bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& mocJob, bool* generated) { bool success = true; std::string const mocFileAbs = cmSystemTools::CollapseCombinedPath( - this->AutogenBuildDir, job.BuildFileRel); + this->AutogenBuildDir, mocJob.BuildFileRel); - bool generateMoc = (this->MocSettingsChanged || this->MocPredefsChanged); - if (!generateMoc) { - // Test if the source file is newer that the build file - generateMoc = FileAbsentOrOlder(mocFileAbs, job.SourceFile); + bool generate = false; + std::string generateReason; + if (!generate && !cmSystemTools::FileExists(mocFileAbs.c_str())) { + if (this->Verbose) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(mocFileAbs); + generateReason += " from its source file "; + generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile); + generateReason += " because it doesn't exist"; + } + generate = true; } - if (!generateMoc && !this->MocPredefsFileAbs.empty()) { - // Check if moc_predefs is newer - generateMoc = FileAbsentOrOlder(mocFileAbs, this->MocPredefsFileAbs); + if (!generate && this->MocSettingsChanged) { + if (this->Verbose) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(mocFileAbs); + generateReason += " from "; + generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile); + generateReason += " because the MOC settings changed"; + } + generate = true; + } + if (!generate && this->MocPredefsChanged) { + if (this->Verbose) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(mocFileAbs); + generateReason += " from "; + generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile); + generateReason += " because moc_predefs.h changed"; + } + generate = true; } - if (!generateMoc) { + if (!generate) { + std::string error; + if (FileIsOlderThan(mocFileAbs, mocJob.SourceFile, &error)) { + if (this->Verbose) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(mocFileAbs); + generateReason += " because it's older than its source file "; + generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile); + } + generate = true; + } else { + if (!error.empty()) { + this->LogError(cmQtAutoGen::MOC, error); + success = false; + } + } + } + if (success && !generate) { // Test if a dependency file is newer - for (std::string const& depFile : job.Depends) { - if (FileAbsentOrOlder(mocFileAbs, depFile)) { - generateMoc = true; + std::string error; + for (std::string const& depFile : mocJob.Depends) { + if (FileIsOlderThan(mocFileAbs, depFile, &error)) { + if (this->Verbose) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(mocFileAbs); + generateReason += " from "; + generateReason += cmQtAutoGen::Quoted(mocJob.SourceFile); + generateReason += " because it is older than "; + generateReason += cmQtAutoGen::Quoted(depFile); + } + generate = true; + break; + } + if (!error.empty()) { + this->LogError(cmQtAutoGen::MOC, error); + success = false; break; } } } - if (generateMoc) { + + if (generate) { // Log if (this->Verbose) { - this->LogBold("Generating MOC source " + job.BuildFileRel); + this->LogBold("Generating MOC source " + mocJob.BuildFileRel); + this->LogInfo(cmQtAutoGen::MOC, generateReason); } // Make sure the parent directory exists @@ -1505,7 +1579,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& job, } cmd.push_back("-o"); cmd.push_back(mocFileAbs); - cmd.push_back(job.SourceFile); + cmd.push_back(mocJob.SourceFile); // Execute moc command std::string output; @@ -1518,7 +1592,7 @@ bool cmQtAutoGenerators::MocGenerateFile(const MocJobAuto& job, // Moc command failed { std::string emsg = "moc failed for\n "; - emsg += cmQtAutoGen::Quoted(job.SourceFile); + emsg += cmQtAutoGen::Quoted(mocJob.SourceFile); this->LogCommandError(cmQtAutoGen::MOC, emsg, cmd, output); } cmSystemTools::RemoveFile(mocFileAbs); @@ -1732,15 +1806,50 @@ bool cmQtAutoGenerators::UicGenerateFile(const UicJob& uicJob) std::string const uicFileAbs = cmSystemTools::CollapseCombinedPath( this->AutogenBuildDir, uicJob.BuildFileRel); - bool generateUic = this->UicSettingsChanged; - if (!generateUic) { - // Test if the source file is newer that the build file - generateUic = FileAbsentOrOlder(uicFileAbs, uicJob.SourceFile); + bool generate = false; + std::string generateReason; + if (!generate && !cmSystemTools::FileExists(uicFileAbs.c_str())) { + if (this->Verbose) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(uicFileAbs); + generateReason += " from its source file "; + generateReason += cmQtAutoGen::Quoted(uicJob.SourceFile); + generateReason += " because it doesn't exist"; + } + generate = true; + } + if (!generate && this->UicSettingsChanged) { + if (this->Verbose) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(uicFileAbs); + generateReason += " from "; + generateReason += cmQtAutoGen::Quoted(uicJob.SourceFile); + generateReason += " because the UIC settings changed"; + } + generate = true; } - if (generateUic) { + if (!generate) { + std::string error; + if (FileIsOlderThan(uicFileAbs, uicJob.SourceFile, &error)) { + if (this->Verbose) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(uicFileAbs); + generateReason += " because it's older than its source file "; + generateReason += cmQtAutoGen::Quoted(uicJob.SourceFile); + } + generate = true; + } else { + if (!error.empty()) { + this->LogError(cmQtAutoGen::UIC, error); + success = false; + } + } + } + if (generate) { // Log if (this->Verbose) { this->LogBold("Generating UIC header " + uicJob.BuildFileRel); + this->LogInfo(cmQtAutoGen::UIC, generateReason); } // Make sure the parent directory exists @@ -1821,42 +1930,110 @@ bool cmQtAutoGenerators::RccGenerateFile(const RccJob& rccJob) this->AutogenBuildDir.c_str(), rccFileAbs.c_str()); // Check if regeneration is required - bool generateRcc = this->RccSettingsChanged; - if (!generateRcc) { - // Test if the resources list file is newer than build file - generateRcc = FileAbsentOrOlder(rccFileAbs, rccJob.QrcFile); + bool generate = false; + std::string generateReason; + if (!cmSystemTools::FileExists(rccJob.QrcFile)) { + { + std::string error = "Could not find the file\n "; + error += cmQtAutoGen::Quoted(rccJob.QrcFile); + this->LogError(cmQtAutoGen::RCC, error); + } + success = false; + } + if (success && !generate && !cmSystemTools::FileExists(rccFileAbs.c_str())) { + if (this->Verbose) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(rccFileAbs); + generateReason += " from its source file "; + generateReason += cmQtAutoGen::Quoted(rccJob.QrcFile); + generateReason += " because it doesn't exist"; + } + generate = true; } - if (!generateRcc) { + if (success && !generate && this->RccSettingsChanged) { + if (this->Verbose) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(rccFileAbs); + generateReason += " from "; + generateReason += cmQtAutoGen::Quoted(rccJob.QrcFile); + generateReason += " because the RCC settings changed"; + } + generate = true; + } + if (success && !generate) { + std::string error; + if (FileIsOlderThan(rccFileAbs, rccJob.QrcFile, &error)) { + if (this->Verbose) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(rccFileAbs); + generateReason += " because it is older than "; + generateReason += cmQtAutoGen::Quoted(rccJob.QrcFile); + } + generate = true; + } else { + if (!error.empty()) { + this->LogError(cmQtAutoGen::RCC, error); + success = false; + } + } + } + if (success && !generate) { // Acquire input file list std::vector readFiles; - std::vector const* files = &rccJob.Inputs; - if (rccJob.Inputs.empty()) { + std::vector const* files = nullptr; + if (!rccJob.Inputs.empty()) { + files = &rccJob.Inputs; + } else { // Read input file list from qrc file std::string error; if (cmQtAutoGen::RccListInputs(this->QtMajorVersion, this->RccExecutable, rccJob.QrcFile, readFiles, &error)) { files = &readFiles; } else { - files = nullptr; this->LogFileError(cmQtAutoGen::RCC, rccJob.QrcFile, error); success = false; } } // Test if any input file is newer than the build file if (files != nullptr) { - for (std::string const& file : *files) { - if (FileAbsentOrOlder(rccFileAbs, file)) { - generateRcc = true; + std::string error; + for (std::string const& resFile : *files) { + if (!cmSystemTools::FileExists(resFile.c_str())) { + error = "Could not find the file\n "; + error += cmQtAutoGen::Quoted(resFile); + error += "\nwhich is listed in\n "; + error += cmQtAutoGen::Quoted(rccJob.QrcFile); break; } + if (FileIsOlderThan(rccFileAbs, resFile, &error)) { + if (this->Verbose) { + generateReason = "Generating "; + generateReason += cmQtAutoGen::Quoted(rccFileAbs); + generateReason += " from "; + generateReason += cmQtAutoGen::Quoted(rccJob.QrcFile); + generateReason += " because it is older than "; + generateReason += cmQtAutoGen::Quoted(resFile); + } + generate = true; + break; + } + if (!error.empty()) { + break; + } + } + // Print error + if (!error.empty()) { + this->LogError(cmQtAutoGen::RCC, error); + success = false; } } } // Regenerate on demand - if (generateRcc) { + if (generate) { // Log if (this->Verbose) { this->LogBold("Generating RCC source " + rccFileRel); + this->LogInfo(cmQtAutoGen::RCC, generateReason); } // Make sure the parent directory exists @@ -1901,7 +2078,7 @@ bool cmQtAutoGenerators::RccGenerateFile(const RccJob& rccJob) content += "\"\n"; // Write content to file if (this->FileDiffers(wrapperFileAbs, content)) { - // Write new wrapper file if the content differs + // Write new wrapper file if (this->Verbose) { this->LogBold("Generating RCC wrapper " + wrapperFileRel); } @@ -1911,7 +2088,7 @@ bool cmQtAutoGenerators::RccGenerateFile(const RccJob& rccJob) success = false; } } else if (rccGenerated) { - // Only touch wrapper file if the content matches + // Just touch the wrapper file if (this->Verbose) { this->LogInfo(cmQtAutoGen::RCC, "Touching RCC wrapper " + wrapperFileRel); diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index aeffbb1..0b502de 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -134,7 +134,7 @@ private: std::string const& contentText); bool MocGenerateAll(); - bool MocGenerateFile(const MocJobAuto& job, bool* generated = nullptr); + bool MocGenerateFile(const MocJobAuto& mocJob, bool* generated = nullptr); // -- Uic bool UicEnabled() const { return !this->UicExecutable.empty(); } -- cgit v0.12 From 3f2237433991764479362c3f530201a0305a64d6 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Thu, 14 Sep 2017 20:51:12 +0200 Subject: Autogen: Read relative paths from rcc output --- Source/cmQtAutoGen.cxx | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx index 95cd122..d9b1fd3 100644 --- a/Source/cmQtAutoGen.cxx +++ b/Source/cmQtAutoGen.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoGen.h" #include "cmAlgorithms.h" +#include "cmProcessOutput.h" #include "cmSystemTools.h" #include "cmsys/FStream.hxx" @@ -158,15 +159,18 @@ static bool RccListInputsQt5(const std::string& rccCommand, std::string rccStdOut; std::string rccStdErr; int retVal = 0; - bool result = - cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal, - nullptr, cmSystemTools::OUTPUT_NONE); + bool result = cmSystemTools::RunSingleCommand( + command, &rccStdOut, &rccStdErr, &retVal, nullptr, + cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto); if (result && retVal == 0 && rccStdOut.find("--list") != std::string::npos) { hasDashDashList = true; } } + std::string const fileDir = cmSystemTools::GetFilenamePath(fileName); + std::string const fileNameName = cmSystemTools::GetFilenameName(fileName); + // Run rcc list command bool result = false; int retVal = 0; @@ -176,16 +180,16 @@ static bool RccListInputsQt5(const std::string& rccCommand, std::vector command; command.push_back(rccCommand); command.push_back(hasDashDashList ? "--list" : "-list"); - command.push_back(fileName); - result = - cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal, - nullptr, cmSystemTools::OUTPUT_NONE); + command.push_back(fileNameName); + result = cmSystemTools::RunSingleCommand( + command, &rccStdOut, &rccStdErr, &retVal, fileDir.c_str(), + cmSystemTools::OUTPUT_NONE, 0.0, cmProcessOutput::Auto); } if (!result || retVal) { if (errorMessage != nullptr) { std::ostringstream ost; - ost << "rcc list process for " << cmQtAutoGen::Quoted(fileName) - << " failed:\n" + ost << "rcc list process failed for\n " << cmQtAutoGen::Quoted(fileName) + << "\n" << rccStdOut << "\n" << rccStdErr << "\n"; *errorMessage = ost.str(); @@ -230,6 +234,11 @@ static bool RccListInputsQt5(const std::string& rccCommand, } } + // Convert relative paths to absolute paths + for (std::string& resFile : files) { + resFile = cmSystemTools::CollapseCombinedPath(fileDir, resFile); + } + return true; } -- cgit v0.12 From 4eb7d81791d38042e13ced8c01cb4e3a3452c704 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Sun, 3 Sep 2017 21:12:14 +0200 Subject: Autogen: Tests: Add /item.moc includes to sameName test --- Tests/QtAutogen/sameName/aaa/bbb/item.cpp | 12 ++++++++++++ Tests/QtAutogen/sameName/aaa/item.cpp | 12 ++++++++++++ Tests/QtAutogen/sameName/bbb/aaa/item.cpp | 12 ++++++++++++ Tests/QtAutogen/sameName/bbb/item.cpp | 12 ++++++++++++ Tests/QtAutogen/sameName/ccc/item.cpp | 17 ++++++++--------- Tests/QtAutogen/sameName/item.cpp | 12 ++++++++++++ 6 files changed, 68 insertions(+), 9 deletions(-) diff --git a/Tests/QtAutogen/sameName/aaa/bbb/item.cpp b/Tests/QtAutogen/sameName/aaa/bbb/item.cpp index 20d0044..850206f 100644 --- a/Tests/QtAutogen/sameName/aaa/bbb/item.cpp +++ b/Tests/QtAutogen/sameName/aaa/bbb/item.cpp @@ -3,8 +3,20 @@ namespace aaa { namespace bbb { +class MocLocal : public QObject +{ + Q_OBJECT; + +public: + MocLocal() = default; + ~MocLocal() = default; +}; + void Item::go() { + MocLocal obj; } } } + +#include "aaa/bbb/item.moc" diff --git a/Tests/QtAutogen/sameName/aaa/item.cpp b/Tests/QtAutogen/sameName/aaa/item.cpp index 95dd3b6..85312e9 100644 --- a/Tests/QtAutogen/sameName/aaa/item.cpp +++ b/Tests/QtAutogen/sameName/aaa/item.cpp @@ -2,7 +2,19 @@ namespace aaa { +class MocLocal : public QObject +{ + Q_OBJECT; + +public: + MocLocal() = default; + ~MocLocal() = default; +}; + void Item::go() { + MocLocal obj; } } + +#include "aaa/item.moc" diff --git a/Tests/QtAutogen/sameName/bbb/aaa/item.cpp b/Tests/QtAutogen/sameName/bbb/aaa/item.cpp index ac4b2c2..7ad01c3 100644 --- a/Tests/QtAutogen/sameName/bbb/aaa/item.cpp +++ b/Tests/QtAutogen/sameName/bbb/aaa/item.cpp @@ -3,8 +3,20 @@ namespace bbb { namespace aaa { +class MocLocal : public QObject +{ + Q_OBJECT; + +public: + MocLocal() = default; + ~MocLocal() = default; +}; + void Item::go() { + MocLocal obj; } } } + +#include "bbb/aaa/item.moc" diff --git a/Tests/QtAutogen/sameName/bbb/item.cpp b/Tests/QtAutogen/sameName/bbb/item.cpp index f97a143..b851bb6 100644 --- a/Tests/QtAutogen/sameName/bbb/item.cpp +++ b/Tests/QtAutogen/sameName/bbb/item.cpp @@ -2,7 +2,19 @@ namespace bbb { +class MocLocal : public QObject +{ + Q_OBJECT; + +public: + MocLocal() = default; + ~MocLocal() = default; +}; + void Item::go() { + MocLocal obj; } } + +#include "bbb/item.moc" diff --git a/Tests/QtAutogen/sameName/ccc/item.cpp b/Tests/QtAutogen/sameName/ccc/item.cpp index d90b2b8..e27a784 100644 --- a/Tests/QtAutogen/sameName/ccc/item.cpp +++ b/Tests/QtAutogen/sameName/ccc/item.cpp @@ -2,22 +2,21 @@ namespace ccc { -void Item::go() -{ -} - -class MocTest : public QObject +class MocLocal : public QObject { Q_OBJECT; - Q_SLOT - void go(); + +public: + MocLocal() = default; + ~MocLocal() = default; }; -void MocTest::go() +void Item::go() { + MocLocal obj; } } // Include own moc files -#include "item.moc" +#include "ccc/item.moc" #include "moc_item.cpp" diff --git a/Tests/QtAutogen/sameName/item.cpp b/Tests/QtAutogen/sameName/item.cpp index e013cf3..c614a84 100644 --- a/Tests/QtAutogen/sameName/item.cpp +++ b/Tests/QtAutogen/sameName/item.cpp @@ -1,5 +1,17 @@ #include "item.hpp" +class MocLocal : public QObject +{ + Q_OBJECT; + +public: + MocLocal() = default; + ~MocLocal() = default; +}; + void Item::go() { + MocLocal obj; } + +#include "item.moc" -- cgit v0.12 From 932656527bdbf580335a082f8ecbaa888a710901 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Sun, 3 Sep 2017 21:31:11 +0200 Subject: Autogen: Tests: Add /ui_view.h AUTOUIC includes to sameName test --- Tests/QtAutogen/sameName/CMakeLists.txt | 5 ++++- Tests/QtAutogen/sameName/aaa/item.cpp | 2 ++ Tests/QtAutogen/sameName/aaa/item.hpp | 2 ++ Tests/QtAutogen/sameName/aaa/view.ui | 24 ++++++++++++++++++++++++ Tests/QtAutogen/sameName/bbb/item.cpp | 3 +++ Tests/QtAutogen/sameName/bbb/item.hpp | 1 + Tests/QtAutogen/sameName/bbb/view.ui | 24 ++++++++++++++++++++++++ Tests/QtAutogen/sameName/ccc/item.cpp | 3 +++ Tests/QtAutogen/sameName/ccc/item.hpp | 2 ++ Tests/QtAutogen/sameName/ccc/view.ui | 24 ++++++++++++++++++++++++ Tests/QtAutogen/sameName/item.cpp | 3 +++ Tests/QtAutogen/sameName/item.hpp | 2 ++ Tests/QtAutogen/sameName/view.ui | 24 ++++++++++++++++++++++++ 13 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 Tests/QtAutogen/sameName/aaa/view.ui create mode 100644 Tests/QtAutogen/sameName/bbb/view.ui create mode 100644 Tests/QtAutogen/sameName/ccc/view.ui create mode 100644 Tests/QtAutogen/sameName/view.ui diff --git a/Tests/QtAutogen/sameName/CMakeLists.txt b/Tests/QtAutogen/sameName/CMakeLists.txt index 4d2dcd9..f695875 100644 --- a/Tests/QtAutogen/sameName/CMakeLists.txt +++ b/Tests/QtAutogen/sameName/CMakeLists.txt @@ -17,7 +17,10 @@ add_executable(sameName main.cpp ) target_link_libraries(sameName ${QT_LIBRARIES}) -set_target_properties(sameName PROPERTIES AUTOMOC TRUE AUTORCC TRUE) +set_target_properties(sameName PROPERTIES + AUTOMOC TRUE + AUTOUIC TRUE + AUTORCC TRUE) # Set different compression levels if (QT_TEST_VERSION STREQUAL 4) diff --git a/Tests/QtAutogen/sameName/aaa/item.cpp b/Tests/QtAutogen/sameName/aaa/item.cpp index 85312e9..e35d3d1 100644 --- a/Tests/QtAutogen/sameName/aaa/item.cpp +++ b/Tests/QtAutogen/sameName/aaa/item.cpp @@ -1,4 +1,5 @@ #include "item.hpp" +// Include ui_view.h only in header namespace aaa { @@ -13,6 +14,7 @@ public: void Item::go() { + Ui_ViewAAA ui; MocLocal obj; } } diff --git a/Tests/QtAutogen/sameName/aaa/item.hpp b/Tests/QtAutogen/sameName/aaa/item.hpp index b63466f..875f72f 100644 --- a/Tests/QtAutogen/sameName/aaa/item.hpp +++ b/Tests/QtAutogen/sameName/aaa/item.hpp @@ -2,6 +2,8 @@ #define AAA_ITEM_HPP #include +// Include ui_view.h only in header +#include namespace aaa { diff --git a/Tests/QtAutogen/sameName/aaa/view.ui b/Tests/QtAutogen/sameName/aaa/view.ui new file mode 100644 index 0000000..0f09980 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/view.ui @@ -0,0 +1,24 @@ + + + ViewAAA + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + + + + + diff --git a/Tests/QtAutogen/sameName/bbb/item.cpp b/Tests/QtAutogen/sameName/bbb/item.cpp index b851bb6..9ef128e 100644 --- a/Tests/QtAutogen/sameName/bbb/item.cpp +++ b/Tests/QtAutogen/sameName/bbb/item.cpp @@ -1,4 +1,6 @@ #include "item.hpp" +// Include ui_view.h only in source +#include namespace bbb { @@ -13,6 +15,7 @@ public: void Item::go() { + Ui_ViewBBB ui; MocLocal obj; } } diff --git a/Tests/QtAutogen/sameName/bbb/item.hpp b/Tests/QtAutogen/sameName/bbb/item.hpp index 5b7f985..d39a9d7 100644 --- a/Tests/QtAutogen/sameName/bbb/item.hpp +++ b/Tests/QtAutogen/sameName/bbb/item.hpp @@ -2,6 +2,7 @@ #define BBB_ITEM_HPP #include +// Include ui_view.h only in source namespace bbb { diff --git a/Tests/QtAutogen/sameName/bbb/view.ui b/Tests/QtAutogen/sameName/bbb/view.ui new file mode 100644 index 0000000..a8f506e --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/view.ui @@ -0,0 +1,24 @@ + + + ViewBBB + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + + + + + diff --git a/Tests/QtAutogen/sameName/ccc/item.cpp b/Tests/QtAutogen/sameName/ccc/item.cpp index e27a784..ab8a281 100644 --- a/Tests/QtAutogen/sameName/ccc/item.cpp +++ b/Tests/QtAutogen/sameName/ccc/item.cpp @@ -1,4 +1,6 @@ #include "item.hpp" +// Include ui_view.h in source and header +#include namespace ccc { @@ -13,6 +15,7 @@ public: void Item::go() { + Ui_ViewCCC ui; MocLocal obj; } } diff --git a/Tests/QtAutogen/sameName/ccc/item.hpp b/Tests/QtAutogen/sameName/ccc/item.hpp index 96fcc24..20d9dd9 100644 --- a/Tests/QtAutogen/sameName/ccc/item.hpp +++ b/Tests/QtAutogen/sameName/ccc/item.hpp @@ -2,6 +2,8 @@ #define CCC_ITEM_HPP #include +// Include ui_view.h in source and header +#include namespace ccc { diff --git a/Tests/QtAutogen/sameName/ccc/view.ui b/Tests/QtAutogen/sameName/ccc/view.ui new file mode 100644 index 0000000..7989c69 --- /dev/null +++ b/Tests/QtAutogen/sameName/ccc/view.ui @@ -0,0 +1,24 @@ + + + ViewCCC + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + + + + + diff --git a/Tests/QtAutogen/sameName/item.cpp b/Tests/QtAutogen/sameName/item.cpp index c614a84..3d1fbe7 100644 --- a/Tests/QtAutogen/sameName/item.cpp +++ b/Tests/QtAutogen/sameName/item.cpp @@ -1,4 +1,6 @@ #include "item.hpp" +// Include ui_view.h in source and header +#include class MocLocal : public QObject { @@ -11,6 +13,7 @@ public: void Item::go() { + Ui_View ui; MocLocal obj; } diff --git a/Tests/QtAutogen/sameName/item.hpp b/Tests/QtAutogen/sameName/item.hpp index 91bba3b..75e83f4 100644 --- a/Tests/QtAutogen/sameName/item.hpp +++ b/Tests/QtAutogen/sameName/item.hpp @@ -2,6 +2,8 @@ #define ITEM_HPP #include +// Include ui_view.h in source and header +#include class Item : public QObject { diff --git a/Tests/QtAutogen/sameName/view.ui b/Tests/QtAutogen/sameName/view.ui new file mode 100644 index 0000000..2ffe734 --- /dev/null +++ b/Tests/QtAutogen/sameName/view.ui @@ -0,0 +1,24 @@ + + + View + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + + + + + -- cgit v0.12 From e5c6610aba66b0a792f5fedb83e73a43460c3248 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Sun, 3 Sep 2017 22:26:09 +0200 Subject: Autogen: Tests: Extend CMAKE_AUTOMOC_DEPEND_FILTERS rebuild test The CMAKE_AUTOMOC_DEPEND_FILTERS must also detect filtered file changes from files that are registered to AUTOMOC by a `#include "moc_.cpp"` statement. --- Tests/QtAutogenRerun/CMakeLists.txt | 42 ++++++++++++++++++----- Tests/QtAutogenRerun/mocPlugin/CMakeLists.txt | 4 ++- Tests/QtAutogenRerun/mocPlugin/StyleA.hpp | 4 +-- Tests/QtAutogenRerun/mocPlugin/StyleB.hpp | 4 +-- Tests/QtAutogenRerun/mocPlugin/StyleC.hpp | 2 +- Tests/QtAutogenRerun/mocPlugin/StyleCommon.hpp | 7 ---- Tests/QtAutogenRerun/mocPlugin/StyleD.hpp | 2 +- Tests/QtAutogenRerun/mocPlugin/StyleE.cpp | 3 ++ Tests/QtAutogenRerun/mocPlugin/StyleE.hpp | 17 +++------ Tests/QtAutogenRerun/mocPlugin/StyleEInclude.hpp | 17 +++++++++ Tests/QtAutogenRerun/mocPlugin/UtilityMacros.hpp | 7 ++++ Tests/QtAutogenRerun/mocPlugin/jsonIn/StyleB.json | 2 +- Tests/QtAutogenRerun/mocPlugin/jsonIn/StyleE.json | 1 + 13 files changed, 76 insertions(+), 36 deletions(-) delete mode 100644 Tests/QtAutogenRerun/mocPlugin/StyleCommon.hpp create mode 100644 Tests/QtAutogenRerun/mocPlugin/StyleEInclude.hpp create mode 100644 Tests/QtAutogenRerun/mocPlugin/UtilityMacros.hpp create mode 100644 Tests/QtAutogenRerun/mocPlugin/jsonIn/StyleE.json diff --git a/Tests/QtAutogenRerun/CMakeLists.txt b/Tests/QtAutogenRerun/CMakeLists.txt index 088025f..a7fe105 100644 --- a/Tests/QtAutogenRerun/CMakeLists.txt +++ b/Tests/QtAutogenRerun/CMakeLists.txt @@ -171,9 +171,16 @@ endif() # -- Test # Tests Q_PLUGIN_METADATA json file change detection if (NOT QT_TEST_VERSION STREQUAL 4) + + # Utility variables + set(timeformat "%Y%j%H%M%S") + set(mocPlugSrcDir "${CMAKE_CURRENT_SOURCE_DIR}/mocPlugin") + set(mocPlugBinDir "${CMAKE_CURRENT_BINARY_DIR}/mocPlugin") + + # Initial buid try_compile(MOC_PLUGIN - "${CMAKE_CURRENT_BINARY_DIR}/mocPlugin" - "${CMAKE_CURRENT_SOURCE_DIR}/mocPlugin" + "${mocPlugBinDir}" + "${mocPlugSrcDir}" mocPlugin CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}" "-DCMAKE_PREFIX_PATH=${Qt_PREFIX_DIR}" @@ -183,29 +190,32 @@ if (NOT QT_TEST_VERSION STREQUAL 4) message(SEND_ERROR "Initial build of mocPlugin failed. Output: ${output}") endif() - set(timeformat "%Y%j%H%M%S") - set(mocPlugSrcDir "${CMAKE_CURRENT_SOURCE_DIR}/mocPlugin") - set(mocPlugBinDir "${CMAKE_CURRENT_BINARY_DIR}/mocPlugin") find_library(plAFile "PlugA" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH) find_library(plBFile "PlugB" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH) find_library(plCFile "PlugC" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH) find_library(plDFile "PlugD" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH) + find_library(plEFile "PlugE" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH) + # - Ensure that the timestamp will change. + # - Change the json files referenced by Q_PLUGIN_METADATA + # - Rebuild file(TIMESTAMP "${plAFile}" plABefore "${timeformat}") file(TIMESTAMP "${plBFile}" plBBefore "${timeformat}") file(TIMESTAMP "${plCFile}" plCBefore "${timeformat}") file(TIMESTAMP "${plDFile}" plDBefore "${timeformat}") + file(TIMESTAMP "${plEFile}" plEBefore "${timeformat}") - # Ensure that the timestamp will change and change the json files execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) configure_file("${mocPlugSrcDir}/jsonIn/StyleD.json" "${mocPlugBinDir}/jsonFiles/StyleC.json") - configure_file("${mocPlugSrcDir}/jsonIn/StyleC.json" "${mocPlugBinDir}/jsonFiles/sub/StyleD.json") + configure_file("${mocPlugSrcDir}/jsonIn/StyleE.json" "${mocPlugBinDir}/jsonFiles/sub/StyleD.json") + configure_file("${mocPlugSrcDir}/jsonIn/StyleC.json" "${mocPlugBinDir}/jsonFiles/StyleE.json") execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocPlugBinDir}") file(TIMESTAMP "${plAFile}" plAAfter "${timeformat}") file(TIMESTAMP "${plBFile}" plBAfter "${timeformat}") file(TIMESTAMP "${plCFile}" plCAfter "${timeformat}") file(TIMESTAMP "${plDFile}" plDAfter "${timeformat}") + file(TIMESTAMP "${plEFile}" plEAfter "${timeformat}") if (plAAfter GREATER plABefore) message(SEND_ERROR "file (${plAFile}) should not have changed!") @@ -219,21 +229,35 @@ if (NOT QT_TEST_VERSION STREQUAL 4) if (NOT plDAfter GREATER plDBefore) message(SEND_ERROR "file (${plDFile}) should have changed!") endif() + if (NOT plEAfter GREATER plEBefore) + message(SEND_ERROR "file (${plEFile}) should have changed!") + endif() - # Test custom macro + # - Ensure that the timestamp will change. + # - Change the json files referenced by A_CUSTOM_MACRO + # - Rebuild file(TIMESTAMP "${plCFile}" plCBefore "${timeformat}") file(TIMESTAMP "${plDFile}" plDBefore "${timeformat}") + file(TIMESTAMP "${plEFile}" plEBefore "${timeformat}") + execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) - configure_file("${mocPlugSrcDir}/jsonIn/StyleD.json" "${mocPlugBinDir}/jsonFiles/StyleC_Custom.json") + configure_file("${mocPlugSrcDir}/jsonIn/StyleE.json" "${mocPlugBinDir}/jsonFiles/StyleC_Custom.json") configure_file("${mocPlugSrcDir}/jsonIn/StyleC.json" "${mocPlugBinDir}/jsonFiles/sub/StyleD_Custom.json") + configure_file("${mocPlugSrcDir}/jsonIn/StyleD.json" "${mocPlugBinDir}/jsonFiles/StyleE_Custom.json") execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocPlugBinDir}") + file(TIMESTAMP "${plCFile}" plCAfter "${timeformat}") file(TIMESTAMP "${plDFile}" plDAfter "${timeformat}") + file(TIMESTAMP "${plEFile}" plEAfter "${timeformat}") + if (NOT plCAfter GREATER plCBefore) message(SEND_ERROR "file (${plCFile}) should have changed!") endif() if (NOT plDAfter GREATER plDBefore) message(SEND_ERROR "file (${plDFile}) should have changed!") endif() + if (NOT plEAfter GREATER plEBefore) + message(SEND_ERROR "file (${plEFile}) should have changed!") + endif() endif() diff --git a/Tests/QtAutogenRerun/mocPlugin/CMakeLists.txt b/Tests/QtAutogenRerun/mocPlugin/CMakeLists.txt index 9b224fb..b7cc5e9 100644 --- a/Tests/QtAutogenRerun/mocPlugin/CMakeLists.txt +++ b/Tests/QtAutogenRerun/mocPlugin/CMakeLists.txt @@ -16,9 +16,11 @@ if(Qt5_POSITION_INDEPENDENT_CODE AND CMAKE_CXX_COMPILE_OPTIONS_PIC) endif() configure_file(jsonIn/StyleC.json jsonFiles/StyleC.json) -configure_file(jsonIn/StyleD.json jsonFiles/sub/StyleD.json) configure_file(jsonIn/StyleC.json jsonFiles/StyleC_Custom.json) +configure_file(jsonIn/StyleD.json jsonFiles/sub/StyleD.json) configure_file(jsonIn/StyleD.json jsonFiles/sub/StyleD_Custom.json) +configure_file(jsonIn/StyleE.json jsonFiles/StyleE.json) +configure_file(jsonIn/StyleE.json jsonFiles/StyleE_Custom.json) # Enable automoc set(CMAKE_AUTOMOC TRUE) diff --git a/Tests/QtAutogenRerun/mocPlugin/StyleA.hpp b/Tests/QtAutogenRerun/mocPlugin/StyleA.hpp index 1b6154d..35158a4 100644 --- a/Tests/QtAutogenRerun/mocPlugin/StyleA.hpp +++ b/Tests/QtAutogenRerun/mocPlugin/StyleA.hpp @@ -1,13 +1,13 @@ #ifndef STYLEA_HPP #define STYLEA_HPP -#include "StyleCommon.hpp" +#include "UtilityMacros.hpp" #include class StyleA : public QStylePlugin { Q_OBJECT - // Json file in local directory + // Json file in source local directory Q_PLUGIN_METADATA(IID "org.styles.A" FILE "StyleA.json") A_CUSTOM_MACRO(SomeArg, "StyleA_Custom.json", AnotherArg) public: diff --git a/Tests/QtAutogenRerun/mocPlugin/StyleB.hpp b/Tests/QtAutogenRerun/mocPlugin/StyleB.hpp index 163c9b2..15b79c5 100644 --- a/Tests/QtAutogenRerun/mocPlugin/StyleB.hpp +++ b/Tests/QtAutogenRerun/mocPlugin/StyleB.hpp @@ -1,13 +1,13 @@ #ifndef STYLEB_HPP #define STYLEB_HPP -#include "StyleCommon.hpp" +#include "UtilityMacros.hpp" #include class StyleB : public QStylePlugin { Q_OBJECT - // Json file in local subdirectory + // Json file in source local subdirectory Q_PLUGIN_METADATA(IID "org.styles.B" FILE "jsonIn/StyleB.json") A_CUSTOM_MACRO(SomeArg, "jsonIn/StyleB_Custom.json", AnotherArg) public: diff --git a/Tests/QtAutogenRerun/mocPlugin/StyleC.hpp b/Tests/QtAutogenRerun/mocPlugin/StyleC.hpp index 52a887a..b0a4115 100644 --- a/Tests/QtAutogenRerun/mocPlugin/StyleC.hpp +++ b/Tests/QtAutogenRerun/mocPlugin/StyleC.hpp @@ -1,7 +1,7 @@ #ifndef STYLEC_HPP #define STYLEC_HPP -#include "StyleCommon.hpp" +#include "UtilityMacros.hpp" #include class StyleC : public QStylePlugin diff --git a/Tests/QtAutogenRerun/mocPlugin/StyleCommon.hpp b/Tests/QtAutogenRerun/mocPlugin/StyleCommon.hpp deleted file mode 100644 index f1a7ec6..0000000 --- a/Tests/QtAutogenRerun/mocPlugin/StyleCommon.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef STYLECOMMON_HPP -#define STYLECOMMON_HPP - -// Empty test macro definition -#define A_CUSTOM_MACRO(name, jsonFile, pluginRegistrations) - -#endif diff --git a/Tests/QtAutogenRerun/mocPlugin/StyleD.hpp b/Tests/QtAutogenRerun/mocPlugin/StyleD.hpp index df8a439..9696aaa 100644 --- a/Tests/QtAutogenRerun/mocPlugin/StyleD.hpp +++ b/Tests/QtAutogenRerun/mocPlugin/StyleD.hpp @@ -1,7 +1,7 @@ #ifndef STYLED_HPP #define STYLED_HPP -#include "StyleCommon.hpp" +#include "UtilityMacros.hpp" #include class StyleD : public QStylePlugin diff --git a/Tests/QtAutogenRerun/mocPlugin/StyleE.cpp b/Tests/QtAutogenRerun/mocPlugin/StyleE.cpp index 8fc9a7f..3448319 100644 --- a/Tests/QtAutogenRerun/mocPlugin/StyleE.cpp +++ b/Tests/QtAutogenRerun/mocPlugin/StyleE.cpp @@ -4,3 +4,6 @@ QStyle* StyleE::create(const QString& key) { return 0; } + +// AUTOMOC the StyleEInclude.hpp header +#include "moc_StyleEInclude.cpp" diff --git a/Tests/QtAutogenRerun/mocPlugin/StyleE.hpp b/Tests/QtAutogenRerun/mocPlugin/StyleE.hpp index e7915a8..a069034 100644 --- a/Tests/QtAutogenRerun/mocPlugin/StyleE.hpp +++ b/Tests/QtAutogenRerun/mocPlugin/StyleE.hpp @@ -1,17 +1,10 @@ #ifndef STYLEE_HPP #define STYLEE_HPP -#include "StyleCommon.hpp" -#include - -class StyleE : public QStylePlugin -{ - Q_OBJECT - // No Json file - Q_PLUGIN_METADATA(IID "org.styles.E") - A_CUSTOM_MACRO(SomeArg, InvalidFileArg, AnotherArg) -public: - QStyle* create(const QString& key); -}; +// The included file is not in the sources list and won't be detected by +// AUTOMOC source file with the same base name. +// It is registered to AUTOMOCed via a moc_.cpp include in StyleE.cpp +// though. +#include "StyleEInclude.hpp" #endif diff --git a/Tests/QtAutogenRerun/mocPlugin/StyleEInclude.hpp b/Tests/QtAutogenRerun/mocPlugin/StyleEInclude.hpp new file mode 100644 index 0000000..f9734db --- /dev/null +++ b/Tests/QtAutogenRerun/mocPlugin/StyleEInclude.hpp @@ -0,0 +1,17 @@ +#ifndef STYLEE_INCLUDE_HPP +#define STYLEE_INCLUDE_HPP + +#include "UtilityMacros.hpp" +#include + +class StyleE : public QStylePlugin +{ + Q_OBJECT + // Json files in global root directory + Q_PLUGIN_METADATA(IID "org.styles.E" FILE "StyleE.json") + A_CUSTOM_MACRO(SomeArg, "StyleE_Custom.json", AnotherArg) +public: + QStyle* create(const QString& key); +}; + +#endif diff --git a/Tests/QtAutogenRerun/mocPlugin/UtilityMacros.hpp b/Tests/QtAutogenRerun/mocPlugin/UtilityMacros.hpp new file mode 100644 index 0000000..53a4284 --- /dev/null +++ b/Tests/QtAutogenRerun/mocPlugin/UtilityMacros.hpp @@ -0,0 +1,7 @@ +#ifndef UTILITYMACROS_HPP +#define UTILITYMACROS_HPP + +// Empty test macro definition +#define A_CUSTOM_MACRO(name, jsonFile, pluginRegistrations) + +#endif diff --git a/Tests/QtAutogenRerun/mocPlugin/jsonIn/StyleB.json b/Tests/QtAutogenRerun/mocPlugin/jsonIn/StyleB.json index 129cac4..cd155dc 100644 --- a/Tests/QtAutogenRerun/mocPlugin/jsonIn/StyleB.json +++ b/Tests/QtAutogenRerun/mocPlugin/jsonIn/StyleB.json @@ -1 +1 @@ -{ "Keys": [ "Rocket", "StarbusterB" ] } +{ "Keys": [ "Red", "Green" ] } diff --git a/Tests/QtAutogenRerun/mocPlugin/jsonIn/StyleE.json b/Tests/QtAutogenRerun/mocPlugin/jsonIn/StyleE.json new file mode 100644 index 0000000..5412c94 --- /dev/null +++ b/Tests/QtAutogenRerun/mocPlugin/jsonIn/StyleE.json @@ -0,0 +1 @@ +{ "Keys": [ "Floor", "Ceiling" ] } -- cgit v0.12 From 04a0daeeed5d57a545d0a8a450b51a009913808e Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Tue, 5 Sep 2017 14:00:49 +0200 Subject: Autogen: Tests: Move each rerun test script to a NAME.cmake file --- Tests/QtAutogenRerun/CMakeLists.txt | 223 +--------------------------------- Tests/QtAutogenRerun/mocPlugin.cmake | 88 ++++++++++++++ Tests/QtAutogenRerun/mocRerun.cmake | 39 ++++++ Tests/QtAutogenRerun/rccDepends.cmake | 91 ++++++++++++++ 4 files changed, 224 insertions(+), 217 deletions(-) create mode 100644 Tests/QtAutogenRerun/mocPlugin.cmake create mode 100644 Tests/QtAutogenRerun/mocRerun.cmake create mode 100644 Tests/QtAutogenRerun/rccDepends.cmake diff --git a/Tests/QtAutogenRerun/CMakeLists.txt b/Tests/QtAutogenRerun/CMakeLists.txt index a7fe105..e72c191 100644 --- a/Tests/QtAutogenRerun/CMakeLists.txt +++ b/Tests/QtAutogenRerun/CMakeLists.txt @@ -36,228 +36,17 @@ else() endif() -# -- Test -# Dummy test to generate clean target +# Dummy executable to generate clean target add_executable(dummy dummy.cpp) # -- Test -# When a file listed in a .qrc file changes the target must be rebuilt -set(timeformat "%Y%j%H%M%S") -set(RCC_DEPENDS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/rccDepends") -set(RCC_DEPENDS_BIN "${CMAKE_CURRENT_BINARY_DIR}/rccDepends") -configure_file(${RCC_DEPENDS_SRC}/res1a.qrc.in ${RCC_DEPENDS_BIN}/res1.qrc COPYONLY) -configure_file(${RCC_DEPENDS_SRC}/res2a.qrc.in ${RCC_DEPENDS_BIN}/res2.qrc.in COPYONLY) -try_compile(RCC_DEPENDS - "${RCC_DEPENDS_BIN}" - "${RCC_DEPENDS_SRC}" - 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 rccDepends failed. Output: ${output}") -endif() -# Get name and timestamp of the output binary -file(STRINGS "${RCC_DEPENDS_BIN}/target.txt" targetList ENCODING UTF-8) -list(GET targetList 0 rccDependsBin) -file(TIMESTAMP "${rccDependsBin}" timeBegin "${timeformat}") -# Sleep, touch regular qrc input file, rebuild and compare timestamp -execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. -execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${RCC_DEPENDS_BIN}/res1/input.txt") -execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${RCC_DEPENDS_BIN}" RESULT_VARIABLE result) -if (result) - message(SEND_ERROR "Second build of rccDepends failed.") -endif() -file(TIMESTAMP "${rccDependsBin}" timeStep1 "${timeformat}") -if (NOT timeStep1 GREATER timeBegin) - message(SEND_ERROR "File (${rccDependsBin}) should have changed in the first step!") -endif() -# Sleep, update regular qrc file, rebuild and compare timestamp -execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. -configure_file(${RCC_DEPENDS_SRC}/res1b.qrc.in ${RCC_DEPENDS_BIN}/res1.qrc COPYONLY) -execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${RCC_DEPENDS_BIN}" RESULT_VARIABLE result) -if (result) - message(SEND_ERROR "Third build of rccDepends failed.") -endif() -file(TIMESTAMP "${rccDependsBin}" timeStep2 "${timeformat}") -if (NOT timeStep2 GREATER timeStep1) - message(SEND_ERROR "File (${rccDependsBin}) should have changed in the second step!") -endif() -# Sleep, touch regular qrc newly added input file, rebuild and compare timestamp -execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. -execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${RCC_DEPENDS_BIN}/res1/inputAdded.txt") -execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${RCC_DEPENDS_BIN}" RESULT_VARIABLE result) -if (result) - message(SEND_ERROR "Fourth build of rccDepends failed.") -endif() -file(TIMESTAMP "${rccDependsBin}" timeStep3 "${timeformat}") -if (NOT timeStep3 GREATER timeStep2) - message(SEND_ERROR "File (${rccDependsBin}) should have changed in the third step!") -endif() -# Sleep, touch generated qrc input file, rebuild and compare timestamp -execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. -execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${RCC_DEPENDS_BIN}/res2/input.txt") -execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${RCC_DEPENDS_BIN}" RESULT_VARIABLE result) -if (result) - message(SEND_ERROR "Fifth build of rccDepends failed.") -endif() -file(TIMESTAMP "${rccDependsBin}" timeStep4 "${timeformat}") -if (NOT timeStep4 GREATER timeStep3) - message(SEND_ERROR "File (${rccDependsBin}) should have changed in the fourth step!") -endif() -# Sleep, update generated qrc file, rebuild and compare timestamp -execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. -configure_file(${RCC_DEPENDS_SRC}/res2b.qrc.in ${RCC_DEPENDS_BIN}/res2.qrc.in COPYONLY) -execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${RCC_DEPENDS_BIN}" RESULT_VARIABLE result) -if (result) - message(SEND_ERROR "Sixth build of rccDepends failed.") -endif() -file(TIMESTAMP "${rccDependsBin}" timeStep5 "${timeformat}") -if (NOT timeStep5 GREATER timeStep4) - message(SEND_ERROR "File (${rccDependsBin}) should have changed in the fitfh step!") -endif() -# Sleep, touch generated qrc newly added input file, rebuild and compare timestamp -execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. -execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${RCC_DEPENDS_BIN}/res2/inputAdded.txt") -execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${RCC_DEPENDS_BIN}" RESULT_VARIABLE result) -if (result) - message(SEND_ERROR "Seventh build of rccDepends failed.") -endif() -file(TIMESTAMP "${rccDependsBin}" timeStep6 "${timeformat}") -if (NOT timeStep6 GREATER timeStep5) - message(SEND_ERROR "File (${rccDependsBin}) should have changed in the sixth step!") -endif() - - -# -- Test -# Ensure a repeated build succeeds when a header containing a QObject changes -set(timeformat "%Y%j%H%M%S") -configure_file(mocRerun/test1a.h.in mocRerun/test1.h COPYONLY) -try_compile(MOC_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 mocRerun failed. Output: ${output}") -endif() -# Get name and timestamp of the output binary -file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/mocRerun/target1.txt" target1List ENCODING UTF-8) -list(GET target1List 0 binFile) -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}/mocRerun" - RESULT_VARIABLE mocRerun_result - ) -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() - +include("mocRerun.cmake") # -- Test # Tests Q_PLUGIN_METADATA json file change detection if (NOT QT_TEST_VERSION STREQUAL 4) - - # Utility variables - set(timeformat "%Y%j%H%M%S") - set(mocPlugSrcDir "${CMAKE_CURRENT_SOURCE_DIR}/mocPlugin") - set(mocPlugBinDir "${CMAKE_CURRENT_BINARY_DIR}/mocPlugin") - - # Initial buid - try_compile(MOC_PLUGIN - "${mocPlugBinDir}" - "${mocPlugSrcDir}" - mocPlugin - CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}" - "-DCMAKE_PREFIX_PATH=${Qt_PREFIX_DIR}" - OUTPUT_VARIABLE output - ) - if (NOT MOC_PLUGIN) - message(SEND_ERROR "Initial build of mocPlugin failed. Output: ${output}") - endif() - - find_library(plAFile "PlugA" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH) - find_library(plBFile "PlugB" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH) - find_library(plCFile "PlugC" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH) - find_library(plDFile "PlugD" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH) - find_library(plEFile "PlugE" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH) - - # - Ensure that the timestamp will change. - # - Change the json files referenced by Q_PLUGIN_METADATA - # - Rebuild - file(TIMESTAMP "${plAFile}" plABefore "${timeformat}") - file(TIMESTAMP "${plBFile}" plBBefore "${timeformat}") - file(TIMESTAMP "${plCFile}" plCBefore "${timeformat}") - file(TIMESTAMP "${plDFile}" plDBefore "${timeformat}") - file(TIMESTAMP "${plEFile}" plEBefore "${timeformat}") - - execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) - configure_file("${mocPlugSrcDir}/jsonIn/StyleD.json" "${mocPlugBinDir}/jsonFiles/StyleC.json") - configure_file("${mocPlugSrcDir}/jsonIn/StyleE.json" "${mocPlugBinDir}/jsonFiles/sub/StyleD.json") - configure_file("${mocPlugSrcDir}/jsonIn/StyleC.json" "${mocPlugBinDir}/jsonFiles/StyleE.json") - execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocPlugBinDir}") - - file(TIMESTAMP "${plAFile}" plAAfter "${timeformat}") - file(TIMESTAMP "${plBFile}" plBAfter "${timeformat}") - file(TIMESTAMP "${plCFile}" plCAfter "${timeformat}") - file(TIMESTAMP "${plDFile}" plDAfter "${timeformat}") - file(TIMESTAMP "${plEFile}" plEAfter "${timeformat}") - - if (plAAfter GREATER plABefore) - message(SEND_ERROR "file (${plAFile}) should not have changed!") - endif() - if (plBAfter GREATER plBBefore) - message(SEND_ERROR "file (${plBFile}) should not have changed!") - endif() - if (NOT plCAfter GREATER plCBefore) - message(SEND_ERROR "file (${plCFile}) should have changed!") - endif() - if (NOT plDAfter GREATER plDBefore) - message(SEND_ERROR "file (${plDFile}) should have changed!") - endif() - if (NOT plEAfter GREATER plEBefore) - message(SEND_ERROR "file (${plEFile}) should have changed!") - endif() - - # - Ensure that the timestamp will change. - # - Change the json files referenced by A_CUSTOM_MACRO - # - Rebuild - file(TIMESTAMP "${plCFile}" plCBefore "${timeformat}") - file(TIMESTAMP "${plDFile}" plDBefore "${timeformat}") - file(TIMESTAMP "${plEFile}" plEBefore "${timeformat}") - - execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) - configure_file("${mocPlugSrcDir}/jsonIn/StyleE.json" "${mocPlugBinDir}/jsonFiles/StyleC_Custom.json") - configure_file("${mocPlugSrcDir}/jsonIn/StyleC.json" "${mocPlugBinDir}/jsonFiles/sub/StyleD_Custom.json") - configure_file("${mocPlugSrcDir}/jsonIn/StyleD.json" "${mocPlugBinDir}/jsonFiles/StyleE_Custom.json") - execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocPlugBinDir}") - - file(TIMESTAMP "${plCFile}" plCAfter "${timeformat}") - file(TIMESTAMP "${plDFile}" plDAfter "${timeformat}") - file(TIMESTAMP "${plEFile}" plEAfter "${timeformat}") - - if (NOT plCAfter GREATER plCBefore) - message(SEND_ERROR "file (${plCFile}) should have changed!") - endif() - if (NOT plDAfter GREATER plDBefore) - message(SEND_ERROR "file (${plDFile}) should have changed!") - endif() - if (NOT plEAfter GREATER plEBefore) - message(SEND_ERROR "file (${plEFile}) should have changed!") - endif() - + include("mocPlugin.cmake") endif() + +# -- Test +include("rccDepends.cmake") diff --git a/Tests/QtAutogenRerun/mocPlugin.cmake b/Tests/QtAutogenRerun/mocPlugin.cmake new file mode 100644 index 0000000..27ca691 --- /dev/null +++ b/Tests/QtAutogenRerun/mocPlugin.cmake @@ -0,0 +1,88 @@ + +# Utility variables +set(timeformat "%Y%j%H%M%S") +set(mocPlugSrcDir "${CMAKE_CURRENT_SOURCE_DIR}/mocPlugin") +set(mocPlugBinDir "${CMAKE_CURRENT_BINARY_DIR}/mocPlugin") + +# Initial buid +try_compile(MOC_PLUGIN + "${mocPlugBinDir}" + "${mocPlugSrcDir}" + mocPlugin + CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}" + "-DCMAKE_PREFIX_PATH=${Qt_PREFIX_DIR}" + OUTPUT_VARIABLE output +) +if (NOT MOC_PLUGIN) + message(SEND_ERROR "Initial build of mocPlugin failed. Output: ${output}") +endif() + +find_library(plAFile "PlugA" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH) +find_library(plBFile "PlugB" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH) +find_library(plCFile "PlugC" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH) +find_library(plDFile "PlugD" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH) +find_library(plEFile "PlugE" PATHS "${mocPlugBinDir}/Debug" "${mocPlugBinDir}" NO_DEFAULT_PATH) + +# - Ensure that the timestamp will change. +# - Change the json files referenced by Q_PLUGIN_METADATA +# - Rebuild +file(TIMESTAMP "${plAFile}" plABefore "${timeformat}") +file(TIMESTAMP "${plBFile}" plBBefore "${timeformat}") +file(TIMESTAMP "${plCFile}" plCBefore "${timeformat}") +file(TIMESTAMP "${plDFile}" plDBefore "${timeformat}") +file(TIMESTAMP "${plEFile}" plEBefore "${timeformat}") + +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) +configure_file("${mocPlugSrcDir}/jsonIn/StyleD.json" "${mocPlugBinDir}/jsonFiles/StyleC.json") +configure_file("${mocPlugSrcDir}/jsonIn/StyleE.json" "${mocPlugBinDir}/jsonFiles/sub/StyleD.json") +configure_file("${mocPlugSrcDir}/jsonIn/StyleC.json" "${mocPlugBinDir}/jsonFiles/StyleE.json") +execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocPlugBinDir}") + +file(TIMESTAMP "${plAFile}" plAAfter "${timeformat}") +file(TIMESTAMP "${plBFile}" plBAfter "${timeformat}") +file(TIMESTAMP "${plCFile}" plCAfter "${timeformat}") +file(TIMESTAMP "${plDFile}" plDAfter "${timeformat}") +file(TIMESTAMP "${plEFile}" plEAfter "${timeformat}") + +if (plAAfter GREATER plABefore) + message(SEND_ERROR "file (${plAFile}) should not have changed!") +endif() +if (plBAfter GREATER plBBefore) + message(SEND_ERROR "file (${plBFile}) should not have changed!") +endif() +if (NOT plCAfter GREATER plCBefore) + message(SEND_ERROR "file (${plCFile}) should have changed!") +endif() +if (NOT plDAfter GREATER plDBefore) + message(SEND_ERROR "file (${plDFile}) should have changed!") +endif() +if (NOT plEAfter GREATER plEBefore) + message(SEND_ERROR "file (${plEFile}) should have changed!") +endif() + +# - Ensure that the timestamp will change. +# - Change the json files referenced by A_CUSTOM_MACRO +# - Rebuild +file(TIMESTAMP "${plCFile}" plCBefore "${timeformat}") +file(TIMESTAMP "${plDFile}" plDBefore "${timeformat}") +file(TIMESTAMP "${plEFile}" plEBefore "${timeformat}") + +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) +configure_file("${mocPlugSrcDir}/jsonIn/StyleE.json" "${mocPlugBinDir}/jsonFiles/StyleC_Custom.json") +configure_file("${mocPlugSrcDir}/jsonIn/StyleC.json" "${mocPlugBinDir}/jsonFiles/sub/StyleD_Custom.json") +configure_file("${mocPlugSrcDir}/jsonIn/StyleD.json" "${mocPlugBinDir}/jsonFiles/StyleE_Custom.json") +execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocPlugBinDir}") + +file(TIMESTAMP "${plCFile}" plCAfter "${timeformat}") +file(TIMESTAMP "${plDFile}" plDAfter "${timeformat}") +file(TIMESTAMP "${plEFile}" plEAfter "${timeformat}") + +if (NOT plCAfter GREATER plCBefore) + message(SEND_ERROR "file (${plCFile}) should have changed!") +endif() +if (NOT plDAfter GREATER plDBefore) + message(SEND_ERROR "file (${plDFile}) should have changed!") +endif() + if (NOT plEAfter GREATER plEBefore) + message(SEND_ERROR "file (${plEFile}) should have changed!") +endif() diff --git a/Tests/QtAutogenRerun/mocRerun.cmake b/Tests/QtAutogenRerun/mocRerun.cmake new file mode 100644 index 0000000..eb7a07c --- /dev/null +++ b/Tests/QtAutogenRerun/mocRerun.cmake @@ -0,0 +1,39 @@ + +set(timeformat "%Y%j%H%M%S") +set(mocRerunSrcDir "${CMAKE_CURRENT_SOURCE_DIR}/mocRerun") +set(mocRerunBinDir "${CMAKE_CURRENT_BINARY_DIR}/mocRerun") + +# Initial build +configure_file(mocRerun/test1a.h.in mocRerun/test1.h COPYONLY) +try_compile(MOC_RERUN + "${mocRerunBinDir}" + "${mocRerunSrcDir}" + 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 mocRerun failed. Output: ${output}") +endif() + +# Get name of the output binary +file(STRINGS "${mocRerunBinDir}/target1.txt" target1List ENCODING UTF-8) +list(GET target1List 0 binFile) + +file(TIMESTAMP "${binFile}" timeBegin "${timeformat}") + +# Change header 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 "${mocRerunBinDir}" RESULT_VARIABLE result ) +if (result) + message(SEND_ERROR "Second build of mocRerun failed.") +endif() + +file(TIMESTAMP "${binFile}" timeStep1 "${timeformat}") + +if (NOT timeStep1 GREATER timeBegin) + message(SEND_ERROR "File (${binFile}) should have changed in the first step!") +endif() diff --git a/Tests/QtAutogenRerun/rccDepends.cmake b/Tests/QtAutogenRerun/rccDepends.cmake new file mode 100644 index 0000000..e4cd282 --- /dev/null +++ b/Tests/QtAutogenRerun/rccDepends.cmake @@ -0,0 +1,91 @@ +# When a file listed in a .qrc file changes the target must be rebuilt +set(timeformat "%Y%j%H%M%S") +set(rccDependsSrcDir "${CMAKE_CURRENT_SOURCE_DIR}/rccDepends") +set(rccDependsBinDir "${CMAKE_CURRENT_BINARY_DIR}/rccDepends") + +# Initial build +configure_file(${rccDependsSrcDir}/res1a.qrc.in ${rccDependsBinDir}/res1.qrc COPYONLY) +configure_file(${rccDependsSrcDir}/res2a.qrc.in ${rccDependsBinDir}/res2.qrc.in COPYONLY) +try_compile(RCC_DEPENDS + "${rccDependsBinDir}" + "${rccDependsSrcDir}" + 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 rccDepends failed. Output: ${output}") +endif() +# Get name of the output binary +file(STRINGS "${rccDependsBinDir}/target.txt" targetList ENCODING UTF-8) +list(GET targetList 0 rccDependsBin) + +file(TIMESTAMP "${rccDependsBin}" timeBegin "${timeformat}") +# Sleep, touch regular qrc input file, rebuild and compare timestamp +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. +execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDependsBinDir}/res1/input.txt") +execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDependsBinDir}" RESULT_VARIABLE result) +if (result) + message(SEND_ERROR "Second build of rccDepends failed.") +endif() +file(TIMESTAMP "${rccDependsBin}" timeStep1 "${timeformat}") +if (NOT timeStep1 GREATER timeBegin) + message(SEND_ERROR "File (${rccDependsBin}) should have changed in the first step!") +endif() +# Sleep, update regular qrc file, rebuild and compare timestamp +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. +configure_file(${rccDependsSrcDir}/res1b.qrc.in ${rccDependsBinDir}/res1.qrc COPYONLY) +execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDependsBinDir}" RESULT_VARIABLE result) +if (result) + message(SEND_ERROR "Third build of rccDepends failed.") +endif() +file(TIMESTAMP "${rccDependsBin}" timeStep2 "${timeformat}") +if (NOT timeStep2 GREATER timeStep1) + message(SEND_ERROR "File (${rccDependsBin}) should have changed in the second step!") +endif() +# Sleep, touch regular qrc newly added input file, rebuild and compare timestamp +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. +execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDependsBinDir}/res1/inputAdded.txt") +execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDependsBinDir}" RESULT_VARIABLE result) +if (result) + message(SEND_ERROR "Fourth build of rccDepends failed.") +endif() +file(TIMESTAMP "${rccDependsBin}" timeStep3 "${timeformat}") +if (NOT timeStep3 GREATER timeStep2) + message(SEND_ERROR "File (${rccDependsBin}) should have changed in the third step!") +endif() +# Sleep, touch generated qrc input file, rebuild and compare timestamp +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. +execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDependsBinDir}/res2/input.txt") +execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDependsBinDir}" RESULT_VARIABLE result) +if (result) + message(SEND_ERROR "Fifth build of rccDepends failed.") +endif() +file(TIMESTAMP "${rccDependsBin}" timeStep4 "${timeformat}") +if (NOT timeStep4 GREATER timeStep3) + message(SEND_ERROR "File (${rccDependsBin}) should have changed in the fourth step!") +endif() +# Sleep, update generated qrc file, rebuild and compare timestamp +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. +configure_file(${rccDependsSrcDir}/res2b.qrc.in ${rccDependsBinDir}/res2.qrc.in COPYONLY) +execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDependsBinDir}" RESULT_VARIABLE result) +if (result) + message(SEND_ERROR "Sixth build of rccDepends failed.") +endif() +file(TIMESTAMP "${rccDependsBin}" timeStep5 "${timeformat}") +if (NOT timeStep5 GREATER timeStep4) + message(SEND_ERROR "File (${rccDependsBin}) should have changed in the fitfh step!") +endif() +# Sleep, touch generated qrc newly added input file, rebuild and compare timestamp +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. +execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDependsBinDir}/res2/inputAdded.txt") +execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDependsBinDir}" RESULT_VARIABLE result) +if (result) + message(SEND_ERROR "Seventh build of rccDepends failed.") +endif() +file(TIMESTAMP "${rccDependsBin}" timeStep6 "${timeformat}") +if (NOT timeStep6 GREATER timeStep5) + message(SEND_ERROR "File (${rccDependsBin}) should have changed in the sixth step!") +endif() -- cgit v0.12 From 3c77515e1377aefcb3f2f26bc6f30440c6d25d96 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Tue, 5 Sep 2017 15:01:28 +0200 Subject: Autogen: Tests: Refactor the QtAutogenRebuild rccDepends test Refactors the QtAutogenRebuild rccDepends test script to be more readable. --- Tests/QtAutogenRerun/rccDepends.cmake | 160 +++++++++++++-------- Tests/QtAutogenRerun/rccDepends/CMakeLists.txt | 44 +++--- Tests/QtAutogenRerun/rccDepends/res/input1.txt.in | 1 - Tests/QtAutogenRerun/rccDepends/res/input2.txt.in | 1 - Tests/QtAutogenRerun/rccDepends/res1a.qrc.in | 5 - Tests/QtAutogenRerun/rccDepends/res1b.qrc.in | 6 - Tests/QtAutogenRerun/rccDepends/res2a.qrc.in | 5 - Tests/QtAutogenRerun/rccDepends/res2b.qrc.in | 6 - .../QtAutogenRerun/rccDepends/resGen/input.txt.in | 1 + .../rccDepends/resGen/inputAdded.txt.in | 1 + Tests/QtAutogenRerun/rccDepends/resGenA.qrc.in | 5 + Tests/QtAutogenRerun/rccDepends/resGenB.qrc.in | 6 + .../rccDepends/resPlain/input.txt.in | 1 + .../rccDepends/resPlain/inputAdded.txt.in | 1 + Tests/QtAutogenRerun/rccDepends/resPlainA.qrc.in | 5 + Tests/QtAutogenRerun/rccDepends/resPlainB.qrc.in | 6 + 16 files changed, 151 insertions(+), 103 deletions(-) delete mode 100644 Tests/QtAutogenRerun/rccDepends/res/input1.txt.in delete mode 100644 Tests/QtAutogenRerun/rccDepends/res/input2.txt.in delete mode 100644 Tests/QtAutogenRerun/rccDepends/res1a.qrc.in delete mode 100644 Tests/QtAutogenRerun/rccDepends/res1b.qrc.in delete mode 100644 Tests/QtAutogenRerun/rccDepends/res2a.qrc.in delete mode 100644 Tests/QtAutogenRerun/rccDepends/res2b.qrc.in create mode 100644 Tests/QtAutogenRerun/rccDepends/resGen/input.txt.in create mode 100644 Tests/QtAutogenRerun/rccDepends/resGen/inputAdded.txt.in create mode 100644 Tests/QtAutogenRerun/rccDepends/resGenA.qrc.in create mode 100644 Tests/QtAutogenRerun/rccDepends/resGenB.qrc.in create mode 100644 Tests/QtAutogenRerun/rccDepends/resPlain/input.txt.in create mode 100644 Tests/QtAutogenRerun/rccDepends/resPlain/inputAdded.txt.in create mode 100644 Tests/QtAutogenRerun/rccDepends/resPlainA.qrc.in create mode 100644 Tests/QtAutogenRerun/rccDepends/resPlainB.qrc.in diff --git a/Tests/QtAutogenRerun/rccDepends.cmake b/Tests/QtAutogenRerun/rccDepends.cmake index e4cd282..68e1482 100644 --- a/Tests/QtAutogenRerun/rccDepends.cmake +++ b/Tests/QtAutogenRerun/rccDepends.cmake @@ -1,14 +1,15 @@ -# When a file listed in a .qrc file changes the target must be rebuilt +# When a .qrc or a file listed in a .qrc file changes, +# the target must be rebuilt set(timeformat "%Y%j%H%M%S") -set(rccDependsSrcDir "${CMAKE_CURRENT_SOURCE_DIR}/rccDepends") -set(rccDependsBinDir "${CMAKE_CURRENT_BINARY_DIR}/rccDepends") +set(rccDepSD "${CMAKE_CURRENT_SOURCE_DIR}/rccDepends") +set(rccDepBD "${CMAKE_CURRENT_BINARY_DIR}/rccDepends") # Initial build -configure_file(${rccDependsSrcDir}/res1a.qrc.in ${rccDependsBinDir}/res1.qrc COPYONLY) -configure_file(${rccDependsSrcDir}/res2a.qrc.in ${rccDependsBinDir}/res2.qrc.in COPYONLY) +configure_file(${rccDepSD}/resPlainA.qrc.in ${rccDepBD}/resPlain.qrc COPYONLY) +configure_file(${rccDepSD}/resGenA.qrc.in ${rccDepBD}/resGen.qrc.in COPYONLY) try_compile(RCC_DEPENDS - "${rccDependsBinDir}" - "${rccDependsSrcDir}" + "${rccDepBD}" + "${rccDepSD}" rccDepends CMAKE_FLAGS "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}" "-DQT_TEST_VERSION=${QT_TEST_VERSION}" @@ -18,74 +19,113 @@ try_compile(RCC_DEPENDS if (NOT RCC_DEPENDS) message(SEND_ERROR "Initial build of rccDepends failed. Output: ${output}") endif() -# Get name of the output binary -file(STRINGS "${rccDependsBinDir}/target.txt" targetList ENCODING UTF-8) -list(GET targetList 0 rccDependsBin) -file(TIMESTAMP "${rccDependsBin}" timeBegin "${timeformat}") -# Sleep, touch regular qrc input file, rebuild and compare timestamp -execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. -execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDependsBinDir}/res1/input.txt") -execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDependsBinDir}" RESULT_VARIABLE result) +# Get name of the output binaries +file(STRINGS "${rccDepBD}/targetPlain.txt" targetListPlain ENCODING UTF-8) +file(STRINGS "${rccDepBD}/targetGen.txt" targetListGen ENCODING UTF-8) +list(GET targetListPlain 0 rccDepBinPlain) +list(GET targetListGen 0 rccDepBinGen) +message("Target that uses a plain .qrc file is:\n ${rccDepBinPlain}") +message("Target that uses a GENERATED .qrc file is:\n ${rccDepBinGen}") + + +message("Changing a resource files listed in the .qrc file") +# - Acquire binary timestamps before the build +file(TIMESTAMP "${rccDepBinPlain}" rdPlainBefore "${timeformat}") +file(TIMESTAMP "${rccDepBinGen}" rdGenBefore "${timeformat}") +# - Ensure that the timestamp will change +# - Change a resource files listed in the .qrc file +# - Rebuild +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) +execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDepBD}/resPlain/input.txt") +execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDepBD}/resGen/input.txt") +execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result) if (result) message(SEND_ERROR "Second build of rccDepends failed.") endif() -file(TIMESTAMP "${rccDependsBin}" timeStep1 "${timeformat}") -if (NOT timeStep1 GREATER timeBegin) - message(SEND_ERROR "File (${rccDependsBin}) should have changed in the first step!") +# - Acquire binary timestamps after the build +file(TIMESTAMP "${rccDepBinPlain}" rdPlainAfter "${timeformat}") +file(TIMESTAMP "${rccDepBinGen}" rdGenAfter "${timeformat}") +# - Test if timestamps changed +if (NOT rdPlainAfter GREATER rdPlainBefore) + message(SEND_ERROR "Plain .qrc binary ${rccDepBinPlain}) should have changed!") endif() -# Sleep, update regular qrc file, rebuild and compare timestamp -execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. -configure_file(${rccDependsSrcDir}/res1b.qrc.in ${rccDependsBinDir}/res1.qrc COPYONLY) -execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDependsBinDir}" RESULT_VARIABLE result) +if (NOT rdGenAfter GREATER rdGenBefore) + message(SEND_ERROR "GENERATED .qrc binary ${rccDepBinGen} should have changed!") +endif() + + +message("Changing a the .qrc file") +# - Acquire binary timestamps before the build +file(TIMESTAMP "${rccDepBinPlain}" rdPlainBefore "${timeformat}") +file(TIMESTAMP "${rccDepBinGen}" rdGenBefore "${timeformat}") +# - Ensure that the timestamp will change +# - Change the .qrc file +# - Rebuild +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) +configure_file(${rccDepSD}/resPlainB.qrc.in ${rccDepBD}/resPlain.qrc COPYONLY) +configure_file(${rccDepSD}/resGenB.qrc.in ${rccDepBD}/resGen.qrc.in COPYONLY) +execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result) if (result) message(SEND_ERROR "Third build of rccDepends failed.") endif() -file(TIMESTAMP "${rccDependsBin}" timeStep2 "${timeformat}") -if (NOT timeStep2 GREATER timeStep1) - message(SEND_ERROR "File (${rccDependsBin}) should have changed in the second step!") +# - Acquire binary timestamps after the build +file(TIMESTAMP "${rccDepBinPlain}" rdPlainAfter "${timeformat}") +file(TIMESTAMP "${rccDepBinGen}" rdGenAfter "${timeformat}") +# - Test if timestamps changed +if (NOT rdPlainAfter GREATER rdPlainBefore) + message(SEND_ERROR "Plain .qrc binary ${rccDepBinPlain}) should have changed!") +endif() +if (NOT rdGenAfter GREATER rdGenBefore) + message(SEND_ERROR "GENERATED .qrc binary ${rccDepBinGen} should have changed!") endif() -# Sleep, touch regular qrc newly added input file, rebuild and compare timestamp -execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. -execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDependsBinDir}/res1/inputAdded.txt") -execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDependsBinDir}" RESULT_VARIABLE result) + + +message("Changing a newly added resource files listed in the .qrc file") +# - Acquire binary timestamps before the build +file(TIMESTAMP "${rccDepBinPlain}" rdPlainBefore "${timeformat}") +file(TIMESTAMP "${rccDepBinGen}" rdGenBefore "${timeformat}") +# - Ensure that the timestamp will change +# - Change a newly added resource files listed in the .qrc file +# - Rebuild +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) +execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDepBD}/resPlain/inputAdded.txt") +execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDepBD}/resGen/inputAdded.txt") +execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result) if (result) message(SEND_ERROR "Fourth build of rccDepends failed.") endif() -file(TIMESTAMP "${rccDependsBin}" timeStep3 "${timeformat}") -if (NOT timeStep3 GREATER timeStep2) - message(SEND_ERROR "File (${rccDependsBin}) should have changed in the third step!") +# - Acquire binary timestamps after the build +file(TIMESTAMP "${rccDepBinPlain}" rdPlainAfter "${timeformat}") +file(TIMESTAMP "${rccDepBinGen}" rdGenAfter "${timeformat}") +# - Test if timestamps changed +if (NOT rdPlainAfter GREATER rdPlainBefore) + message(SEND_ERROR "Plain .qrc binary ${rccDepBinPlain}) should have changed!") endif() -# Sleep, touch generated qrc input file, rebuild and compare timestamp -execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. -execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDependsBinDir}/res2/input.txt") -execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDependsBinDir}" RESULT_VARIABLE result) -if (result) - message(SEND_ERROR "Fifth build of rccDepends failed.") +if (NOT rdGenAfter GREATER rdGenBefore) + message(SEND_ERROR "GENERATED .qrc binary ${rccDepBinGen} should have changed!") endif() -file(TIMESTAMP "${rccDependsBin}" timeStep4 "${timeformat}") -if (NOT timeStep4 GREATER timeStep3) - message(SEND_ERROR "File (${rccDependsBin}) should have changed in the fourth step!") -endif() -# Sleep, update generated qrc file, rebuild and compare timestamp -execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. -configure_file(${rccDependsSrcDir}/res2b.qrc.in ${rccDependsBinDir}/res2.qrc.in COPYONLY) -execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDependsBinDir}" RESULT_VARIABLE result) + + +message("Changing nothing in the .qrc file") +# - Acquire binary timestamps before the build +file(TIMESTAMP "${rccDepBinPlain}" rdPlainBefore "${timeformat}") +file(TIMESTAMP "${rccDepBinGen}" rdGenBefore "${timeformat}") +# - Ensure that the timestamp will change +# - Change nothing +# - Rebuild +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) +execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDepBD}" RESULT_VARIABLE result) if (result) - message(SEND_ERROR "Sixth build of rccDepends failed.") -endif() -file(TIMESTAMP "${rccDependsBin}" timeStep5 "${timeformat}") -if (NOT timeStep5 GREATER timeStep4) - message(SEND_ERROR "File (${rccDependsBin}) should have changed in the fitfh step!") + message(SEND_ERROR "Fifth build of rccDepends failed.") endif() -# Sleep, touch generated qrc newly added input file, rebuild and compare timestamp -execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. -execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${rccDependsBinDir}/res2/inputAdded.txt") -execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${rccDependsBinDir}" RESULT_VARIABLE result) -if (result) - message(SEND_ERROR "Seventh build of rccDepends failed.") +# - Acquire binary timestamps after the build +file(TIMESTAMP "${rccDepBinPlain}" rdPlainAfter "${timeformat}") +file(TIMESTAMP "${rccDepBinGen}" rdGenAfter "${timeformat}") +# - Test if timestamps changed +if (rdPlainAfter GREATER rdPlainBefore) + message(SEND_ERROR "Plain .qrc binary ${rccDepBinPlain}) should NOT have changed!") endif() -file(TIMESTAMP "${rccDependsBin}" timeStep6 "${timeformat}") -if (NOT timeStep6 GREATER timeStep5) - message(SEND_ERROR "File (${rccDependsBin}) should have changed in the sixth step!") +if (rdGenAfter GREATER rdGenBefore) + message(SEND_ERROR "GENERATED .qrc binary ${rccDepBinGen} should NOT have changed!") endif() diff --git a/Tests/QtAutogenRerun/rccDepends/CMakeLists.txt b/Tests/QtAutogenRerun/rccDepends/CMakeLists.txt index edc0ac3..291592e 100644 --- a/Tests/QtAutogenRerun/rccDepends/CMakeLists.txt +++ b/Tests/QtAutogenRerun/rccDepends/CMakeLists.txt @@ -1,8 +1,6 @@ cmake_minimum_required(VERSION 3.9) project(rccDepends CXX) -set(CMAKE_AUTORCC ON) - if (QT_TEST_VERSION STREQUAL 4) find_package(Qt4 REQUIRED) set(QT_CORE_TARGET Qt4::QtCore) @@ -15,21 +13,29 @@ else() set(QT_CORE_TARGET Qt5::Core) endif() -configure_file(res/input1.txt.in res1/input.txt COPYONLY) -configure_file(res/input1.txt.in res1/inputAdded.txt COPYONLY) -configure_file(res/input2.txt.in res2/input.txt COPYONLY) -configure_file(res/input2.txt.in res2/inputAdded.txt COPYONLY) -# Dependency generated qrc file -add_custom_command(OUTPUT res2.qrc - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/res2.qrc.in - COMMAND ${CMAKE_COMMAND} -E sleep 2 - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/res2.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/res2.qrc - ) +# Enable AUTORCC for all targets +set(CMAKE_AUTORCC ON) + +# Initial resource files setup +configure_file(resPlain/input.txt.in resPlain/input.txt COPYONLY) +configure_file(resPlain/input.txt.in resPlain/inputAdded.txt COPYONLY) +configure_file(resGen/input.txt.in resGen/input.txt COPYONLY) +configure_file(resGen/input.txt.in resGen/inputAdded.txt COPYONLY) + +# Generated qrc file with dependency +add_custom_command(OUTPUT resGen.qrc + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/resGen.qrc.in + COMMAND ${CMAKE_COMMAND} -E sleep 2 + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/resGen.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/resGen.qrc) + +# Target that uses a plain .qrc file +add_executable(rccDependsPlain main.cpp ${CMAKE_CURRENT_BINARY_DIR}/resPlain.qrc) +target_link_libraries(rccDependsPlain ${QT_CORE_TARGET}) +add_custom_command(TARGET rccDependsPlain POST_BUILD COMMAND + ${CMAKE_COMMAND} -E echo "$" > targetPlain.txt) -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.txt) +# Target that uses a GENERATED .qrc file +add_executable(rccDependsGen main.cpp ${CMAKE_CURRENT_BINARY_DIR}/resGen.qrc ) +target_link_libraries(rccDependsGen ${QT_CORE_TARGET}) +add_custom_command(TARGET rccDependsGen POST_BUILD COMMAND + ${CMAKE_COMMAND} -E echo "$" > targetGen.txt) diff --git a/Tests/QtAutogenRerun/rccDepends/res/input1.txt.in b/Tests/QtAutogenRerun/rccDepends/res/input1.txt.in deleted file mode 100644 index da62762..0000000 --- a/Tests/QtAutogenRerun/rccDepends/res/input1.txt.in +++ /dev/null @@ -1 +0,0 @@ -Res1 input. diff --git a/Tests/QtAutogenRerun/rccDepends/res/input2.txt.in b/Tests/QtAutogenRerun/rccDepends/res/input2.txt.in deleted file mode 100644 index 08e14b7..0000000 --- a/Tests/QtAutogenRerun/rccDepends/res/input2.txt.in +++ /dev/null @@ -1 +0,0 @@ -Res2 input. diff --git a/Tests/QtAutogenRerun/rccDepends/res1a.qrc.in b/Tests/QtAutogenRerun/rccDepends/res1a.qrc.in deleted file mode 100644 index d111ffb..0000000 --- a/Tests/QtAutogenRerun/rccDepends/res1a.qrc.in +++ /dev/null @@ -1,5 +0,0 @@ - - - res1/input.txt - - diff --git a/Tests/QtAutogenRerun/rccDepends/res1b.qrc.in b/Tests/QtAutogenRerun/rccDepends/res1b.qrc.in deleted file mode 100644 index 4cb3f04..0000000 --- a/Tests/QtAutogenRerun/rccDepends/res1b.qrc.in +++ /dev/null @@ -1,6 +0,0 @@ - - - res1/input.txt - res1/inputAdded.txt - - diff --git a/Tests/QtAutogenRerun/rccDepends/res2a.qrc.in b/Tests/QtAutogenRerun/rccDepends/res2a.qrc.in deleted file mode 100644 index 19f34ac..0000000 --- a/Tests/QtAutogenRerun/rccDepends/res2a.qrc.in +++ /dev/null @@ -1,5 +0,0 @@ - - - res2/input.txt - - diff --git a/Tests/QtAutogenRerun/rccDepends/res2b.qrc.in b/Tests/QtAutogenRerun/rccDepends/res2b.qrc.in deleted file mode 100644 index 19e8ba1..0000000 --- a/Tests/QtAutogenRerun/rccDepends/res2b.qrc.in +++ /dev/null @@ -1,6 +0,0 @@ - - - res2/input.txt - res2/inputAdded.txt - - diff --git a/Tests/QtAutogenRerun/rccDepends/resGen/input.txt.in b/Tests/QtAutogenRerun/rccDepends/resGen/input.txt.in new file mode 100644 index 0000000..4f24589 --- /dev/null +++ b/Tests/QtAutogenRerun/rccDepends/resGen/input.txt.in @@ -0,0 +1 @@ +Generated resource input. diff --git a/Tests/QtAutogenRerun/rccDepends/resGen/inputAdded.txt.in b/Tests/QtAutogenRerun/rccDepends/resGen/inputAdded.txt.in new file mode 100644 index 0000000..4f24589 --- /dev/null +++ b/Tests/QtAutogenRerun/rccDepends/resGen/inputAdded.txt.in @@ -0,0 +1 @@ +Generated resource input. diff --git a/Tests/QtAutogenRerun/rccDepends/resGenA.qrc.in b/Tests/QtAutogenRerun/rccDepends/resGenA.qrc.in new file mode 100644 index 0000000..c131a34 --- /dev/null +++ b/Tests/QtAutogenRerun/rccDepends/resGenA.qrc.in @@ -0,0 +1,5 @@ + + + resGen/input.txt + + diff --git a/Tests/QtAutogenRerun/rccDepends/resGenB.qrc.in b/Tests/QtAutogenRerun/rccDepends/resGenB.qrc.in new file mode 100644 index 0000000..8c7e643 --- /dev/null +++ b/Tests/QtAutogenRerun/rccDepends/resGenB.qrc.in @@ -0,0 +1,6 @@ + + + resGen/input.txt + resGen/inputAdded.txt + + diff --git a/Tests/QtAutogenRerun/rccDepends/resPlain/input.txt.in b/Tests/QtAutogenRerun/rccDepends/resPlain/input.txt.in new file mode 100644 index 0000000..a5e407a --- /dev/null +++ b/Tests/QtAutogenRerun/rccDepends/resPlain/input.txt.in @@ -0,0 +1 @@ +Plaint resource input. diff --git a/Tests/QtAutogenRerun/rccDepends/resPlain/inputAdded.txt.in b/Tests/QtAutogenRerun/rccDepends/resPlain/inputAdded.txt.in new file mode 100644 index 0000000..a5e407a --- /dev/null +++ b/Tests/QtAutogenRerun/rccDepends/resPlain/inputAdded.txt.in @@ -0,0 +1 @@ +Plaint resource input. diff --git a/Tests/QtAutogenRerun/rccDepends/resPlainA.qrc.in b/Tests/QtAutogenRerun/rccDepends/resPlainA.qrc.in new file mode 100644 index 0000000..c135d85 --- /dev/null +++ b/Tests/QtAutogenRerun/rccDepends/resPlainA.qrc.in @@ -0,0 +1,5 @@ + + + resPlain/input.txt + + diff --git a/Tests/QtAutogenRerun/rccDepends/resPlainB.qrc.in b/Tests/QtAutogenRerun/rccDepends/resPlainB.qrc.in new file mode 100644 index 0000000..186b653 --- /dev/null +++ b/Tests/QtAutogenRerun/rccDepends/resPlainB.qrc.in @@ -0,0 +1,6 @@ + + + resPlain/input.txt + resPlain/inputAdded.txt + + -- cgit v0.12 From c8f92db72cedb4aa970be3c29b0fa1e3beff96f9 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Sat, 9 Sep 2017 22:32:16 +0200 Subject: Autogen: Tests: Disable an AUTOMOC_DEPENDS_FILTER test for Ninja Ninja does not recognize changes in included files that are generated by AUTOMOC on the first run. This is an open issue: https://gitlab.kitware.com/cmake/cmake/issues/16776 --- Tests/QtAutogenRerun/mocPlugin.cmake | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Tests/QtAutogenRerun/mocPlugin.cmake b/Tests/QtAutogenRerun/mocPlugin.cmake index 27ca691..7ad5ccb 100644 --- a/Tests/QtAutogenRerun/mocPlugin.cmake +++ b/Tests/QtAutogenRerun/mocPlugin.cmake @@ -57,7 +57,11 @@ if (NOT plDAfter GREATER plDBefore) message(SEND_ERROR "file (${plDFile}) should have changed!") endif() if (NOT plEAfter GREATER plEBefore) - message(SEND_ERROR "file (${plEFile}) should have changed!") + # There's a bug in Ninja on Windows + # https://gitlab.kitware.com/cmake/cmake/issues/16776 + if(NOT ("${CMAKE_GENERATOR}" MATCHES "Ninja")) + message(SEND_ERROR "file (${plEFile}) should have changed!") + endif() endif() # - Ensure that the timestamp will change. @@ -83,6 +87,10 @@ endif() if (NOT plDAfter GREATER plDBefore) message(SEND_ERROR "file (${plDFile}) should have changed!") endif() - if (NOT plEAfter GREATER plEBefore) - message(SEND_ERROR "file (${plEFile}) should have changed!") +if (NOT plEAfter GREATER plEBefore) + # There's a bug in Ninja on Windows + # https://gitlab.kitware.com/cmake/cmake/issues/16776 + if(NOT ("${CMAKE_GENERATOR}" MATCHES "Ninja")) + message(SEND_ERROR "file (${plEFile}) should have changed!") + endif() endif() -- cgit v0.12 From 51fd7b714ba518e70f4aa192b1d39e32eea79aef Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Thu, 14 Sep 2017 20:34:32 +0200 Subject: Autogen: Tests: Add a change-not test to the mocRerun test --- Tests/QtAutogenRerun/mocRerun.cmake | 43 +++++++++++++++++++++------- Tests/QtAutogenRerun/mocRerun/CMakeLists.txt | 10 +++---- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/Tests/QtAutogenRerun/mocRerun.cmake b/Tests/QtAutogenRerun/mocRerun.cmake index eb7a07c..a92912b 100644 --- a/Tests/QtAutogenRerun/mocRerun.cmake +++ b/Tests/QtAutogenRerun/mocRerun.cmake @@ -4,7 +4,7 @@ set(mocRerunSrcDir "${CMAKE_CURRENT_SOURCE_DIR}/mocRerun") set(mocRerunBinDir "${CMAKE_CURRENT_BINARY_DIR}/mocRerun") # Initial build -configure_file(mocRerun/test1a.h.in mocRerun/test1.h COPYONLY) +configure_file("${mocRerunSrcDir}/test1a.h.in" "${mocRerunBinDir}/test1.h" COPYONLY) try_compile(MOC_RERUN "${mocRerunBinDir}" "${mocRerunSrcDir}" @@ -17,23 +17,44 @@ try_compile(MOC_RERUN if (NOT MOC_RERUN) message(SEND_ERROR "Initial build of mocRerun failed. Output: ${output}") endif() - # Get name of the output binary -file(STRINGS "${mocRerunBinDir}/target1.txt" target1List ENCODING UTF-8) -list(GET target1List 0 binFile) - -file(TIMESTAMP "${binFile}" timeBegin "${timeformat}") +file(STRINGS "${mocRerunBinDir}/mocRerun.txt" mocRerunList ENCODING UTF-8) +list(GET mocRerunList 0 mocRerunBin) -# Change header file content and rebuild +message("Changing the header content for a MOC rerun") +# - Acquire binary timestamps before the build +file(TIMESTAMP "${mocRerunBin}" timeBefore "${timeformat}") +# - Ensure that the timestamp will change +# - Change header file content and rebuild +# - Rebuild execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) -configure_file(mocRerun/test1b.h.in mocRerun/test1.h COPYONLY) +configure_file("${mocRerunSrcDir}/test1b.h.in" "${mocRerunBinDir}/test1.h" COPYONLY) execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocRerunBinDir}" RESULT_VARIABLE result ) if (result) message(SEND_ERROR "Second build of mocRerun failed.") endif() +# - Acquire binary timestamps after the build +file(TIMESTAMP "${mocRerunBin}" timeAfter "${timeformat}") +# - Test if timestamps changed +if (NOT timeAfter GREATER timeBefore) + message(SEND_ERROR "File (${mocRerunBin}) should have changed!") +endif() -file(TIMESTAMP "${binFile}" timeStep1 "${timeformat}") -if (NOT timeStep1 GREATER timeBegin) - message(SEND_ERROR "File (${binFile}) should have changed in the first step!") +message("Changing nothing for a MOC rerun") +# - Acquire binary timestamps before the build +file(TIMESTAMP "${mocRerunBin}" timeBefore "${timeformat}") +# - Ensure that the timestamp would change +# - Change nothing +# - Rebuild +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) +execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${mocRerunBinDir}" RESULT_VARIABLE result ) +if (result) + message(SEND_ERROR "Third build of mocRerun failed.") +endif() +# - Acquire binary timestamps after the build +file(TIMESTAMP "${mocRerunBin}" timeAfter "${timeformat}") +# - Test if timestamps changed +if (timeAfter GREATER timeBefore) + message(SEND_ERROR "File (${mocRerunBin}) should not have changed!") endif() diff --git a/Tests/QtAutogenRerun/mocRerun/CMakeLists.txt b/Tests/QtAutogenRerun/mocRerun/CMakeLists.txt index 7380bdd..bafd9cf 100644 --- a/Tests/QtAutogenRerun/mocRerun/CMakeLists.txt +++ b/Tests/QtAutogenRerun/mocRerun/CMakeLists.txt @@ -19,17 +19,15 @@ set(CMAKE_AUTORCC ON) # Generated source file add_custom_command(OUTPUT main.cpp - COMMAND ${CMAKE_COMMAND} -E sleep 2 - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/main.cpp - ) + COMMAND ${CMAKE_COMMAND} -E sleep 2 + 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 - ) + 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 "$" > target1.txt) + ${CMAKE_COMMAND} -E echo "$" > mocRerun.txt) -- cgit v0.12