From 057ac11bfbc5501c8037b173a73a55466163774d Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Thu, 1 Dec 2016 09:24:48 +0100 Subject: [PATCH] QtAutogen: Use checksum based subdirectories to avoid name collisions --- Source/CMakeLists.txt | 4 +- Source/cmFilePathChecksum.cxx | 88 ++++++++++++++++++ Source/cmFilePathChecksum.h | 65 +++++++++++++ Source/cmFilePathUuid.cxx | 118 ------------------------ Source/cmFilePathUuid.h | 69 -------------- Source/cmQtAutoGeneratorInitializer.cxx | 40 +++++--- Source/cmQtAutoGenerators.cxx | 47 +++++----- Source/cmQtAutoGenerators.h | 3 + 8 files changed, 205 insertions(+), 229 deletions(-) create mode 100644 Source/cmFilePathChecksum.cxx create mode 100644 Source/cmFilePathChecksum.h delete mode 100644 Source/cmFilePathUuid.cxx delete mode 100644 Source/cmFilePathUuid.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 5b381b4071..d15fdbe03d 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -243,8 +243,8 @@ set(SRCS cmFileLockPool.h cmFileLockResult.cxx cmFileLockResult.h - cmFilePathUuid.cxx - cmFilePathUuid.h + cmFilePathChecksum.cxx + cmFilePathChecksum.h cmFileTimeComparison.cxx cmFileTimeComparison.h cmFortranLexer.cxx diff --git a/Source/cmFilePathChecksum.cxx b/Source/cmFilePathChecksum.cxx new file mode 100644 index 0000000000..3d8b695345 --- /dev/null +++ b/Source/cmFilePathChecksum.cxx @@ -0,0 +1,88 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmFilePathChecksum.h" + +#include "cmBase32.h" +#include "cmCryptoHash.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" + +#include + +cmFilePathChecksum::cmFilePathChecksum() +{ +} + +cmFilePathChecksum::cmFilePathChecksum(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir) +{ + setupParentDirs(currentSrcDir, currentBinDir, projectSrcDir, projectBinDir); +} + +cmFilePathChecksum::cmFilePathChecksum(cmMakefile* makefile) +{ + setupParentDirs(makefile->GetCurrentSourceDirectory(), + makefile->GetCurrentBinaryDirectory(), + makefile->GetHomeDirectory(), + makefile->GetHomeOutputDirectory()); +} + +void cmFilePathChecksum::setupParentDirs(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 cmFilePathChecksum::get(const std::string& filePath) +{ + std::string relPath; + std::string relSeed; + { + const std::string fileReal = cmsys::SystemTools::GetRealPath(filePath); + std::string parentDir; + // 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(fileReal, pDir)) { + relSeed = parentDirs[ii].second; + parentDir = pDir; + break; + } + } + // Use file system root as fallback parent directory + if (parentDir.empty()) { + relSeed = "FileSystemRoot"; + cmsys::SystemTools::SplitPathRootComponent(fileReal, &parentDir); + } + // Calculate relative path from project parent directory + relPath = cmsys::SystemTools::RelativePath( + parentDir, cmsys::SystemTools::GetParentDirectory(fileReal)); + } + + // Calculate the file ( seed + relative path ) binary checksum + std::vector hashBytes = + cmCryptoHash(cmCryptoHash::AlgoSHA256).ByteHashString(relSeed + relPath); + + // Convert binary checksum to string + return cmBase32Encoder().encodeString(&hashBytes[0], hashBytes.size(), + false); +} + +std::string cmFilePathChecksum::getPart(const std::string& filePath, + size_t length) +{ + return get(filePath).substr(0, length); +} diff --git a/Source/cmFilePathChecksum.h b/Source/cmFilePathChecksum.h new file mode 100644 index 0000000000..df19053fbf --- /dev/null +++ b/Source/cmFilePathChecksum.h @@ -0,0 +1,65 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmFilePathChecksum_h +#define cmFilePathChecksum_h + +#include // IWYU pragma: keep + +#include +#include +#include + +class cmMakefile; + +/** \class cmFilePathChecksum + * @brief Generates a checksum for the parent directory of a file + * + * 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 cmFilePathChecksum +{ +public: + /// Maximum number of characters to use from the path checksum + static const size_t partLengthDefault = 10; + + /// @brief Parent directories are empty + cmFilePathChecksum(); + + /// @brief Initilizes the parent directories manually + cmFilePathChecksum(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir); + + /// @brief Initilizes the parent directories from a makefile + cmFilePathChecksum(cmMakefile* makefile); + + /// @brief Allows parent directories setup after construction + /// + void setupParentDirs(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir); + + /* @brief Calculates the path checksum for the parent directory of a file + * + */ + std::string get(const std::string& filePath); + + /* @brief Same as get() but returns only the first length characters + * + */ + std::string getPart(const std::string& filePath, + size_t length = partLengthDefault); + +private: + /// Size of the parent directory list + static const size_t numParentDirs = 4; + /// List of (directory name, seed name) pairs + std::pair parentDirs[numParentDirs]; +}; + +#endif diff --git a/Source/cmFilePathUuid.cxx b/Source/cmFilePathUuid.cxx deleted file mode 100644 index 03d25249c5..0000000000 --- a/Source/cmFilePathUuid.cxx +++ /dev/null @@ -1,118 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmFilePathUuid.h" - -#include "cmBase32.h" -#include "cmCryptoHash.h" -#include "cmMakefile.h" -#include "cmSystemTools.h" - -#include - -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 checksumBase32; - { - // Calculate the file ( seed + relative path + name ) checksum - std::vector hashBytes = - cmCryptoHash(cmCryptoHash::AlgoSHA256) - .ByteHashString(sourceRelSeed + sourceRelPath + sourceFilename); - - checksumBase32 = - cmBase32Encoder().encodeString(&hashBytes[0], hashBytes.size(), false); - } - - return checksumBase32; -} diff --git a/Source/cmFilePathUuid.h b/Source/cmFilePathUuid.h deleted file mode 100644 index a450526718..0000000000 --- a/Source/cmFilePathUuid.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cmFilePathUuid_h -#define cmFilePathUuid_h - -#include // IWYU pragma: keep - -#include -#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 = CM_NULLPTR, - const char* outputSuffix = CM_NULLPTR); - -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 diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index e589a5adfc..9766a5a485 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -4,7 +4,7 @@ #include "cmAlgorithms.h" #include "cmCustomCommandLines.h" -#include "cmFilePathUuid.h" +#include "cmFilePathChecksum.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" @@ -96,7 +96,7 @@ static void SetupSourceFiles(cmGeneratorTarget const* target, std::vector newRccFiles; - cmFilePathUuid fpathUuid(makefile); + cmFilePathChecksum fpathCheckSum(makefile); for (std::vector::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; @@ -115,15 +115,21 @@ static void SetupSourceFiles(cmGeneratorTarget const* target, if (ext == "qrc" && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { - 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"); + std::string rccOutputFile = GetAutogenTargetBuildDir(target); + rccOutputFile += fpathCheckSum.getPart(absFile); + rccOutputFile += "/qrc_"; + rccOutputFile += + cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); + rccOutputFile += ".cpp"; makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", - rcc_output_file.c_str(), false); - makefile->GetOrCreateSource(rcc_output_file, true); - newRccFiles.push_back(rcc_output_file); + rccOutputFile.c_str(), false); + makefile->GetOrCreateSource(rccOutputFile, true); + newRccFiles.push_back(rccOutputFile); + + // Create output directory + cmSystemTools::MakeDirectory( + cmsys::SystemTools::GetFilenamePath(rccOutputFile)); } } @@ -755,9 +761,9 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( #endif ) { if (target->GetPropertyAsBool("AUTORCC")) { + cmFilePathChecksum fpathCheckSum(makefile); std::vector srcFiles; target->GetConfigCommonSourceFiles(srcFiles); - cmFilePathUuid fpathUuid(makefile); for (std::vector::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { @@ -767,11 +773,17 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( { const std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); - std::string rcc_output_file = GetAutogenTargetBuildDir(target); + + std::string rccOutputFile = GetAutogenTargetBuildDir(target); + rccOutputFile += fpathCheckSum.getPart(absFile); + rccOutputFile += "/qrc_"; + rccOutputFile += + cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); + rccOutputFile += ".cpp"; + rcc_output.push_back(rccOutputFile); // 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); + cmSystemTools::MakeDirectory( + cmsys::SystemTools::GetFilenamePath(rccOutputFile)); } if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { RccListInputs(qtMajorVersion, sf, target, depends); diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index bd01d50337..bb18e2e2dd 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -15,7 +15,6 @@ #include #include "cmAlgorithms.h" -#include "cmFilePathUuid.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmOutputConverter.h" @@ -397,6 +396,11 @@ void cmQtAutoGenerators::Init() this->OutMocCppFilenameAbs = this->Builddir + this->OutMocCppFilenameRel; + // Init file path checksum generator + fpathCheckSum.setupParentDirs(this->Srcdir, this->Builddir, + this->ProjectSourceDir, + this->ProjectBinaryDir); + std::vector cdefList; cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList); for (std::vector::const_iterator it = cdefList.begin(); @@ -967,8 +971,6 @@ 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; @@ -984,8 +986,10 @@ void cmQtAutoGenerators::ParseHeaders( std::string macroName; if (requiresMocing(contents, macroName)) { - notIncludedMocs[headerName] = - this->TargetBuildSubDir + fpathUuid.get(headerName, "moc_", ".cpp"); + notIncludedMocs[headerName] = this->TargetBuildSubDir + + fpathCheckSum.getPart(headerName) + "/moc_" + + cmsys::SystemTools::GetFilenameWithoutLastExtension(headerName) + + ".cpp"; } } this->ParseForUic(headerName, contents, includedUis); @@ -1318,18 +1322,13 @@ bool cmQtAutoGenerators::GenerateQrcFiles() { // generate single map with input / output names std::map qrcGenMap; - { - 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")); - } + 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 + fpathCheckSum.getPart(*si) + + "/qrc_" + cmsys::SystemTools::GetFilenameWithoutLastExtension(*si) + + ".cpp"; } } @@ -1368,15 +1367,11 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, const std::string& qrcOutputFile, bool unique_n) { - 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); + std::string symbolName = + cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); + if (!unique_n) { + symbolName += "_"; + symbolName += fpathCheckSum.getPart(qrcInputFile); } // Replace '-' with '_'. The former is valid for // file names but not for symbol names. diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 466acb2377..302c9be3a5 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -4,6 +4,7 @@ #define cmQtAutoGenerators_h #include // IWYU pragma: keep +#include #include #include @@ -130,6 +131,8 @@ private: std::map RccOptions; std::map > RccInputs; + cmFilePathChecksum fpathCheckSum; + bool IncludeProjectDirsBefore; bool Verbose; bool ColorOutput;