Pre-compute object file names before VS project generation

Implement cmGlobalGenerator::ComputeTargetObjects in the VS generator
to pre-compute all the object file names.  Use the results during
generation instead of re-computing it later.
This commit is contained in:
Brad King 2012-03-07 14:04:33 -05:00
parent 3baaf6ccec
commit d57047de33
10 changed files with 104 additions and 136 deletions

View File

@ -41,6 +41,7 @@ public:
std::string ModuleDefinitionFile; std::string ModuleDefinitionFile;
std::map<cmSourceFile const*, std::string> Objects; std::map<cmSourceFile const*, std::string> Objects;
std::set<cmSourceFile const*> ExplicitObjectName;
private: private:
void ClassifySources(); void ClassifySources();

View File

@ -12,8 +12,10 @@
#include "cmGlobalVisualStudioGenerator.h" #include "cmGlobalVisualStudioGenerator.h"
#include "cmCallVisualStudioMacro.h" #include "cmCallVisualStudioMacro.h"
#include "cmLocalGenerator.h" #include "cmGeneratorTarget.h"
#include "cmLocalVisualStudioGenerator.h"
#include "cmMakefile.h" #include "cmMakefile.h"
#include "cmSourceFile.h"
#include "cmTarget.h" #include "cmTarget.h"
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -97,6 +99,48 @@ void cmGlobalVisualStudioGenerator::Generate()
this->cmGlobalGenerator::Generate(); this->cmGlobalGenerator::Generate();
} }
//----------------------------------------------------------------------------
void
cmGlobalVisualStudioGenerator
::ComputeTargetObjects(cmGeneratorTarget* gt) const
{
cmLocalVisualStudioGenerator* lg =
static_cast<cmLocalVisualStudioGenerator*>(gt->LocalGenerator);
std::string dir_max = lg->ComputeLongestObjectDirectory(*gt->Target);
// Count the number of object files with each name. Note that
// windows file names are not case sensitive.
std::map<cmStdString, int> counts;
for(std::vector<cmSourceFile*>::const_iterator
si = gt->ObjectSources.begin();
si != gt->ObjectSources.end(); ++si)
{
cmSourceFile* sf = *si;
std::string objectNameLower = cmSystemTools::LowerCase(
cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()));
objectNameLower += ".obj";
counts[objectNameLower] += 1;
}
// For all source files producing duplicate names we need unique
// object name computation.
for(std::vector<cmSourceFile*>::const_iterator
si = gt->ObjectSources.begin();
si != gt->ObjectSources.end(); ++si)
{
cmSourceFile* sf = *si;
std::string objectName =
cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
objectName += ".obj";
if(counts[cmSystemTools::LowerCase(objectName)] > 1)
{
gt->ExplicitObjectName.insert(sf);
objectName = lg->GetObjectFileNameWithoutTarget(*sf, dir_max);
}
gt->Objects[sf] = objectName;
}
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile, bool IsVisualStudioMacrosFileRegistered(const std::string& macrosFile,
const std::string& regKeyBase, const std::string& regKeyBase,

View File

@ -97,6 +97,8 @@ protected:
typedef std::map<cmTarget*, cmStdString> UtilityDependsMap; typedef std::map<cmTarget*, cmStdString> UtilityDependsMap;
UtilityDependsMap UtilityDepends; UtilityDependsMap UtilityDepends;
private: private:
void ComputeTargetObjects(cmGeneratorTarget* gt) const;
void FollowLinkDepends(cmTarget* target, std::set<cmTarget*>& linked); void FollowLinkDepends(cmTarget* target, std::set<cmTarget*>& linked);
class TargetSetMap: public std::map<cmTarget*, TargetSet> {}; class TargetSetMap: public std::map<cmTarget*, TargetSet> {};

View File

@ -15,6 +15,7 @@
#include "cmSystemTools.h" #include "cmSystemTools.h"
#include "cmSourceFile.h" #include "cmSourceFile.h"
#include "cmCacheManager.h" #include "cmCacheManager.h"
#include "cmGeneratorTarget.h"
#include "cmake.h" #include "cmake.h"
#include "cmComputeLinkInformation.h" #include "cmComputeLinkInformation.h"
@ -336,9 +337,6 @@ void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout,
} }
} }
// Compute which sources need unique object computation.
this->ComputeObjectNameRequirements(classes);
// Write the DSP file's header. // Write the DSP file's header.
this->WriteDSPHeader(fout, libName, target, sourceGroups); this->WriteDSPHeader(fout, libName, target, sourceGroups);
@ -358,6 +356,8 @@ void cmLocalVisualStudio6Generator
::WriteGroup(const cmSourceGroup *sg, cmTarget& target, ::WriteGroup(const cmSourceGroup *sg, cmTarget& target,
std::ostream &fout, const char *libName) std::ostream &fout, const char *libName)
{ {
cmGeneratorTarget* gt =
this->GlobalGenerator->GetGeneratorTarget(&target);
const std::vector<const cmSourceFile *> &sourceFiles = const std::vector<const cmSourceFile *> &sourceFiles =
sg->GetSourceFiles(); sg->GetSourceFiles();
// If the group is empty, don't write it at all. // If the group is empty, don't write it at all.
@ -374,28 +374,6 @@ void cmLocalVisualStudio6Generator
this->WriteDSPBeginGroup(fout, name.c_str(), ""); this->WriteDSPBeginGroup(fout, name.c_str(), "");
} }
// Compute the maximum length configuration name.
std::string config_max;
for(std::vector<std::string>::iterator i = this->Configurations.begin();
i != this->Configurations.end(); ++i)
{
// Strip the subdirectory name out of the configuration name.
std::string config = this->GetConfigName(*i);
if(config.size() > config_max.size())
{
config_max = config;
}
}
// Compute the maximum length full path to the intermediate
// files directory for any configuration. This is used to construct
// object file names that do not produce paths that are too long.
std::string dir_max;
dir_max += this->Makefile->GetCurrentOutputDirectory();
dir_max += "/";
dir_max += config_max;
dir_max += "/";
// Loop through each source in the source group. // Loop through each source in the source group.
for(std::vector<const cmSourceFile *>::const_iterator sf = for(std::vector<const cmSourceFile *>::const_iterator sf =
sourceFiles.begin(); sf != sourceFiles.end(); ++sf) sourceFiles.begin(); sf != sourceFiles.end(); ++sf)
@ -406,11 +384,9 @@ void cmLocalVisualStudio6Generator
std::string compileFlags; std::string compileFlags;
std::vector<std::string> depends; std::vector<std::string> depends;
std::string objectNameDir; std::string objectNameDir;
if(this->NeedObjectName.find(*sf) != this->NeedObjectName.end()) if(gt->ExplicitObjectName.find(*sf) != gt->ExplicitObjectName.end())
{ {
objectNameDir = objectNameDir = cmSystemTools::GetFilenamePath(gt->Objects[*sf]);
cmSystemTools::GetFilenamePath(
this->GetObjectFileNameWithoutTarget(*(*sf), dir_max));
} }
// Add per-source file flags. // Add per-source file flags.
@ -1795,6 +1771,36 @@ cmLocalVisualStudio6Generator
return ""; return "";
} }
//----------------------------------------------------------------------------
std::string
cmLocalVisualStudio6Generator
::ComputeLongestObjectDirectory(cmTarget&) const
{
// Compute the maximum length configuration name.
std::string config_max;
for(std::vector<std::string>::const_iterator
i = this->Configurations.begin();
i != this->Configurations.end(); ++i)
{
// Strip the subdirectory name out of the configuration name.
std::string config = this->GetConfigName(*i);
if(config.size() > config_max.size())
{
config_max = config;
}
}
// Compute the maximum length full path to the intermediate
// files directory for any configuration. This is used to construct
// object file names that do not produce paths that are too long.
std::string dir_max;
dir_max += this->Makefile->GetCurrentOutputDirectory();
dir_max += "/";
dir_max += config_max;
dir_max += "/";
return dir_max;
}
std::string std::string
cmLocalVisualStudio6Generator cmLocalVisualStudio6Generator
::GetConfigName(std::string const& configuration) const ::GetConfigName(std::string const& configuration) const

