| /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying | 
 |    file Copyright.txt or https://cmake.org/licensing for details.  */ | 
 | #include "cmComputeTargetDepends.h" | 
 |  | 
 | #include <cassert> | 
 | #include <cstdio> | 
 | #include <memory> | 
 | #include <sstream> | 
 | #include <utility> | 
 |  | 
 | #include "cmComputeComponentGraph.h" | 
 | #include "cmGeneratorTarget.h" | 
 | #include "cmGlobalGenerator.h" | 
 | #include "cmLinkItem.h" | 
 | #include "cmListFileCache.h" | 
 | #include "cmLocalGenerator.h" | 
 | #include "cmMakefile.h" | 
 | #include "cmMessageType.h" | 
 | #include "cmPolicies.h" | 
 | #include "cmRange.h" | 
 | #include "cmSourceFile.h" | 
 | #include "cmSourceFileLocationKind.h" | 
 | #include "cmState.h" | 
 | #include "cmStateTypes.h" | 
 | #include "cmSystemTools.h" | 
 | #include "cmTarget.h" | 
 | #include "cmTargetDepend.h" | 
 | #include "cmValue.h" | 
 | #include "cmake.h" | 
 |  | 
 | /* | 
 |  | 
 | This class is meant to analyze inter-target dependencies globally | 
 | during the generation step.  The goal is to produce a set of direct | 
 | dependencies for each target such that no cycles are left and the | 
 | build order is safe. | 
 |  | 
 | For most target types cyclic dependencies are not allowed.  However | 
 | STATIC libraries may depend on each other in a cyclic fashion.  In | 
 | general the directed dependency graph forms a directed-acyclic-graph | 
 | of strongly connected components.  All strongly connected components | 
 | should consist of only STATIC_LIBRARY targets. | 
 |  | 
 | In order to safely break dependency cycles we must preserve all other | 
 | dependencies passing through the corresponding strongly connected component. | 
 | The approach taken by this class is as follows: | 
 |  | 
 |   - Collect all targets and form the original dependency graph | 
 |   - Run Tarjan's algorithm to extract the strongly connected components | 
 |     (error if any member of a non-trivial component is not STATIC) | 
 |   - The original dependencies imply a DAG on the components. | 
 |     Use the implied DAG to construct a final safe set of dependencies. | 
 |  | 
 | The final dependency set is constructed as follows: | 
 |  | 
 |   - For each connected component targets are placed in an arbitrary | 
 |     order.  Each target depends on the target following it in the order. | 
 |     The first target is designated the head and the last target the tail. | 
 |     (most components will be just 1 target anyway) | 
 |  | 
 |   - Original dependencies between targets in different components are | 
 |     converted to connect the depender's component tail to the | 
 |     dependee's component head. | 
 |  | 
 | In most cases this will reproduce the original dependencies.  However | 
 | when there are cycles of static libraries they will be broken in a | 
 | safe manner. | 
 |  | 
 | For example, consider targets A0, A1, A2, B0, B1, B2, and C with these | 
 | dependencies: | 
 |  | 
 |   A0 -> A1 -> A2 -> A0  ,  B0 -> B1 -> B2 -> B0 -> A0  ,  C -> B0 | 
 |  | 
 | Components may be identified as | 
 |  | 
 |   Component 0: A0, A1, A2 | 
 |   Component 1: B0, B1, B2 | 
 |   Component 2: C | 
 |  | 
 | Intra-component dependencies are: | 
 |  | 
 |   0: A0 -> A1 -> A2   , head=A0, tail=A2 | 
 |   1: B0 -> B1 -> B2   , head=B0, tail=B2 | 
 |   2: head=C, tail=C | 
 |  | 
 | The inter-component dependencies are converted as: | 
 |  | 
 |   B0 -> A0  is component 1->0 and becomes  B2 -> A0 | 
 |   C  -> B0  is component 2->1 and becomes  C  -> B0 | 
 |  | 
 | This leads to the final target dependencies: | 
 |  | 
 |   C -> B0 -> B1 -> B2 -> A0 -> A1 -> A2 | 
 |  | 
 | These produce a safe build order since C depends directly or | 
 | transitively on all the static libraries it links. | 
 |  | 
 | */ | 
 |  | 
 | cmComputeTargetDepends::cmComputeTargetDepends(cmGlobalGenerator* gg) | 
 | { | 
 |   this->GlobalGenerator = gg; | 
 |   cmake* cm = this->GlobalGenerator->GetCMakeInstance(); | 
 |   this->DebugMode = | 
 |     cm->GetState()->GetGlobalPropertyAsBool("GLOBAL_DEPENDS_DEBUG_MODE"); | 
 |   this->NoCycles = | 
 |     cm->GetState()->GetGlobalPropertyAsBool("GLOBAL_DEPENDS_NO_CYCLES"); | 
 | } | 
 |  | 
 | cmComputeTargetDepends::~cmComputeTargetDepends() = default; | 
 |  | 
 | bool cmComputeTargetDepends::Compute() | 
 | { | 
 |   // Build the original graph. | 
 |   this->CollectTargets(); | 
 |   this->CollectDepends(); | 
 |   if (this->DebugMode) { | 
 |     this->DisplayGraph(this->InitialGraph, "initial"); | 
 |   } | 
 |   cmComputeComponentGraph ccg1(this->InitialGraph); | 
 |   ccg1.Compute(); | 
 |   if (!this->CheckComponents(ccg1)) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   // Compute the intermediate graph. | 
 |   this->CollectSideEffects(); | 
 |   this->ComputeIntermediateGraph(); | 
 |   if (this->DebugMode) { | 
 |     this->DisplaySideEffects(); | 
 |     this->DisplayGraph(this->IntermediateGraph, "intermediate"); | 
 |   } | 
 |  | 
 |   // Identify components. | 
 |   cmComputeComponentGraph ccg2(this->IntermediateGraph); | 
 |   ccg2.Compute(); | 
 |   if (this->DebugMode) { | 
 |     this->DisplayComponents(ccg2, "intermediate"); | 
 |   } | 
 |   if (!this->CheckComponents(ccg2)) { | 
 |     return false; | 
 |   } | 
 |  | 
 |   // Compute the final dependency graph. | 
 |   if (!this->ComputeFinalDepends(ccg2)) { | 
 |     return false; | 
 |   } | 
 |   if (this->DebugMode) { | 
 |     this->DisplayGraph(this->FinalGraph, "final"); | 
 |   } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::GetTargetDirectDepends(cmGeneratorTarget const* t, | 
 |                                                     cmTargetDependSet& deps) | 
 | { | 
 |   // Lookup the index for this target.  All targets should be known by | 
 |   // this point. | 
 |   auto tii = this->TargetIndex.find(t); | 
 |   assert(tii != this->TargetIndex.end()); | 
 |   int i = tii->second; | 
 |  | 
 |   // Get its final dependencies. | 
 |   EdgeList const& nl = this->FinalGraph[i]; | 
 |   for (cmGraphEdge const& ni : nl) { | 
 |     cmGeneratorTarget const* dep = this->Targets[ni]; | 
 |     auto di = deps.insert(dep).first; | 
 |     di->SetType(ni.IsStrong()); | 
 |     di->SetCross(ni.IsCross()); | 
 |     di->SetBacktrace(ni.GetBacktrace()); | 
 |   } | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::CollectTargets() | 
 | { | 
 |   // Collect all targets from all generators. | 
 |   auto const& lgens = this->GlobalGenerator->GetLocalGenerators(); | 
 |   for (const auto& lgen : lgens) { | 
 |     for (const auto& ti : lgen->GetGeneratorTargets()) { | 
 |       int index = static_cast<int>(this->Targets.size()); | 
 |       this->TargetIndex[ti.get()] = index; | 
 |       this->Targets.push_back(ti.get()); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::CollectDepends() | 
 | { | 
 |   // Allocate the dependency graph adjacency lists. | 
 |   this->InitialGraph.resize(this->Targets.size()); | 
 |  | 
 |   // Compute each dependency list. | 
 |   for (unsigned int i = 0; i < this->Targets.size(); ++i) { | 
 |     this->CollectTargetDepends(i); | 
 |   } | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::CollectTargetDepends(int depender_index) | 
 | { | 
 |   // Get the depender. | 
 |   cmGeneratorTarget const* depender = this->Targets[depender_index]; | 
 |   if (!depender->IsInBuildSystem()) { | 
 |     return; | 
 |   } | 
 |  | 
 |   // Loop over all targets linked directly in all configs. | 
 |   // We need to make targets depend on the union of all config-specific | 
 |   // dependencies in all targets, because the generated build-systems can't | 
 |   // deal with config-specific dependencies. | 
 |   { | 
 |     std::set<cmLinkItem> emitted; | 
 |  | 
 |     std::vector<std::string> const& configs = | 
 |       depender->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); | 
 |     for (std::string const& it : configs) { | 
 |       // A target should not depend on itself. | 
 |       emitted.insert(cmLinkItem(depender, false, cmListFileBacktrace())); | 
 |       emitted.insert(cmLinkItem(depender, true, cmListFileBacktrace())); | 
 |  | 
 |       if (cmLinkImplementation const* impl = depender->GetLinkImplementation( | 
 |             it, cmGeneratorTarget::LinkInterfaceFor::Link)) { | 
 |         for (cmLinkImplItem const& lib : impl->Libraries) { | 
 |           // Don't emit the same library twice for this target. | 
 |           if (emitted.insert(lib).second) { | 
 |             this->AddTargetDepend(depender_index, lib, true, false); | 
 |             this->AddInterfaceDepends(depender_index, lib, it, emitted); | 
 |           } | 
 |         } | 
 |         for (cmLinkItem const& obj : impl->Objects) { | 
 |           if (cmSourceFile const* o = depender->Makefile->GetSource( | 
 |                 obj.AsStr(), cmSourceFileLocationKind::Known)) { | 
 |             this->AddObjectDepends(depender_index, o, emitted); | 
 |           } | 
 |         } | 
 |       } | 
 |  | 
 |       // Add dependencies on object libraries not otherwise handled above. | 
 |       std::vector<cmSourceFile const*> objectFiles; | 
 |       depender->GetExternalObjects(objectFiles, it); | 
 |       for (cmSourceFile const* o : objectFiles) { | 
 |         this->AddObjectDepends(depender_index, o, emitted); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // Loop over all utility dependencies. | 
 |   { | 
 |     std::set<cmLinkItem> const& tutils = depender->GetUtilityItems(); | 
 |     std::set<cmLinkItem> emitted; | 
 |     // A target should not depend on itself. | 
 |     emitted.insert(cmLinkItem(depender, false, cmListFileBacktrace())); | 
 |     emitted.insert(cmLinkItem(depender, true, cmListFileBacktrace())); | 
 |     for (cmLinkItem const& litem : tutils) { | 
 |       // Don't emit the same utility twice for this target. | 
 |       if (emitted.insert(litem).second) { | 
 |         this->AddTargetDepend(depender_index, litem, false, litem.Cross); | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::AddInterfaceDepends( | 
 |   int depender_index, const cmGeneratorTarget* dependee, | 
 |   cmListFileBacktrace const& dependee_backtrace, const std::string& config, | 
 |   std::set<cmLinkItem>& emitted) | 
 | { | 
 |   cmGeneratorTarget const* depender = this->Targets[depender_index]; | 
 |   if (cmLinkInterface const* iface = | 
 |         dependee->GetLinkInterface(config, depender)) { | 
 |     for (cmLinkItem const& lib : iface->Libraries) { | 
 |       // Don't emit the same library twice for this target. | 
 |       if (emitted.insert(lib).second) { | 
 |         // Inject the backtrace of the original link dependency whose | 
 |         // link interface we are adding.  This indicates the line of | 
 |         // code in the project that caused this dependency to be added. | 
 |         cmLinkItem libBT = lib; | 
 |         libBT.Backtrace = dependee_backtrace; | 
 |         this->AddTargetDepend(depender_index, libBT, true, false); | 
 |         this->AddInterfaceDepends(depender_index, libBT, config, emitted); | 
 |       } | 
 |     } | 
 |     for (cmLinkItem const& obj : iface->Objects) { | 
 |       if (cmSourceFile const* o = depender->Makefile->GetSource( | 
 |             obj.AsStr(), cmSourceFileLocationKind::Known)) { | 
 |         this->AddObjectDepends(depender_index, o, emitted); | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::AddInterfaceDepends( | 
 |   int depender_index, cmLinkItem const& dependee_name, | 
 |   const std::string& config, std::set<cmLinkItem>& emitted) | 
 | { | 
 |   cmGeneratorTarget const* depender = this->Targets[depender_index]; | 
 |   cmGeneratorTarget const* dependee = dependee_name.Target; | 
 |   // Skip targets that will not really be linked.  This is probably a | 
 |   // name conflict between an external library and an executable | 
 |   // within the project. | 
 |   if (dependee && dependee->GetType() == cmStateEnums::EXECUTABLE && | 
 |       !dependee->IsExecutableWithExports()) { | 
 |     dependee = nullptr; | 
 |   } | 
 |  | 
 |   if (dependee) { | 
 |     // A target should not depend on itself. | 
 |     emitted.insert(cmLinkItem(depender, false, cmListFileBacktrace())); | 
 |     emitted.insert(cmLinkItem(depender, true, cmListFileBacktrace())); | 
 |     this->AddInterfaceDepends(depender_index, dependee, | 
 |                               dependee_name.Backtrace, config, emitted); | 
 |   } | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::AddObjectDepends(int depender_index, | 
 |                                               cmSourceFile const* o, | 
 |                                               std::set<cmLinkItem>& emitted) | 
 | { | 
 |   std::string const& objLib = o->GetObjectLibrary(); | 
 |   if (objLib.empty()) { | 
 |     return; | 
 |   } | 
 |   cmGeneratorTarget const* depender = this->Targets[depender_index]; | 
 |   cmLinkItem const& objItem = | 
 |     depender->ResolveLinkItem(BT<std::string>(objLib)); | 
 |   if (emitted.insert(objItem).second) { | 
 |     if (depender->GetType() != cmStateEnums::EXECUTABLE && | 
 |         depender->GetType() != cmStateEnums::STATIC_LIBRARY && | 
 |         depender->GetType() != cmStateEnums::SHARED_LIBRARY && | 
 |         depender->GetType() != cmStateEnums::MODULE_LIBRARY && | 
 |         depender->GetType() != cmStateEnums::OBJECT_LIBRARY) { | 
 |       this->GlobalGenerator->GetCMakeInstance()->IssueMessage( | 
 |         MessageType::FATAL_ERROR, | 
 |         "Only executables and libraries may reference target objects.", | 
 |         depender->GetBacktrace()); | 
 |       return; | 
 |     } | 
 |     const_cast<cmGeneratorTarget*>(depender)->Target->AddUtility(objLib, | 
 |                                                                  false); | 
 |   } | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::AddTargetDepend(int depender_index, | 
 |                                              cmLinkItem const& dependee_name, | 
 |                                              bool linking, bool cross) | 
 | { | 
 |   // Get the depender. | 
 |   cmGeneratorTarget const* depender = this->Targets[depender_index]; | 
 |  | 
 |   // Check the target's makefile first. | 
 |   cmGeneratorTarget const* dependee = dependee_name.Target; | 
 |  | 
 |   if (!dependee && !linking && | 
 |       (depender->GetType() != cmStateEnums::GLOBAL_TARGET)) { | 
 |     MessageType messageType = MessageType::AUTHOR_WARNING; | 
 |     bool issueMessage = false; | 
 |     std::ostringstream e; | 
 |     switch (depender->GetPolicyStatusCMP0046()) { | 
 |       case cmPolicies::WARN: | 
 |         e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0046) << "\n"; | 
 |         issueMessage = true; | 
 |         CM_FALLTHROUGH; | 
 |       case cmPolicies::OLD: | 
 |         break; | 
 |       case cmPolicies::NEW: | 
 |       case cmPolicies::REQUIRED_IF_USED: | 
 |       case cmPolicies::REQUIRED_ALWAYS: | 
 |         issueMessage = true; | 
 |         messageType = MessageType::FATAL_ERROR; | 
 |         break; | 
 |     } | 
 |     if (issueMessage) { | 
 |       cmake* cm = this->GlobalGenerator->GetCMakeInstance(); | 
 |  | 
 |       e << "The dependency target \"" << dependee_name << "\" of target \"" | 
 |         << depender->GetName() << "\" does not exist."; | 
 |  | 
 |       cm->IssueMessage(messageType, e.str(), dependee_name.Backtrace); | 
 |     } | 
 |   } | 
 |  | 
 |   // Skip targets that will not really be linked.  This is probably a | 
 |   // name conflict between an external library and an executable | 
 |   // within the project. | 
 |   if (linking && dependee && dependee->GetType() == cmStateEnums::EXECUTABLE && | 
 |       !dependee->IsExecutableWithExports()) { | 
 |     dependee = nullptr; | 
 |   } | 
 |  | 
 |   if (dependee) { | 
 |     this->AddTargetDepend(depender_index, dependee, dependee_name.Backtrace, | 
 |                           linking, cross); | 
 |   } | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::AddTargetDepend( | 
 |   int depender_index, cmGeneratorTarget const* dependee, | 
 |   cmListFileBacktrace const& dependee_backtrace, bool linking, bool cross) | 
 | { | 
 |   if (!dependee->IsInBuildSystem()) { | 
 |     // Skip targets that are not in the buildsystem but follow their | 
 |     // utility dependencies. | 
 |     std::set<cmLinkItem> const& utils = dependee->GetUtilityItems(); | 
 |     for (cmLinkItem const& i : utils) { | 
 |       if (cmGeneratorTarget const* transitive_dependee = i.Target) { | 
 |         this->AddTargetDepend(depender_index, transitive_dependee, i.Backtrace, | 
 |                               false, i.Cross); | 
 |       } | 
 |     } | 
 |   } else { | 
 |     // Lookup the index for this target.  All targets should be known by | 
 |     // this point. | 
 |     auto tii = this->TargetIndex.find(dependee); | 
 |     assert(tii != this->TargetIndex.end()); | 
 |     int dependee_index = tii->second; | 
 |  | 
 |     // Add this entry to the dependency graph. | 
 |     this->InitialGraph[depender_index].emplace_back(dependee_index, !linking, | 
 |                                                     cross, dependee_backtrace); | 
 |   } | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::CollectSideEffects() | 
 | { | 
 |   this->SideEffects.resize(0); | 
 |   this->SideEffects.resize(this->InitialGraph.size()); | 
 |  | 
 |   int n = static_cast<int>(this->InitialGraph.size()); | 
 |   std::set<int> visited; | 
 |   for (int i = 0; i < n; ++i) { | 
 |     this->CollectSideEffectsForTarget(visited, i); | 
 |   } | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::CollectSideEffectsForTarget( | 
 |   std::set<int>& visited, int depender_index) | 
 | { | 
 |   if (!visited.count(depender_index)) { | 
 |     auto& se = this->SideEffects[depender_index]; | 
 |     visited.insert(depender_index); | 
 |     this->Targets[depender_index]->AppendCustomCommandSideEffects( | 
 |       se.CustomCommandSideEffects); | 
 |     this->Targets[depender_index]->AppendLanguageSideEffects( | 
 |       se.LanguageSideEffects); | 
 |  | 
 |     for (auto const& edge : this->InitialGraph[depender_index]) { | 
 |       this->CollectSideEffectsForTarget(visited, edge); | 
 |       auto const& dse = this->SideEffects[edge]; | 
 |       se.CustomCommandSideEffects.insert(dse.CustomCommandSideEffects.cbegin(), | 
 |                                          dse.CustomCommandSideEffects.cend()); | 
 |       for (auto const& it : dse.LanguageSideEffects) { | 
 |         se.LanguageSideEffects[it.first].insert(it.second.cbegin(), | 
 |                                                 it.second.cend()); | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::ComputeIntermediateGraph() | 
 | { | 
 |   this->IntermediateGraph.resize(0); | 
 |   this->IntermediateGraph.resize(this->InitialGraph.size()); | 
 |  | 
 |   int n = static_cast<int>(this->InitialGraph.size()); | 
 |   for (int i = 0; i < n; ++i) { | 
 |     auto const& initialEdges = this->InitialGraph[i]; | 
 |     auto& intermediateEdges = this->IntermediateGraph[i]; | 
 |     cmGeneratorTarget const* gt = this->Targets[i]; | 
 |     if (gt->GetType() != cmStateEnums::STATIC_LIBRARY && | 
 |         gt->GetType() != cmStateEnums::OBJECT_LIBRARY) { | 
 |       intermediateEdges = initialEdges; | 
 |     } else { | 
 |       if (cmValue optimizeDependencies = | 
 |             gt->GetProperty("OPTIMIZE_DEPENDENCIES")) { | 
 |         if (cmIsOn(optimizeDependencies)) { | 
 |           this->OptimizeLinkDependencies(gt, intermediateEdges, initialEdges); | 
 |         } else { | 
 |           intermediateEdges = initialEdges; | 
 |         } | 
 |       } else { | 
 |         intermediateEdges = initialEdges; | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::OptimizeLinkDependencies( | 
 |   cmGeneratorTarget const* gt, cmGraphEdgeList& outputEdges, | 
 |   cmGraphEdgeList const& inputEdges) | 
 | { | 
 |   std::set<int> emitted; | 
 |   for (auto const& edge : inputEdges) { | 
 |     if (edge.IsStrong()) { | 
 |       // Preserve strong edges | 
 |       outputEdges.push_back(edge); | 
 |     } else { | 
 |       auto const& dse = this->SideEffects[edge]; | 
 |  | 
 |       // Add edges that have custom command side effects | 
 |       for (cmGeneratorTarget const* dep : dse.CustomCommandSideEffects) { | 
 |         auto index = this->TargetIndex[dep]; | 
 |         if (!emitted.count(index)) { | 
 |           emitted.insert(index); | 
 |           outputEdges.push_back( | 
 |             cmGraphEdge(index, false, edge.IsCross(), edge.GetBacktrace())); | 
 |         } | 
 |       } | 
 |  | 
 |       // Add edges that have language side effects for languages we | 
 |       // care about | 
 |       for (auto const& lang : gt->GetAllConfigCompileLanguages()) { | 
 |         auto it = dse.LanguageSideEffects.find(lang); | 
 |         if (it != dse.LanguageSideEffects.end()) { | 
 |           for (cmGeneratorTarget const* dep : it->second) { | 
 |             auto index = this->TargetIndex[dep]; | 
 |             if (!emitted.count(index)) { | 
 |               emitted.insert(index); | 
 |               outputEdges.push_back(cmGraphEdge(index, false, edge.IsCross(), | 
 |                                                 edge.GetBacktrace())); | 
 |             } | 
 |           } | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::DisplayGraph(Graph const& graph, | 
 |                                           const std::string& name) | 
 | { | 
 |   fprintf(stderr, "The %s target dependency graph is:\n", name.c_str()); | 
 |   int n = static_cast<int>(graph.size()); | 
 |   for (int depender_index = 0; depender_index < n; ++depender_index) { | 
 |     EdgeList const& nl = graph[depender_index]; | 
 |     cmGeneratorTarget const* depender = this->Targets[depender_index]; | 
 |     fprintf(stderr, "target %d is [%s]\n", depender_index, | 
 |             depender->GetName().c_str()); | 
 |     for (cmGraphEdge const& ni : nl) { | 
 |       int dependee_index = ni; | 
 |       cmGeneratorTarget const* dependee = this->Targets[dependee_index]; | 
 |       fprintf(stderr, "  depends on target %d [%s] (%s)\n", dependee_index, | 
 |               dependee->GetName().c_str(), ni.IsStrong() ? "strong" : "weak"); | 
 |     } | 
 |   } | 
 |   fprintf(stderr, "\n"); | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::DisplaySideEffects() | 
 | { | 
 |   fprintf(stderr, "The side effects are:\n"); | 
 |   int n = static_cast<int>(this->SideEffects.size()); | 
 |   for (int depender_index = 0; depender_index < n; ++depender_index) { | 
 |     cmGeneratorTarget const* depender = this->Targets[depender_index]; | 
 |     fprintf(stderr, "target %d is [%s]\n", depender_index, | 
 |             depender->GetName().c_str()); | 
 |     if (!this->SideEffects[depender_index].CustomCommandSideEffects.empty()) { | 
 |       fprintf(stderr, "  custom commands\n"); | 
 |       for (auto const* gt : | 
 |            this->SideEffects[depender_index].CustomCommandSideEffects) { | 
 |         fprintf(stderr, "    from target %d [%s]\n", this->TargetIndex[gt], | 
 |                 gt->GetName().c_str()); | 
 |       } | 
 |     } | 
 |     for (auto const& it : | 
 |          this->SideEffects[depender_index].LanguageSideEffects) { | 
 |       fprintf(stderr, "  language %s\n", it.first.c_str()); | 
 |       for (auto const* gt : it.second) { | 
 |         fprintf(stderr, "    from target %d [%s]\n", this->TargetIndex[gt], | 
 |                 gt->GetName().c_str()); | 
 |       } | 
 |     } | 
 |   } | 
 |   fprintf(stderr, "\n"); | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::DisplayComponents( | 
 |   cmComputeComponentGraph const& ccg, const std::string& name) | 
 | { | 
 |   fprintf(stderr, "The strongly connected components for the %s graph are:\n", | 
 |           name.c_str()); | 
 |   std::vector<NodeList> const& components = ccg.GetComponents(); | 
 |   int n = static_cast<int>(components.size()); | 
 |   for (int c = 0; c < n; ++c) { | 
 |     NodeList const& nl = components[c]; | 
 |     fprintf(stderr, "Component (%d):\n", c); | 
 |     for (int i : nl) { | 
 |       fprintf(stderr, "  contains target %d [%s]\n", i, | 
 |               this->Targets[i]->GetName().c_str()); | 
 |     } | 
 |   } | 
 |   fprintf(stderr, "\n"); | 
 | } | 
 |  | 
 | bool cmComputeTargetDepends::CheckComponents( | 
 |   cmComputeComponentGraph const& ccg) | 
 | { | 
 |   // All non-trivial components should consist only of static | 
 |   // libraries. | 
 |   std::vector<NodeList> const& components = ccg.GetComponents(); | 
 |   int nc = static_cast<int>(components.size()); | 
 |   for (int c = 0; c < nc; ++c) { | 
 |     // Get the current component. | 
 |     NodeList const& nl = components[c]; | 
 |  | 
 |     // Skip trivial components. | 
 |     if (nl.size() < 2) { | 
 |       continue; | 
 |     } | 
 |  | 
 |     // Immediately complain if no cycles are allowed at all. | 
 |     if (this->NoCycles) { | 
 |       this->ComplainAboutBadComponent(ccg, c); | 
 |       return false; | 
 |     } | 
 |  | 
 |     // Make sure the component is all STATIC_LIBRARY targets. | 
 |     for (int ni : nl) { | 
 |       if (this->Targets[ni]->GetType() != cmStateEnums::STATIC_LIBRARY) { | 
 |         this->ComplainAboutBadComponent(ccg, c); | 
 |         return false; | 
 |       } | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | void cmComputeTargetDepends::ComplainAboutBadComponent( | 
 |   cmComputeComponentGraph const& ccg, int c, bool strong) | 
 | { | 
 |   // Construct the error message. | 
 |   std::ostringstream e; | 
 |   e << "The inter-target dependency graph contains the following " | 
 |     << "strongly connected component (cycle):\n"; | 
 |   std::vector<NodeList> const& components = ccg.GetComponents(); | 
 |   std::vector<int> const& cmap = ccg.GetComponentMap(); | 
 |   NodeList const& cl = components[c]; | 
 |   for (int i : cl) { | 
 |     // Get the depender. | 
 |     cmGeneratorTarget const* depender = this->Targets[i]; | 
 |  | 
 |     // Describe the depender. | 
 |     e << "  \"" << depender->GetName() << "\" of type " | 
 |       << cmState::GetTargetTypeName(depender->GetType()) << "\n"; | 
 |  | 
 |     // List its dependencies that are inside the component. | 
 |     EdgeList const& nl = this->InitialGraph[i]; | 
 |     for (cmGraphEdge const& ni : nl) { | 
 |       int j = ni; | 
 |       if (cmap[j] == c) { | 
 |         cmGeneratorTarget const* dependee = this->Targets[j]; | 
 |         e << "    depends on \"" << dependee->GetName() << "\"" | 
 |           << " (" << (ni.IsStrong() ? "strong" : "weak") << ")\n"; | 
 |       } | 
 |     } | 
 |   } | 
 |   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."; | 
 |   } else { | 
 |     e << "At least one of these targets is not a STATIC_LIBRARY.  " | 
 |       << "Cyclic dependencies are allowed only among static libraries."; | 
 |   } | 
 |   cmSystemTools::Error(e.str()); | 
 | } | 
 |  | 
 | 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 (cmGraphEdge const& edge : el) { | 
 |       int j = edge; | 
 |       if (cmap[j] == c && edge.IsStrong()) { | 
 |         this->FinalGraph[i].emplace_back(j, true, edge.IsCross(), | 
 |                                          edge.GetBacktrace()); | 
 |         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].emplace_back(*head, false, false, | 
 |                                        cmListFileBacktrace()); | 
 |     } else { | 
 |       this->ComponentTail[c] = i; | 
 |     } | 
 |     *head = i; | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool cmComputeTargetDepends::ComputeFinalDepends( | 
 |   cmComputeComponentGraph const& ccg) | 
 | { | 
 |   // Get the component graph information. | 
 |   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()); | 
 |  | 
 |   // 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 (int ni : cmReverseRange(nl)) { | 
 |       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 = this->ComponentTail[depender_component]; | 
 |     EdgeList const& nl = cgraph[depender_component]; | 
 |     for (cmGraphEdge const& ni : nl) { | 
 |       int dependee_component = ni; | 
 |       int dependee_component_head = this->ComponentHead[dependee_component]; | 
 |       this->FinalGraph[depender_component_tail].emplace_back( | 
 |         dependee_component_head, ni.IsStrong(), ni.IsCross(), | 
 |         ni.GetBacktrace()); | 
 |     } | 
 |   } | 
 |   return true; | 
 | } |