blob: 3233217e661fdc68c1a2e7f3207be4281eba6bdf [file] [log] [blame]
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
#include "cmConfigure.h" // IWYU pragma: keep
#include <cstddef>
#include <map>
#include <memory>
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "cmComputeComponentGraph.h"
#include "cmGraphAdjacencyList.h"
#include "cmLinkItem.h"
#include "cmListFileCache.h"
#include "cmTargetLinkLibraryType.h"
class cmGeneratorTarget;
class cmGlobalGenerator;
class cmMakefile;
class cmSourceFile;
class cmake;
/** \class cmComputeLinkDepends
* \brief Compute link dependencies for targets.
*/
class cmComputeLinkDepends
{
public:
cmComputeLinkDepends(cmGeneratorTarget const* target,
const std::string& config,
const std::string& linkLanguage);
~cmComputeLinkDepends();
cmComputeLinkDepends(const cmComputeLinkDepends&) = delete;
cmComputeLinkDepends& operator=(const cmComputeLinkDepends&) = delete;
// Basic information about each link item.
struct LinkEntry
{
LinkEntry() = default;
LinkEntry(BT<std::string> item, cmGeneratorTarget const* target = nullptr)
: Item(std::move(item))
, Target(target)
{
}
static const std::string DEFAULT;
enum EntryKind
{
Library,
Object,
SharedDep,
Flag,
// The following member is for the management of items specified
// through genex $<LINK_GROUP:...>
Group
};
BT<std::string> Item;
cmGeneratorTarget const* Target = nullptr;
// The source file representing the external object (used when linking
// `$<TARGET_OBJECTS>`)
cmSourceFile const* ObjectSource = nullptr;
EntryKind Kind = Library;
// The following member is for the management of items specified
// through genex $<LINK_LIBRARY:...>
std::string Feature = std::string(DEFAULT);
};
using EntryVector = std::vector<LinkEntry>;
EntryVector const& Compute();
void SetOldLinkDirMode(bool b);
std::set<cmGeneratorTarget const*> const& GetOldWrongConfigItems() const
{
return this->OldWrongConfigItems;
}
private:
// Context information.
cmGeneratorTarget const* Target;
cmMakefile* Makefile;
cmGlobalGenerator const* GlobalGenerator;
cmake* CMakeInstance;
std::string LinkLanguage;
std::string Config;
EntryVector FinalLinkEntries;
std::map<std::string, std::string> LinkLibraryOverride;
std::string const& GetCurrentFeature(
std::string const& item, std::string const& defaultFeature) const;
std::pair<std::map<cmLinkItem, size_t>::iterator, bool> AllocateLinkEntry(
cmLinkItem const& item);
std::pair<size_t, bool> AddLinkEntry(
cmLinkItem const& item,
size_t groupIndex = cmComputeComponentGraph::INVALID_COMPONENT);
void AddLinkObject(cmLinkItem const& item);
void AddVarLinkEntries(size_t depender_index, const char* value);
void AddDirectLinkEntries();
template <typename T>
void AddLinkEntries(size_t depender_index, std::vector<T> const& libs);
void AddLinkObjects(std::vector<cmLinkItem> const& objs);
cmLinkItem ResolveLinkItem(size_t depender_index, const std::string& name);
// One entry for each unique item.
std::vector<LinkEntry> EntryList;
std::map<cmLinkItem, size_t> LinkEntryIndex;
// map storing, for each group, the list of items
std::map<size_t, std::vector<size_t>> GroupItems;
// BFS of initial dependencies.
struct BFSEntry
{
size_t Index;
size_t GroupIndex;
const char* LibDepends;
};
std::queue<BFSEntry> BFSQueue;
void FollowLinkEntry(BFSEntry qe);
// Shared libraries that are included only because they are
// dependencies of other shared libraries, not because they are part
// of the interface.
struct SharedDepEntry
{
cmLinkItem Item;
size_t DependerIndex;
};
std::queue<SharedDepEntry> SharedDepQueue;
std::set<size_t> SharedDepFollowed;
void FollowSharedDeps(size_t depender_index, cmLinkInterface const* iface,
bool follow_interface = false);
void QueueSharedDependencies(size_t depender_index,
std::vector<cmLinkItem> const& deps);
void HandleSharedDependency(SharedDepEntry const& dep);
// Dependency inferral for each link item.
struct DependSet : public std::set<size_t>
{
};
struct DependSetList : public std::vector<DependSet>
{
bool Initialized = false;
};
std::vector<DependSetList> InferredDependSets;
void InferDependencies();
// To finalize dependencies over groups in place of raw items
void UpdateGroupDependencies();
// Ordering constraint graph adjacency list.
using NodeList = cmGraphNodeList;
using EdgeList = cmGraphEdgeList;
using Graph = cmGraphAdjacencyList;
Graph EntryConstraintGraph;
void CleanConstraintGraph();
bool CheckCircularDependencies() const;
void DisplayConstraintGraph();
// Ordering algorithm.
void OrderLinkEntries();
std::vector<char> ComponentVisited;
std::vector<size_t> ComponentOrder;
struct PendingComponent
{
// The real component id. Needed because the map is indexed by
// component topological index.
size_t Id;
// The number of times the component needs to be seen. This is
// always 1 for trivial components and is initially 2 for
// non-trivial components.
size_t Count;
// The entries yet to be seen to complete the component.
std::set<size_t> Entries;
};
std::map<size_t, PendingComponent> PendingComponents;
std::unique_ptr<cmComputeComponentGraph> CCG;
std::vector<size_t> FinalLinkOrder;
void DisplayComponents();
void VisitComponent(size_t c);
void VisitEntry(size_t index);
PendingComponent& MakePendingComponent(size_t component);
size_t ComputeComponentCount(NodeList const& nl);
void DisplayFinalEntries();
// Record of the original link line.
std::vector<size_t> OriginalEntries;
std::set<cmGeneratorTarget const*> OldWrongConfigItems;
void CheckWrongConfigItem(cmLinkItem const& item);
// Record of explicitly linked object files.
std::vector<size_t> ObjectEntries;
size_t ComponentOrderId;
cmTargetLinkLibraryType LinkType;
bool HasConfig;
bool DebugMode;
bool OldLinkDirMode;
};