View File

@ -50,6 +50,7 @@ public:
void SetBuildType(BuildType, const char* libName, cmTarget&); void SetBuildType(BuildType, const char* libName, cmTarget&);
virtual std::string GetTargetDirectory(cmTarget const& target) const; virtual std::string GetTargetDirectory(cmTarget const& target) const;
virtual std::string ComputeLongestObjectDirectory(cmTarget&) const;
private: private:
std::string DSPHeaderTemplate; std::string DSPHeaderTemplate;
std::string DSPFooterTemplate; std::string DSPFooterTemplate;

View File

@ -17,6 +17,7 @@
#include "cmSystemTools.h" #include "cmSystemTools.h"
#include "cmSourceFile.h" #include "cmSourceFile.h"
#include "cmCacheManager.h" #include "cmCacheManager.h"
#include "cmGeneratorTarget.h"
#include "cmake.h" #include "cmake.h"
#include "cmComputeLinkInformation.h" #include "cmComputeLinkInformation.h"
@ -1310,9 +1311,6 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
sourceGroup.AssignSource(*i); sourceGroup.AssignSource(*i);
} }
// Compute which sources need unique object computation.
this->ComputeObjectNameRequirements(classes);
// 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
@ -1352,8 +1350,7 @@ public:
cmLocalVisualStudio7GeneratorFCInfo(cmLocalVisualStudio7Generator* lg, cmLocalVisualStudio7GeneratorFCInfo(cmLocalVisualStudio7Generator* lg,
cmTarget& target, cmTarget& target,
cmSourceFile const& sf, cmSourceFile const& sf,
std::vector<std::string>* configs, std::vector<std::string>* configs);
std::string const& dir_max);
std::map<cmStdString, cmLVS7GFileConfig> FileConfigMap; std::map<cmStdString, cmLVS7GFileConfig> FileConfigMap;
}; };
@ -1361,13 +1358,14 @@ cmLocalVisualStudio7GeneratorFCInfo
::cmLocalVisualStudio7GeneratorFCInfo(cmLocalVisualStudio7Generator* lg, ::cmLocalVisualStudio7GeneratorFCInfo(cmLocalVisualStudio7Generator* lg,
cmTarget& target, cmTarget& target,
cmSourceFile const& sf, cmSourceFile const& sf,
std::vector<std::string>* configs, std::vector<std::string>* configs)
std::string const& dir_max)
{ {
cmGeneratorTarget* gt =
lg->GetGlobalGenerator()->GetGeneratorTarget(&target);
std::string objectName; std::string objectName;
if(lg->NeedObjectName.find(&sf) != lg->NeedObjectName.end()) if(gt->ExplicitObjectName.find(&sf) != gt->ExplicitObjectName.end())
{ {
objectName = lg->GetObjectFileNameWithoutTarget(sf, dir_max); objectName = gt->Objects[&sf];
} }
// Compute per-source, per-config information. // Compute per-source, per-config information.
@ -1478,11 +1476,11 @@ cmLocalVisualStudio7GeneratorFCInfo
} }
} }
//----------------------------------------------------------------------------
void cmLocalVisualStudio7Generator std::string
::ComputeMaxDirectoryLength(std::string& maxdir, cmLocalVisualStudio7Generator
cmTarget& target) ::ComputeLongestObjectDirectory(cmTarget& target) const
{ {
std::vector<std::string> *configs = std::vector<std::string> *configs =
static_cast<cmGlobalVisualStudio7Generator *> static_cast<cmGlobalVisualStudio7Generator *>
(this->GlobalGenerator)->GetConfigurations(); (this->GlobalGenerator)->GetConfigurations();
@ -1507,7 +1505,7 @@ void cmLocalVisualStudio7Generator
dir_max += "/"; dir_max += "/";
dir_max += config_max; dir_max += config_max;
dir_max += "/"; dir_max += "/";
maxdir = dir_max; return dir_max;
} }
void cmLocalVisualStudio7Generator void cmLocalVisualStudio7Generator
@ -1530,19 +1528,13 @@ void cmLocalVisualStudio7Generator
this->WriteVCProjBeginGroup(fout, name.c_str(), ""); this->WriteVCProjBeginGroup(fout, name.c_str(), "");
} }
// Compute the maximum length full path to the intermediate
// files directory for any configuration. This is used to construct
// object file names that do not produce paths that are too long.
std::string dir_max;
this->ComputeMaxDirectoryLength(dir_max, target);
// Loop through each source in the source group. // Loop through each source in the source group.
std::string objectName; std::string objectName;
for(std::vector<const cmSourceFile *>::const_iterator sf = for(std::vector<const cmSourceFile *>::const_iterator sf =
sourceFiles.begin(); sf != sourceFiles.end(); ++sf) sourceFiles.begin(); sf != sourceFiles.end(); ++sf)
{ {
std::string source = (*sf)->GetFullPath(); std::string source = (*sf)->GetFullPath();
FCInfo fcinfo(this, target, *(*sf), configs, dir_max); FCInfo fcinfo(this, target, *(*sf), configs);
if (source != libName || target.GetType() == cmTarget::UTILITY || if (source != libName || target.GetType() == cmTarget::UTILITY ||
target.GetType() == cmTarget::GLOBAL_TARGET ) target.GetType() == cmTarget::GLOBAL_TARGET )

View File

@ -60,11 +60,7 @@ public:
virtual std::string GetTargetDirectory(cmTarget const&) const; virtual std::string GetTargetDirectory(cmTarget const&) const;
cmSourceFile* CreateVCProjBuildRule(); cmSourceFile* CreateVCProjBuildRule();
void WriteStampFiles(); void WriteStampFiles();
// Compute the maximum length full path to the intermediate virtual std::string ComputeLongestObjectDirectory(cmTarget&) const;
// files directory for any configuration. This is used to construct
// object file names that do not produce paths that are too long.
void ComputeMaxDirectoryLength(std::string& maxdir,
cmTarget& target);
virtual void ReadAndStoreExternalGUID(const char* name, virtual void ReadAndStoreExternalGUID(const char* name,
const char* path); const char* path);

View File

@ -64,69 +64,6 @@ cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmTarget& target,
return pcc; return pcc;
} }
//----------------------------------------------------------------------------
bool cmLocalVisualStudioGenerator::SourceFileCompiles(const cmSourceFile* sf)
{
// Identify the language of the source file.
if(const char* lang = this->GetSourceFileLanguage(*sf))
{
// Check whether this source will actually be compiled.
return (!sf->GetCustomCommand() &&
!sf->GetPropertyAsBool("HEADER_FILE_ONLY") &&
!sf->GetPropertyAsBool("EXTERNAL_OBJECT"));
}
else
{
// Unknown source file language. Assume it will not be compiled.
return false;
}
}
//----------------------------------------------------------------------------
void
cmLocalVisualStudioGenerator::ComputeObjectNameRequirements(
std::vector<cmSourceFile*> const& sources
)
{
// Clear the current set of requirements.
this->NeedObjectName.clear();
// Count the number of object files with each name. Note that
// windows file names are not case sensitive.
std::map<cmStdString, int> counts;
for(std::vector<cmSourceFile*>::const_iterator s = sources.begin();
s != sources.end(); ++s)
{
const cmSourceFile* sf = *s;
if(this->SourceFileCompiles(sf))
{
std::string objectName = cmSystemTools::LowerCase(
cmSystemTools::GetFilenameWithoutLastExtension(
sf->GetFullPath()));
objectName += ".obj";
counts[objectName] += 1;
}
}
// For all source files producing duplicate names we need unique
// object name computation.
for(std::vector<cmSourceFile*>::const_iterator s = sources.begin();
s != sources.end(); ++s)
{
const cmSourceFile* sf = *s;
if(this->SourceFileCompiles(sf))
{
std::string objectName = cmSystemTools::LowerCase(
cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()));
objectName += ".obj";
if(counts[objectName] > 1)
{
this->NeedObjectName.insert(sf);
}
}
}
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
const char* cmLocalVisualStudioGenerator::ReportErrorLabel() const const char* cmLocalVisualStudioGenerator::ReportErrorLabel() const
{ {

View File

@ -56,6 +56,8 @@ public:
/** Version of Visual Studio. */ /** Version of Visual Studio. */
VSVersion GetVersion() const { return this->Version; } VSVersion GetVersion() const { return this->Version; }
virtual std::string ComputeLongestObjectDirectory(cmTarget&) const = 0;
protected: protected:
virtual const char* ReportErrorLabel() const; virtual const char* ReportErrorLabel() const;
virtual bool CustomCommandUseLocal() const { return false; } virtual bool CustomCommandUseLocal() const { return false; }
@ -64,12 +66,6 @@ protected:
cmsys::auto_ptr<cmCustomCommand> cmsys::auto_ptr<cmCustomCommand>
MaybeCreateImplibDir(cmTarget& target, const char* config, bool isFortran); MaybeCreateImplibDir(cmTarget& target, const char* config, bool isFortran);
// Safe object file name generation.
void ComputeObjectNameRequirements(std::vector<cmSourceFile*> const&);
bool SourceFileCompiles(const cmSourceFile* sf);
std::set<const cmSourceFile*> NeedObjectName;
friend class cmVisualStudio10TargetGenerator;
VSVersion Version; VSVersion Version;
}; };

