ENH: Improve link line generation for static library cycles.
- Move Tarjan algorithm from cmComputeTargetDepends into its own class cmComputeComponentGraph - Use cmComputeComponentGraph to identify the component DAG of link dependencies in cmComputeLinkDepends - Emit non-trivial component members more than once but always in a contiguous group on the link line
This commit is contained in:
parent
0bfad2946d
commit
4987e17f46
|
@ -87,6 +87,8 @@ SET(SRCS
|
||||||
cmCommandArgumentLexer.cxx
|
cmCommandArgumentLexer.cxx
|
||||||
cmCommandArgumentParser.cxx
|
cmCommandArgumentParser.cxx
|
||||||
cmCommandArgumentParserHelper.cxx
|
cmCommandArgumentParserHelper.cxx
|
||||||
|
cmComputeComponentGraph.cxx
|
||||||
|
cmComputeComponentGraph.h
|
||||||
cmComputeLinkDepends.cxx
|
cmComputeLinkDepends.cxx
|
||||||
cmComputeLinkDepends.h
|
cmComputeLinkDepends.h
|
||||||
cmComputeLinkInformation.cxx
|
cmComputeLinkInformation.cxx
|
||||||
|
@ -138,6 +140,7 @@ SET(SRCS
|
||||||
cmGlobalGenerator.h
|
cmGlobalGenerator.h
|
||||||
cmGlobalUnixMakefileGenerator3.cxx
|
cmGlobalUnixMakefileGenerator3.cxx
|
||||||
cmGlobalUnixMakefileGenerator3.h
|
cmGlobalUnixMakefileGenerator3.h
|
||||||
|
cmGraphAdjacencyList.h
|
||||||
cmInstallGenerator.h
|
cmInstallGenerator.h
|
||||||
cmInstallGenerator.cxx
|
cmInstallGenerator.cxx
|
||||||
cmInstallExportGenerator.cxx
|
cmInstallExportGenerator.cxx
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
/*=========================================================================
|
||||||
|
|
||||||
|
Program: CMake - Cross-Platform Makefile Generator
|
||||||
|
Module: $RCSfile$
|
||||||
|
Language: C++
|
||||||
|
Date: $Date$
|
||||||
|
Version: $Revision$
|
||||||
|
|
||||||
|
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
|
||||||
|
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. See the above copyright notices for more information.
|
||||||
|
|
||||||
|
=========================================================================*/
|
||||||
|
#include "cmComputeComponentGraph.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
cmComputeComponentGraph::cmComputeComponentGraph(Graph const& input):
|
||||||
|
InputGraph(input)
|
||||||
|
{
|
||||||
|
// Identify components.
|
||||||
|
this->Tarjan();
|
||||||
|
|
||||||
|
// Compute the component graph.
|
||||||
|
this->ComponentGraph.resize(0);
|
||||||
|
this->ComponentGraph.resize(this->Components.size());
|
||||||
|
this->TransferEdges();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
cmComputeComponentGraph::~cmComputeComponentGraph()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmComputeComponentGraph::Tarjan()
|
||||||
|
{
|
||||||
|
int n = static_cast<int>(this->InputGraph.size());
|
||||||
|
TarjanEntry entry = {0,0};
|
||||||
|
this->TarjanEntries.resize(0);
|
||||||
|
this->TarjanEntries.resize(n, entry);
|
||||||
|
this->TarjanComponents.resize(0);
|
||||||
|
this->TarjanComponents.resize(n, -1);
|
||||||
|
this->TarjanWalkId = 0;
|
||||||
|
this->TarjanVisited.resize(0);
|
||||||
|
this->TarjanVisited.resize(n, 0);
|
||||||
|
for(int i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
// Start a new DFS from this node if it has never been visited.
|
||||||
|
if(!this->TarjanVisited[i])
|
||||||
|
{
|
||||||
|
assert(this->TarjanStack.empty());
|
||||||
|
++this->TarjanWalkId;
|
||||||
|
this->TarjanIndex = 0;
|
||||||
|
this->TarjanVisit(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmComputeComponentGraph::TarjanVisit(int i)
|
||||||
|
{
|
||||||
|
// We are now visiting this node.
|
||||||
|
this->TarjanVisited[i] = this->TarjanWalkId;
|
||||||
|
|
||||||
|
// Initialize the entry.
|
||||||
|
this->TarjanEntries[i].Root = i;
|
||||||
|
this->TarjanComponents[i] = -1;
|
||||||
|
this->TarjanEntries[i].VisitIndex = ++this->TarjanIndex;
|
||||||
|
this->TarjanStack.push(i);
|
||||||
|
|
||||||
|
// Follow outgoing edges.
|
||||||
|
NodeList const& nl = this->InputGraph[i];
|
||||||
|
for(NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni)
|
||||||
|
{
|
||||||
|
int j = *ni;
|
||||||
|
|
||||||
|
// Ignore edges to nodes that have been reached by a previous DFS
|
||||||
|
// walk. Since we did not reach the current node from that walk
|
||||||
|
// it must not belong to the same component and it has already
|
||||||
|
// been assigned to a component.
|
||||||
|
if(this->TarjanVisited[j] > 0 &&
|
||||||
|
this->TarjanVisited[j] < this->TarjanWalkId)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visit the destination if it has not yet been visited.
|
||||||
|
if(!this->TarjanVisited[j])
|
||||||
|
{
|
||||||
|
this->TarjanVisit(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the destination has not yet been assigned to a component,
|
||||||
|
// check if it has a better root for the current object.
|
||||||
|
if(this->TarjanComponents[j] < 0)
|
||||||
|
{
|
||||||
|
if(this->TarjanEntries[this->TarjanEntries[j].Root].VisitIndex <
|
||||||
|
this->TarjanEntries[this->TarjanEntries[i].Root].VisitIndex)
|
||||||
|
{
|
||||||
|
this->TarjanEntries[i].Root = this->TarjanEntries[j].Root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have found a component.
|
||||||
|
if(this->TarjanEntries[i].Root == i)
|
||||||
|
{
|
||||||
|
// Yes. Create it.
|
||||||
|
int c = static_cast<int>(this->Components.size());
|
||||||
|
this->Components.push_back(NodeList());
|
||||||
|
NodeList& component = this->Components[c];
|
||||||
|
|
||||||
|
// Populate the component list.
|
||||||
|
int j;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Get the next member of the component.
|
||||||
|
j = this->TarjanStack.top();
|
||||||
|
this->TarjanStack.pop();
|
||||||
|
|
||||||
|
// Assign the member to the component.
|
||||||
|
this->TarjanComponents[j] = c;
|
||||||
|
this->TarjanEntries[j].Root = i;
|
||||||
|
|
||||||
|
// Store the node in its component.
|
||||||
|
component.push_back(j);
|
||||||
|
} while(j != i);
|
||||||
|
|
||||||
|
// Sort the component members for clarity.
|
||||||
|
std::sort(component.begin(), component.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmComputeComponentGraph::TransferEdges()
|
||||||
|
{
|
||||||
|
// Map inter-component edges in the original graph to edges in the
|
||||||
|
// component graph.
|
||||||
|
int n = static_cast<int>(this->InputGraph.size());
|
||||||
|
for(int i=0; i < n; ++i)
|
||||||
|
{
|
||||||
|
int i_component = this->TarjanComponents[i];
|
||||||
|
NodeList const& nl = this->InputGraph[i];
|
||||||
|
for(NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni)
|
||||||
|
{
|
||||||
|
int j = *ni;
|
||||||
|
int j_component = this->TarjanComponents[j];
|
||||||
|
if(i_component != j_component)
|
||||||
|
{
|
||||||
|
this->ComponentGraph[i_component].push_back(j_component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*=========================================================================
|
||||||
|
|
||||||
|
Program: CMake - Cross-Platform Makefile Generator
|
||||||
|
Module: $RCSfile$
|
||||||
|
Language: C++
|
||||||
|
Date: $Date$
|
||||||
|
Version: $Revision$
|
||||||
|
|
||||||
|
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
|
||||||
|
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. See the above copyright notices for more information.
|
||||||
|
|
||||||
|
=========================================================================*/
|
||||||
|
#ifndef cmComputeComponentGraph_h
|
||||||
|
#define cmComputeComponentGraph_h
|
||||||
|
|
||||||
|
#include "cmStandardIncludes.h"
|
||||||
|
|
||||||
|
#include "cmGraphAdjacencyList.h"
|
||||||
|
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
/** \class cmComputeComponentGraph
|
||||||
|
* \brief Analyze a graph to determine strongly connected components.
|
||||||
|
*
|
||||||
|
* Convert a directed graph into a directed acyclic graph whose nodes
|
||||||
|
* correspond to strongly connected components of the original graph.
|
||||||
|
*
|
||||||
|
* We use Tarjan's algorithm to enumerate the components efficiently.
|
||||||
|
* An advantage of this approach is that the components are identified
|
||||||
|
* in a topologically sorted order.
|
||||||
|
*/
|
||||||
|
class cmComputeComponentGraph
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Represent the graph with an adjacency list.
|
||||||
|
typedef cmGraphNodeList NodeList;
|
||||||
|
typedef cmGraphAdjacencyList Graph;
|
||||||
|
|
||||||
|
cmComputeComponentGraph(Graph const& input);
|
||||||
|
~cmComputeComponentGraph();
|
||||||
|
|
||||||
|
/** Get the adjacency list of the component graph. */
|
||||||
|
Graph const& GetComponentGraph() const
|
||||||
|
{ return this->ComponentGraph; }
|
||||||
|
NodeList const& GetComponentGraphEdges(int c) const
|
||||||
|
{ return this->ComponentGraph[c]; }
|
||||||
|
|
||||||
|
/** Get map from component index to original node indices. */
|
||||||
|
std::vector<NodeList> const& GetComponents() const
|
||||||
|
{ return this->Components; }
|
||||||
|
NodeList const& GetComponent(int c) const
|
||||||
|
{ return this->Components[c]; }
|
||||||
|
|
||||||
|
/** Get map from original node index to component index. */
|
||||||
|
std::vector<int> const& GetComponentMap() const
|
||||||
|
{ return this->TarjanComponents; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void TransferEdges();
|
||||||
|
|
||||||
|
Graph const& InputGraph;
|
||||||
|
Graph ComponentGraph;
|
||||||
|
|
||||||
|
// Tarjan's algorithm.
|
||||||
|
struct TarjanEntry
|
||||||
|
{
|
||||||
|
int Root;
|
||||||
|
int VisitIndex;
|
||||||
|
};
|
||||||
|
int TarjanWalkId;
|
||||||
|
std::vector<int> TarjanVisited;
|
||||||
|
std::vector<int> TarjanComponents;
|
||||||
|
std::vector<TarjanEntry> TarjanEntries;
|
||||||
|
std::stack<int> TarjanStack;
|
||||||
|
int TarjanIndex;
|
||||||
|
void Tarjan();
|
||||||
|
void TarjanVisit(int i);
|
||||||
|
|
||||||
|
// Connected components.
|
||||||
|
std::vector<NodeList> Components;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -16,6 +16,7 @@
|
||||||
=========================================================================*/
|
=========================================================================*/
|
||||||
#include "cmComputeLinkDepends.h"
|
#include "cmComputeLinkDepends.h"
|
||||||
|
|
||||||
|
#include "cmComputeComponentGraph.h"
|
||||||
#include "cmGlobalGenerator.h"
|
#include "cmGlobalGenerator.h"
|
||||||
#include "cmLocalGenerator.h"
|
#include "cmLocalGenerator.h"
|
||||||
#include "cmMakefile.h"
|
#include "cmMakefile.h"
|
||||||
|
@ -96,31 +97,47 @@ For the unknown items, we infer dependencies by looking at the
|
||||||
B: intersect( {Y,C} , {} ) = {} ; infer no edges
|
B: intersect( {Y,C} , {} ) = {} ; infer no edges
|
||||||
C: intersect( {} , {B} ) = {} ; infer no edges
|
C: intersect( {} , {B} ) = {} ; infer no edges
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
Once the complete graph is formed from all known and inferred
|
Once the complete graph is formed from all known and inferred
|
||||||
dependencies, we walk the graph with a series of depth-first-searches
|
dependencies we must use it to produce a valid link line. If the
|
||||||
in order to emit link items. When visiting a node all edges are
|
dependency graph were known to be acyclic a simple depth-first-search
|
||||||
followed first because the neighbors must precede the item. Once
|
would produce a correct link line. Unfortunately we cannot make this
|
||||||
neighbors across all edges have been emitted it is safe to emit the
|
assumption so the following technique is used.
|
||||||
current node.
|
|
||||||
|
|
||||||
If a single DFS returns to a node it previously reached then a cycle
|
The original graph is converted to a directed acyclic graph in which
|
||||||
is present. Cyclic link dependencies are resolved simply by repeating
|
each node corresponds to a strongly connected component of the
|
||||||
one of the cycle entries at the beginning and end of the cycle
|
original graph. For example, the dependency graph
|
||||||
members. For example, the graph
|
|
||||||
|
|
||||||
A <- B , B <- C , C <- A
|
X <- A <- B <- C <- A <- Y
|
||||||
|
|
||||||
can be satisfied with the link item list
|
contains strongly connected components {X}, {A,B,C}, and {Y}. The
|
||||||
|
implied directed acyclic graph (DAG) is
|
||||||
|
|
||||||
A B C A
|
{X} <- {A,B,C} <- {Y}
|
||||||
|
|
||||||
When a node is reached a second time during the same DFS we make sure
|
The final list of link items is constructed by a series of
|
||||||
its item has been emitted and then skip following its outgoing edges
|
depth-first-searches through this DAG of components. When visiting a
|
||||||
again.
|
component all outgoing edges are followed first because the neighbors
|
||||||
|
must precede it. Once neighbors across all edges have been emitted it
|
||||||
|
is safe to emit the current component.
|
||||||
|
|
||||||
|
Trivial components (those with one item) are handled simply by
|
||||||
|
emitting the item. Non-trivial components (those with more than one
|
||||||
|
item) are assumed to consist only of static libraries that may be
|
||||||
|
safely repeated on the link line. We emit members of the component
|
||||||
|
multiple times (see code below for details). The final link line for
|
||||||
|
the example graph might be
|
||||||
|
|
||||||
|
X A B C A B C Y
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
The initial exploration of dependencies using a BFS associates an
|
The initial exploration of dependencies using a BFS associates an
|
||||||
integer index with each link item. When the graph is built outgoing
|
integer index with each link item. When the graph is built outgoing
|
||||||
edges are sorted by this index. This preserves the original link
|
edges are sorted by this index.
|
||||||
|
|
||||||
|
This preserves the original link
|
||||||
order as much as possible subject to the dependencies.
|
order as much as possible subject to the dependencies.
|
||||||
|
|
||||||
After the initial exploration of the link interface tree, any
|
After the initial exploration of the link interface tree, any
|
||||||
|
@ -190,6 +207,9 @@ cmComputeLinkDepends::Compute()
|
||||||
// Infer dependencies of targets for which they were not known.
|
// Infer dependencies of targets for which they were not known.
|
||||||
this->InferDependencies();
|
this->InferDependencies();
|
||||||
|
|
||||||
|
// Cleanup the constraint graph.
|
||||||
|
this->CleanConstraintGraph();
|
||||||
|
|
||||||
// Display the constraint graph.
|
// Display the constraint graph.
|
||||||
if(this->DebugMode)
|
if(this->DebugMode)
|
||||||
{
|
{
|
||||||
|
@ -223,7 +243,7 @@ cmComputeLinkDepends::AllocateLinkEntry(std::string const& item)
|
||||||
lei = this->LinkEntryIndex.insert(index_entry).first;
|
lei = this->LinkEntryIndex.insert(index_entry).first;
|
||||||
this->EntryList.push_back(LinkEntry());
|
this->EntryList.push_back(LinkEntry());
|
||||||
this->InferredDependSets.push_back(0);
|
this->InferredDependSets.push_back(0);
|
||||||
this->EntryConstraintGraph.push_back(EntryConstraintSet());
|
this->EntryConstraintGraph.push_back(NodeList());
|
||||||
return lei;
|
return lei;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,7 +374,7 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep)
|
||||||
|
|
||||||
// This shared library dependency must be preceded by the item that
|
// This shared library dependency must be preceded by the item that
|
||||||
// listed it.
|
// listed it.
|
||||||
this->EntryConstraintGraph[index].insert(dep.DependerIndex);
|
this->EntryConstraintGraph[index].push_back(dep.DependerIndex);
|
||||||
|
|
||||||
// Target items may have their own dependencies.
|
// Target items may have their own dependencies.
|
||||||
if(entry.Target)
|
if(entry.Target)
|
||||||
|
@ -469,7 +489,7 @@ cmComputeLinkDepends::AddLinkEntries(int depender_index,
|
||||||
// The depender must come before the dependee.
|
// The depender must come before the dependee.
|
||||||
if(depender_index >= 0)
|
if(depender_index >= 0)
|
||||||
{
|
{
|
||||||
this->EntryConstraintGraph[dependee_index].insert(depender_index);
|
this->EntryConstraintGraph[dependee_index].push_back(depender_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the inferred dependencies for earlier items.
|
// Update the inferred dependencies for earlier items.
|
||||||
|
@ -531,22 +551,37 @@ void cmComputeLinkDepends::InferDependencies()
|
||||||
for(DependSet::const_iterator j = common.begin(); j != common.end(); ++j)
|
for(DependSet::const_iterator j = common.begin(); j != common.end(); ++j)
|
||||||
{
|
{
|
||||||
int dependee_index = *j;
|
int dependee_index = *j;
|
||||||
this->EntryConstraintGraph[dependee_index].insert(depender_index);
|
this->EntryConstraintGraph[dependee_index].push_back(depender_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmComputeLinkDepends::CleanConstraintGraph()
|
||||||
|
{
|
||||||
|
for(Graph::iterator i = this->EntryConstraintGraph.begin();
|
||||||
|
i != this->EntryConstraintGraph.end(); ++i)
|
||||||
|
{
|
||||||
|
// Sort the outgoing edges for each graph node so that the
|
||||||
|
// original order will be preserved as much as possible.
|
||||||
|
cmsys_stl::sort(i->begin(), i->end());
|
||||||
|
|
||||||
|
// Make the edge list unique.
|
||||||
|
NodeList::iterator last = cmsys_stl::unique(i->begin(), i->end());
|
||||||
|
i->erase(last, i->end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void cmComputeLinkDepends::DisplayConstraintGraph()
|
void cmComputeLinkDepends::DisplayConstraintGraph()
|
||||||
{
|
{
|
||||||
// Display the conflict graph.
|
// Display the graph nodes and their edges.
|
||||||
cmOStringStream e;
|
cmOStringStream e;
|
||||||
for(unsigned int i=0; i < this->EntryConstraintGraph.size(); ++i)
|
for(unsigned int i=0; i < this->EntryConstraintGraph.size(); ++i)
|
||||||
{
|
{
|
||||||
EntryConstraintSet const& cset = this->EntryConstraintGraph[i];
|
NodeList const& nl = this->EntryConstraintGraph[i];
|
||||||
e << "item " << i << " is [" << this->EntryList[i].Item << "]\n";
|
e << "item " << i << " is [" << this->EntryList[i].Item << "]\n";
|
||||||
for(EntryConstraintSet::const_iterator j = cset.begin();
|
for(NodeList::const_iterator j = nl.begin(); j != nl.end(); ++j)
|
||||||
j != cset.end(); ++j)
|
|
||||||
{
|
{
|
||||||
e << " item " << *j << " must precede it\n";
|
e << " item " << *j << " must precede it\n";
|
||||||
}
|
}
|
||||||
|
@ -557,56 +592,107 @@ void cmComputeLinkDepends::DisplayConstraintGraph()
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void cmComputeLinkDepends::OrderLinkEntires()
|
void cmComputeLinkDepends::OrderLinkEntires()
|
||||||
{
|
{
|
||||||
// Setup visit tracking.
|
// Compute the DAG of strongly connected components. The algorithm
|
||||||
this->EntryVisited.resize(this->EntryList.size(), 0);
|
// used by cmComputeComponentGraph should identify the components in
|
||||||
this->WalkId = 0;
|
// the same order in which the items were originally discovered in
|
||||||
|
// the BFS. This should preserve the original order when no
|
||||||
// Start a DFS from every entry.
|
// constraints disallow it.
|
||||||
for(unsigned int i=0; i < this->EntryList.size(); ++i)
|
cmComputeComponentGraph ccg(this->EntryConstraintGraph);
|
||||||
|
Graph const& cgraph = ccg.GetComponentGraph();
|
||||||
|
if(this->DebugMode)
|
||||||
{
|
{
|
||||||
++this->WalkId;
|
this->DisplayComponents(ccg);
|
||||||
this->VisitLinkEntry(i);
|
}
|
||||||
|
|
||||||
|
// Setup visit tracking.
|
||||||
|
this->ComponentVisited.resize(cgraph.size(), 0);
|
||||||
|
|
||||||
|
// The component graph is guaranteed to be acyclic. Start a DFS
|
||||||
|
// from every entry.
|
||||||
|
for(unsigned int c=0; c < cgraph.size(); ++c)
|
||||||
|
{
|
||||||
|
this->VisitComponent(ccg, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void cmComputeLinkDepends::VisitLinkEntry(unsigned int i)
|
void
|
||||||
|
cmComputeLinkDepends::DisplayComponents(cmComputeComponentGraph const& ccg)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "The strongly connected components are:\n");
|
||||||
|
std::vector<NodeList> const& components = ccg.GetComponents();
|
||||||
|
for(unsigned int c=0; c < components.size(); ++c)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Component (%u):\n", c);
|
||||||
|
NodeList const& nl = components[c];
|
||||||
|
for(NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni)
|
||||||
|
{
|
||||||
|
int i = *ni;
|
||||||
|
fprintf(stderr, " item %d [%s]\n", i,
|
||||||
|
this->EntryList[i].Item.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void
|
||||||
|
cmComputeLinkDepends::VisitComponent(cmComputeComponentGraph const& ccg,
|
||||||
|
unsigned int c)
|
||||||
{
|
{
|
||||||
// Check if the node has already been visited.
|
// Check if the node has already been visited.
|
||||||
if(this->EntryVisited[i])
|
if(this->ComponentVisited[c])
|
||||||
{
|
{
|
||||||
if(this->EntryVisited[i] == this->WalkId)
|
|
||||||
{
|
|
||||||
// We have reached a node previously visited on this DFS. There
|
|
||||||
// is a cycle. In order to allow linking with cyclic
|
|
||||||
// dependencies we make sure the item is emitted but do not
|
|
||||||
// follow its outgoing edges again.
|
|
||||||
if(this->EntryEmitted.insert(i).second)
|
|
||||||
{
|
|
||||||
// The item has not been previously emitted so we emit it now.
|
|
||||||
// It will be emitted again when the stack unwinds back up to
|
|
||||||
// the beginning of the cycle.
|
|
||||||
this->FinalLinkEntries.push_back(this->EntryList[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are now visiting this node so mark it.
|
// We are now visiting this component so mark it.
|
||||||
this->EntryVisited[i] = this->WalkId;
|
this->ComponentVisited[c] = 1;
|
||||||
|
|
||||||
// Visit the neighbors of the node first.
|
// Visit the neighbors of the component first.
|
||||||
EntryConstraintSet const& cset = this->EntryConstraintGraph[i];
|
NodeList const& nl = ccg.GetComponentGraphEdges(c);
|
||||||
for(EntryConstraintSet::const_iterator j = cset.begin();
|
for(NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni)
|
||||||
j != cset.end(); ++j)
|
|
||||||
{
|
{
|
||||||
this->VisitLinkEntry(*j);
|
this->VisitComponent(ccg, *ni);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that all items required to come before this one have been
|
// Now that all items required to come before this one have been
|
||||||
// emmitted, emit this item.
|
// emmitted, emit this component's items.
|
||||||
this->EntryEmitted.insert(i);
|
this->EmitComponent(ccg.GetComponent(c));
|
||||||
this->FinalLinkEntries.push_back(this->EntryList[i]);
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void cmComputeLinkDepends::EmitComponent(NodeList const& nl)
|
||||||
|
{
|
||||||
|
assert(!nl.empty());
|
||||||
|
|
||||||
|
// Handle trivial components.
|
||||||
|
if(nl.size() == 1)
|
||||||
|
{
|
||||||
|
this->FinalLinkEntries.push_back(this->EntryList[nl[0]]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a non-trivial strongly connected component of the
|
||||||
|
// original graph. It consists of two or more libraries (archives)
|
||||||
|
// that mutually require objects from one another. In the worst
|
||||||
|
// case we may have to repeat the list of libraries as many times as
|
||||||
|
// there are object files in the biggest archive. For now we just
|
||||||
|
// list them twice.
|
||||||
|
//
|
||||||
|
// The list of items in the component has been sorted by the order
|
||||||
|
// of discovery in the original BFS of dependencies. This has the
|
||||||
|
// advantage that the item directly linked by a target requiring
|
||||||
|
// this component will come first which minimizes the number of
|
||||||
|
// repeats needed.
|
||||||
|
for(NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni)
|
||||||
|
{
|
||||||
|
this->FinalLinkEntries.push_back(this->EntryList[*ni]);
|
||||||
|
}
|
||||||
|
for(NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni)
|
||||||
|
{
|
||||||
|
this->FinalLinkEntries.push_back(this->EntryList[*ni]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -20,8 +20,11 @@
|
||||||
#include "cmStandardIncludes.h"
|
#include "cmStandardIncludes.h"
|
||||||
#include "cmTarget.h"
|
#include "cmTarget.h"
|
||||||
|
|
||||||
|
#include "cmGraphAdjacencyList.h"
|
||||||
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
|
class cmComputeComponentGraph;
|
||||||
class cmGlobalGenerator;
|
class cmGlobalGenerator;
|
||||||
class cmLocalGenerator;
|
class cmLocalGenerator;
|
||||||
class cmMakefile;
|
class cmMakefile;
|
||||||
|
@ -109,16 +112,18 @@ private:
|
||||||
void InferDependencies();
|
void InferDependencies();
|
||||||
|
|
||||||
// Ordering constraint graph adjacency list.
|
// Ordering constraint graph adjacency list.
|
||||||
struct EntryConstraintSet: public std::set<int> {};
|
typedef cmGraphNodeList NodeList;
|
||||||
std::vector<EntryConstraintSet> EntryConstraintGraph;
|
typedef cmGraphAdjacencyList Graph;
|
||||||
|
Graph EntryConstraintGraph;
|
||||||
|
void CleanConstraintGraph();
|
||||||
void DisplayConstraintGraph();
|
void DisplayConstraintGraph();
|
||||||
|
|
||||||
// Ordering algorithm.
|
// Ordering algorithm.
|
||||||
std::vector<int> EntryVisited;
|
|
||||||
std::set<int> EntryEmitted;
|
|
||||||
int WalkId;
|
|
||||||
void OrderLinkEntires();
|
void OrderLinkEntires();
|
||||||
void VisitLinkEntry(unsigned int i);
|
std::vector<char> ComponentVisited;
|
||||||
|
void DisplayComponents(cmComputeComponentGraph const& ccg);
|
||||||
|
void VisitComponent(cmComputeComponentGraph const& ccg, unsigned int i);
|
||||||
|
void EmitComponent(NodeList const& nl);
|
||||||
void DisplayFinalEntries();
|
void DisplayFinalEntries();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
=========================================================================*/
|
=========================================================================*/
|
||||||
#include "cmComputeTargetDepends.h"
|
#include "cmComputeTargetDepends.h"
|
||||||
|
|
||||||
|
#include "cmComputeComponentGraph.h"
|
||||||
#include "cmGlobalGenerator.h"
|
#include "cmGlobalGenerator.h"
|
||||||
#include "cmLocalGenerator.h"
|
#include "cmLocalGenerator.h"
|
||||||
#include "cmMakefile.h"
|
#include "cmMakefile.h"
|
||||||
|
@ -117,25 +118,25 @@ bool cmComputeTargetDepends::Compute()
|
||||||
this->CollectDepends();
|
this->CollectDepends();
|
||||||
if(this->DebugMode)
|
if(this->DebugMode)
|
||||||
{
|
{
|
||||||
this->DisplayGraph(this->TargetDependGraph, "initial");
|
this->DisplayGraph(this->InitialGraph, "initial");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identify components.
|
// Identify components.
|
||||||
this->Tarjan();
|
cmComputeComponentGraph ccg(this->InitialGraph);
|
||||||
if(this->DebugMode)
|
if(this->DebugMode)
|
||||||
{
|
{
|
||||||
this->DisplayComponents();
|
this->DisplayComponents(ccg);
|
||||||
}
|
}
|
||||||
if(!this->CheckComponents())
|
if(!this->CheckComponents(ccg))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the final dependency graph.
|
// Compute the final dependency graph.
|
||||||
this->ComputeFinalDepends();
|
this->ComputeFinalDepends(ccg);
|
||||||
if(this->DebugMode)
|
if(this->DebugMode)
|
||||||
{
|
{
|
||||||
this->DisplayGraph(this->FinalDependGraph, "final");
|
this->DisplayGraph(this->FinalGraph, "final");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -153,11 +154,10 @@ cmComputeTargetDepends::GetTargetDirectDepends(cmTarget* t,
|
||||||
int i = tii->second;
|
int i = tii->second;
|
||||||
|
|
||||||
// Get its final dependencies.
|
// Get its final dependencies.
|
||||||
TargetDependList const& tdl = this->FinalDependGraph[i];
|
NodeList const& nl = this->FinalGraph[i];
|
||||||
for(TargetDependList::const_iterator di = tdl.begin();
|
for(NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni)
|
||||||
di != tdl.end(); ++di)
|
|
||||||
{
|
{
|
||||||
deps.insert(this->Targets[*di]);
|
deps.insert(this->Targets[*ni]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ void cmComputeTargetDepends::CollectTargets()
|
||||||
void cmComputeTargetDepends::CollectDepends()
|
void cmComputeTargetDepends::CollectDepends()
|
||||||
{
|
{
|
||||||
// Allocate the dependency graph adjacency lists.
|
// Allocate the dependency graph adjacency lists.
|
||||||
this->TargetDependGraph.resize(this->Targets.size());
|
this->InitialGraph.resize(this->Targets.size());
|
||||||
|
|
||||||
// Compute each dependency list.
|
// Compute each dependency list.
|
||||||
for(unsigned int i=0; i < this->Targets.size(); ++i)
|
for(unsigned int i=0; i < this->Targets.size(); ++i)
|
||||||
|
@ -265,27 +265,24 @@ void cmComputeTargetDepends::AddTargetDepend(int depender_index,
|
||||||
int dependee_index = tii->second;
|
int dependee_index = tii->second;
|
||||||
|
|
||||||
// Add this entry to the dependency graph.
|
// Add this entry to the dependency graph.
|
||||||
this->TargetDependGraph[depender_index].push_back(dependee_index);
|
this->InitialGraph[depender_index].push_back(dependee_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void
|
void
|
||||||
cmComputeTargetDepends
|
cmComputeTargetDepends::DisplayGraph(Graph const& graph, const char* name)
|
||||||
::DisplayGraph(std::vector<TargetDependList> const& graph,
|
|
||||||
const char* name)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "The %s target dependency graph is:\n", name);
|
fprintf(stderr, "The %s target dependency graph is:\n", name);
|
||||||
int n = static_cast<int>(graph.size());
|
int n = static_cast<int>(graph.size());
|
||||||
for(int depender_index = 0; depender_index < n; ++depender_index)
|
for(int depender_index = 0; depender_index < n; ++depender_index)
|
||||||
{
|
{
|
||||||
TargetDependList const& tdl = graph[depender_index];
|
NodeList const& nl = graph[depender_index];
|
||||||
cmTarget* depender = this->Targets[depender_index];
|
cmTarget* depender = this->Targets[depender_index];
|
||||||
fprintf(stderr, "target %d is [%s]\n",
|
fprintf(stderr, "target %d is [%s]\n",
|
||||||
depender_index, depender->GetName());
|
depender_index, depender->GetName());
|
||||||
for(TargetDependList::const_iterator di = tdl.begin();
|
for(NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni)
|
||||||
di != tdl.end(); ++di)
|
|
||||||
{
|
{
|
||||||
int dependee_index = *di;
|
int dependee_index = *ni;
|
||||||
cmTarget* dependee = this->Targets[dependee_index];
|
cmTarget* dependee = this->Targets[dependee_index];
|
||||||
fprintf(stderr, " depends on target %d [%s]\n", dependee_index,
|
fprintf(stderr, " depends on target %d [%s]\n", dependee_index,
|
||||||
dependee->GetName());
|
dependee->GetName());
|
||||||
|
@ -295,115 +292,20 @@ cmComputeTargetDepends
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void cmComputeTargetDepends::Tarjan()
|
void
|
||||||
{
|
cmComputeTargetDepends
|
||||||
int n = static_cast<int>(this->TargetDependGraph.size());
|
::DisplayComponents(cmComputeComponentGraph const& ccg)
|
||||||
TarjanEntry entry = {0,-1,0};
|
|
||||||
this->TarjanEntries.resize(n, entry);
|
|
||||||
this->TarjanWalkId = 0;
|
|
||||||
this->TarjanVisited.resize(n, 0);
|
|
||||||
for(int i = 0; i < n; ++i)
|
|
||||||
{
|
|
||||||
// Start a new DFS from this node if it has never been visited.
|
|
||||||
if(!this->TarjanVisited[i])
|
|
||||||
{
|
|
||||||
assert(this->TarjanStack.empty());
|
|
||||||
++this->TarjanWalkId;
|
|
||||||
this->TarjanIndex = 0;
|
|
||||||
this->TarjanVisit(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void cmComputeTargetDepends::TarjanVisit(int i)
|
|
||||||
{
|
|
||||||
// We are now visiting this node.
|
|
||||||
this->TarjanVisited[i] = this->TarjanWalkId;
|
|
||||||
|
|
||||||
// Initialize the entry.
|
|
||||||
this->TarjanEntries[i].Root = i;
|
|
||||||
this->TarjanEntries[i].Component = -1;
|
|
||||||
this->TarjanEntries[i].VisitIndex = ++this->TarjanIndex;
|
|
||||||
this->TarjanStack.push(i);
|
|
||||||
|
|
||||||
// Follow outgoing edges.
|
|
||||||
TargetDependList const& tdl = this->TargetDependGraph[i];
|
|
||||||
for(TargetDependList::const_iterator di = tdl.begin();
|
|
||||||
di != tdl.end(); ++di)
|
|
||||||
{
|
|
||||||
int j = *di;
|
|
||||||
|
|
||||||
// Ignore edges to nodes that have been reached by a previous DFS
|
|
||||||
// walk. Since we did not reach the current node from that walk
|
|
||||||
// it must not belong to the same component and it has already
|
|
||||||
// been assigned to a component.
|
|
||||||
if(this->TarjanVisited[j] > 0 &&
|
|
||||||
this->TarjanVisited[j] < this->TarjanWalkId)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Visit the destination if it has not yet been visited.
|
|
||||||
if(!this->TarjanVisited[j])
|
|
||||||
{
|
|
||||||
this->TarjanVisit(j);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the destination has not yet been assigned to a component,
|
|
||||||
// check if it is a better potential root for the current object.
|
|
||||||
if(this->TarjanEntries[j].Component < 0)
|
|
||||||
{
|
|
||||||
if(this->TarjanEntries[this->TarjanEntries[j].Root].VisitIndex <
|
|
||||||
this->TarjanEntries[this->TarjanEntries[i].Root].VisitIndex)
|
|
||||||
{
|
|
||||||
this->TarjanEntries[i].Root = this->TarjanEntries[j].Root;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we have found a component.
|
|
||||||
if(this->TarjanEntries[i].Root == i)
|
|
||||||
{
|
|
||||||
// Yes. Create it.
|
|
||||||
int c = static_cast<int>(this->Components.size());
|
|
||||||
this->Components.push_back(ComponentList());
|
|
||||||
ComponentList& component = this->Components[c];
|
|
||||||
|
|
||||||
// Populate the component list.
|
|
||||||
int j;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// Get the next member of the component.
|
|
||||||
j = this->TarjanStack.top();
|
|
||||||
this->TarjanStack.pop();
|
|
||||||
|
|
||||||
// Assign the member to the component.
|
|
||||||
this->TarjanEntries[j].Component = c;
|
|
||||||
this->TarjanEntries[j].Root = i;
|
|
||||||
|
|
||||||
// Store the node in its component.
|
|
||||||
component.push_back(j);
|
|
||||||
} while(j != i);
|
|
||||||
|
|
||||||
// Sort the component members for clarity.
|
|
||||||
std::sort(component.begin(), component.end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void cmComputeTargetDepends::DisplayComponents()
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "The strongly connected components are:\n");
|
fprintf(stderr, "The strongly connected components are:\n");
|
||||||
int n = static_cast<int>(this->Components.size());
|
std::vector<NodeList> const& components = ccg.GetComponents();
|
||||||
|
int n = static_cast<int>(components.size());
|
||||||
for(int c = 0; c < n; ++c)
|
for(int c = 0; c < n; ++c)
|
||||||
{
|
{
|
||||||
ComponentList const& cl = this->Components[c];
|
NodeList const& nl = components[c];
|
||||||
fprintf(stderr, "Component (%d):\n", c);
|
fprintf(stderr, "Component (%d):\n", c);
|
||||||
for(ComponentList::const_iterator ci = cl.begin();
|
for(NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni)
|
||||||
ci != cl.end(); ++ci)
|
|
||||||
{
|
{
|
||||||
int i = *ci;
|
int i = *ni;
|
||||||
fprintf(stderr, " contains target %d [%s]\n",
|
fprintf(stderr, " contains target %d [%s]\n",
|
||||||
i, this->Targets[i]->GetName());
|
i, this->Targets[i]->GetName());
|
||||||
}
|
}
|
||||||
|
@ -412,28 +314,31 @@ void cmComputeTargetDepends::DisplayComponents()
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bool cmComputeTargetDepends::CheckComponents()
|
bool
|
||||||
|
cmComputeTargetDepends
|
||||||
|
::CheckComponents(cmComputeComponentGraph const& ccg)
|
||||||
{
|
{
|
||||||
// All non-trivial components should consist only of static
|
// All non-trivial components should consist only of static
|
||||||
// libraries.
|
// libraries.
|
||||||
int nc = static_cast<int>(this->Components.size());
|
std::vector<NodeList> const& components = ccg.GetComponents();
|
||||||
|
int nc = static_cast<int>(components.size());
|
||||||
for(int c=0; c < nc; ++c)
|
for(int c=0; c < nc; ++c)
|
||||||
{
|
{
|
||||||
// Get the current component.
|
// Get the current component.
|
||||||
ComponentList const& cl = this->Components[c];
|
NodeList const& nl = components[c];
|
||||||
|
|
||||||
// Skip trivial components.
|
// Skip trivial components.
|
||||||
if(cl.size() < 2)
|
if(nl.size() < 2)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the component is all STATIC_LIBRARY targets.
|
// Make sure the component is all STATIC_LIBRARY targets.
|
||||||
for(ComponentList::const_iterator ci = cl.begin(); ci != cl.end(); ++ci)
|
for(NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni)
|
||||||
{
|
{
|
||||||
if(this->Targets[*ci]->GetType() != cmTarget::STATIC_LIBRARY)
|
if(this->Targets[*ni]->GetType() != cmTarget::STATIC_LIBRARY)
|
||||||
{
|
{
|
||||||
this->ComplainAboutBadComponent(c);
|
this->ComplainAboutBadComponent(ccg, c);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,16 +348,17 @@ bool cmComputeTargetDepends::CheckComponents()
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void
|
void
|
||||||
cmComputeTargetDepends::ComplainAboutBadComponent(int c)
|
cmComputeTargetDepends
|
||||||
|
::ComplainAboutBadComponent(cmComputeComponentGraph const& ccg, int c)
|
||||||
{
|
{
|
||||||
// Get the bad component.
|
|
||||||
ComponentList const& cl = this->Components[c];
|
|
||||||
|
|
||||||
// Construct the error message.
|
// Construct the error message.
|
||||||
cmOStringStream e;
|
cmOStringStream e;
|
||||||
e << "The inter-target dependency graph contains the following "
|
e << "The inter-target dependency graph contains the following "
|
||||||
<< "strongly connected component (cycle):\n";
|
<< "strongly connected component (cycle):\n";
|
||||||
for(ComponentList::const_iterator ci = cl.begin(); ci != cl.end(); ++ci)
|
std::vector<NodeList> const& components = ccg.GetComponents();
|
||||||
|
std::vector<int> const& cmap = ccg.GetComponentMap();
|
||||||
|
NodeList const& cl = components[c];
|
||||||
|
for(NodeList::const_iterator ci = cl.begin(); ci != cl.end(); ++ci)
|
||||||
{
|
{
|
||||||
// Get the depender.
|
// Get the depender.
|
||||||
int i = *ci;
|
int i = *ci;
|
||||||
|
@ -463,12 +369,11 @@ cmComputeTargetDepends::ComplainAboutBadComponent(int c)
|
||||||
<< cmTarget::TargetTypeNames[depender->GetType()] << "\n";
|
<< cmTarget::TargetTypeNames[depender->GetType()] << "\n";
|
||||||
|
|
||||||
// List its dependencies that are inside the component.
|
// List its dependencies that are inside the component.
|
||||||
TargetDependList const& tdl = this->TargetDependGraph[i];
|
NodeList const& nl = this->InitialGraph[i];
|
||||||
for(TargetDependList::const_iterator di = tdl.begin();
|
for(NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni)
|
||||||
di != tdl.end(); ++di)
|
|
||||||
{
|
{
|
||||||
int j = *di;
|
int j = *ni;
|
||||||
if(this->TarjanEntries[j].Component == c)
|
if(cmap[j] == c)
|
||||||
{
|
{
|
||||||
cmTarget* dependee = this->Targets[j];
|
cmTarget* dependee = this->Targets[j];
|
||||||
e << " depends on " << dependee->GetName() << "\n";
|
e << " depends on " << dependee->GetName() << "\n";
|
||||||
|
@ -481,46 +386,45 @@ cmComputeTargetDepends::ComplainAboutBadComponent(int c)
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void cmComputeTargetDepends::ComputeFinalDepends()
|
void
|
||||||
|
cmComputeTargetDepends
|
||||||
|
::ComputeFinalDepends(cmComputeComponentGraph const& ccg)
|
||||||
{
|
{
|
||||||
int n = static_cast<int>(this->TargetDependGraph.size());
|
// Get the component graph information.
|
||||||
this->FinalDependGraph.resize(n);
|
std::vector<NodeList> const& components = ccg.GetComponents();
|
||||||
|
Graph const& cgraph = ccg.GetComponentGraph();
|
||||||
|
|
||||||
|
// Allocate the final graph.
|
||||||
|
this->FinalGraph.resize(0);
|
||||||
|
this->FinalGraph.resize(this->InitialGraph.size());
|
||||||
|
|
||||||
// Convert inter-component edges to connect component tails to heads.
|
// Convert inter-component edges to connect component tails to heads.
|
||||||
for(int i=0; i < n; ++i)
|
int n = static_cast<int>(cgraph.size());
|
||||||
|
for(int depender_component=0; depender_component < n; ++depender_component)
|
||||||
{
|
{
|
||||||
int depender_component = this->TarjanEntries[i].Component;
|
int depender_component_tail = components[depender_component].back();
|
||||||
int depender_component_tail =
|
NodeList const& nl = cgraph[depender_component];
|
||||||
this->Components[depender_component].back();
|
for(NodeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni)
|
||||||
|
|
||||||
TargetDependList const& tdl = this->TargetDependGraph[i];
|
|
||||||
for(TargetDependList::const_iterator di = tdl.begin();
|
|
||||||
di != tdl.end(); ++di)
|
|
||||||
{
|
{
|
||||||
int j = *di;
|
int dependee_component = *ni;
|
||||||
int dependee_component = this->TarjanEntries[j].Component;
|
int dependee_component_head = components[dependee_component].front();
|
||||||
int dependee_component_head =
|
this->FinalGraph[depender_component_tail]
|
||||||
this->Components[dependee_component].front();
|
.push_back(dependee_component_head);
|
||||||
if(depender_component != dependee_component)
|
|
||||||
{
|
|
||||||
this->FinalDependGraph[depender_component_tail]
|
|
||||||
.push_back(dependee_component_head);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute intra-component edges.
|
// Compute intra-component edges.
|
||||||
int nc = static_cast<int>(this->Components.size());
|
int nc = static_cast<int>(components.size());
|
||||||
for(int c=0; c < nc; ++c)
|
for(int c=0; c < nc; ++c)
|
||||||
{
|
{
|
||||||
// Within the component each target depends on that following it.
|
// Within the component each target depends on that following it.
|
||||||
ComponentList const& cl = this->Components[c];
|
NodeList const& nl = components[c];
|
||||||
ComponentList::const_iterator ci = cl.begin();
|
NodeList::const_iterator ni = nl.begin();
|
||||||
int last_i = *ci;
|
int last_i = *ni;
|
||||||
for(++ci; ci != cl.end(); ++ci)
|
for(++ni; ni != nl.end(); ++ni)
|
||||||
{
|
{
|
||||||
int i = *ci;
|
int i = *ni;
|
||||||
this->FinalDependGraph[last_i].push_back(i);
|
this->FinalGraph[last_i].push_back(i);
|
||||||
last_i = i;
|
last_i = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,11 @@
|
||||||
|
|
||||||
#include "cmStandardIncludes.h"
|
#include "cmStandardIncludes.h"
|
||||||
|
|
||||||
|
#include "cmGraphAdjacencyList.h"
|
||||||
|
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
|
||||||
|
class cmComputeComponentGraph;
|
||||||
class cmGlobalGenerator;
|
class cmGlobalGenerator;
|
||||||
class cmTarget;
|
class cmTarget;
|
||||||
|
|
||||||
|
@ -46,7 +49,7 @@ private:
|
||||||
void CollectDepends();
|
void CollectDepends();
|
||||||
void CollectTargetDepends(int depender_index);
|
void CollectTargetDepends(int depender_index);
|
||||||
void AddTargetDepend(int depender_index, const char* dependee_name);
|
void AddTargetDepend(int depender_index, const char* dependee_name);
|
||||||
void ComputeFinalDepends();
|
void ComputeFinalDepends(cmComputeComponentGraph const& ccg);
|
||||||
|
|
||||||
cmGlobalGenerator* GlobalGenerator;
|
cmGlobalGenerator* GlobalGenerator;
|
||||||
bool DebugMode;
|
bool DebugMode;
|
||||||
|
@ -58,33 +61,16 @@ private:
|
||||||
// Represent the target dependency graph. The entry at each
|
// Represent the target dependency graph. The entry at each
|
||||||
// top-level index corresponds to a depender whose dependencies are
|
// top-level index corresponds to a depender whose dependencies are
|
||||||
// listed.
|
// listed.
|
||||||
struct TargetDependList: public std::vector<int> {};
|
typedef cmGraphNodeList NodeList;
|
||||||
std::vector<TargetDependList> TargetDependGraph;
|
typedef cmGraphAdjacencyList Graph;
|
||||||
std::vector<TargetDependList> FinalDependGraph;
|
Graph InitialGraph;
|
||||||
void DisplayGraph(std::vector<TargetDependList> const& graph,
|
Graph FinalGraph;
|
||||||
const char* name);
|
void DisplayGraph(Graph const& graph, const char* name);
|
||||||
|
|
||||||
// Tarjan's algorithm.
|
// Deal with connected components.
|
||||||
struct TarjanEntry
|
void DisplayComponents(cmComputeComponentGraph const& ccg);
|
||||||
{
|
bool CheckComponents(cmComputeComponentGraph const& ccg);
|
||||||
int Root;
|
void ComplainAboutBadComponent(cmComputeComponentGraph const& ccg, int c);
|
||||||
int Component;
|
|
||||||
int VisitIndex;
|
|
||||||
};
|
|
||||||
int TarjanWalkId;
|
|
||||||
std::vector<int> TarjanVisited;
|
|
||||||
std::vector<TarjanEntry> TarjanEntries;
|
|
||||||
std::stack<int> TarjanStack;
|
|
||||||
int TarjanIndex;
|
|
||||||
void Tarjan();
|
|
||||||
void TarjanVisit(int i);
|
|
||||||
|
|
||||||
// Connected components.
|
|
||||||
struct ComponentList: public std::vector<int> {};
|
|
||||||
std::vector<ComponentList> Components;
|
|
||||||
void DisplayComponents();
|
|
||||||
bool CheckComponents();
|
|
||||||
void ComplainAboutBadComponent(int c);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*=========================================================================
|
||||||
|
|
||||||
|
Program: CMake - Cross-Platform Makefile Generator
|
||||||
|
Module: $RCSfile$
|
||||||
|
Language: C++
|
||||||
|
Date: $Date$
|
||||||
|
Version: $Revision$
|
||||||
|
|
||||||
|
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
|
||||||
|
See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
|
||||||
|
|
||||||
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
||||||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. See the above copyright notices for more information.
|
||||||
|
|
||||||
|
=========================================================================*/
|
||||||
|
#ifndef cmGraphAdjacencyList_h
|
||||||
|
#define cmGraphAdjacencyList_h
|
||||||
|
|
||||||
|
#include "cmStandardIncludes.h"
|
||||||
|
|
||||||
|
struct cmGraphNodeList: public std::vector<int> {};
|
||||||
|
struct cmGraphAdjacencyList: public std::vector<cmGraphNodeList> {};
|
||||||
|
|
||||||
|
#endif
|
|
@ -171,6 +171,7 @@ CMAKE_CXX_SOURCES="\
|
||||||
cmComputeLinkInformation \
|
cmComputeLinkInformation \
|
||||||
cmOrderRuntimeDirectories \
|
cmOrderRuntimeDirectories \
|
||||||
cmComputeTargetDepends \
|
cmComputeTargetDepends \
|
||||||
|
cmComputeComponentGraph \
|
||||||
"
|
"
|
||||||
|
|
||||||
if ${cmake_system_mingw}; then
|
if ${cmake_system_mingw}; then
|
||||||
|
|
Loading…
Reference in New Issue