Use modern global dependency graph for VS < 8 deps
VS 7.1 and below have 2 behaviors that make the cmComputeTargetDepends
result difficult to use for solution-level dependencies. Update the
method cmGlobalVisualStudioGenerator::ComputeTargetDepends to document
the behaviors and work around them. Commit 1a0c166a
(Store direct
dependencies in solutions for VS >= 8, 2010-08-20) isolated VS >= 8 from
this computation so those versions should be unaffected.
This change removes the last use of cmTarget::GetLinkLibraries for
purposes other than backward compatibility with legacy interfaces
(export_library_dependencies, VS 6 custom .dsp templates). Now the
cmComputeTargetDepends results are used for all generators so global
target dependency computation is fully centralized.
This commit is contained in:
parent
605f4bc097
commit
fd614e60b5
|
@ -236,6 +236,59 @@ std::string cmGlobalVisualStudioGenerator::GetUserMacrosRegKeyBase()
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmGlobalVisualStudioGenerator::FillLinkClosure(cmTarget* target,
|
||||||
|
TargetSet& linked)
|
||||||
|
{
|
||||||
|
if(linked.insert(target).second)
|
||||||
|
{
|
||||||
|
TargetDependSet const& depends = this->GetTargetDirectDepends(*target);
|
||||||
|
for(TargetDependSet::const_iterator di = depends.begin();
|
||||||
|
di != depends.end(); ++di)
|
||||||
|
{
|
||||||
|
if(di->IsLink())
|
||||||
|
{
|
||||||
|
this->FillLinkClosure(*di, linked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
cmGlobalVisualStudioGenerator::TargetSet const&
|
||||||
|
cmGlobalVisualStudioGenerator::GetTargetLinkClosure(cmTarget* target)
|
||||||
|
{
|
||||||
|
TargetSetMap::iterator i = this->TargetLinkClosure.find(target);
|
||||||
|
if(i == this->TargetLinkClosure.end())
|
||||||
|
{
|
||||||
|
TargetSetMap::value_type entry(target, TargetSet());
|
||||||
|
i = this->TargetLinkClosure.insert(entry).first;
|
||||||
|
this->FillLinkClosure(target, i->second);
|
||||||
|
}
|
||||||
|
return i->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmGlobalVisualStudioGenerator::FollowLinkDepends(
|
||||||
|
cmTarget* target, std::set<cmTarget*>& linked)
|
||||||
|
{
|
||||||
|
if(linked.insert(target).second &&
|
||||||
|
target->GetType() == cmTarget::STATIC_LIBRARY)
|
||||||
|
{
|
||||||
|
// Static library targets do not list their link dependencies so
|
||||||
|
// we must follow them transitively now.
|
||||||
|
TargetDependSet const& depends = this->GetTargetDirectDepends(*target);
|
||||||
|
for(TargetDependSet::const_iterator di = depends.begin();
|
||||||
|
di != depends.end(); ++di)
|
||||||
|
{
|
||||||
|
if(di->IsLink())
|
||||||
|
{
|
||||||
|
this->FollowLinkDepends(*di, linked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bool cmGlobalVisualStudioGenerator::ComputeTargetDepends()
|
bool cmGlobalVisualStudioGenerator::ComputeTargetDepends()
|
||||||
{
|
{
|
||||||
|
@ -269,51 +322,94 @@ void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(cmTarget& target)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
VSDependSet& vsTargetDepend = this->VSTargetDepends[&target];
|
VSDependSet& vsTargetDepend = this->VSTargetDepends[&target];
|
||||||
|
// VS <= 7.1 has two behaviors that affect solution dependencies.
|
||||||
|
//
|
||||||
|
// (1) Solution-level dependencies between a linkable target and a
|
||||||
|
// library cause that library to be linked. We use an intermedite
|
||||||
|
// empty utility target to express the dependency. (VS 8 and above
|
||||||
|
// provide a project file "LinkLibraryDependencies" setting to
|
||||||
|
// choose whether to activate this behavior. We disable it except
|
||||||
|
// when linking external project files.)
|
||||||
|
//
|
||||||
|
// (2) We cannot let static libraries depend directly on targets to
|
||||||
|
// which they "link" because the librarian tool will copy the
|
||||||
|
// targets into the static library. While the work-around for
|
||||||
|
// behavior (1) would also avoid this, it would create a large
|
||||||
|
// number of extra utility targets for little gain. Instead, use
|
||||||
|
// the above work-around only for dependencies explicitly added by
|
||||||
|
// the add_dependencies() command. Approximate link dependencies by
|
||||||
|
// leaving them out for the static library itself but following them
|
||||||
|
// transitively for other targets.
|
||||||
|
|
||||||
|
bool allowLinkable = (target.GetType() != cmTarget::STATIC_LIBRARY &&
|
||||||
|
target.GetType() != cmTarget::SHARED_LIBRARY &&
|
||||||
|
target.GetType() != cmTarget::MODULE_LIBRARY &&
|
||||||
|
target.GetType() != cmTarget::EXECUTABLE);
|
||||||
|
|
||||||
|
TargetDependSet const& depends = this->GetTargetDirectDepends(target);
|
||||||
|
|
||||||
|
// Collect implicit link dependencies (target_link_libraries).
|
||||||
|
// Static libraries cannot depend on their link implementation
|
||||||
|
// due to behavior (2), but they do not really need to.
|
||||||
|
std::set<cmTarget*> linkDepends;
|
||||||
if(target.GetType() != cmTarget::STATIC_LIBRARY)
|
if(target.GetType() != cmTarget::STATIC_LIBRARY)
|
||||||
{
|
{
|
||||||
cmTarget::LinkLibraryVectorType const& libs = target.GetLinkLibraries();
|
for(TargetDependSet::const_iterator di = depends.begin();
|
||||||
for(cmTarget::LinkLibraryVectorType::const_iterator j = libs.begin();
|
di != depends.end(); ++di)
|
||||||
j != libs.end(); ++j)
|
|
||||||
{
|
{
|
||||||
if(j->first != target.GetName() &&
|
cmTargetDepend dep = *di;
|
||||||
this->FindTarget(0, j->first.c_str()))
|
if(dep.IsLink())
|
||||||
{
|
{
|
||||||
vsTargetDepend.insert(j->first);
|
this->FollowLinkDepends(dep, linkDepends);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::set<cmStdString> const& utils = target.GetUtilities();
|
|
||||||
for(std::set<cmStdString>::const_iterator i = utils.begin();
|
|
||||||
i != utils.end(); ++i)
|
|
||||||
{
|
|
||||||
if(*i != target.GetName())
|
|
||||||
{
|
|
||||||
std::string name = this->GetUtilityForTarget(target, i->c_str());
|
|
||||||
vsTargetDepend.insert(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
// Collext explicit util dependencies (add_dependencies).
|
||||||
bool cmGlobalVisualStudioGenerator::CheckTargetLinks(cmTarget& target,
|
std::set<cmTarget*> utilDepends;
|
||||||
const char* name)
|
for(TargetDependSet::const_iterator di = depends.begin();
|
||||||
{
|
di != depends.end(); ++di)
|
||||||
// Return whether the given target links to a target with the given name.
|
|
||||||
if(target.GetType() == cmTarget::STATIC_LIBRARY)
|
|
||||||
{
|
{
|
||||||
// Static libraries never link to anything.
|
cmTargetDepend dep = *di;
|
||||||
return false;
|
if(dep.IsUtil())
|
||||||
}
|
|
||||||
cmTarget::LinkLibraryVectorType const& libs = target.GetLinkLibraries();
|
|
||||||
for(cmTarget::LinkLibraryVectorType::const_iterator i = libs.begin();
|
|
||||||
i != libs.end(); ++i)
|
|
||||||
{
|
|
||||||
if(i->first == name)
|
|
||||||
{
|
{
|
||||||
return true;
|
this->FollowLinkDepends(dep, utilDepends);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect all targets linked by this target so we can avoid
|
||||||
|
// intermediate targets below.
|
||||||
|
TargetSet linked;
|
||||||
|
if(target.GetType() != cmTarget::STATIC_LIBRARY)
|
||||||
|
{
|
||||||
|
linked = this->GetTargetLinkClosure(&target);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit link dependencies.
|
||||||
|
for(std::set<cmTarget*>::iterator di = linkDepends.begin();
|
||||||
|
di != linkDepends.end(); ++di)
|
||||||
|
{
|
||||||
|
cmTarget* dep = *di;
|
||||||
|
vsTargetDepend.insert(dep->GetName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit util dependencies. Possibly use intermediate targets.
|
||||||
|
for(std::set<cmTarget*>::iterator di = utilDepends.begin();
|
||||||
|
di != utilDepends.end(); ++di)
|
||||||
|
{
|
||||||
|
cmTarget* dep = *di;
|
||||||
|
if(allowLinkable || !dep->IsLinkable() || linked.count(dep))
|
||||||
|
{
|
||||||
|
// Direct dependency allowed.
|
||||||
|
vsTargetDepend.insert(dep->GetName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Direct dependency on linkable target not allowed.
|
||||||
|
// Use an intermediate utility target.
|
||||||
|
vsTargetDepend.insert(this->GetUtilityDepend(dep));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -329,45 +425,6 @@ std::string cmGlobalVisualStudioGenerator::GetUtilityDepend(cmTarget* target)
|
||||||
return i->second;
|
return i->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
std::string
|
|
||||||
cmGlobalVisualStudioGenerator::GetUtilityForTarget(cmTarget& target,
|
|
||||||
const char* name)
|
|
||||||
{
|
|
||||||
if(!this->VSLinksDependencies())
|
|
||||||
{
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Possibly depend on an intermediate utility target to avoid
|
|
||||||
// linking.
|
|
||||||
if(target.GetType() == cmTarget::STATIC_LIBRARY ||
|
|
||||||
target.GetType() == cmTarget::SHARED_LIBRARY ||
|
|
||||||
target.GetType() == cmTarget::MODULE_LIBRARY ||
|
|
||||||
target.GetType() == cmTarget::EXECUTABLE)
|
|
||||||
{
|
|
||||||
// The depender is a target that links.
|
|
||||||
if(cmTarget* depTarget = this->FindTarget(0, name))
|
|
||||||
{
|
|
||||||
if(depTarget->GetType() == cmTarget::STATIC_LIBRARY ||
|
|
||||||
depTarget->GetType() == cmTarget::SHARED_LIBRARY ||
|
|
||||||
depTarget->GetType() == cmTarget::MODULE_LIBRARY)
|
|
||||||
{
|
|
||||||
// This utility dependency will cause an attempt to link. If
|
|
||||||
// the depender does not already link the dependee we need an
|
|
||||||
// intermediate target.
|
|
||||||
if(!this->CheckTargetLinks(target, name))
|
|
||||||
{
|
|
||||||
return this->GetUtilityDepend(depTarget);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No special case. Just use the original dependency name.
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
@ -706,11 +763,22 @@ cmGlobalVisualStudioGenerator::TargetCompare
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
cmGlobalVisualStudioGenerator::OrderedTargetDependSet
|
cmGlobalVisualStudioGenerator::OrderedTargetDependSet
|
||||||
::OrderedTargetDependSet(cmGlobalGenerator::TargetDependSet const& targets)
|
::OrderedTargetDependSet(TargetDependSet const& targets)
|
||||||
{
|
{
|
||||||
for(cmGlobalGenerator::TargetDependSet::const_iterator ti =
|
for(TargetDependSet::const_iterator ti =
|
||||||
targets.begin(); ti != targets.end(); ++ti)
|
targets.begin(); ti != targets.end(); ++ti)
|
||||||
{
|
{
|
||||||
this->insert(*ti);
|
this->insert(*ti);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
cmGlobalVisualStudioGenerator::OrderedTargetDependSet
|
||||||
|
::OrderedTargetDependSet(TargetSet const& targets)
|
||||||
|
{
|
||||||
|
for(TargetSet::const_iterator ti = targets.begin();
|
||||||
|
ti != targets.end(); ++ti)
|
||||||
|
{
|
||||||
|
this->insert(*ti);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -69,15 +69,12 @@ public:
|
||||||
i.e. "Can I build Debug and Release in the same tree?" */
|
i.e. "Can I build Debug and Release in the same tree?" */
|
||||||
virtual bool IsMultiConfig() { return true; }
|
virtual bool IsMultiConfig() { return true; }
|
||||||
|
|
||||||
|
class TargetSet: public std::set<cmTarget*> {};
|
||||||
struct TargetCompare
|
struct TargetCompare
|
||||||
{
|
{
|
||||||
bool operator()(cmTarget const* l, cmTarget const* r) const;
|
bool operator()(cmTarget const* l, cmTarget const* r) const;
|
||||||
};
|
};
|
||||||
class OrderedTargetDependSet: public std::multiset<cmTarget*, TargetCompare>
|
class OrderedTargetDependSet;
|
||||||
{
|
|
||||||
public:
|
|
||||||
OrderedTargetDependSet(cmGlobalGenerator::TargetDependSet const&);
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Does this VS version link targets to each other if there are
|
// Does this VS version link targets to each other if there are
|
||||||
|
@ -99,6 +96,24 @@ protected:
|
||||||
std::string GetUtilityDepend(cmTarget* target);
|
std::string GetUtilityDepend(cmTarget* target);
|
||||||
typedef std::map<cmTarget*, cmStdString> UtilityDependsMap;
|
typedef std::map<cmTarget*, cmStdString> UtilityDependsMap;
|
||||||
UtilityDependsMap UtilityDepends;
|
UtilityDependsMap UtilityDepends;
|
||||||
|
private:
|
||||||
|
void FollowLinkDepends(cmTarget* target, std::set<cmTarget*>& linked);
|
||||||
|
|
||||||
|
class TargetSetMap: public std::map<cmTarget*, TargetSet> {};
|
||||||
|
TargetSetMap TargetLinkClosure;
|
||||||
|
void FillLinkClosure(cmTarget* target, TargetSet& linked);
|
||||||
|
TargetSet const& GetTargetLinkClosure(cmTarget* target);
|
||||||
|
};
|
||||||
|
|
||||||
|
class cmGlobalVisualStudioGenerator::OrderedTargetDependSet:
|
||||||
|
public std::multiset<cmTargetDepend,
|
||||||
|
cmGlobalVisualStudioGenerator::TargetCompare>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef cmGlobalGenerator::TargetDependSet TargetDependSet;
|
||||||
|
typedef cmGlobalVisualStudioGenerator::TargetSet TargetSet;
|
||||||
|
OrderedTargetDependSet(TargetDependSet const&);
|
||||||
|
OrderedTargetDependSet(TargetSet const&);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue