ENH: Moved unique object file name computation from cmLocalUnixMakefileGenerator3 up to cmLocalGenerator for use by all generators. Created cmLocalVisualStudioGenerator as superclass for all VS generators. Implemented on-demand unique object file name computation for VS 7 generator to avoid slow compiles when all sources are in subdirectories.

This commit is contained in:
Brad King 2006-07-11 11:41:38 -04:00
parent c05b8fb993
commit 9bf5af6e32
9 changed files with 270 additions and 126 deletions

View File

@ -205,6 +205,8 @@ IF (WIN32)
cmLocalVisualStudio6Generator.h cmLocalVisualStudio6Generator.h
cmLocalVisualStudio7Generator.cxx cmLocalVisualStudio7Generator.cxx
cmLocalVisualStudio7Generator.h cmLocalVisualStudio7Generator.h
cmLocalVisualStudioGenerator.cxx
cmLocalVisualStudioGenerator.h
cmWin32ProcessExecution.cxx cmWin32ProcessExecution.cxx
cmWin32ProcessExecution.h cmWin32ProcessExecution.h
) )

View File

@ -2081,3 +2081,120 @@ cmLocalGenerator
} }
} }
} }
//----------------------------------------------------------------------------
std::string& cmLocalGenerator::CreateSafeUniqueObjectFileName(const char* sin)
{
// Look for an existing mapped name for this object file.
std::map<cmStdString,cmStdString>::iterator it =
this->UniqueObjectNamesMap.find(sin);
// If no entry exists create one.
if(it == this->UniqueObjectNamesMap.end())
{
// Start with the original name.
std::string ssin = sin;
// Avoid full paths by removing leading slashes.
std::string::size_type pos = 0;
for(;pos < ssin.size() && ssin[pos] == '/'; ++pos);
ssin = ssin.substr(pos);
// Avoid full paths by removing colons.
cmSystemTools::ReplaceString(ssin, ":", "_");
// Avoid relative paths that go up the tree.
cmSystemTools::ReplaceString(ssin, "../", "__/");
// Avoid spaces.
cmSystemTools::ReplaceString(ssin, " ", "_");
// Mangle the name if necessary.
if(this->Makefile->IsOn("CMAKE_MANGLE_OBJECT_FILE_NAMES"))
{
bool done;
int cc = 0;
char rpstr[100];
sprintf(rpstr, "_p_");
cmSystemTools::ReplaceString(ssin, "+", rpstr);
std::string sssin = sin;
do
{
done = true;
for ( it = this->UniqueObjectNamesMap.begin();
it != this->UniqueObjectNamesMap.end();
++ it )
{
if ( it->second == ssin )
{
done = false;
}
}
if ( done )
{
break;
}
sssin = ssin;
cmSystemTools::ReplaceString(ssin, "_p_", rpstr);
sprintf(rpstr, "_p%d_", cc++);
}
while ( !done );
}
// Insert the newly mapped object file name.
std::map<cmStdString, cmStdString>::value_type e(sin, ssin);
it = this->UniqueObjectNamesMap.insert(e).first;
}
// Return the map entry.
return it->second;
}
//----------------------------------------------------------------------------
std::string
cmLocalGenerator::GetObjectFileNameWithoutTarget(const cmSourceFile& source)
{
// If the source file is located below the current binary directory
// then use that relative path for the object file name.
std::string objectName = this->Convert(source.GetFullPath().c_str(),
START_OUTPUT);
if(cmSystemTools::FileIsFullPath(objectName.c_str()) ||
objectName.empty() || objectName[0] == '.')
{
// If the source file is located below the current source
// directory then use that relative path for the object file name.
// Otherwise just use the relative path from the current binary
// directory.
std::string relFromSource = this->Convert(source.GetFullPath().c_str(),
START);
if(!cmSystemTools::FileIsFullPath(relFromSource.c_str()) &&
!relFromSource.empty() && relFromSource[0] != '.')
{
objectName = relFromSource;
}
}
// Replace the original source file extension with the object file
// extension.
std::string::size_type dot_pos = objectName.rfind(".");
if(dot_pos != std::string::npos)
{
objectName = objectName.substr(0, dot_pos);
}
if ( source.GetPropertyAsBool("KEEP_EXTENSION") )
{
if ( !source.GetSourceExtension().empty() )
{
objectName += "." + source.GetSourceExtension();
}
}
else
{
objectName +=
this->GlobalGenerator->GetLanguageOutputExtensionFromExtension(
source.GetSourceExtension().c_str());
}
// Convert to a safe name.
return this->CreateSafeUniqueObjectFileName(objectName.c_str());
}

View File

@ -254,6 +254,10 @@ protected:
std::ostream& os, const char* config, std::ostream& os, const char* config,
std::vector<std::string> const& configurationTypes); std::vector<std::string> const& configurationTypes);
// Compute object file names.
std::string GetObjectFileNameWithoutTarget(const cmSourceFile& source);
std::string& CreateSafeUniqueObjectFileName(const char* sin);
cmMakefile *Makefile; cmMakefile *Makefile;
cmGlobalGenerator *GlobalGenerator; cmGlobalGenerator *GlobalGenerator;
// members used for relative path function ConvertToMakefilePath // members used for relative path function ConvertToMakefilePath
@ -267,6 +271,7 @@ protected:
cmLocalGenerator* Parent; cmLocalGenerator* Parent;
std::vector<cmLocalGenerator*> Children; std::vector<cmLocalGenerator*> Children;
std::map<cmStdString, cmStdString> LanguageToIncludeFlags; std::map<cmStdString, cmStdString> LanguageToIncludeFlags;
std::map<cmStdString, cmStdString> UniqueObjectNamesMap;
bool WindowsShell; bool WindowsShell;
bool ForceUnixPath; bool ForceUnixPath;
bool UseRelativePaths; bool UseRelativePaths;

View File

@ -1061,75 +1061,6 @@ std::string cmLocalUnixMakefileGenerator3
return ret; return ret;
} }
//----------------------------------------------------------------------------
std::string&
cmLocalUnixMakefileGenerator3::CreateSafeUniqueObjectFileName(const char* sin)
{
// Look for an existing mapped name for this object file.
std::map<cmStdString,cmStdString>::iterator it =
this->UniqueObjectNamesMap.find(sin);
// If no entry exists create one.
if(it == this->UniqueObjectNamesMap.end())
{
// Start with the original name.
std::string ssin = sin;
// Avoid full paths by removing leading slashes.
std::string::size_type pos = 0;
for(;pos < ssin.size() && ssin[pos] == '/'; ++pos);
ssin = ssin.substr(pos);
// Avoid full paths by removing colons.
cmSystemTools::ReplaceString(ssin, ":", "_");
// Avoid relative paths that go up the tree.
cmSystemTools::ReplaceString(ssin, "../", "__/");
// Avoid spaces.
cmSystemTools::ReplaceString(ssin, " ", "_");
// Mangle the name if necessary.
if(this->Makefile->IsOn("CMAKE_MANGLE_OBJECT_FILE_NAMES"))
{
bool done;
int cc = 0;
char rpstr[100];
sprintf(rpstr, "_p_");
cmSystemTools::ReplaceString(ssin, "+", rpstr);
std::string sssin = sin;
do
{
done = true;
for ( it = this->UniqueObjectNamesMap.begin();
it != this->UniqueObjectNamesMap.end();
++ it )
{
if ( it->second == ssin )
{
done = false;
}
}
if ( done )
{
break;
}
sssin = ssin;
cmSystemTools::ReplaceString(ssin, "_p_", rpstr);
sprintf(rpstr, "_p%d_", cc++);
}
while ( !done );
}
// Insert the newly mapped object file name.
std::map<cmStdString, cmStdString>::value_type e(sin, ssin);
it = this->UniqueObjectNamesMap.insert(e).first;
}
// Return the map entry.
return it->second;
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
std::string std::string
cmLocalUnixMakefileGenerator3 cmLocalUnixMakefileGenerator3
@ -1707,50 +1638,13 @@ cmLocalUnixMakefileGenerator3
const cmSourceFile& source, const cmSourceFile& source,
std::string* nameWithoutTargetDir) std::string* nameWithoutTargetDir)
{ {
// If the source file is located below the current binary directory // Get the object file name independent of target.
// then use that relative path for the object file name. std::string objectName = this->GetObjectFileNameWithoutTarget(source);
std::string objectName = this->Convert(source.GetFullPath().c_str(), if(nameWithoutTargetDir)
START_OUTPUT);
if(cmSystemTools::FileIsFullPath(objectName.c_str()) ||
objectName.empty() || objectName[0] == '.')
{ {
// If the source file is located below the current source *nameWithoutTargetDir = objectName;
// directory then use that relative path for the object file name.
// Otherwise just use the relative path from the current binary
// directory.
std::string relFromSource = this->Convert(source.GetFullPath().c_str(),
START);
if(!cmSystemTools::FileIsFullPath(relFromSource.c_str()) &&
!relFromSource.empty() && relFromSource[0] != '.')
{
objectName = relFromSource;
}
} }
// Replace the original source file extension with the object file
// extension.
std::string::size_type dot_pos = objectName.rfind(".");
if(dot_pos != std::string::npos)
{
objectName = objectName.substr(0, dot_pos);
}
if ( source.GetPropertyAsBool("KEEP_EXTENSION") )
{
if ( !source.GetSourceExtension().empty() )
{
objectName += "." + source.GetSourceExtension();
}
}
else
{
objectName +=
this->GlobalGenerator->GetLanguageOutputExtensionFromExtension(
source.GetSourceExtension().c_str());
}
// Convert to a safe name.
objectName = this->CreateSafeUniqueObjectFileName(objectName.c_str());
// Prepend the target directory. // Prepend the target directory.
std::string obj; std::string obj;
const char* fileTargetDirectory = const char* fileTargetDirectory =
@ -1788,10 +1682,6 @@ cmLocalUnixMakefileGenerator3
} }
obj += "/"; obj += "/";
obj += objectName; obj += objectName;
if(nameWithoutTargetDir)
{
*nameWithoutTargetDir = objectName;
}
return obj; return obj;
} }

