/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file LICENSE.rst or https://cmake.org/licensing for details.  */
#include "cmComputeTargetDepends.h"

#include <cassert>
#include <cstddef>
#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 "cmRange.h"
#include "cmSourceFile.h"
#include "cmSourceFileLocationKind.h"
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.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());
  size_t 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 (auto const& lgen : lgens) {
    for (auto const& ti : lgen->GetGeneratorTargets()) {
      size_t index = 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 (size_t i = 0; i < this->Targets.size(); ++i) {
    this->CollectTargetDepends(i);
  }
}

void cmComputeTargetDepends::CollectTargetDepends(size_t 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::UseTo::Link)) {
        for (cmLinkItem 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, emitted);
            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,
                              emitted);
      }
    }
  }
}

void cmComputeTargetDepends::AddInterfaceDepends(
  size_t depender_index, cmGeneratorTarget const* dependee,
  cmListFileBacktrace const& dependee_backtrace, std::string const& 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, emitted);
        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(
  size_t depender_index, cmLinkItem const& dependee_name,
  std::string const& 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(size_t 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(size_t depender_index,
                                             cmLinkItem const& dependee_name,
                                             bool linking, bool cross,
                                             std::set<cmLinkItem>& emitted)
{
  // 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)) {
    this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
      MessageType::FATAL_ERROR,
      cmStrCat("The dependency target \"", dependee_name.AsStr(),
               "\" of target \"", depender->GetName(), "\" does not exist."),
      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, emitted);
  }
}

void cmComputeTargetDepends::AddTargetDepend(
  size_t depender_index, cmGeneratorTarget const* dependee,
  cmListFileBacktrace const& dependee_backtrace, bool linking, bool cross,
  std::set<cmLinkItem>& emitted)
{
  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 (emitted.insert(i).second) {
        if (cmGeneratorTarget const* transitive_dependee = i.Target) {
          this->AddTargetDepend(depender_index, transitive_dependee,
                                i.Backtrace, false, i.Cross, emitted);
        }
      }
    }
  } 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());
    size_t 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());

  size_t n = this->InitialGraph.size();
  std::set<size_t> visited;
  for (size_t i = 0; i < n; ++i) {
    this->CollectSideEffectsForTarget(visited, i);
  }
}

void cmComputeTargetDepends::CollectSideEffectsForTarget(
  std::set<size_t>& visited, size_t 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());

  size_t n = this->InitialGraph.size();
  for (size_t 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 (optimizeDependencies.IsOn()) {
          this->OptimizeLinkDependencies(gt, intermediateEdges, initialEdges);
        } else {
          intermediateEdges = initialEdges;
        }
      } else {
        intermediateEdges = initialEdges;
      }
    }
  }
}

void cmComputeTargetDepends::OptimizeLinkDependencies(
  cmGeneratorTarget const* gt, cmGraphEdgeList& outputEdges,
  cmGraphEdgeList const& inputEdges)
{
  std::set<size_t> 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,
                                          std::string const& name)
{
  fprintf(stderr, "The %s target dependency graph is:\n", name.c_str());
  size_t n = graph.size();
  for (size_t depender_index = 0; depender_index < n; ++depender_index) {
    EdgeList const& nl = graph[depender_index];
    cmGeneratorTarget const* depender = this->Targets[depender_index];
    fprintf(stderr, "target %zu is [%s]\n", depender_index,
            depender->GetName().c_str());
    for (cmGraphEdge const& ni : nl) {
      size_t dependee_index = ni;
      cmGeneratorTarget const* dependee = this->Targets[dependee_index];
      fprintf(stderr, "  depends on target %zu [%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");
  size_t n = this->SideEffects.size();
  for (size_t depender_index = 0; depender_index < n; ++depender_index) {
    cmGeneratorTarget const* depender = this->Targets[depender_index];
    fprintf(stderr, "target %zu 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 %zu [%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 %zu [%s]\n", this->TargetIndex[gt],
                gt->GetName().c_str());
      }
    }
  }
  fprintf(stderr, "\n");
}

void cmComputeTargetDepends::DisplayComponents(
  cmComputeComponentGraph const& ccg, std::string const& name)
{
  fprintf(stderr, "The strongly connected components for the %s graph are:\n",
          name.c_str());
  std::vector<NodeList> const& components = ccg.GetComponents();
  size_t n = components.size();
  for (size_t c = 0; c < n; ++c) {
    NodeList const& nl = components[c];
    fprintf(stderr, "Component (%zu):\n", c);
    for (size_t i : nl) {
      fprintf(stderr, "  contains target %zu [%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();
  size_t nc = components.size();
  for (size_t 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 (size_t ni : nl) {
      if (this->Targets[ni]->GetType() != cmStateEnums::STATIC_LIBRARY) {
        this->ComplainAboutBadComponent(ccg, c);
        return false;
      }
    }
  }
  return true;
}

void cmComputeTargetDepends::ComplainAboutBadComponent(
  cmComputeComponentGraph const& ccg, size_t 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<size_t> const& cmap = ccg.GetComponentMap();
  NodeList const& cl = components[c];
  for (size_t 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) {
      size_t 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<size_t> const& cmap,
                                            size_t c, size_t i, size_t* head,
                                            std::set<size_t>& emitted,
                                            std::set<size_t>& 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) {
      size_t 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 != cmComputeComponentGraph::INVALID_COMPONENT) {
      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<size_t> const& cmap = ccg.GetComponentMap();
  this->ComponentHead.resize(components.size());
  this->ComponentTail.resize(components.size());
  size_t nc = components.size();
  for (size_t c = 0; c < nc; ++c) {
    size_t head = cmComputeComponentGraph::INVALID_COMPONENT;
    std::set<size_t> emitted;
    NodeList const& nl = components[c];
    for (size_t ni : cmReverseRange(nl)) {
      std::set<size_t> 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.
  size_t n = cgraph.size();
  for (size_t depender_component = 0; depender_component < n;
       ++depender_component) {
    size_t depender_component_tail = this->ComponentTail[depender_component];
    EdgeList const& nl = cgraph[depender_component];
    for (cmGraphEdge const& ni : nl) {
      size_t dependee_component = ni;
      size_t 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;
}