View File

@ -72,8 +72,6 @@ cmVisualStudio10TargetGenerator(cmTarget* target,
this->GlobalGenerator->CreateGUID(this->Name.c_str()); this->GlobalGenerator->CreateGUID(this->Name.c_str());
this->GUID = this->GlobalGenerator->GetGUID(this->Name.c_str()); this->GUID = this->GlobalGenerator->GetGUID(this->Name.c_str());
this->Platform = gg->GetPlatformName(); this->Platform = gg->GetPlatformName();
this->LocalGenerator
->ComputeObjectNameRequirements(target->GetSourceFiles());
this->BuildFileStream = 0; this->BuildFileStream = 0;
} }
@ -883,16 +881,11 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
cmSourceFile& sf = *source; cmSourceFile& sf = *source;
cmLocalVisualStudio7Generator* lg = this->LocalGenerator; cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
// Compute the maximum length full path to the intermediate
// files directory for any configuration. This is used to construct
// object file names that do not produce paths that are too long.
std::string dir_max;
lg->ComputeMaxDirectoryLength(dir_max, *this->Target);
std::string objectName; std::string objectName;
if(lg->NeedObjectName.find(&sf) != lg->NeedObjectName.end()) if(this->GeneratorTarget->ExplicitObjectName.find(&sf)
!= this->GeneratorTarget->ExplicitObjectName.end())
{ {
objectName = lg->GetObjectFileNameWithoutTarget(sf, dir_max); objectName = this->GeneratorTarget->Objects[&sf];
} }
std::string flags; std::string flags;
std::string defines; std::string defines;