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.
This commit is contained in:
Stephen Kelly 2014-02-13 21:07:31 +01:00
parent d3682d8647
commit 64d398416a
3 changed files with 243 additions and 128 deletions

View File

@ -24,6 +24,194 @@
#include "assert.h"
//----------------------------------------------------------------------------
void reportBadObjLib(std::vector<cmSourceFile*> const& badObjLib,
cmTarget *target, cmake *cm)
{
if(!badObjLib.empty())
{
cmOStringStream e;
e << "OBJECT library \"" << target->GetName() << "\" contains:\n";
for(std::vector<cmSourceFile*>::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<typename Tag, typename OtherTag>
struct IsSameTag
{
enum {
Result = false
};
};
template<typename Tag>
struct IsSameTag<Tag, Tag>
{
enum {
Result = true
};
};
#else
struct IsSameTagBase
{
typedef char (&no_type)[1];
typedef char (&yes_type)[2];
template<typename T> struct Check;
template<typename T> static yes_type check(Check<T>*, Check<T>*);
static no_type check(...);
};
template<typename Tag1, typename Tag2>
struct IsSameTag: public IsSameTagBase
{
enum {
Result = (sizeof(check(static_cast< Check<Tag1>* >(0),
static_cast< Check<Tag2>* >(0))) ==
sizeof(yes_type))
};
};
#endif
template<bool>
struct DoAccept
{
template <typename T> static void Do(T&, cmSourceFile*) {}
};
template<>
struct DoAccept<true>
{
static void Do(std::vector<cmSourceFile*>& 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<typename Tag, typename DataType = std::vector<cmSourceFile*> >
struct TagVisitor
{
DataType& Data;
std::vector<cmSourceFile*> 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<IsSameTag<Tag, CustomCommandsTag>::Result>::Do(this->Data, sf);
}
else if(this->Target->GetType() == cmTarget::UTILITY)
{
DoAccept<IsSameTag<Tag, ExtraSourcesTag>::Result>::Do(this->Data, sf);
}
else if(sf->GetPropertyAsBool("HEADER_FILE_ONLY"))
{
DoAccept<IsSameTag<Tag, HeaderSourcesTag>::Result>::Do(this->Data, sf);
}
else if(sf->GetPropertyAsBool("EXTERNAL_OBJECT"))
{
DoAccept<IsSameTag<Tag, ExternalObjectsTag>::Result>::Do(this->Data, sf);
if(this->IsObjLib)
{
this->BadObjLibFiles.push_back(sf);
}
}
else if(sf->GetLanguage())
{
DoAccept<IsSameTag<Tag, ObjectSourcesTag>::Result>::Do(this->Data, sf);
}
else if(ext == "def")
{
DoAccept<IsSameTag<Tag, ModuleDefinitionFileTag>::Result>::Do(this->Data,
sf);
if(this->IsObjLib)
{
this->BadObjLibFiles.push_back(sf);
}
}
else if(ext == "idl")
{
DoAccept<IsSameTag<Tag, IDLSourcesTag>::Result>::Do(this->Data, sf);
if(this->IsObjLib)
{
this->BadObjLibFiles.push_back(sf);
}
}
else if(ext == "resx")
{
DoAccept<IsSameTag<Tag, ResxTag>::Result>::Do(this->Data, sf);
}
else if(this->Header.find(sf->GetFullPath().c_str()))
{
DoAccept<IsSameTag<Tag, HeaderSourcesTag>::Result>::Do(this->Data, sf);
}
else if(this->GlobalGenerator->IgnoreFile(sf->GetExtension().c_str()))
{
DoAccept<IsSameTag<Tag, ExtraSourcesTag>::Result>::Do(this->Data, sf);
}
else
{
DoAccept<IsSameTag<Tag, ExtraSourcesTag>::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<cmSourceFile*> sourceFiles; \
this->Target->GetSourceFiles(sourceFiles); \
TagVisitor<DATA ## Tag DATATYPE> visitor(this->Target, data); \
for(std::vector<cmSourceFile*>::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<cmSourceFile*> &objs) const
cmGeneratorTarget::GetObjectSources(std::vector<cmSourceFile*> &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<cmSourceFile*>& srcs) const
void cmGeneratorTarget::GetIDLSources(std::vector<cmSourceFile*>& data) const
{
srcs = this->ResxSources;
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::GetIDLSources(std::vector<cmSourceFile*>& srcs) const
{
srcs = this->IDLSources;
IMPLEMENT_VISIT(IDLSources);
}
//----------------------------------------------------------------------------
void
cmGeneratorTarget::GetHeaderSources(std::vector<cmSourceFile*>& srcs) const
cmGeneratorTarget::GetHeaderSources(std::vector<cmSourceFile*>& data) const
{
srcs = this->HeaderSources;
IMPLEMENT_VISIT(HeaderSources);
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile*>& srcs) const
void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile*>& data) const
{
srcs = this->ExtraSources;
IMPLEMENT_VISIT(ExtraSources);
}
//----------------------------------------------------------------------------
void
cmGeneratorTarget::GetCustomCommands(std::vector<cmSourceFile*>& srcs) const
cmGeneratorTarget::GetCustomCommands(std::vector<cmSourceFile*>& data) const
{
srcs = this->CustomCommands;
IMPLEMENT_VISIT(CustomCommands);
}
//----------------------------------------------------------------------------
void
cmGeneratorTarget::GetExternalObjects(std::vector<cmSourceFile*>& data) const
{
IMPLEMENT_VISIT(ExternalObjects);
}
//----------------------------------------------------------------------------
void
cmGeneratorTarget::GetExpectedResxHeaders(std::set<std::string>& srcs) const
{
srcs = this->ExpectedResxHeaders;
ResxData data;
IMPLEMENT_VISIT_IMPL(Resx, COMMA cmGeneratorTarget::ResxData)
srcs = data.ExpectedResxHeaders;
}
//----------------------------------------------------------------------------
void
cmGeneratorTarget::GetExternalObjects(std::vector<cmSourceFile*>& srcs) const
void cmGeneratorTarget::GetResxSources(std::vector<cmSourceFile*>& 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<cmSourceFile*> &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<cmSourceFile*> badObjLib;
std::vector<cmSourceFile*> sources;
this->Target->GetSourceFiles(sources);
for(std::vector<cmSourceFile*>::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<cmSourceFile*>::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;
}
//----------------------------------------------------------------------------

View File

@ -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<std::string> ExpectedResxHeaders;
mutable std::vector<cmSourceFile*> ResxSources;
};
private:
friend class cmTargetTraceDependencies;
struct SourceEntry { std::vector<cmSourceFile*> Depends; };
typedef std::map<cmSourceFile*, SourceEntry> SourceEntriesType;
SourceEntriesType SourceEntries;
std::string ModuleDefinitionFile;
std::vector<cmSourceFile*> CustomCommands;
std::vector<cmSourceFile*> ExtraSources;
std::vector<cmSourceFile*> HeaderSources;
std::vector<cmSourceFile*> ExternalObjects;
std::vector<cmSourceFile*> IDLSources;
std::vector<cmSourceFile*> ResxSources;
std::map<cmSourceFile const*, std::string> Objects;
std::set<cmSourceFile const*> ExplicitObjectName;
std::set<std::string> ExpectedResxHeaders;
std::vector<cmSourceFile*> ObjectSources;
mutable std::vector<cmSourceFile*> ObjectSources;
std::vector<cmTarget*> ObjectLibraries;
mutable std::map<std::string, std::vector<std::string> > SystemIncludesCache;

View File

@ -1439,7 +1439,6 @@ void cmGlobalGenerator::ComputeGeneratorTargetObjects()
continue;
}
cmGeneratorTarget* gt = ti->second;
gt->ClassifySources();
gt->LookupObjectLibraries();
this->ComputeTargetObjects(gt);
}