diff options
-rw-r--r-- | Source/cmComputeTargetDepends.cxx | 107 | ||||
-rw-r--r-- | Source/cmComputeTargetDepends.h | 10 | ||||
-rw-r--r-- | Tests/Dependency/Four/CMakeLists.txt | 3 | ||||
-rw-r--r-- | Tests/Dependency/Four/FourSrc.c | 1 |
4 files changed, 97 insertions, 24 deletions
diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index 2b6b5ec..313c680 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -129,7 +129,10 @@ bool cmComputeTargetDepends::Compute() } // Compute the final dependency graph. - this->ComputeFinalDepends(ccg); + if(!this->ComputeFinalDepends(ccg)) + { + return false; + } if(this->DebugMode) { this->DisplayGraph(this->FinalGraph, "final"); @@ -368,7 +371,8 @@ cmComputeTargetDepends //---------------------------------------------------------------------------- void cmComputeTargetDepends -::ComplainAboutBadComponent(cmComputeComponentGraph const& ccg, int c) +::ComplainAboutBadComponent(cmComputeComponentGraph const& ccg, int c, + bool strong) { // Construct the error message. cmOStringStream e; @@ -400,7 +404,15 @@ cmComputeTargetDepends } } } - if(this->NoCycles) + if(strong) + { + // Custom command executable dependencies cannot occur within a + // component of static libraries. The cycle must appear in calls + // to add_dependencies. + e << "The component contains at least one cycle consisting of strong " + << "dependencies (created by add_dependencies) that cannot be broken."; + } + else if(this->NoCycles) { e << "The GLOBAL_DEPENDS_NO_CYCLES global property is enabled, so " << "cyclic dependencies are not allowed even among static libraries."; @@ -414,7 +426,49 @@ cmComputeTargetDepends } //---------------------------------------------------------------------------- -void +bool +cmComputeTargetDepends +::IntraComponent(std::vector<int> const& cmap, int c, int i, int* head, + std::set<int>& emitted, std::set<int>& visited) +{ + if(!visited.insert(i).second) + { + // Cycle in utility depends! + return false; + } + if(emitted.insert(i).second) + { + // Honor strong intra-component edges in the final order. + EdgeList const& el = this->InitialGraph[i]; + for(EdgeList::const_iterator ei = el.begin(); ei != el.end(); ++ei) + { + int j = *ei; + if(cmap[j] == c && ei->IsStrong()) + { + this->FinalGraph[i].push_back(j); + if(!this->IntraComponent(cmap, c, j, head, emitted, visited)) + { + return false; + } + } + } + + // Prepend to a linear linked-list of intra-component edges. + if(*head >= 0) + { + this->FinalGraph[i].push_back(*head); + } + else + { + this->ComponentTail[c] = i; + } + *head = i; + } + return true; +} + +//---------------------------------------------------------------------------- +bool cmComputeTargetDepends ::ComputeFinalDepends(cmComputeComponentGraph const& ccg) { @@ -426,34 +480,43 @@ cmComputeTargetDepends this->FinalGraph.resize(0); this->FinalGraph.resize(this->InitialGraph.size()); + // Choose intra-component edges to linearize dependencies. + std::vector<int> const& cmap = ccg.GetComponentMap(); + this->ComponentHead.resize(components.size()); + this->ComponentTail.resize(components.size()); + int nc = static_cast<int>(components.size()); + for(int c=0; c < nc; ++c) + { + int head = -1; + std::set<int> emitted; + NodeList const& nl = components[c]; + for(NodeList::const_reverse_iterator ni = nl.rbegin(); + ni != nl.rend(); ++ni) + { + std::set<int> visited; + if(!this->IntraComponent(cmap, c, *ni, &head, emitted, visited)) + { + // Cycle in add_dependencies within component! + this->ComplainAboutBadComponent(ccg, c, true); + return false; + } + } + this->ComponentHead[c] = head; + } + // Convert inter-component edges to connect component tails to heads. int n = static_cast<int>(cgraph.size()); for(int depender_component=0; depender_component < n; ++depender_component) { - int depender_component_tail = components[depender_component].back(); + int depender_component_tail = this->ComponentTail[depender_component]; EdgeList const& nl = cgraph[depender_component]; for(EdgeList::const_iterator ni = nl.begin(); ni != nl.end(); ++ni) { int dependee_component = *ni; - int dependee_component_head = components[dependee_component].front(); + int dependee_component_head = this->ComponentHead[dependee_component]; this->FinalGraph[depender_component_tail] .push_back(dependee_component_head); } } - - // Compute intra-component edges. - int nc = static_cast<int>(components.size()); - for(int c=0; c < nc; ++c) - { - // Within the component each target depends on that following it. - NodeList const& nl = components[c]; - NodeList::const_iterator ni = nl.begin(); - int last_i = *ni; - for(++ni; ni != nl.end(); ++ni) - { - int i = *ni; - this->FinalGraph[last_i].push_back(i); - last_i = i; - } - } + return true; } diff --git a/Source/cmComputeTargetDepends.h b/Source/cmComputeTargetDepends.h index b18a053..240de76 100644 --- a/Source/cmComputeTargetDepends.h +++ b/Source/cmComputeTargetDepends.h @@ -45,7 +45,7 @@ private: void CollectTargetDepends(int depender_index); void AddTargetDepend(int depender_index, const char* dependee_name, bool linking); - void ComputeFinalDepends(cmComputeComponentGraph const& ccg); + bool ComputeFinalDepends(cmComputeComponentGraph const& ccg); cmGlobalGenerator* GlobalGenerator; bool DebugMode; @@ -68,7 +68,13 @@ private: // Deal with connected components. void DisplayComponents(cmComputeComponentGraph const& ccg); bool CheckComponents(cmComputeComponentGraph const& ccg); - void ComplainAboutBadComponent(cmComputeComponentGraph const& ccg, int c); + void ComplainAboutBadComponent(cmComputeComponentGraph const& ccg, int c, + bool strong = false); + + std::vector<int> ComponentHead; + std::vector<int> ComponentTail; + bool IntraComponent(std::vector<int> const& cmap, int c, int i, int* head, + std::set<int>& emitted, std::set<int>& visited); }; #endif diff --git a/Tests/Dependency/Four/CMakeLists.txt b/Tests/Dependency/Four/CMakeLists.txt index ba3711f..df0f162 100644 --- a/Tests/Dependency/Four/CMakeLists.txt +++ b/Tests/Dependency/Four/CMakeLists.txt @@ -1,3 +1,6 @@ +INCLUDE_DIRECTORIES(${Dependency_BINARY_DIR}/Two) ADD_LIBRARY( Four FourSrc.c ) TARGET_LINK_LIBRARIES( Four One Two NoDepA ) +# TwoCustom must build before Four. +ADD_DEPENDENCIES(Four TwoCustom) diff --git a/Tests/Dependency/Four/FourSrc.c b/Tests/Dependency/Four/FourSrc.c index e8fefcd..23a66a4 100644 --- a/Tests/Dependency/Four/FourSrc.c +++ b/Tests/Dependency/Four/FourSrc.c @@ -1,3 +1,4 @@ +#include <two-test.h> /* Requires TwoCustom to be built first. */ void NoDepAFunction(); void OneFunction(); void TwoFunction(); |