CMake/Source/cmGeneratorTarget.cxx
Stephen Kelly 64d398416a 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.
2014-02-24 16:44:51 +01:00

1102 lines
34 KiB
C++

/*============================================================================
CMake - Cross Platform Makefile Generator
Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
Distributed under the OSI-approved BSD License (the "License");
see accompanying file Copyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the License for more information.
============================================================================*/
#include "cmGeneratorTarget.h"
#include "cmTarget.h"
#include "cmMakefile.h"
#include "cmLocalGenerator.h"
#include "cmGlobalGenerator.h"
#include "cmSourceFile.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorExpressionDAGChecker.h"
#include "cmComputeLinkInformation.h"
#include <queue>
#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)
{
this->Makefile = this->Target->GetMakefile();
this->LocalGenerator = this->Makefile->GetLocalGenerator();
this->GlobalGenerator = this->LocalGenerator->GetGlobalGenerator();
}
//----------------------------------------------------------------------------
int cmGeneratorTarget::GetType() const
{
return this->Target->GetType();
}
//----------------------------------------------------------------------------
const char *cmGeneratorTarget::GetName() const
{
return this->Target->GetName();
}
//----------------------------------------------------------------------------
const char *cmGeneratorTarget::GetProperty(const char *prop) const
{
return this->Target->GetProperty(prop);
}
//----------------------------------------------------------------------------
std::vector<cmSourceFile*> const*
cmGeneratorTarget::GetSourceDepends(cmSourceFile* sf) const
{
SourceEntriesType::const_iterator i = this->SourceEntries.find(sf);
if(i != this->SourceEntries.end())
{
return &i->second.Depends;
}
return 0;
}
static void handleSystemIncludesDep(cmMakefile *mf, cmTarget* depTgt,
const char *config, cmTarget *headTarget,
cmGeneratorExpressionDAGChecker *dagChecker,
std::vector<std::string>& result,
bool excludeImported)
{
cmListFileBacktrace lfbt;
if (const char* dirs =
depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES"))
{
cmGeneratorExpression ge(lfbt);
cmSystemTools::ExpandListArgument(ge.Parse(dirs)
->Evaluate(mf,
config, false, headTarget,
depTgt, dagChecker), result);
}
if (!depTgt->IsImported() || excludeImported)
{
return;
}
if (const char* dirs =
depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES"))
{
cmGeneratorExpression ge(lfbt);
cmSystemTools::ExpandListArgument(ge.Parse(dirs)
->Evaluate(mf,
config, false, headTarget,
depTgt, dagChecker), result);
}
}
#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*> &data) const
{
IMPLEMENT_VISIT(ObjectSources);
if (this->Target->GetType() == cmTarget::OBJECT_LIBRARY)
{
this->ObjectSources = data;
}
}
//----------------------------------------------------------------------------
const std::string& cmGeneratorTarget::GetObjectName(cmSourceFile const* file)
{
return this->Objects[file];
}
void cmGeneratorTarget::AddObject(cmSourceFile *sf, std::string const&name)
{
this->Objects[sf] = name;
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::AddExplicitObjectName(cmSourceFile* sf)
{
this->ExplicitObjectName.insert(sf);
}
//----------------------------------------------------------------------------
bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const
{
std::set<cmSourceFile const*>::const_iterator it
= this->ExplicitObjectName.find(file);
return it != this->ExplicitObjectName.end();
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::GetIDLSources(std::vector<cmSourceFile*>& data) const
{
IMPLEMENT_VISIT(IDLSources);
}
//----------------------------------------------------------------------------
void
cmGeneratorTarget::GetHeaderSources(std::vector<cmSourceFile*>& data) const
{
IMPLEMENT_VISIT(HeaderSources);
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::GetExtraSources(std::vector<cmSourceFile*>& data) const
{
IMPLEMENT_VISIT(ExtraSources);
}
//----------------------------------------------------------------------------
void
cmGeneratorTarget::GetCustomCommands(std::vector<cmSourceFile*>& data) const
{
IMPLEMENT_VISIT(CustomCommands);
}
//----------------------------------------------------------------------------
void
cmGeneratorTarget::GetExternalObjects(std::vector<cmSourceFile*>& data) const
{
IMPLEMENT_VISIT(ExternalObjects);
}
//----------------------------------------------------------------------------
void
cmGeneratorTarget::GetExpectedResxHeaders(std::set<std::string>& srcs) const
{
ResxData data;
IMPLEMENT_VISIT_IMPL(Resx, COMMA cmGeneratorTarget::ResxData)
srcs = data.ExpectedResxHeaders;
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::GetResxSources(std::vector<cmSourceFile*>& srcs) const
{
ResxData data;
IMPLEMENT_VISIT_IMPL(Resx, COMMA cmGeneratorTarget::ResxData)
srcs = data.ResxSources;
}
//----------------------------------------------------------------------------
bool cmGeneratorTarget::IsSystemIncludeDirectory(const char *dir,
const char *config) const
{
assert(this->GetType() != cmTarget::INTERFACE_LIBRARY);
std::string config_upper;
if(config && *config)
{
config_upper = cmSystemTools::UpperCase(config);
}
typedef std::map<std::string, std::vector<std::string> > IncludeCacheType;
IncludeCacheType::const_iterator iter =
this->SystemIncludesCache.find(config_upper);
if (iter == this->SystemIncludesCache.end())
{
cmTarget::LinkImplementation const* impl
= this->Target->GetLinkImplementation(config, this->Target);
if(!impl)
{
return false;
}
cmListFileBacktrace lfbt;
cmGeneratorExpressionDAGChecker dagChecker(lfbt,
this->GetName(),
"SYSTEM_INCLUDE_DIRECTORIES", 0, 0);
bool excludeImported
= this->Target->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED");
std::vector<std::string> result;
for (std::set<cmStdString>::const_iterator
it = this->Target->GetSystemIncludeDirectories().begin();
it != this->Target->GetSystemIncludeDirectories().end(); ++it)
{
cmGeneratorExpression ge(lfbt);
cmSystemTools::ExpandListArgument(ge.Parse(*it)
->Evaluate(this->Makefile,
config, false, this->Target,
&dagChecker), result);
}
std::set<cmTarget*> uniqueDeps;
for(std::vector<std::string>::const_iterator li = impl->Libraries.begin();
li != impl->Libraries.end(); ++li)
{
cmTarget* tgt = this->Makefile->FindTargetToUse(*li);
if (!tgt)
{
continue;
}
if (uniqueDeps.insert(tgt).second)
{
handleSystemIncludesDep(this->Makefile, tgt, config, this->Target,
&dagChecker, result, excludeImported);
std::vector<cmTarget*> deps;
tgt->GetTransitivePropertyTargets(config, this->Target, deps);
for(std::vector<cmTarget*>::const_iterator di = deps.begin();
di != deps.end(); ++di)
{
if (uniqueDeps.insert(*di).second)
{
handleSystemIncludesDep(this->Makefile, *di, config, this->Target,
&dagChecker, result, excludeImported);
}
}
}
}
std::set<cmStdString> unique;
for(std::vector<std::string>::iterator li = result.begin();
li != result.end(); ++li)
{
cmSystemTools::ConvertToUnixSlashes(*li);
unique.insert(*li);
}
result.clear();
for(std::set<cmStdString>::iterator li = unique.begin();
li != unique.end(); ++li)
{
result.push_back(*li);
}
IncludeCacheType::value_type entry(config_upper, result);
iter = this->SystemIncludesCache.insert(entry).first;
}
std::string dirString = dir;
return std::binary_search(iter->second.begin(), iter->second.end(),
dirString);
}
//----------------------------------------------------------------------------
bool cmGeneratorTarget::GetPropertyAsBool(const char *prop) const
{
return this->Target->GetPropertyAsBool(prop);
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*> &files) const
{
this->Target->GetSourceFiles(files);
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::LookupObjectLibraries()
{
std::vector<std::string> const& objLibs =
this->Target->GetObjectLibraries();
for(std::vector<std::string>::const_iterator oli = objLibs.begin();
oli != objLibs.end(); ++oli)
{
std::string const& objLibName = *oli;
if(cmTarget* objLib = this->Makefile->FindTargetToUse(objLibName))
{
if(objLib->GetType() == cmTarget::OBJECT_LIBRARY)
{
if(this->Target->GetType() != cmTarget::EXECUTABLE &&
this->Target->GetType() != cmTarget::STATIC_LIBRARY &&
this->Target->GetType() != cmTarget::SHARED_LIBRARY &&
this->Target->GetType() != cmTarget::MODULE_LIBRARY)
{
this->GlobalGenerator->GetCMakeInstance()
->IssueMessage(cmake::FATAL_ERROR,
"Only executables and non-OBJECT libraries may "
"reference target objects.",
this->Target->GetBacktrace());
return;
}
this->Target->AddUtility(objLib->GetName());
this->ObjectLibraries.push_back(objLib);
}
else
{
cmOStringStream e;
e << "Objects of target \"" << objLibName
<< "\" referenced but is not an OBJECT library.";
this->GlobalGenerator->GetCMakeInstance()
->IssueMessage(cmake::FATAL_ERROR, e.str(),
this->Target->GetBacktrace());
return;
}
}
else
{
cmOStringStream e;
e << "Objects of target \"" << objLibName
<< "\" referenced but no such target exists.";
this->GlobalGenerator->GetCMakeInstance()
->IssueMessage(cmake::FATAL_ERROR, e.str(),
this->Target->GetBacktrace());
return;
}
}
}
//----------------------------------------------------------------------------
std::string cmGeneratorTarget::GetModuleDefinitionFile() const
{
std::string data;
IMPLEMENT_VISIT_IMPL(ModuleDefinitionFile, COMMA std::string)
return data;
}
//----------------------------------------------------------------------------
void
cmGeneratorTarget::UseObjectLibraries(std::vector<std::string>& objs) const
{
for(std::vector<cmTarget*>::const_iterator
ti = this->ObjectLibraries.begin();
ti != this->ObjectLibraries.end(); ++ti)
{
cmTarget* objLib = *ti;
cmGeneratorTarget* ogt =
this->GlobalGenerator->GetGeneratorTarget(objLib);
for(std::vector<cmSourceFile*>::const_iterator
si = ogt->ObjectSources.begin();
si != ogt->ObjectSources.end(); ++si)
{
std::string obj = ogt->ObjectDirectory;
obj += ogt->Objects[*si];
objs.push_back(obj);
}
}
}
//----------------------------------------------------------------------------
class cmTargetTraceDependencies
{
public:
cmTargetTraceDependencies(cmGeneratorTarget* target);
void Trace();
private:
cmTarget* Target;
cmGeneratorTarget* GeneratorTarget;
cmMakefile* Makefile;
cmGlobalGenerator const* GlobalGenerator;
typedef cmGeneratorTarget::SourceEntry SourceEntry;
SourceEntry* CurrentEntry;
std::queue<cmSourceFile*> SourceQueue;
std::set<cmSourceFile*> SourcesQueued;
typedef std::map<cmStdString, cmSourceFile*> NameMapType;
NameMapType NameMap;
void QueueSource(cmSourceFile* sf);
void FollowName(std::string const& name);
void FollowNames(std::vector<std::string> const& names);
bool IsUtility(std::string const& dep);
void CheckCustomCommand(cmCustomCommand const& cc);
void CheckCustomCommands(const std::vector<cmCustomCommand>& commands);
};
//----------------------------------------------------------------------------
cmTargetTraceDependencies
::cmTargetTraceDependencies(cmGeneratorTarget* target):
Target(target->Target), GeneratorTarget(target)
{
// Convenience.
this->Makefile = this->Target->GetMakefile();
this->GlobalGenerator =
this->Makefile->GetLocalGenerator()->GetGlobalGenerator();
this->CurrentEntry = 0;
// Queue all the source files already specified for the target.
std::vector<cmSourceFile*> sources;
if (this->Target->GetType() != cmTarget::INTERFACE_LIBRARY)
{
this->Target->GetSourceFiles(sources);
for(std::vector<cmSourceFile*>::const_iterator si = sources.begin();
si != sources.end(); ++si)
{
this->QueueSource(*si);
}
}
// Queue pre-build, pre-link, and post-build rule dependencies.
this->CheckCustomCommands(this->Target->GetPreBuildCommands());
this->CheckCustomCommands(this->Target->GetPreLinkCommands());
this->CheckCustomCommands(this->Target->GetPostBuildCommands());
}
//----------------------------------------------------------------------------
void cmTargetTraceDependencies::Trace()
{
// Process one dependency at a time until the queue is empty.
while(!this->SourceQueue.empty())
{
// Get the next source from the queue.
cmSourceFile* sf = this->SourceQueue.front();
this->SourceQueue.pop();
this->CurrentEntry = &this->GeneratorTarget->SourceEntries[sf];
// Queue dependencies added explicitly by the user.
if(const char* additionalDeps = sf->GetProperty("OBJECT_DEPENDS"))
{
std::vector<std::string> objDeps;
cmSystemTools::ExpandListArgument(additionalDeps, objDeps);
this->FollowNames(objDeps);
}
// Queue the source needed to generate this file, if any.
this->FollowName(sf->GetFullPath());
// Queue dependencies added programatically by commands.
this->FollowNames(sf->GetDepends());
// Queue custom command dependencies.
if(cmCustomCommand const* cc = sf->GetCustomCommand())
{
this->CheckCustomCommand(*cc);
}
}
this->CurrentEntry = 0;
}
//----------------------------------------------------------------------------
void cmTargetTraceDependencies::QueueSource(cmSourceFile* sf)
{
if(this->SourcesQueued.insert(sf).second)
{
this->SourceQueue.push(sf);
// Make sure this file is in the target.
this->Target->AddSourceFile(sf);
}
}
//----------------------------------------------------------------------------
void cmTargetTraceDependencies::FollowName(std::string const& name)
{
NameMapType::iterator i = this->NameMap.find(name);
if(i == this->NameMap.end())
{
// Check if we know how to generate this file.
cmSourceFile* sf = this->Makefile->GetSourceFileWithOutput(name.c_str());
NameMapType::value_type entry(name, sf);
i = this->NameMap.insert(entry).first;
}
if(cmSourceFile* sf = i->second)
{
// Record the dependency we just followed.
if(this->CurrentEntry)
{
this->CurrentEntry->Depends.push_back(sf);
}
this->QueueSource(sf);
}
}
//----------------------------------------------------------------------------
void
cmTargetTraceDependencies::FollowNames(std::vector<std::string> const& names)
{
for(std::vector<std::string>::const_iterator i = names.begin();
i != names.end(); ++i)
{
this->FollowName(*i);
}
}
//----------------------------------------------------------------------------
bool cmTargetTraceDependencies::IsUtility(std::string const& dep)
{
// Dependencies on targets (utilities) are supposed to be named by
// just the target name. However for compatibility we support
// naming the output file generated by the target (assuming there is
// no output-name property which old code would not have set). In
// that case the target name will be the file basename of the
// dependency.
std::string util = cmSystemTools::GetFilenameName(dep);
if(cmSystemTools::GetFilenameLastExtension(util) == ".exe")
{
util = cmSystemTools::GetFilenameWithoutLastExtension(util);
}
// Check for a target with this name.
if(cmTarget* t = this->Makefile->FindTargetToUse(util))
{
// If we find the target and the dep was given as a full path,
// then make sure it was not a full path to something else, and
// the fact that the name matched a target was just a coincidence.
if(cmSystemTools::FileIsFullPath(dep.c_str()))
{
if(t->GetType() >= cmTarget::EXECUTABLE &&
t->GetType() <= cmTarget::MODULE_LIBRARY)
{
// This is really only for compatibility so we do not need to
// worry about configuration names and output names.
std::string tLocation = t->GetLocation(0);
tLocation = cmSystemTools::GetFilenamePath(tLocation);
std::string depLocation = cmSystemTools::GetFilenamePath(dep);
depLocation = cmSystemTools::CollapseFullPath(depLocation.c_str());
tLocation = cmSystemTools::CollapseFullPath(tLocation.c_str());
if(depLocation == tLocation)
{
this->Target->AddUtility(util.c_str());
return true;
}
}
}
else
{
// The original name of the dependency was not a full path. It
// must name a target, so add the target-level dependency.
this->Target->AddUtility(util.c_str());
return true;
}
}
// The dependency does not name a target built in this project.
return false;
}
//----------------------------------------------------------------------------
void
cmTargetTraceDependencies
::CheckCustomCommand(cmCustomCommand const& cc)
{
// Transform command names that reference targets built in this
// project to corresponding target-level dependencies.
cmGeneratorExpression ge(cc.GetBacktrace());
// Add target-level dependencies referenced by generator expressions.
std::set<cmTarget*> targets;
for(cmCustomCommandLines::const_iterator cit = cc.GetCommandLines().begin();
cit != cc.GetCommandLines().end(); ++cit)
{
std::string const& command = *cit->begin();
// Check for a target with this name.
if(cmTarget* t = this->Makefile->FindTargetToUse(command))
{
if(t->GetType() == cmTarget::EXECUTABLE)
{
// The command refers to an executable target built in
// this project. Add the target-level dependency to make
// sure the executable is up to date before this custom
// command possibly runs.
this->Target->AddUtility(command.c_str());
}
}
// Check for target references in generator expressions.
for(cmCustomCommandLine::const_iterator cli = cit->begin();
cli != cit->end(); ++cli)
{
const cmsys::auto_ptr<cmCompiledGeneratorExpression> cge
= ge.Parse(*cli);
cge->Evaluate(this->Makefile, 0, true);
std::set<cmTarget*> geTargets = cge->GetTargets();
for(std::set<cmTarget*>::const_iterator it = geTargets.begin();
it != geTargets.end(); ++it)
{
targets.insert(*it);
}
}
}
for(std::set<cmTarget*>::iterator ti = targets.begin();
ti != targets.end(); ++ti)
{
this->Target->AddUtility((*ti)->GetName());
}
// Queue the custom command dependencies.
std::vector<std::string> const& depends = cc.GetDepends();
for(std::vector<std::string>::const_iterator di = depends.begin();
di != depends.end(); ++di)
{
std::string const& dep = *di;
if(!this->IsUtility(dep))
{
// The dependency does not name a target and may be a file we
// know how to generate. Queue it.
this->FollowName(dep);
}
}
}
//----------------------------------------------------------------------------
void
cmTargetTraceDependencies
::CheckCustomCommands(const std::vector<cmCustomCommand>& commands)
{
for(std::vector<cmCustomCommand>::const_iterator cli = commands.begin();
cli != commands.end(); ++cli)
{
this->CheckCustomCommand(*cli);
}
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::TraceDependencies()
{
// CMake-generated targets have no dependencies to trace. Normally tracing
// would find nothing anyway, but when building CMake itself the "install"
// target command ends up referencing the "cmake" target but we do not
// really want the dependency because "install" depend on "all" anyway.
if(this->GetType() == cmTarget::GLOBAL_TARGET)
{
return;
}
// Use a helper object to trace the dependencies.
cmTargetTraceDependencies tracer(this);
tracer.Trace();
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::GetAppleArchs(const char* config,
std::vector<std::string>& archVec) const
{
const char* archs = 0;
if(config && *config)
{
std::string defVarName = "OSX_ARCHITECTURES_";
defVarName += cmSystemTools::UpperCase(config);
archs = this->Target->GetProperty(defVarName.c_str());
}
if(!archs)
{
archs = this->Target->GetProperty("OSX_ARCHITECTURES");
}
if(archs)
{
cmSystemTools::ExpandListArgument(std::string(archs), archVec);
}
}
//----------------------------------------------------------------------------
const char* cmGeneratorTarget::GetCreateRuleVariable() const
{
switch(this->GetType())
{
case cmTarget::STATIC_LIBRARY:
return "_CREATE_STATIC_LIBRARY";
case cmTarget::SHARED_LIBRARY:
return "_CREATE_SHARED_LIBRARY";
case cmTarget::MODULE_LIBRARY:
return "_CREATE_SHARED_MODULE";
case cmTarget::EXECUTABLE:
return "_LINK_EXECUTABLE";
default:
break;
}
return "";
}
//----------------------------------------------------------------------------
std::vector<std::string>
cmGeneratorTarget::GetIncludeDirectories(const char *config) const
{
return this->Target->GetIncludeDirectories(config);
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::GenerateTargetManifest(const char* config) const
{
if (this->Target->IsImported())
{
return;
}
cmMakefile* mf = this->Target->GetMakefile();
cmLocalGenerator* lg = mf->GetLocalGenerator();
cmGlobalGenerator* gg = lg->GetGlobalGenerator();
// Get the names.
std::string name;
std::string soName;
std::string realName;
std::string impName;
std::string pdbName;
if(this->GetType() == cmTarget::EXECUTABLE)
{
this->Target->GetExecutableNames(name, realName, impName, pdbName,
config);
}
else if(this->GetType() == cmTarget::STATIC_LIBRARY ||
this->GetType() == cmTarget::SHARED_LIBRARY ||
this->GetType() == cmTarget::MODULE_LIBRARY)
{
this->Target->GetLibraryNames(name, soName, realName, impName, pdbName,
config);
}
else
{
return;
}
// Get the directory.
std::string dir = this->Target->GetDirectory(config, false);
// Add each name.
std::string f;
if(!name.empty())
{
f = dir;
f += "/";
f += name;
gg->AddToManifest(config? config:"", f);
}
if(!soName.empty())
{
f = dir;
f += "/";
f += soName;
gg->AddToManifest(config? config:"", f);
}
if(!realName.empty())
{
f = dir;
f += "/";
f += realName;
gg->AddToManifest(config? config:"", f);
}
if(!pdbName.empty())
{
f = dir;
f += "/";
f += pdbName;
gg->AddToManifest(config? config:"", f);
}
if(!impName.empty())
{
f = this->Target->GetDirectory(config, true);
f += "/";
f += impName;
gg->AddToManifest(config? config:"", f);
}
}
bool cmStrictTargetComparison::operator()(cmTarget const* t1,
cmTarget const* t2) const
{
int nameResult = strcmp(t1->GetName(), t2->GetName());
if (nameResult == 0)
{
return strcmp(t1->GetMakefile()->GetStartOutputDirectory(),
t2->GetMakefile()->GetStartOutputDirectory()) < 0;
}
return nameResult < 0;
}
//----------------------------------------------------------------------------
struct cmGeneratorTarget::SourceFileFlags
cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const
{
struct SourceFileFlags flags;
this->ConstructSourceFileFlags();
std::map<cmSourceFile const*, SourceFileFlags>::iterator si =
this->SourceFlagsMap.find(sf);
if(si != this->SourceFlagsMap.end())
{
flags = si->second;
}
return flags;
}
//----------------------------------------------------------------------------
void cmGeneratorTarget::ConstructSourceFileFlags() const
{
if(this->SourceFileFlagsConstructed)
{
return;
}
this->SourceFileFlagsConstructed = true;
// Process public headers to mark the source files.
if(const char* files = this->Target->GetProperty("PUBLIC_HEADER"))
{
std::vector<std::string> relFiles;
cmSystemTools::ExpandListArgument(files, relFiles);
for(std::vector<std::string>::iterator it = relFiles.begin();
it != relFiles.end(); ++it)
{
if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str()))
{
SourceFileFlags& flags = this->SourceFlagsMap[sf];
flags.MacFolder = "Headers";
flags.Type = cmGeneratorTarget::SourceFileTypePublicHeader;
}
}
}
// Process private headers after public headers so that they take
// precedence if a file is listed in both.
if(const char* files = this->Target->GetProperty("PRIVATE_HEADER"))
{
std::vector<std::string> relFiles;
cmSystemTools::ExpandListArgument(files, relFiles);
for(std::vector<std::string>::iterator it = relFiles.begin();
it != relFiles.end(); ++it)
{
if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str()))
{
SourceFileFlags& flags = this->SourceFlagsMap[sf];
flags.MacFolder = "PrivateHeaders";
flags.Type = cmGeneratorTarget::SourceFileTypePrivateHeader;
}
}
}
// Mark sources listed as resources.
if(const char* files = this->Target->GetProperty("RESOURCE"))
{
std::vector<std::string> relFiles;
cmSystemTools::ExpandListArgument(files, relFiles);
for(std::vector<std::string>::iterator it = relFiles.begin();
it != relFiles.end(); ++it)
{
if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str()))
{
SourceFileFlags& flags = this->SourceFlagsMap[sf];
flags.MacFolder = "Resources";
flags.Type = cmGeneratorTarget::SourceFileTypeResource;
}
}
}
// Handle the MACOSX_PACKAGE_LOCATION property on source files that
// were not listed in one of the other lists.
std::vector<cmSourceFile*> sources;
this->GetSourceFiles(sources);
for(std::vector<cmSourceFile*>::const_iterator si = sources.begin();
si != sources.end(); ++si)
{
cmSourceFile* sf = *si;
if(const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION"))
{
SourceFileFlags& flags = this->SourceFlagsMap[sf];
if(flags.Type == cmGeneratorTarget::SourceFileTypeNormal)
{
flags.MacFolder = location;
if(strcmp(location, "Resources") == 0)
{
flags.Type = cmGeneratorTarget::SourceFileTypeResource;
}
else
{
flags.Type = cmGeneratorTarget::SourceFileTypeMacContent;
}
}
}
}
}