View File

@ -168,7 +168,6 @@ public:
static std::string ConvertToQuotedOutputPath(const char* p); static std::string ConvertToQuotedOutputPath(const char* p);
std::string& CreateSafeUniqueObjectFileName(const char* sin);
std::string CreateMakeVariable(const char* sin, const char* s2in); std::string CreateMakeVariable(const char* sin, const char* s2in);
// cleanup the name of a potential target // cleanup the name of a potential target
@ -326,7 +325,6 @@ private:
std::vector<cmMakefileTargetGenerator *> TargetGenerators; std::vector<cmMakefileTargetGenerator *> TargetGenerators;
std::map<cmStdString, cmStdString> MakeVariableMap; std::map<cmStdString, cmStdString> MakeVariableMap;
std::map<cmStdString, cmStdString> ShortMakeVariableMap; std::map<cmStdString, cmStdString> ShortMakeVariableMap;
std::map<cmStdString, cmStdString> UniqueObjectNamesMap;
}; };
#endif #endif

View File

@ -1012,6 +1012,9 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
sourceGroup.AssignSource(*i); sourceGroup.AssignSource(*i);
} }
// Compute which sources need unique object computation.
this->ComputeObjectNameRequirements(sourceGroups);
// open the project // open the project
this->WriteProjectStart(fout, libName, target, sourceGroups); this->WriteProjectStart(fout, libName, target, sourceGroups);
// write the configuration information // write the configuration information
@ -1064,12 +1067,9 @@ void cmLocalVisualStudio7Generator
const cmCustomCommand *command = (*sf)->GetCustomCommand(); const cmCustomCommand *command = (*sf)->GetCustomCommand();
std::string compileFlags; std::string compileFlags;
std::string additionalDeps; std::string additionalDeps;
objectName = (*sf)->GetSourceName(); if(this->NeedObjectName.find(*sf) != this->NeedObjectName.end())
if(!(*sf)->GetPropertyAsBool("HEADER_FILE_ONLY" )
&& objectName.find("/") != objectName.npos)
{ {
cmSystemTools::ReplaceString(objectName, "/", "_"); objectName = this->GetObjectFileNameWithoutTarget(*(*sf));
objectName += ".obj";
} }
else else
{ {

View File

@ -17,7 +17,7 @@
#ifndef cmLocalVisualStudio7Generator_h #ifndef cmLocalVisualStudio7Generator_h
#define cmLocalVisualStudio7Generator_h #define cmLocalVisualStudio7Generator_h
#include "cmLocalGenerator.h" #include "cmLocalVisualStudioGenerator.h"
class cmMakeDepend; class cmMakeDepend;
class cmTarget; class cmTarget;
@ -27,12 +27,12 @@ class cmSourceGroup;
struct cmVS7FlagTable; struct cmVS7FlagTable;
/** \class cmLocalVisualStudio7Generator /** \class cmLocalVisualStudio7Generator
* \brief Write a LocalUnix makefiles. * \brief Write Visual Studio .NET project files.
* *
* cmLocalVisualStudio7Generator produces a LocalUnix makefile from its * cmLocalVisualStudio7Generator produces a Visual Studio .NET project
* member Makefile. * file for each target in its directory.
*/ */
class cmLocalVisualStudio7Generator : public cmLocalGenerator class cmLocalVisualStudio7Generator : public cmLocalVisualStudioGenerator
{ {
public: public:
///! Set cache only and recurse to false by default. ///! Set cache only and recurse to false by default.

View File

@ -0,0 +1,89 @@
/*=========================================================================
Program: CMake - Cross-Platform Makefile Generator
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#include "cmLocalVisualStudioGenerator.h"
#include "cmMakefile.h"
#include "cmSourceFile.h"
#include "cmSystemTools.h"
//----------------------------------------------------------------------------
cmLocalVisualStudioGenerator::cmLocalVisualStudioGenerator()
{
}
//----------------------------------------------------------------------------
cmLocalVisualStudioGenerator::~cmLocalVisualStudioGenerator()
{
}
//----------------------------------------------------------------------------
void
cmLocalVisualStudioGenerator
::ComputeObjectNameRequirements(std::vector<cmSourceGroup> const& sourceGroups)
{
// Clear the current set of requirements.
this->NeedObjectName.clear();
// Count the number of object files with each name.
std::map<cmStdString, int> objectNameCounts;
for(unsigned int i = 0; i < sourceGroups.size(); ++i)
{
cmSourceGroup sg = sourceGroups[i];
std::vector<const cmSourceFile*> const& srcs = sg.GetSourceFiles();
for(std::vector<const cmSourceFile*>::const_iterator s = srcs.begin();
s != srcs.end(); ++s)
{
const cmSourceFile& sf = *(*s);
if(!sf.GetCustomCommand() &&
!sf.GetPropertyAsBool("HEADER_FILE_ONLY") &&
!sf.GetPropertyAsBool("EXTERNAL_OBJECT"))
{
std::string objectName =
cmSystemTools::GetFilenameWithoutLastExtension(
sf.GetFullPath().c_str());
objectName += ".obj";
objectNameCounts[objectName] += 1;
}
}
}
// For all source files producing duplicate names we need unique
// object name computation.
for(unsigned int i = 0; i < sourceGroups.size(); ++i)
{
cmSourceGroup sg = sourceGroups[i];
std::vector<const cmSourceFile*> const& srcs = sg.GetSourceFiles();
for(std::vector<const cmSourceFile*>::const_iterator s = srcs.begin();
s != srcs.end(); ++s)
{
const cmSourceFile* sf = *s;
if(!sf->GetCustomCommand() &&
!sf->GetPropertyAsBool("HEADER_FILE_ONLY") &&
!sf->GetPropertyAsBool("EXTERNAL_OBJECT"))
{
std::string objectName =
cmSystemTools::GetFilenameWithoutLastExtension(
sf->GetFullPath().c_str());
objectName += ".obj";
if(objectNameCounts[objectName] > 1)
{
this->NeedObjectName.insert(sf);
}
}
}
}
}

View File

@ -0,0 +1,43 @@
/*=========================================================================
Program: CMake - Cross-Platform Makefile Generator
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef cmLocalVisualStudioGenerator_h
#define cmLocalVisualStudioGenerator_h
#include "cmLocalGenerator.h"
class cmSourceFile;
class cmSourceGroup;
/** \class cmLocalVisualStudioGenerator
* \brief Base class for Visual Studio generators.
*
* cmLocalVisualStudioGenerator provides functionality common to all
* Visual Studio generators.
*/
class cmLocalVisualStudioGenerator : public cmLocalGenerator
{
public:
cmLocalVisualStudioGenerator();
virtual ~cmLocalVisualStudioGenerator();
protected:
// Safe object file name generation.
void ComputeObjectNameRequirements(std::vector<cmSourceGroup> const&);
std::set<const cmSourceFile*> NeedObjectName;
};
#endif