Merge branch 'vs-target-dependencies' into imported-target-dependencies
This commit is contained in:
commit
bc7395c096
|
@ -144,7 +144,7 @@ bool cmComputeTargetDepends::Compute()
|
|||
//----------------------------------------------------------------------------
|
||||
void
|
||||
cmComputeTargetDepends::GetTargetDirectDepends(cmTarget* t,
|
||||
std::set<cmTarget*>& deps)
|
||||
cmTargetDependSet& deps)
|
||||
{
|
||||
// Lookup the index for this target. All targets should be known by
|
||||
// this point.
|
||||
|
@ -156,7 +156,9 @@ cmComputeTargetDepends::GetTargetDirectDepends(cmTarget* t,
|
|||
EdgeList const& nl = this->FinalGraph[i];
|
||||
for(EdgeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni)
|
||||
{
|
||||
deps.insert(this->Targets[*ni]);
|
||||
cmTarget* dep = this->Targets[*ni];
|
||||
cmTargetDependSet::iterator di = deps.insert(dep).first;
|
||||
di->SetType(ni->IsStrong());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -445,7 +447,7 @@ cmComputeTargetDepends
|
|||
int j = *ei;
|
||||
if(cmap[j] == c && ei->IsStrong())
|
||||
{
|
||||
this->FinalGraph[i].push_back(j);
|
||||
this->FinalGraph[i].push_back(cmGraphEdge(j, true));
|
||||
if(!this->IntraComponent(cmap, c, j, head, emitted, visited))
|
||||
{
|
||||
return false;
|
||||
|
@ -456,7 +458,7 @@ cmComputeTargetDepends
|
|||
// Prepend to a linear linked-list of intra-component edges.
|
||||
if(*head >= 0)
|
||||
{
|
||||
this->FinalGraph[i].push_back(*head);
|
||||
this->FinalGraph[i].push_back(cmGraphEdge(*head, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -515,7 +517,7 @@ cmComputeTargetDepends
|
|||
int dependee_component = *ni;
|
||||
int dependee_component_head = this->ComponentHead[dependee_component];
|
||||
this->FinalGraph[depender_component_tail]
|
||||
.push_back(dependee_component_head);
|
||||
.push_back(cmGraphEdge(dependee_component_head, ni->IsStrong()));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
class cmComputeComponentGraph;
|
||||
class cmGlobalGenerator;
|
||||
class cmTarget;
|
||||
class cmTargetDependSet;
|
||||
|
||||
/** \class cmComputeTargetDepends
|
||||
* \brief Compute global interdependencies among targets.
|
||||
|
@ -38,7 +39,7 @@ public:
|
|||
bool Compute();
|
||||
|
||||
std::vector<cmTarget*> const& GetTargets() const { return this->Targets; }
|
||||
void GetTargetDirectDepends(cmTarget* t, std::set<cmTarget*>& deps);
|
||||
void GetTargetDirectDepends(cmTarget* t, cmTargetDependSet& deps);
|
||||
private:
|
||||
void CollectTargets();
|
||||
void CollectDepends();
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "cmStandardIncludes.h"
|
||||
|
||||
#include "cmTarget.h" // For cmTargets
|
||||
#include "cmTargetDepend.h" // For cmTargetDependSet
|
||||
|
||||
class cmake;
|
||||
class cmMakefile;
|
||||
|
@ -233,7 +234,7 @@ public:
|
|||
virtual const char* GetCleanTargetName() { return 0; }
|
||||
|
||||
// Class to track a set of dependencies.
|
||||
class TargetDependSet: public std::set<cmTarget*> {};
|
||||
typedef cmTargetDependSet TargetDependSet;
|
||||
|
||||
// what targets does the specified target depend on directly
|
||||
// via a target_link_libraries or add_dependencies
|
||||
|
|
|
@ -236,6 +236,59 @@ std::string cmGlobalVisualStudioGenerator::GetUserMacrosRegKeyBase()
|
|||
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()
|
||||
{
|
||||
|
@ -269,51 +322,94 @@ void cmGlobalVisualStudioGenerator::ComputeVSTargetDepends(cmTarget& target)
|
|||
return;
|
||||
}
|
||||
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)
|
||||
{
|
||||
cmTarget::LinkLibraryVectorType const& libs = target.GetLinkLibraries();
|
||||
for(cmTarget::LinkLibraryVectorType::const_iterator j = libs.begin();
|
||||
j != libs.end(); ++j)
|
||||
for(TargetDependSet::const_iterator di = depends.begin();
|
||||
di != depends.end(); ++di)
|
||||
{
|
||||
if(j->first != target.GetName() &&
|
||||
this->FindTarget(0, j->first.c_str()))
|
||||
cmTargetDepend dep = *di;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool cmGlobalVisualStudioGenerator::CheckTargetLinks(cmTarget& target,
|
||||
const char* name)
|
||||
{
|
||||
// Return whether the given target links to a target with the given name.
|
||||
if(target.GetType() == cmTarget::STATIC_LIBRARY)
|
||||
// Collext explicit util dependencies (add_dependencies).
|
||||
std::set<cmTarget*> utilDepends;
|
||||
for(TargetDependSet::const_iterator di = depends.begin();
|
||||
di != depends.end(); ++di)
|
||||
{
|
||||
// Static libraries never link to anything.
|
||||
return false;
|
||||
}
|
||||
cmTarget::LinkLibraryVectorType const& libs = target.GetLinkLibraries();
|
||||
for(cmTarget::LinkLibraryVectorType::const_iterator i = libs.begin();
|
||||
i != libs.end(); ++i)
|
||||
{
|
||||
if(i->first == name)
|
||||
cmTargetDepend dep = *di;
|
||||
if(dep.IsUtil())
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
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>
|
||||
|
||||
|
@ -706,11 +763,22 @@ cmGlobalVisualStudioGenerator::TargetCompare
|
|||
|
||||
//----------------------------------------------------------------------------
|
||||
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)
|
||||
{
|
||||
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?" */
|
||||
virtual bool IsMultiConfig() { return true; }
|
||||
|
||||
class TargetSet: public std::set<cmTarget*> {};
|
||||
struct TargetCompare
|
||||
{
|
||||
bool operator()(cmTarget const* l, cmTarget const* r) const;
|
||||
};
|
||||
class OrderedTargetDependSet: public std::multiset<cmTarget*, TargetCompare>
|
||||
{
|
||||
public:
|
||||
OrderedTargetDependSet(cmGlobalGenerator::TargetDependSet const&);
|
||||
};
|
||||
class OrderedTargetDependSet;
|
||||
|
||||
protected:
|
||||
// Does this VS version link targets to each other if there are
|
||||
|
@ -99,6 +96,24 @@ protected:
|
|||
std::string GetUtilityDepend(cmTarget* target);
|
||||
typedef std::map<cmTarget*, cmStdString> UtilityDependsMap;
|
||||
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
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*============================================================================
|
||||
CMake - Cross Platform Makefile Generator
|
||||
Copyright 2000-2010 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.
|
||||
============================================================================*/
|
||||
#ifndef cmTargetDepend_h
|
||||
#define cmTargetDepend_h
|
||||
|
||||
#include "cmStandardIncludes.h"
|
||||
|
||||
class cmTarget;
|
||||
|
||||
/** One edge in the global target dependency graph.
|
||||
It may be marked as a 'link' or 'util' edge or both. */
|
||||
class cmTargetDepend
|
||||
{
|
||||
cmTarget* Target;
|
||||
|
||||
// The set order depends only on the Target, so we use
|
||||
// mutable members to acheive a map with set syntax.
|
||||
mutable bool Link;
|
||||
mutable bool Util;
|
||||
public:
|
||||
cmTargetDepend(cmTarget* t): Target(t), Link(false), Util(false) {}
|
||||
operator cmTarget*() const { return this->Target; }
|
||||
cmTarget* operator->() const { return this->Target; }
|
||||
cmTarget& operator*() const { return *this->Target; }
|
||||
friend bool operator < (cmTargetDepend const& l, cmTargetDepend const& r)
|
||||
{ return l.Target < r.Target; }
|
||||
void SetType(bool strong) const
|
||||
{
|
||||
if(strong) { this->Util = true; }
|
||||
else { this->Link = true; }
|
||||
}
|
||||
bool IsLink() const { return this->Link; }
|
||||
bool IsUtil() const { return this->Util; }
|
||||
};
|
||||
|
||||
/** Unordered set of (direct) dependencies of a target. */
|
||||
class cmTargetDependSet: public std::set<cmTargetDepend> {};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue