From 0a5dd3c700f1873be217707aa89a805d009bac3e Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Sat, 6 Aug 2016 13:09:59 +0200 Subject: [PATCH 1/6] cmFilePathUuid: Add class to generate deterministic unique file names The class generates a semi-unique (checksum based) pathless file name from a full source file path. --- Source/CMakeLists.txt | 2 + Source/cmFilePathUuid.cxx | 132 ++++++++++++++++++++++++++++++++++++++ Source/cmFilePathUuid.h | 77 ++++++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 Source/cmFilePathUuid.cxx create mode 100644 Source/cmFilePathUuid.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index a79099497..cdc8fb132 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -238,6 +238,8 @@ set(SRCS cmFileLockPool.h cmFileLockResult.cxx cmFileLockResult.h + cmFilePathUuid.cxx + cmFilePathUuid.h cmFileTimeComparison.cxx cmFileTimeComparison.h cmFortranLexer.cxx diff --git a/Source/cmFilePathUuid.cxx b/Source/cmFilePathUuid.cxx new file mode 100644 index 000000000..2839b63da --- /dev/null +++ b/Source/cmFilePathUuid.cxx @@ -0,0 +1,132 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2016 Sebastian Holtermann (sebholt@xwmw.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmFilePathUuid.h" + +#include "cmCryptoHash.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" +#include "cmsys/Base64.h" + +cmFilePathUuid::cmFilePathUuid(cmMakefile* makefile) +{ + initParentDirs(makefile->GetCurrentSourceDirectory(), + makefile->GetCurrentBinaryDirectory(), + makefile->GetHomeDirectory(), + makefile->GetHomeOutputDirectory()); +} + +cmFilePathUuid::cmFilePathUuid(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir) +{ + initParentDirs(currentSrcDir, currentBinDir, projectSrcDir, projectBinDir); +} + +void cmFilePathUuid::initParentDirs(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir) +{ + parentDirs[0].first = cmsys::SystemTools::GetRealPath(currentSrcDir); + parentDirs[1].first = cmsys::SystemTools::GetRealPath(currentBinDir); + parentDirs[2].first = cmsys::SystemTools::GetRealPath(projectSrcDir); + parentDirs[3].first = cmsys::SystemTools::GetRealPath(projectBinDir); + + parentDirs[0].second = "CurrentSource"; + parentDirs[1].second = "CurrentBinary"; + parentDirs[2].second = "ProjectSource"; + parentDirs[3].second = "ProjectBinary"; +} + +std::string cmFilePathUuid::get(const std::string& filePath, + const char* outputPrefix, + const char* outputSuffix) +{ + std::string sourceFilename = cmsys::SystemTools::GetFilenameName(filePath); + std::string sourceBasename = + cmsys::SystemTools::GetFilenameWithoutLastExtension(sourceFilename); + + // Acquire checksum string + std::string checksum; + { + std::string sourceRelPath; + std::string sourceRelSeed; + GetRelPathSeed(filePath, sourceRelPath, sourceRelSeed); + checksum = GetChecksumString(sourceFilename, sourceRelPath, sourceRelSeed); + } + + // Compose the file name + std::string uuid; + if (outputPrefix) { + uuid += outputPrefix; + } + uuid += sourceBasename.substr(0, partLengthName); + uuid += "_"; + uuid += checksum.substr(0, partLengthCheckSum); + if (outputSuffix) { + uuid += outputSuffix; + } + return uuid; +} + +void cmFilePathUuid::GetRelPathSeed(const std::string& filePath, + std::string& sourceRelPath, + std::string& sourceRelSeed) +{ + const std::string sourceNameReal = cmsys::SystemTools::GetRealPath(filePath); + std::string parentDirectory; + // Find closest project parent directory + for (size_t ii = 0; ii != numParentDirs; ++ii) { + const std::string& pDir = parentDirs[ii].first; + if (!pDir.empty() && + cmsys::SystemTools::IsSubDirectory(sourceNameReal, pDir)) { + sourceRelSeed = parentDirs[ii].second; + parentDirectory = pDir; + break; + } + } + // Check if the file path is below a known project directory + if (parentDirectory.empty()) { + // Use file syste root as fallback parent directory + sourceRelSeed = "FileSystemRoot"; + cmsys::SystemTools::SplitPathRootComponent(sourceNameReal, + &parentDirectory); + } + sourceRelPath = cmsys::SystemTools::RelativePath( + parentDirectory, cmsys::SystemTools::GetParentDirectory(sourceNameReal)); +} + +std::string cmFilePathUuid::GetChecksumString( + const std::string& sourceFilename, const std::string& sourceRelPath, + const std::string& sourceRelSeed) +{ + std::string checksumBase64; + { + // Calculate the file ( seed + relative path + name ) checksum + std::vector hashBytes = + cmCryptoHash::New("SHA256")->ByteHashString( + (sourceRelSeed + sourceRelPath + sourceFilename).c_str()); + // Convert hash bytes to Base64 text string + std::vector base64Bytes(hashBytes.size() * 2, 0); + cmsysBase64_Encode(&hashBytes[0], hashBytes.size(), &base64Bytes[0], 0); + checksumBase64 = reinterpret_cast(&base64Bytes[0]); + } + // Base64 allows '/', '+' and '=' characters which are problematic + // when used in file names. Replace them with safer alternatives. + std::replace(checksumBase64.begin(), checksumBase64.end(), '/', '-'); + std::replace(checksumBase64.begin(), checksumBase64.end(), '+', '_'); + std::replace(checksumBase64.begin(), checksumBase64.end(), '=', '_'); + + return checksumBase64; +} diff --git a/Source/cmFilePathUuid.h b/Source/cmFilePathUuid.h new file mode 100644 index 000000000..42e89b106 --- /dev/null +++ b/Source/cmFilePathUuid.h @@ -0,0 +1,77 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2016 Sebastian Holtermann (sebholt@xwmw.org) + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmFilePathUuid_h +#define cmFilePathUuid_h + +#include "cmStandardIncludes.h" + +#include +#include + +class cmMakefile; + +/** \class cmFilePathUuid + * @brief Generates a unique pathless file name with a checksum component + * calculated from the file path. + * + * The checksum is calculated from the relative file path to the + * closest known project directory. This guarantees reproducibility + * when source and build directory differ e.g. for different project + * build directories. + */ +class cmFilePathUuid +{ +public: + /// Maximum number of characters to use from the file name + static const size_t partLengthName = 14; + /// Maximum number of characters to use from the path checksum + static const size_t partLengthCheckSum = 14; + + /// @brief Initilizes the parent directories from a makefile + cmFilePathUuid(cmMakefile* makefile); + + /// @brief Initilizes the parent directories manually + cmFilePathUuid(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir); + + /* @brief Calculates and returns the uuid for a file path + * + * @arg outputPrefix optional string to prepend to the result + * @arg outputSuffix optional string to append to the result + */ + std::string get(const std::string& filePath, const char* outputPrefix = NULL, + const char* outputSuffix = NULL); + +private: + void initParentDirs(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir); + + /// Returns the relative path and the parent directory key string (seed) + void GetRelPathSeed(const std::string& filePath, std::string& sourceRelPath, + std::string& sourceRelSeed); + + std::string GetChecksumString(const std::string& sourceFilename, + const std::string& sourceRelPath, + const std::string& sourceRelSeed); + + /// Size of the parent directory list + static const size_t numParentDirs = 4; + /// List of (directory name, seed name) pairs + std::pair parentDirs[numParentDirs]; +}; + +#endif From 3c3b37b0bbd3fb78aa60a2b38184b6397d2ea47f Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Sat, 6 Aug 2016 14:05:23 +0200 Subject: [PATCH 2/6] QtAutogen: Use std:: instead of ::std:: --- Source/cmQtAutoGenerators.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 174760f5f..ea8db713d 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -1183,7 +1183,7 @@ bool cmQtAutoGenerators::GenerateUi(const std::string& realName, cmsys::SystemTools::MakeDirectory(this->Builddir.c_str()); } - const ::std::string uiBuildFile = this->Builddir + uiOutputFile; + const std::string uiBuildFile = this->Builddir + uiOutputFile; int sourceNewerThanUi = 0; bool success = cmsys::SystemTools::FileTimeCompare(uiInputFile, uiBuildFile, @@ -1299,7 +1299,7 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, { const std::string basename = cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); - const ::std::string qrcBuildFile = this->Builddir + qrcOutputFile; + const std::string qrcBuildFile = this->Builddir + qrcOutputFile; int sourceNewerThanQrc = 0; bool generateQrc = !cmsys::SystemTools::FileTimeCompare( From 41c9e14afb0bc7e68e4530f76329b7c11cdfa0e4 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Sat, 6 Aug 2016 13:33:46 +0200 Subject: [PATCH 3/6] QtAutogen: Allow multiple moc files with the same name Use cmFilePathUuid for moc files. Closes: #12873 --- Source/cmQtAutoGenerators.cxx | 22 ++++++++++++---------- Source/cmQtAutoGenerators.h | 3 ++- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index ea8db713d..33f7a54a9 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -14,6 +14,7 @@ #include "cmQtAutoGenerators.h" #include "cmAlgorithms.h" +#include "cmFilePathUuid.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmOutputConverter.h" @@ -358,11 +359,13 @@ void cmQtAutoGenerators::WriteOldMocDefinitionsFile( void cmQtAutoGenerators::Init() { + this->TargetBuildSubDir = this->TargetName; + this->TargetBuildSubDir += ".dir/"; + this->OutMocCppFilenameRel = this->TargetName; this->OutMocCppFilenameRel += ".cpp"; - this->OutMocCppFilename = this->Builddir; - this->OutMocCppFilename += this->OutMocCppFilenameRel; + this->OutMocCppFilenameAbs = this->Builddir + this->OutMocCppFilenameRel; std::vector cdefList; cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList); @@ -439,7 +442,7 @@ static std::string ReadAll(const std::string& filename) bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile) { - if (!cmsys::SystemTools::FileExists(this->OutMocCppFilename.c_str()) || + if (!cmsys::SystemTools::FileExists(this->OutMocCppFilenameAbs.c_str()) || (this->OldCompileSettingsStr != this->CurrentCompileSettingsStr)) { this->GenerateAll = true; } @@ -933,6 +936,8 @@ void cmQtAutoGenerators::ParseHeaders( std::map& notIncludedMocs, std::map >& includedUis) { + cmFilePathUuid fpathUuid(this->Srcdir, this->Builddir, + this->ProjectSourceDir, this->ProjectBinaryDir); for (std::set::const_iterator hIt = absHeaders.begin(); hIt != absHeaders.end(); ++hIt) { const std::string& headerName = *hIt; @@ -946,13 +951,10 @@ void cmQtAutoGenerators::ParseHeaders( this->LogInfo(err.str()); } - const std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(headerName); - - const std::string currentMoc = "moc_" + basename + ".cpp"; std::string macroName; if (requiresMocing(contents, macroName)) { - notIncludedMocs[headerName] = currentMoc; + notIncludedMocs[headerName] = + this->TargetBuildSubDir + fpathUuid.get(headerName, "moc_", ".cpp"); } } this->ParseForUic(headerName, contents, includedUis); @@ -1029,7 +1031,7 @@ bool cmQtAutoGenerators::GenerateMocFiles( // check if we even need to update _automoc.cpp if (!automocCppChanged) { // compare contents of the _automoc.cpp file - const std::string oldContents = ReadAll(this->OutMocCppFilename); + const std::string oldContents = ReadAll(this->OutMocCppFilenameAbs); if (oldContents == automocSource) { // nothing changed: don't touch the _automoc.cpp file if (this->Verbose) { @@ -1052,7 +1054,7 @@ bool cmQtAutoGenerators::GenerateMocFiles( } { cmsys::ofstream outfile; - outfile.open(this->OutMocCppFilename.c_str(), std::ios::trunc); + outfile.open(this->OutMocCppFilenameAbs.c_str(), std::ios::trunc); outfile << automocSource; outfile.close(); } diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 86913f078..216b0b034 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -123,8 +123,9 @@ private: std::string CurrentCompileSettingsStr; std::string OldCompileSettingsStr; + std::string TargetBuildSubDir; std::string OutMocCppFilenameRel; - std::string OutMocCppFilename; + std::string OutMocCppFilenameAbs; std::list MocIncludes; std::list MocDefinitions; std::vector MocOptions; From 4e9b97d7397fd526e6b4e4ce43dd305cb8341ac8 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Sat, 6 Aug 2016 14:57:52 +0200 Subject: [PATCH 4/6] QtAutogen: Allow multiple qrc files with the same name Use cmFilePathUuid for qrc files. --- Source/cmQtAutoGeneratorInitializer.cxx | 76 ++++++++++++++----------- Source/cmQtAutoGenerators.cxx | 62 +++++++++++++++----- Source/cmQtAutoGenerators.h | 3 +- 3 files changed, 93 insertions(+), 48 deletions(-) diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index d5634e8ba..7efb333a7 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -13,6 +13,7 @@ #include "cmQtAutoGeneratorInitializer.h" +#include "cmFilePathUuid.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmSourceFile.h" @@ -25,6 +26,34 @@ #include "cmGlobalVisualStudioGenerator.h" #endif +static std::string GetAutogenTargetName(cmGeneratorTarget const* target) +{ + std::string autogenTargetName = target->GetName(); + autogenTargetName += "_automoc"; + return autogenTargetName; +} + +static std::string GetAutogenTargetDir(cmGeneratorTarget const* target) +{ + cmMakefile* makefile = target->Target->GetMakefile(); + std::string targetDir = makefile->GetCurrentBinaryDirectory(); + targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory(); + targetDir += "/"; + targetDir += GetAutogenTargetName(target); + targetDir += ".dir/"; + return targetDir; +} + +static std::string GetAutogenTargetBuildDir(cmGeneratorTarget const* target) +{ + cmMakefile* makefile = target->Target->GetMakefile(); + std::string targetDir = makefile->GetCurrentBinaryDirectory(); + targetDir += "/"; + targetDir += GetAutogenTargetName(target); + targetDir += ".dir/"; + return targetDir; +} + static void SetupSourceFiles(cmGeneratorTarget const* target, std::vector& skipMoc, std::vector& mocSources, @@ -38,6 +67,7 @@ static void SetupSourceFiles(cmGeneratorTarget const* target, std::vector newRccFiles; + cmFilePathUuid fpathUuid(makefile); for (std::vector::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; @@ -55,13 +85,12 @@ static void SetupSourceFiles(cmGeneratorTarget const* target, if (target->GetPropertyAsBool("AUTORCC")) { if (ext == "qrc" && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { - std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); - std::string rcc_output_dir = target->GetSupportDirectory(); - cmSystemTools::MakeDirectory(rcc_output_dir.c_str()); - std::string rcc_output_file = rcc_output_dir; - rcc_output_file += "/qrc_" + basename + ".cpp"; + std::string rcc_output_file = GetAutogenTargetBuildDir(target); + // Create output directory + cmSystemTools::MakeDirectory(rcc_output_file.c_str()); + rcc_output_file += fpathUuid.get(absFile, "qrc_", ".cpp"); + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", rcc_output_file.c_str(), false); makefile->GetOrCreateSource(rcc_output_file, true); @@ -365,24 +394,6 @@ static void MergeRccOptions(std::vector& opts, opts.insert(opts.end(), extraOpts.begin(), extraOpts.end()); } -std::string GetAutogenTargetName(cmGeneratorTarget const* target) -{ - std::string autogenTargetName = target->GetName(); - autogenTargetName += "_automoc"; - return autogenTargetName; -} - -std::string GetAutogenTargetDir(cmGeneratorTarget const* target) -{ - cmMakefile* makefile = target->Target->GetMakefile(); - std::string targetDir = makefile->GetCurrentBinaryDirectory(); - targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory(); - targetDir += "/"; - targetDir += GetAutogenTargetName(target); - targetDir += ".dir/"; - return targetDir; -} - static void copyTargetProperty(cmTarget* destinationTarget, cmTarget* sourceTarget, const std::string& propertyName) @@ -737,6 +748,7 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( ) { std::vector srcFiles; target->GetConfigCommonSourceFiles(srcFiles); + cmFilePathUuid fpathUuid(makefile); for (std::vector::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; @@ -747,15 +759,13 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( if (target->GetPropertyAsBool("AUTORCC")) { if (ext == "qrc" && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { - std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); - - std::string rcc_output_dir = target->GetSupportDirectory(); - cmSystemTools::MakeDirectory(rcc_output_dir.c_str()); - std::string rcc_output_file = rcc_output_dir; - rcc_output_file += "/qrc_" + basename + ".cpp"; - rcc_output.push_back(rcc_output_file); - + { + std::string rcc_output_file = GetAutogenTargetBuildDir(target); + // Create output directory + cmSystemTools::MakeDirectory(rcc_output_file.c_str()); + rcc_output_file += fpathUuid.get(absFile, "qrc_", ".cpp"); + rcc_output.push_back(rcc_output_file); + } if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { if (qtMajorVersion == "5") { ListQt5RccInputs(sf, target, depends); diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 33f7a54a9..a261962a2 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -88,6 +88,23 @@ static std::string extractSubDir(const std::string& absPath, return subDir; } +static bool FileNameIsUnique(const std::string& filePath, + const std::map& fileMap) +{ + size_t count(0); + const std::string fileName = cmsys::SystemTools::GetFilenameName(filePath); + for (std::map::const_iterator si = fileMap.begin(); + si != fileMap.end(); ++si) { + if (cmsys::SystemTools::GetFilenameName(si->first) == fileName) { + ++count; + if (count > 1) { + return false; + } + } + } + return true; +} + cmQtAutoGenerators::cmQtAutoGenerators() : Verbose(cmsys::SystemTools::HasEnv("VERBOSE")) , ColorOutput(true) @@ -1257,15 +1274,18 @@ bool cmQtAutoGenerators::GenerateQrcFiles() { // generate single map with input / output names std::map qrcGenMap; - for (std::vector::const_iterator si = this->RccSources.begin(); - si != this->RccSources.end(); ++si) { - const std::string ext = cmsys::SystemTools::GetFilenameLastExtension(*si); - if (ext == ".qrc") { - std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(*si); - std::string qrcOutputFile = "CMakeFiles/" + this->OriginTargetName + - ".dir/qrc_" + basename + ".cpp"; - qrcGenMap[*si] = qrcOutputFile; + { + cmFilePathUuid fpathUuid(this->Srcdir, this->Builddir, + this->ProjectSourceDir, this->ProjectBinaryDir); + for (std::vector::const_iterator si = + this->RccSources.begin(); + si != this->RccSources.end(); ++si) { + const std::string ext = + cmsys::SystemTools::GetFilenameLastExtension(*si); + if (ext == ".qrc") { + qrcGenMap[*si] = + (this->TargetBuildSubDir + fpathUuid.get(*si, "qrc_", ".cpp")); + } } } @@ -1287,7 +1307,8 @@ bool cmQtAutoGenerators::GenerateQrcFiles() for (std::map::const_iterator si = qrcGenMap.begin(); si != qrcGenMap.end(); ++si) { - if (!this->GenerateQrc(si->first, si->second)) { + bool unique = FileNameIsUnique(si->first, qrcGenMap); + if (!this->GenerateQrc(si->first, si->second, unique)) { if (this->RunRccFailed) { return false; } @@ -1297,10 +1318,23 @@ bool cmQtAutoGenerators::GenerateQrcFiles() } bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, - const std::string& qrcOutputFile) + const std::string& qrcOutputFile, + bool unique_n) { - const std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); + std::string symbolName; + if (unique_n) { + symbolName = + cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); + } else { + symbolName = + cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcOutputFile); + // Remove "qrc_" at string begin + symbolName.erase(0, 4); + } + // Replace '-' with '_'. The former is valid for + // file names but not for symbol names. + std::replace(symbolName.begin(), symbolName.end(), '-', '_'); + const std::string qrcBuildFile = this->Builddir + qrcOutputFile; int sourceNewerThanQrc = 0; @@ -1327,7 +1361,7 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, } command.push_back("-name"); - command.push_back(basename); + command.push_back(symbolName); command.push_back("-o"); command.push_back(qrcBuildFile); command.push_back(qrcInputFile); diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 216b0b034..fab2d1934 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -51,7 +51,8 @@ private: const std::string& uiOutputFile); bool GenerateQrcFiles(); bool GenerateQrc(const std::string& qrcInputFile, - const std::string& qrcOutputFile); + const std::string& qrcOutputFile, bool unique_n); + void ParseCppFile( const std::string& absFilename, const std::vector& headerExtensions, From e4f508e42397549cd966e47349d4030cb793c354 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Sat, 6 Aug 2016 15:22:54 +0200 Subject: [PATCH 5/6] Tests/QtAutogen: Test same moc/qrc source names in different directories --- Tests/QtAutogen/CMakeLists.txt | 4 ++++ Tests/QtAutogen/sameName/CMakeLists.txt | 21 +++++++++++++++++++++ Tests/QtAutogen/sameName/aaa/bbb/data.qrc | 6 ++++++ Tests/QtAutogen/sameName/aaa/bbb/item.cpp | 10 ++++++++++ Tests/QtAutogen/sameName/aaa/bbb/item.hpp | 18 ++++++++++++++++++ Tests/QtAutogen/sameName/aaa/data.qrc | 6 ++++++ Tests/QtAutogen/sameName/aaa/item.cpp | 8 ++++++++ Tests/QtAutogen/sameName/aaa/item.hpp | 16 ++++++++++++++++ Tests/QtAutogen/sameName/bbb/aaa/data.qrc | 6 ++++++ Tests/QtAutogen/sameName/bbb/aaa/item.cpp | 10 ++++++++++ Tests/QtAutogen/sameName/bbb/aaa/item.hpp | 18 ++++++++++++++++++ Tests/QtAutogen/sameName/bbb/data.qrc | 6 ++++++ Tests/QtAutogen/sameName/bbb/item.cpp | 8 ++++++++ Tests/QtAutogen/sameName/bbb/item.hpp | 16 ++++++++++++++++ Tests/QtAutogen/sameName/ccc/data.qrc | 6 ++++++ Tests/QtAutogen/sameName/ccc/item.cpp | 23 +++++++++++++++++++++++ Tests/QtAutogen/sameName/ccc/item.hpp | 16 ++++++++++++++++ Tests/QtAutogen/sameName/data.qrc | 5 +++++ Tests/QtAutogen/sameName/item.cpp | 5 +++++ Tests/QtAutogen/sameName/item.hpp | 13 +++++++++++++ Tests/QtAutogen/sameName/main.cpp | 16 ++++++++++++++++ 21 files changed, 237 insertions(+) create mode 100644 Tests/QtAutogen/sameName/CMakeLists.txt create mode 100644 Tests/QtAutogen/sameName/aaa/bbb/data.qrc create mode 100644 Tests/QtAutogen/sameName/aaa/bbb/item.cpp create mode 100644 Tests/QtAutogen/sameName/aaa/bbb/item.hpp create mode 100644 Tests/QtAutogen/sameName/aaa/data.qrc create mode 100644 Tests/QtAutogen/sameName/aaa/item.cpp create mode 100644 Tests/QtAutogen/sameName/aaa/item.hpp create mode 100644 Tests/QtAutogen/sameName/bbb/aaa/data.qrc create mode 100644 Tests/QtAutogen/sameName/bbb/aaa/item.cpp create mode 100644 Tests/QtAutogen/sameName/bbb/aaa/item.hpp create mode 100644 Tests/QtAutogen/sameName/bbb/data.qrc create mode 100644 Tests/QtAutogen/sameName/bbb/item.cpp create mode 100644 Tests/QtAutogen/sameName/bbb/item.hpp create mode 100644 Tests/QtAutogen/sameName/ccc/data.qrc create mode 100644 Tests/QtAutogen/sameName/ccc/item.cpp create mode 100644 Tests/QtAutogen/sameName/ccc/item.hpp create mode 100644 Tests/QtAutogen/sameName/data.qrc create mode 100644 Tests/QtAutogen/sameName/item.cpp create mode 100644 Tests/QtAutogen/sameName/item.hpp create mode 100644 Tests/QtAutogen/sameName/main.cpp diff --git a/Tests/QtAutogen/CMakeLists.txt b/Tests/QtAutogen/CMakeLists.txt index d5aca55c7..e35e1d1ff 100644 --- a/Tests/QtAutogen/CMakeLists.txt +++ b/Tests/QtAutogen/CMakeLists.txt @@ -110,6 +110,10 @@ set_target_properties( AUTOMOC TRUE ) +# Test AUTOMOC and AUTORCC on source files with the same name +# but in different subdirectories +add_subdirectory(sameName) + include(GenerateExportHeader) # The order is relevant here. B depends on A, and B headers depend on A # headers both subdirectories use CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE and we diff --git a/Tests/QtAutogen/sameName/CMakeLists.txt b/Tests/QtAutogen/sameName/CMakeLists.txt new file mode 100644 index 000000000..ed045fb30 --- /dev/null +++ b/Tests/QtAutogen/sameName/CMakeLists.txt @@ -0,0 +1,21 @@ +# Test AUTOMOC and AUTORCC on source files with the same name +# but in different subdirectories + +add_executable(sameName + aaa/bbb/item.cpp + aaa/bbb/data.qrc + aaa/item.cpp + aaa/data.qrc + bbb/aaa/item.cpp + bbb/aaa/data.qrc + bbb/item.cpp + bbb/data.qrc + ccc/item.cpp + ccc/data.qrc + item.cpp + data.qrc + main.cpp +) +target_include_directories(sameName PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_link_libraries(sameName ${QT_LIBRARIES}) +set_target_properties( sameName PROPERTIES AUTOMOC TRUE AUTORCC TRUE ) diff --git a/Tests/QtAutogen/sameName/aaa/bbb/data.qrc b/Tests/QtAutogen/sameName/aaa/bbb/data.qrc new file mode 100644 index 000000000..0ea353756 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/bbb/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/aaa/bbb/item.cpp b/Tests/QtAutogen/sameName/aaa/bbb/item.cpp new file mode 100644 index 000000000..20d00445e --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/bbb/item.cpp @@ -0,0 +1,10 @@ +#include "item.hpp" + +namespace aaa { +namespace bbb { + +void Item::go() +{ +} +} +} diff --git a/Tests/QtAutogen/sameName/aaa/bbb/item.hpp b/Tests/QtAutogen/sameName/aaa/bbb/item.hpp new file mode 100644 index 000000000..085504385 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/bbb/item.hpp @@ -0,0 +1,18 @@ +#ifndef AAA_BBB_ITEM_HPP +#define AAA_BBB_ITEM_HPP + +#include + +namespace aaa { +namespace bbb { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} +} + +#endif diff --git a/Tests/QtAutogen/sameName/aaa/data.qrc b/Tests/QtAutogen/sameName/aaa/data.qrc new file mode 100644 index 000000000..379af60c8 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/aaa/item.cpp b/Tests/QtAutogen/sameName/aaa/item.cpp new file mode 100644 index 000000000..95dd3b674 --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/item.cpp @@ -0,0 +1,8 @@ +#include "item.hpp" + +namespace aaa { + +void Item::go() +{ +} +} diff --git a/Tests/QtAutogen/sameName/aaa/item.hpp b/Tests/QtAutogen/sameName/aaa/item.hpp new file mode 100644 index 000000000..b63466f6d --- /dev/null +++ b/Tests/QtAutogen/sameName/aaa/item.hpp @@ -0,0 +1,16 @@ +#ifndef AAA_ITEM_HPP +#define AAA_ITEM_HPP + +#include + +namespace aaa { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} + +#endif diff --git a/Tests/QtAutogen/sameName/bbb/aaa/data.qrc b/Tests/QtAutogen/sameName/bbb/aaa/data.qrc new file mode 100644 index 000000000..da980091a --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/aaa/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/bbb/aaa/item.cpp b/Tests/QtAutogen/sameName/bbb/aaa/item.cpp new file mode 100644 index 000000000..ac4b2c27b --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/aaa/item.cpp @@ -0,0 +1,10 @@ +#include "item.hpp" + +namespace bbb { +namespace aaa { + +void Item::go() +{ +} +} +} diff --git a/Tests/QtAutogen/sameName/bbb/aaa/item.hpp b/Tests/QtAutogen/sameName/bbb/aaa/item.hpp new file mode 100644 index 000000000..be07ca84c --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/aaa/item.hpp @@ -0,0 +1,18 @@ +#ifndef BBB_AAA_ITEM_HPP +#define BBB_AAA_ITEM_HPP + +#include + +namespace bbb { +namespace aaa { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} +} + +#endif diff --git a/Tests/QtAutogen/sameName/bbb/data.qrc b/Tests/QtAutogen/sameName/bbb/data.qrc new file mode 100644 index 000000000..5b080f5fa --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/bbb/item.cpp b/Tests/QtAutogen/sameName/bbb/item.cpp new file mode 100644 index 000000000..f97a1431e --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/item.cpp @@ -0,0 +1,8 @@ +#include "item.hpp" + +namespace bbb { + +void Item::go() +{ +} +} diff --git a/Tests/QtAutogen/sameName/bbb/item.hpp b/Tests/QtAutogen/sameName/bbb/item.hpp new file mode 100644 index 000000000..5b7f9850b --- /dev/null +++ b/Tests/QtAutogen/sameName/bbb/item.hpp @@ -0,0 +1,16 @@ +#ifndef BBB_ITEM_HPP +#define BBB_ITEM_HPP + +#include + +namespace bbb { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} + +#endif diff --git a/Tests/QtAutogen/sameName/ccc/data.qrc b/Tests/QtAutogen/sameName/ccc/data.qrc new file mode 100644 index 000000000..f934c39b9 --- /dev/null +++ b/Tests/QtAutogen/sameName/ccc/data.qrc @@ -0,0 +1,6 @@ + + + item.hpp + item.cpp + + diff --git a/Tests/QtAutogen/sameName/ccc/item.cpp b/Tests/QtAutogen/sameName/ccc/item.cpp new file mode 100644 index 000000000..d90b2b8c7 --- /dev/null +++ b/Tests/QtAutogen/sameName/ccc/item.cpp @@ -0,0 +1,23 @@ +#include "item.hpp" + +namespace ccc { + +void Item::go() +{ +} + +class MocTest : public QObject +{ + Q_OBJECT; + Q_SLOT + void go(); +}; + +void MocTest::go() +{ +} +} + +// Include own moc files +#include "item.moc" +#include "moc_item.cpp" diff --git a/Tests/QtAutogen/sameName/ccc/item.hpp b/Tests/QtAutogen/sameName/ccc/item.hpp new file mode 100644 index 000000000..96fcc245c --- /dev/null +++ b/Tests/QtAutogen/sameName/ccc/item.hpp @@ -0,0 +1,16 @@ +#ifndef CCC_ITEM_HPP +#define CCC_ITEM_HPP + +#include + +namespace ccc { + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; +} + +#endif diff --git a/Tests/QtAutogen/sameName/data.qrc b/Tests/QtAutogen/sameName/data.qrc new file mode 100644 index 000000000..4ce0b4ec1 --- /dev/null +++ b/Tests/QtAutogen/sameName/data.qrc @@ -0,0 +1,5 @@ + + + main.cpp + + diff --git a/Tests/QtAutogen/sameName/item.cpp b/Tests/QtAutogen/sameName/item.cpp new file mode 100644 index 000000000..e013cf392 --- /dev/null +++ b/Tests/QtAutogen/sameName/item.cpp @@ -0,0 +1,5 @@ +#include "item.hpp" + +void Item::go() +{ +} diff --git a/Tests/QtAutogen/sameName/item.hpp b/Tests/QtAutogen/sameName/item.hpp new file mode 100644 index 000000000..91bba3b4d --- /dev/null +++ b/Tests/QtAutogen/sameName/item.hpp @@ -0,0 +1,13 @@ +#ifndef ITEM_HPP +#define ITEM_HPP + +#include + +class Item : public QObject +{ + Q_OBJECT + Q_SLOT + void go(); +}; + +#endif diff --git a/Tests/QtAutogen/sameName/main.cpp b/Tests/QtAutogen/sameName/main.cpp new file mode 100644 index 000000000..a4ffcb350 --- /dev/null +++ b/Tests/QtAutogen/sameName/main.cpp @@ -0,0 +1,16 @@ +#include "aaa/bbb/item.hpp" +#include "aaa/item.hpp" +#include "bbb/aaa/item.hpp" +#include "bbb/item.hpp" +#include "ccc/item.hpp" + +int main(int argv, char** args) +{ + // Object instances + ::aaa::Item aaa_item; + ::aaa::bbb::Item aaa_bbb_item; + ::bbb::Item bbb_item; + ::bbb::aaa::Item bbb_aaa_item; + ::ccc::Item ccc_item; + return 0; +} From 61a607e8d43e0d02ff80cca6e60441f56a6741b5 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Mon, 15 Aug 2016 09:07:36 +0200 Subject: [PATCH 6/6] Help: Document AUTORCC behavior for same .qrc name case --- Help/prop_tgt/AUTORCC.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Help/prop_tgt/AUTORCC.rst b/Help/prop_tgt/AUTORCC.rst index 8dce6b184..158fdf8e0 100644 --- a/Help/prop_tgt/AUTORCC.rst +++ b/Help/prop_tgt/AUTORCC.rst @@ -19,5 +19,10 @@ Additional command line options for rcc can be set via the The global property :prop_gbl:`AUTOGEN_TARGETS_FOLDER` can be used to group the autorcc targets together in an IDE, e.g. in MSVS. +When there are multiple ``.qrc`` files with the same name, CMake will +generate unspecified unique names for ``rcc``. Therefore if +``Q_INIT_RESOURCE()`` or ``Q_CLEANUP_RESOURCE()`` need to be used the +``.qrc`` file name must be unique. + See the :manual:`cmake-qt(7)` manual for more information on using CMake with Qt.