1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmComputeTargetDepends.cxx,v $
6 Date: $Date: 2008/02/07 21:14:05 $
7 Version: $Revision: 1.2 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmComputeTargetDepends.h"
19 #include "cmComputeComponentGraph.h"
20 #include "cmGlobalGenerator.h"
21 #include "cmLocalGenerator.h"
22 #include "cmMakefile.h"
23 #include "cmSystemTools.h"
33 This class is meant to analyze inter-target dependencies globally
34 during the generation step. The goal is to produce a set of direct
35 dependencies for each target such that no cycles are left and the
38 For most target types cyclic dependencies are not allowed. However
39 STATIC libraries may depend on each other in a cyclic fasion. In
40 general the directed dependency graph forms a directed-acyclic-graph
41 of strongly connected components. All strongly connected components
42 should consist of only STATIC_LIBRARY targets.
44 In order to safely break dependency cycles we must preserve all other
45 dependencies passing through the corresponding strongly connected component.
46 The approach taken by this class is as follows:
48 - Collect all targets and form the original dependency graph
49 - Run Tarjan's algorithm to extract the strongly connected components
50 (error if any member of a non-trivial component is not STATIC)
51 - The original dependencies imply a DAG on the components.
52 Use the implied DAG to construct a final safe set of dependencies.
54 The final dependency set is constructed as follows:
56 - For each connected component targets are placed in an arbitrary
57 order. Each target depends on the target following it in the order.
58 The first target is designated the head and the last target the tail.
59 (most components will be just 1 target anyway)
61 - Original dependencies between targets in different components are
62 converted to connect the depender's component tail to the
63 dependee's component head.
65 In most cases this will reproduce the original dependencies. However
66 when there are cycles of static libraries they will be broken in a
69 For example, consider targets A0, A1, A2, B0, B1, B2, and C with these
72 A0 -> A1 -> A2 -> A0 , B0 -> B1 -> B2 -> B0 -> A0 , C -> B0
74 Components may be identified as
76 Component 0: A0, A1, A2
77 Component 1: B0, B1, B2
80 Intra-component dependencies are:
82 0: A0 -> A1 -> A2 , head=A0, tail=A2
83 1: B0 -> B1 -> B2 , head=B0, tail=B2
86 The inter-component dependencies are converted as:
88 B0 -> A0 is component 1->0 and becomes B2 -> A0
89 C -> B0 is component 2->1 and becomes C -> B0
91 This leads to the final target dependencies:
93 C -> B0 -> B1 -> B2 -> A0 -> A1 -> A2
95 These produce a safe build order since C depends directly or
96 transitively on all the static libraries it links.
100 //----------------------------------------------------------------------------
101 cmComputeTargetDepends::cmComputeTargetDepends(cmGlobalGenerator
* gg
)
103 this->GlobalGenerator
= gg
;
104 cmake
* cm
= this->GlobalGenerator
->GetCMakeInstance();
105 this->DebugMode
= cm
->GetPropertyAsBool("GLOBAL_DEPENDS_DEBUG_MODE");
108 //----------------------------------------------------------------------------
109 cmComputeTargetDepends::~cmComputeTargetDepends()
113 //----------------------------------------------------------------------------
114 bool cmComputeTargetDepends::Compute()
116 // Build the original graph.
117 this->CollectTargets();
118 this->CollectDepends();
121 this->DisplayGraph(this->InitialGraph
, "initial");
124 // Identify components.
125 cmComputeComponentGraph
ccg(this->InitialGraph
);
128 this->DisplayComponents(ccg
);
130 if(!this->CheckComponents(ccg
))
135 // Compute the final dependency graph.
136 this->ComputeFinalDepends(ccg
);
139 this->DisplayGraph(this->FinalGraph
, "final");
145 //----------------------------------------------------------------------------
147 cmComputeTargetDepends::GetTargetDirectDepends(cmTarget
* t
,
148 std::set
<cmTarget
*>& deps
)
150 // Lookup the index for this target. All targets should be known by
152 std::map
<cmTarget
*, int>::const_iterator tii
= this->TargetIndex
.find(t
);
153 assert(tii
!= this->TargetIndex
.end());
156 // Get its final dependencies.
157 NodeList
const& nl
= this->FinalGraph
[i
];
158 for(NodeList::const_iterator ni
= nl
.begin(); ni
!= nl
.end(); ++ni
)
160 deps
.insert(this->Targets
[*ni
]);
164 //----------------------------------------------------------------------------
165 void cmComputeTargetDepends::CollectTargets()
167 // Collect all targets from all generators.
168 std::vector
<cmLocalGenerator
*> const& lgens
=
169 this->GlobalGenerator
->GetLocalGenerators();
170 for(unsigned int i
= 0; i
< lgens
.size(); ++i
)
172 cmTargets
& targets
= lgens
[i
]->GetMakefile()->GetTargets();
173 for(cmTargets::iterator ti
= targets
.begin(); ti
!= targets
.end(); ++ti
)
175 cmTarget
* target
= &ti
->second
;
176 int index
= static_cast<int>(this->Targets
.size());
177 this->TargetIndex
[target
] = index
;
178 this->Targets
.push_back(target
);
183 //----------------------------------------------------------------------------
184 void cmComputeTargetDepends::CollectDepends()
186 // Allocate the dependency graph adjacency lists.
187 this->InitialGraph
.resize(this->Targets
.size());
189 // Compute each dependency list.
190 for(unsigned int i
=0; i
< this->Targets
.size(); ++i
)
192 this->CollectTargetDepends(i
);
196 //----------------------------------------------------------------------------
197 void cmComputeTargetDepends::CollectTargetDepends(int depender_index
)
200 cmTarget
* depender
= this->Targets
[depender_index
];
202 // Keep track of dependencies already listed.
203 std::set
<cmStdString
> emitted
;
205 // A target should not depend on itself.
206 emitted
.insert(depender
->GetName());
208 // Loop over all targets linked directly.
209 cmTarget::LinkLibraryVectorType
const& tlibs
=
210 depender
->GetOriginalLinkLibraries();
211 for(cmTarget::LinkLibraryVectorType::const_iterator lib
= tlibs
.begin();
212 lib
!= tlibs
.end(); ++lib
)
214 // Don't emit the same library twice for this target.
215 if(emitted
.insert(lib
->first
).second
)
217 this->AddTargetDepend(depender_index
, lib
->first
.c_str());
221 // Loop over all utility dependencies.
222 std::set
<cmStdString
> const& tutils
= depender
->GetUtilities();
223 for(std::set
<cmStdString
>::const_iterator util
= tutils
.begin();
224 util
!= tutils
.end(); ++util
)
226 // Don't emit the same utility twice for this target.
227 if(emitted
.insert(*util
).second
)
229 this->AddTargetDepend(depender_index
, util
->c_str());
234 //----------------------------------------------------------------------------
235 void cmComputeTargetDepends::AddTargetDepend(int depender_index
,
236 const char* dependee_name
)
239 cmTarget
* depender
= this->Targets
[depender_index
];
241 // Check the target's makefile first.
243 depender
->GetMakefile()->FindTarget(dependee_name
);
245 // Then search globally.
248 dependee
= this->GlobalGenerator
->FindTarget(0, dependee_name
);
251 // If not found then skip then the dependee.
257 // No imported targets should have been found.
258 assert(!dependee
->IsImported());
260 // Lookup the index for this target. All targets should be known by
262 std::map
<cmTarget
*, int>::const_iterator tii
=
263 this->TargetIndex
.find(dependee
);
264 assert(tii
!= this->TargetIndex
.end());
265 int dependee_index
= tii
->second
;
267 // Add this entry to the dependency graph.
268 this->InitialGraph
[depender_index
].push_back(dependee_index
);
271 //----------------------------------------------------------------------------
273 cmComputeTargetDepends::DisplayGraph(Graph
const& graph
, const char* name
)
275 fprintf(stderr
, "The %s target dependency graph is:\n", name
);
276 int n
= static_cast<int>(graph
.size());
277 for(int depender_index
= 0; depender_index
< n
; ++depender_index
)
279 NodeList
const& nl
= graph
[depender_index
];
280 cmTarget
* depender
= this->Targets
[depender_index
];
281 fprintf(stderr
, "target %d is [%s]\n",
282 depender_index
, depender
->GetName());
283 for(NodeList::const_iterator ni
= nl
.begin(); ni
!= nl
.end(); ++ni
)
285 int dependee_index
= *ni
;
286 cmTarget
* dependee
= this->Targets
[dependee_index
];
287 fprintf(stderr
, " depends on target %d [%s]\n", dependee_index
,
288 dependee
->GetName());
291 fprintf(stderr
, "\n");
294 //----------------------------------------------------------------------------
296 cmComputeTargetDepends
297 ::DisplayComponents(cmComputeComponentGraph
const& ccg
)
299 fprintf(stderr
, "The strongly connected components are:\n");
300 std::vector
<NodeList
> const& components
= ccg
.GetComponents();
301 int n
= static_cast<int>(components
.size());
302 for(int c
= 0; c
< n
; ++c
)
304 NodeList
const& nl
= components
[c
];
305 fprintf(stderr
, "Component (%d):\n", c
);
306 for(NodeList::const_iterator ni
= nl
.begin(); ni
!= nl
.end(); ++ni
)
309 fprintf(stderr
, " contains target %d [%s]\n",
310 i
, this->Targets
[i
]->GetName());
313 fprintf(stderr
, "\n");
316 //----------------------------------------------------------------------------
318 cmComputeTargetDepends
319 ::CheckComponents(cmComputeComponentGraph
const& ccg
)
321 // All non-trivial components should consist only of static
323 std::vector
<NodeList
> const& components
= ccg
.GetComponents();
324 int nc
= static_cast<int>(components
.size());
325 for(int c
=0; c
< nc
; ++c
)
327 // Get the current component.
328 NodeList
const& nl
= components
[c
];
330 // Skip trivial components.
336 // Make sure the component is all STATIC_LIBRARY targets.
337 for(NodeList::const_iterator ni
= nl
.begin(); ni
!= nl
.end(); ++ni
)
339 if(this->Targets
[*ni
]->GetType() != cmTarget::STATIC_LIBRARY
)
341 this->ComplainAboutBadComponent(ccg
, c
);
349 //----------------------------------------------------------------------------
351 cmComputeTargetDepends
352 ::ComplainAboutBadComponent(cmComputeComponentGraph
const& ccg
, int c
)
354 // Construct the error message.
356 e
<< "The inter-target dependency graph contains the following "
357 << "strongly connected component (cycle):\n";
358 std::vector
<NodeList
> const& components
= ccg
.GetComponents();
359 std::vector
<int> const& cmap
= ccg
.GetComponentMap();
360 NodeList
const& cl
= components
[c
];
361 for(NodeList::const_iterator ci
= cl
.begin(); ci
!= cl
.end(); ++ci
)
365 cmTarget
* depender
= this->Targets
[i
];
367 // Describe the depender.
368 e
<< " " << depender
->GetName() << " of type "
369 << cmTarget::TargetTypeNames
[depender
->GetType()] << "\n";
371 // List its dependencies that are inside the component.
372 NodeList
const& nl
= this->InitialGraph
[i
];
373 for(NodeList::const_iterator ni
= nl
.begin(); ni
!= nl
.end(); ++ni
)
378 cmTarget
* dependee
= this->Targets
[j
];
379 e
<< " depends on " << dependee
->GetName() << "\n";
383 e
<< "At least one of these targets is not a STATIC_LIBRARY. "
384 << "Cyclic dependencies are allowed only among static libraries.";
385 cmSystemTools::Error(e
.str().c_str());
388 //----------------------------------------------------------------------------
390 cmComputeTargetDepends
391 ::ComputeFinalDepends(cmComputeComponentGraph
const& ccg
)
393 // Get the component graph information.
394 std::vector
<NodeList
> const& components
= ccg
.GetComponents();
395 Graph
const& cgraph
= ccg
.GetComponentGraph();
397 // Allocate the final graph.
398 this->FinalGraph
.resize(0);
399 this->FinalGraph
.resize(this->InitialGraph
.size());
401 // Convert inter-component edges to connect component tails to heads.
402 int n
= static_cast<int>(cgraph
.size());
403 for(int depender_component
=0; depender_component
< n
; ++depender_component
)
405 int depender_component_tail
= components
[depender_component
].back();
406 NodeList
const& nl
= cgraph
[depender_component
];
407 for(NodeList::const_iterator ni
= nl
.begin(); ni
!= nl
.end(); ++ni
)
409 int dependee_component
= *ni
;
410 int dependee_component_head
= components
[dependee_component
].front();
411 this->FinalGraph
[depender_component_tail
]
412 .push_back(dependee_component_head
);
416 // Compute intra-component edges.
417 int nc
= static_cast<int>(components
.size());
418 for(int c
=0; c
< nc
; ++c
)
420 // Within the component each target depends on that following it.
421 NodeList
const& nl
= components
[c
];
422 NodeList::const_iterator ni
= nl
.begin();
424 for(++ni
; ni
!= nl
.end(); ++ni
)
427 this->FinalGraph
[last_i
].push_back(i
);