From 64d398416ad678c1c57fbd3a7981623e28d69bca Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Thu, 13 Feb 2014 21:07:31 +0100 Subject: [PATCH] cmGeneratorTarget: Classify sources on demand, not up front. Implement a Visitor to hold the sequence of source file tests for populating outputs. Use VS 6 and 7 workaround from Brad King for lack of partial template specialization and function template specialization capabilities. This will make it possible to use context dependent generator expressions to determine the sources of a target. --- Source/cmGeneratorTarget.cxx | 355 +++++++++++++++++++++++------------ Source/cmGeneratorTarget.h | 15 +- Source/cmGlobalGenerator.cxx | 1 - 3 files changed, 243 insertions(+), 128 deletions(-) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index e2810acb0..4cb19044c 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -24,6 +24,194 @@ #include "assert.h" +//---------------------------------------------------------------------------- +void reportBadObjLib(std::vector const& badObjLib, + cmTarget *target, cmake *cm) +{ + if(!badObjLib.empty()) + { + cmOStringStream e; + e << "OBJECT library \"" << target->GetName() << "\" contains:\n"; + for(std::vector::const_iterator i = badObjLib.begin(); + i != badObjLib.end(); ++i) + { + e << " " << (*i)->GetLocation().GetName() << "\n"; + } + e << "but may contain only headers and sources that compile."; + cm->IssueMessage(cmake::FATAL_ERROR, e.str(), + target->GetBacktrace()); + } +} + +struct ObjectSourcesTag {}; +struct CustomCommandsTag {}; +struct ExtraSourcesTag {}; +struct HeaderSourcesTag {}; +struct ExternalObjectsTag {}; +struct IDLSourcesTag {}; +struct ResxTag {}; +struct ModuleDefinitionFileTag {}; + +#if !defined(_MSC_VER) || _MSC_VER >= 1310 +template +struct IsSameTag +{ + enum { + Result = false + }; +}; + +template +struct IsSameTag +{ + enum { + Result = true + }; +}; +#else +struct IsSameTagBase +{ + typedef char (&no_type)[1]; + typedef char (&yes_type)[2]; + template struct Check; + template static yes_type check(Check*, Check*); + static no_type check(...); +}; +template +struct IsSameTag: public IsSameTagBase +{ + enum { + Result = (sizeof(check(static_cast< Check* >(0), + static_cast< Check* >(0))) == + sizeof(yes_type)) + }; +}; +#endif + +template +struct DoAccept +{ + template static void Do(T&, cmSourceFile*) {} +}; + +template<> +struct DoAccept +{ + static void Do(std::vector& files, cmSourceFile* f) + { + files.push_back(f); + } + static void Do(cmGeneratorTarget::ResxData& data, cmSourceFile* f) + { + // Build and save the name of the corresponding .h file + // This relationship will be used later when building the project files. + // Both names would have been auto generated from Visual Studio + // where the user supplied the file name and Visual Studio + // appended the suffix. + std::string resx = f->GetFullPath(); + std::string hFileName = resx.substr(0, resx.find_last_of(".")) + ".h"; + data.ExpectedResxHeaders.insert(hFileName); + data.ResxSources.push_back(f); + } + static void Do(std::string& data, cmSourceFile* f) + { + data = f->GetFullPath(); + } +}; + +//---------------------------------------------------------------------------- +template > +struct TagVisitor +{ + DataType& Data; + std::vector BadObjLibFiles; + cmTarget *Target; + cmGlobalGenerator *GlobalGenerator; + cmsys::RegularExpression Header; + bool IsObjLib; + + TagVisitor(cmTarget *target, DataType& data) + : Data(data), Target(target), + GlobalGenerator(target->GetMakefile() + ->GetLocalGenerator()->GetGlobalGenerator()), + Header(CM_HEADER_REGEX), + IsObjLib(target->GetType() == cmTarget::OBJECT_LIBRARY) + { + } + + ~TagVisitor() + { + reportBadObjLib(this->BadObjLibFiles, this->Target, + this->GlobalGenerator->GetCMakeInstance()); + } + + void Accept(cmSourceFile *sf) + { + std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); + if(sf->GetCustomCommand()) + { + DoAccept::Result>::Do(this->Data, sf); + } + else if(this->Target->GetType() == cmTarget::UTILITY) + { + DoAccept::Result>::Do(this->Data, sf); + } + else if(sf->GetPropertyAsBool("HEADER_FILE_ONLY")) + { + DoAccept::Result>::Do(this->Data, sf); + } + else if(sf->GetPropertyAsBool("EXTERNAL_OBJECT")) + { + DoAccept::Result>::Do(this->Data, sf); + if(this->IsObjLib) + { + this->BadObjLibFiles.push_back(sf); + } + } + else if(sf->GetLanguage()) + { + DoAccept::Result>::Do(this->Data, sf); + } + else if(ext == "def") + { + DoAccept::Result>::Do(this->Data, + sf); + if(this->IsObjLib) + { + this->BadObjLibFiles.push_back(sf); + } + } + else if(ext == "idl") + { + DoAccept::Result>::Do(this->Data, sf); + if(this->IsObjLib) + { + this->BadObjLibFiles.push_back(sf); + } + } + else if(ext == "resx") + { + DoAccept::Result>::Do(this->Data, sf); + } + else if(this->Header.find(sf->GetFullPath().c_str())) + { + DoAccept::Result>::Do(this->Data, sf); + } + else if(this->GlobalGenerator->IgnoreFile(sf->GetExtension().c_str())) + { + DoAccept::Result>::Do(this->Data, sf); + } + else + { + DoAccept::Result>::Do(this->Data, sf); + if(this->IsObjLib && ext != "txt") + { + this->BadObjLibFiles.push_back(sf); + } + } + } +}; + //---------------------------------------------------------------------------- cmGeneratorTarget::cmGeneratorTarget(cmTarget* t): Target(t), SourceFileFlagsConstructed(false) @@ -96,11 +284,34 @@ static void handleSystemIncludesDep(cmMakefile *mf, cmTarget* depTgt, } } +#define IMPLEMENT_VISIT_IMPL(DATA, DATATYPE) \ + { \ + std::vector sourceFiles; \ + this->Target->GetSourceFiles(sourceFiles); \ + TagVisitor visitor(this->Target, data); \ + for(std::vector::const_iterator si = sourceFiles.begin(); \ + si != sourceFiles.end(); ++si) \ + { \ + visitor.Accept(*si); \ + } \ + } \ + + +#define IMPLEMENT_VISIT(DATA) \ + IMPLEMENT_VISIT_IMPL(DATA, EMPTY) \ + +#define EMPTY +#define COMMA , + //---------------------------------------------------------------------------- void -cmGeneratorTarget::GetObjectSources(std::vector &objs) const +cmGeneratorTarget::GetObjectSources(std::vector &data) const { - objs = this->ObjectSources; + IMPLEMENT_VISIT(ObjectSources); + if (this->Target->GetType() == cmTarget::OBJECT_LIBRARY) + { + this->ObjectSources = data; + } } //---------------------------------------------------------------------------- @@ -129,49 +340,53 @@ bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const } //---------------------------------------------------------------------------- -void cmGeneratorTarget::GetResxSources(std::vector& srcs) const +void cmGeneratorTarget::GetIDLSources(std::vector& data) const { - srcs = this->ResxSources; -} - -//---------------------------------------------------------------------------- -void cmGeneratorTarget::GetIDLSources(std::vector& srcs) const -{ - srcs = this->IDLSources; + IMPLEMENT_VISIT(IDLSources); } //---------------------------------------------------------------------------- void -cmGeneratorTarget::GetHeaderSources(std::vector& srcs) const +cmGeneratorTarget::GetHeaderSources(std::vector& data) const { - srcs = this->HeaderSources; + IMPLEMENT_VISIT(HeaderSources); } //---------------------------------------------------------------------------- -void cmGeneratorTarget::GetExtraSources(std::vector& srcs) const +void cmGeneratorTarget::GetExtraSources(std::vector& data) const { - srcs = this->ExtraSources; + IMPLEMENT_VISIT(ExtraSources); } //---------------------------------------------------------------------------- void -cmGeneratorTarget::GetCustomCommands(std::vector& srcs) const +cmGeneratorTarget::GetCustomCommands(std::vector& data) const { - srcs = this->CustomCommands; + IMPLEMENT_VISIT(CustomCommands); +} + +//---------------------------------------------------------------------------- +void +cmGeneratorTarget::GetExternalObjects(std::vector& data) const +{ + IMPLEMENT_VISIT(ExternalObjects); } //---------------------------------------------------------------------------- void cmGeneratorTarget::GetExpectedResxHeaders(std::set& srcs) const { - srcs = this->ExpectedResxHeaders; + ResxData data; + IMPLEMENT_VISIT_IMPL(Resx, COMMA cmGeneratorTarget::ResxData) + srcs = data.ExpectedResxHeaders; } //---------------------------------------------------------------------------- -void -cmGeneratorTarget::GetExternalObjects(std::vector& srcs) const +void cmGeneratorTarget::GetResxSources(std::vector& srcs) const { - srcs = this->ExternalObjects; + ResxData data; + IMPLEMENT_VISIT_IMPL(Resx, COMMA cmGeneratorTarget::ResxData) + srcs = data.ResxSources; } //---------------------------------------------------------------------------- @@ -282,102 +497,6 @@ void cmGeneratorTarget::GetSourceFiles(std::vector &files) const this->Target->GetSourceFiles(files); } -//---------------------------------------------------------------------------- -void cmGeneratorTarget::ClassifySources() -{ - cmsys::RegularExpression header(CM_HEADER_REGEX); - - cmTarget::TargetType targetType = this->Target->GetType(); - bool isObjLib = targetType == cmTarget::OBJECT_LIBRARY; - - std::vector badObjLib; - std::vector sources; - this->Target->GetSourceFiles(sources); - for(std::vector::const_iterator si = sources.begin(); - si != sources.end(); ++si) - { - cmSourceFile* sf = *si; - std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); - if(sf->GetCustomCommand()) - { - this->CustomCommands.push_back(sf); - } - else if(targetType == cmTarget::UTILITY) - { - this->ExtraSources.push_back(sf); - } - else if(sf->GetPropertyAsBool("HEADER_FILE_ONLY")) - { - this->HeaderSources.push_back(sf); - } - else if(sf->GetPropertyAsBool("EXTERNAL_OBJECT")) - { - this->ExternalObjects.push_back(sf); - if(isObjLib) { badObjLib.push_back(sf); } - } - else if(sf->GetLanguage()) - { - this->ObjectSources.push_back(sf); - } - else if(ext == "def") - { - this->ModuleDefinitionFile = sf->GetFullPath(); - if(isObjLib) { badObjLib.push_back(sf); } - } - else if(ext == "idl") - { - this->IDLSources.push_back(sf); - if(isObjLib) { badObjLib.push_back(sf); } - } - else if(ext == "resx") - { - // Build and save the name of the corresponding .h file - // This relationship will be used later when building the project files. - // Both names would have been auto generated from Visual Studio - // where the user supplied the file name and Visual Studio - // appended the suffix. - std::string resx = sf->GetFullPath(); - std::string hFileName = resx.substr(0, resx.find_last_of(".")) + ".h"; - this->ExpectedResxHeaders.insert(hFileName); - this->ResxSources.push_back(sf); - } - else if(header.find(sf->GetFullPath().c_str())) - { - this->HeaderSources.push_back(sf); - } - else if(this->GlobalGenerator->IgnoreFile(sf->GetExtension().c_str())) - { - // We only get here if a source file is not an external object - // and has an extension that is listed as an ignored file type. - // No message or diagnosis should be given. - this->ExtraSources.push_back(sf); - } - else - { - this->ExtraSources.push_back(sf); - if(isObjLib && ext != "txt") - { - badObjLib.push_back(sf); - } - } - } - - if(!badObjLib.empty()) - { - cmOStringStream e; - e << "OBJECT library \"" << this->Target->GetName() << "\" contains:\n"; - for(std::vector::iterator i = badObjLib.begin(); - i != badObjLib.end(); ++i) - { - e << " " << (*i)->GetLocation().GetName() << "\n"; - } - e << "but may contain only headers and sources that compile."; - this->GlobalGenerator->GetCMakeInstance() - ->IssueMessage(cmake::FATAL_ERROR, e.str(), - this->Target->GetBacktrace()); - } -} - //---------------------------------------------------------------------------- void cmGeneratorTarget::LookupObjectLibraries() { @@ -433,7 +552,9 @@ void cmGeneratorTarget::LookupObjectLibraries() //---------------------------------------------------------------------------- std::string cmGeneratorTarget::GetModuleDefinitionFile() const { - return this->ModuleDefinitionFile; + std::string data; + IMPLEMENT_VISIT_IMPL(ModuleDefinitionFile, COMMA std::string) + return data; } //---------------------------------------------------------------------------- diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 51d51f327..1e6ce64c0 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -82,7 +82,6 @@ public: */ void TraceDependencies(); - void ClassifySources(); void LookupObjectLibraries(); /** Get sources that must be built before the given source. */ @@ -113,23 +112,19 @@ public: struct SourceFileFlags GetTargetSourceFileFlags(const cmSourceFile* sf) const; + struct ResxData { + mutable std::set ExpectedResxHeaders; + mutable std::vector ResxSources; + }; private: friend class cmTargetTraceDependencies; struct SourceEntry { std::vector Depends; }; typedef std::map SourceEntriesType; SourceEntriesType SourceEntries; - std::string ModuleDefinitionFile; - std::vector CustomCommands; - std::vector ExtraSources; - std::vector HeaderSources; - std::vector ExternalObjects; - std::vector IDLSources; - std::vector ResxSources; std::map Objects; std::set ExplicitObjectName; - std::set ExpectedResxHeaders; - std::vector ObjectSources; + mutable std::vector ObjectSources; std::vector ObjectLibraries; mutable std::map > SystemIncludesCache; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index e143ebafa..f76c6d19a 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1439,7 +1439,6 @@ void cmGlobalGenerator::ComputeGeneratorTargetObjects() continue; } cmGeneratorTarget* gt = ti->second; - gt->ClassifySources(); gt->LookupObjectLibraries(); this->ComputeTargetObjects(gt); }