From 9bf5af6e32570195b06df594c1cb07f8c7a6a83e Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 11 Jul 2006 11:41:38 -0400 Subject: 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. --- Source/CMakeLists.txt | 2 + Source/cmLocalGenerator.cxx | 117 ++++++++++++++++++++++++++++++ Source/cmLocalGenerator.h | 5 ++ Source/cmLocalUnixMakefileGenerator3.cxx | 118 ++----------------------------- Source/cmLocalUnixMakefileGenerator3.h | 2 - Source/cmLocalVisualStudio7Generator.cxx | 10 +-- Source/cmLocalVisualStudio7Generator.h | 10 +-- Source/cmLocalVisualStudioGenerator.cxx | 89 +++++++++++++++++++++++ Source/cmLocalVisualStudioGenerator.h | 43 +++++++++++ 9 files changed, 270 insertions(+), 126 deletions(-) create mode 100644 Source/cmLocalVisualStudioGenerator.cxx create mode 100644 Source/cmLocalVisualStudioGenerator.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 35f4fcf..ff49466 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -205,6 +205,8 @@ IF (WIN32) cmLocalVisualStudio6Generator.h cmLocalVisualStudio7Generator.cxx cmLocalVisualStudio7Generator.h + cmLocalVisualStudioGenerator.cxx + cmLocalVisualStudioGenerator.h cmWin32ProcessExecution.cxx cmWin32ProcessExecution.h ) diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index a73fbce..e604320 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2081,3 +2081,120 @@ cmLocalGenerator } } } + +//---------------------------------------------------------------------------- +std::string& cmLocalGenerator::CreateSafeUniqueObjectFileName(const char* sin) +{ + // Look for an existing mapped name for this object file. + std::map::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::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()); +} diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 6e4c60e..49bae5b 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -254,6 +254,10 @@ protected: std::ostream& os, const char* config, std::vector const& configurationTypes); + // Compute object file names. + std::string GetObjectFileNameWithoutTarget(const cmSourceFile& source); + std::string& CreateSafeUniqueObjectFileName(const char* sin); + cmMakefile *Makefile; cmGlobalGenerator *GlobalGenerator; // members used for relative path function ConvertToMakefilePath @@ -267,6 +271,7 @@ protected: cmLocalGenerator* Parent; std::vector Children; std::map LanguageToIncludeFlags; + std::map UniqueObjectNamesMap; bool WindowsShell; bool ForceUnixPath; bool UseRelativePaths; diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index dca1669..2252c16 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1062,75 +1062,6 @@ std::string cmLocalUnixMakefileGenerator3 } //---------------------------------------------------------------------------- -std::string& -cmLocalUnixMakefileGenerator3::CreateSafeUniqueObjectFileName(const char* sin) -{ - // Look for an existing mapped name for this object file. - std::map::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::value_type e(sin, ssin); - it = this->UniqueObjectNamesMap.insert(e).first; - } - - // Return the map entry. - return it->second; -} - -//---------------------------------------------------------------------------- std::string cmLocalUnixMakefileGenerator3 ::CreateMakeVariable(const char* sin, const char* s2in) @@ -1707,50 +1638,13 @@ cmLocalUnixMakefileGenerator3 const cmSourceFile& source, std::string* nameWithoutTargetDir) { - // 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 + // Get the object file name independent of target. + std::string objectName = this->GetObjectFileNameWithoutTarget(source); + if(nameWithoutTargetDir) { - objectName += - this->GlobalGenerator->GetLanguageOutputExtensionFromExtension( - source.GetSourceExtension().c_str()); + *nameWithoutTargetDir = objectName; } - // Convert to a safe name. - objectName = this->CreateSafeUniqueObjectFileName(objectName.c_str()); - // Prepend the target directory. std::string obj; const char* fileTargetDirectory = @@ -1788,10 +1682,6 @@ cmLocalUnixMakefileGenerator3 } obj += "/"; obj += objectName; - if(nameWithoutTargetDir) - { - *nameWithoutTargetDir = objectName; - } return obj; } diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index cae19a3..5674790 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -168,7 +168,6 @@ public: static std::string ConvertToQuotedOutputPath(const char* p); - std::string& CreateSafeUniqueObjectFileName(const char* sin); std::string CreateMakeVariable(const char* sin, const char* s2in); // cleanup the name of a potential target @@ -326,7 +325,6 @@ private: std::vector TargetGenerators; std::map MakeVariableMap; std::map ShortMakeVariableMap; - std::map UniqueObjectNamesMap; }; #endif diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index c755dfb..4466e8d 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -1012,6 +1012,9 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, sourceGroup.AssignSource(*i); } + // Compute which sources need unique object computation. + this->ComputeObjectNameRequirements(sourceGroups); + // open the project this->WriteProjectStart(fout, libName, target, sourceGroups); // write the configuration information @@ -1064,12 +1067,9 @@ void cmLocalVisualStudio7Generator const cmCustomCommand *command = (*sf)->GetCustomCommand(); std::string compileFlags; std::string additionalDeps; - objectName = (*sf)->GetSourceName(); - if(!(*sf)->GetPropertyAsBool("HEADER_FILE_ONLY" ) - && objectName.find("/") != objectName.npos) + if(this->NeedObjectName.find(*sf) != this->NeedObjectName.end()) { - cmSystemTools::ReplaceString(objectName, "/", "_"); - objectName += ".obj"; + objectName = this->GetObjectFileNameWithoutTarget(*(*sf)); } else { diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index 22d5d0b..ad81085 100644 --- a/Source/cmLocalVisualStudio7Generator.h +++ b/Source/cmLocalVisualStudio7Generator.h @@ -17,7 +17,7 @@ #ifndef cmLocalVisualStudio7Generator_h #define cmLocalVisualStudio7Generator_h -#include "cmLocalGenerator.h" +#include "cmLocalVisualStudioGenerator.h" class cmMakeDepend; class cmTarget; @@ -27,12 +27,12 @@ class cmSourceGroup; struct cmVS7FlagTable; /** \class cmLocalVisualStudio7Generator - * \brief Write a LocalUnix makefiles. + * \brief Write Visual Studio .NET project files. * - * cmLocalVisualStudio7Generator produces a LocalUnix makefile from its - * member Makefile. + * cmLocalVisualStudio7Generator produces a Visual Studio .NET project + * file for each target in its directory. */ -class cmLocalVisualStudio7Generator : public cmLocalGenerator +class cmLocalVisualStudio7Generator : public cmLocalVisualStudioGenerator { public: ///! Set cache only and recurse to false by default. diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx new file mode 100644 index 0000000..344fcc6 --- /dev/null +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -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 const& sourceGroups) +{ + // Clear the current set of requirements. + this->NeedObjectName.clear(); + + // Count the number of object files with each name. + std::map objectNameCounts; + for(unsigned int i = 0; i < sourceGroups.size(); ++i) + { + cmSourceGroup sg = sourceGroups[i]; + std::vector const& srcs = sg.GetSourceFiles(); + for(std::vector::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& srcs = sg.GetSourceFiles(); + for(std::vector::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); + } + } + } + } +} diff --git a/Source/cmLocalVisualStudioGenerator.h b/Source/cmLocalVisualStudioGenerator.h new file mode 100644 index 0000000..6fe0034 --- /dev/null +++ b/Source/cmLocalVisualStudioGenerator.h @@ -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 const&); + std::set NeedObjectName; +}; + +#endif -- cgit v0.12