QtAutogen: Use checksum based subdirectories to avoid name collisions

This commit is contained in:
Sebastian Holtermann 2016-12-01 09:24:48 +01:00 committed by Brad King
parent d3afe4070b
commit 057ac11bfb
8 changed files with 205 additions and 229 deletions

View File

@ -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

View File

@ -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 <vector>
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<unsigned char> 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);
}

View File

@ -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 <cmConfigure.h> // IWYU pragma: keep
#include <stddef.h>
#include <string>
#include <utility>
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<std::string, std::string> parentDirs[numParentDirs];
};
#endif

View File

@ -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 <vector>
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<unsigned char> hashBytes =
cmCryptoHash(cmCryptoHash::AlgoSHA256)
.ByteHashString(sourceRelSeed + sourceRelPath + sourceFilename);
checksumBase32 =
cmBase32Encoder().encodeString(&hashBytes[0], hashBytes.size(), false);
}
return checksumBase32;
}

View File

@ -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 <cmConfigure.h> // IWYU pragma: keep
#include <stddef.h>
#include <string>
#include <utility>
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<std::string, std::string> parentDirs[numParentDirs];
};
#endif

View File

@ -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<std::string> newRccFiles;
cmFilePathUuid fpathUuid(makefile);
cmFilePathChecksum fpathCheckSum(makefile);
for (std::vector<cmSourceFile*>::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<cmSourceFile*> srcFiles;
target->GetConfigCommonSourceFiles(srcFiles);
cmFilePathUuid fpathUuid(makefile);
for (std::vector<cmSourceFile*>::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);

View File

@ -15,7 +15,6 @@
#include <utility>
#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<std::string> cdefList;
cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList);
for (std::vector<std::string>::const_iterator it = cdefList.begin();
@ -967,8 +971,6 @@ void cmQtAutoGenerators::ParseHeaders(
std::map<std::string, std::string>& notIncludedMocs,
std::map<std::string, std::vector<std::string> >& includedUis)
{
cmFilePathUuid fpathUuid(this->Srcdir, this->Builddir,
this->ProjectSourceDir, this->ProjectBinaryDir);
for (std::set<std::string>::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<std::string, std::string> qrcGenMap;
{
cmFilePathUuid fpathUuid(this->Srcdir, this->Builddir,
this->ProjectSourceDir, this->ProjectBinaryDir);
for (std::vector<std::string>::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<std::string>::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.

View File

@ -4,6 +4,7 @@
#define cmQtAutoGenerators_h
#include <cmConfigure.h> // IWYU pragma: keep
#include <cmFilePathChecksum.h>
#include <list>
#include <map>
@ -130,6 +131,8 @@ private:
std::map<std::string, std::string> RccOptions;
std::map<std::string, std::vector<std::string> > RccInputs;
cmFilePathChecksum fpathCheckSum;
bool IncludeProjectDirsBefore;
bool Verbose;
bool ColorOutput;