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:
parent
d3682d8647
commit
64d398416a
|
@ -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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -1439,7 +1439,6 @@ void cmGlobalGenerator::ComputeGeneratorTargetObjects()
|
|||
continue;
|
||||
}
|
||||
cmGeneratorTarget* gt = ti->second;
|
||||
gt->ClassifySources();
|
||||
gt->LookupObjectLibraries();
|
||||
this->ComputeTargetObjects(gt);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue