Merge topic 'optimize-static-library-deps'

2e42651dff Add option to optimize link dependencies for static libraries

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !5103
This commit is contained in:
Kyle Edwards
2020-08-13 18:16:18 +00:00
committed by Kitware Robot
47 changed files with 560 additions and 9 deletions
+157 -8
View File
@@ -17,10 +17,12 @@
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
#include "cmProperty.h"
#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmTargetDepend.h"
@@ -115,19 +117,32 @@ bool cmComputeTargetDepends::Compute()
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 ccg(this->InitialGraph);
ccg.Compute();
cmComputeComponentGraph ccg2(this->IntermediateGraph);
ccg2.Compute();
if (this->DebugMode) {
this->DisplayComponents(ccg);
this->DisplayComponents(ccg2, "intermediate");
}
if (!this->CheckComponents(ccg)) {
if (!this->CheckComponents(ccg2)) {
return false;
}
// Compute the final dependency graph.
if (!this->ComputeFinalDepends(ccg)) {
if (!this->ComputeFinalDepends(ccg2)) {
return false;
}
if (this->DebugMode) {
@@ -382,6 +397,111 @@ void cmComputeTargetDepends::AddTargetDepend(
}
}
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 (cmProp 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)
{
@@ -402,10 +522,39 @@ void cmComputeTargetDepends::DisplayGraph(Graph const& graph,
fprintf(stderr, "\n");
}
void cmComputeTargetDepends::DisplayComponents(
cmComputeComponentGraph const& ccg)
void cmComputeTargetDepends::DisplaySideEffects()
{
fprintf(stderr, "The strongly connected components are:\n");
fprintf(stderr, "The side effects are:\n");
int n = static_cast<int>(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) {
+18 -1
View File
@@ -42,6 +42,13 @@ public:
cmTargetDependSet& deps);
private:
struct TargetSideEffects
{
std::set<cmGeneratorTarget const*> CustomCommandSideEffects;
std::map<std::string, std::set<cmGeneratorTarget const*>>
LanguageSideEffects;
};
void CollectTargets();
void CollectDepends();
void CollectTargetDepends(int depender_index);
@@ -50,6 +57,12 @@ private:
void AddTargetDepend(int depender_index, cmGeneratorTarget const* dependee,
cmListFileBacktrace const& dependee_backtrace,
bool linking, bool cross);
void CollectSideEffects();
void CollectSideEffectsForTarget(std::set<int>& visited, int depender_index);
void ComputeIntermediateGraph();
void OptimizeLinkDependencies(cmGeneratorTarget const* gt,
cmGraphEdgeList& outputEdges,
cmGraphEdgeList const& inputEdges);
bool ComputeFinalDepends(cmComputeComponentGraph const& ccg);
void AddInterfaceDepends(int depender_index, cmLinkItem const& dependee_name,
const std::string& config,
@@ -74,11 +87,15 @@ private:
using EdgeList = cmGraphEdgeList;
using Graph = cmGraphAdjacencyList;
Graph InitialGraph;
Graph IntermediateGraph;
Graph FinalGraph;
std::vector<TargetSideEffects> SideEffects;
void DisplayGraph(Graph const& graph, const std::string& name);
void DisplaySideEffects();
// Deal with connected components.
void DisplayComponents(cmComputeComponentGraph const& ccg);
void DisplayComponents(cmComputeComponentGraph const& ccg,
const std::string& name);
bool CheckComponents(cmComputeComponentGraph const& ccg);
void ComplainAboutBadComponent(cmComputeComponentGraph const& ccg, int c,
bool strong = false);
+31
View File
@@ -1084,6 +1084,37 @@ std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPostBuildCommands()
return this->Target->GetPostBuildCommands();
}
void cmGeneratorTarget::AppendCustomCommandSideEffects(
std::set<cmGeneratorTarget const*>& sideEffects) const
{
if (!this->GetPreBuildCommands().empty() ||
!this->GetPreLinkCommands().empty() ||
!this->GetPostBuildCommands().empty()) {
sideEffects.insert(this);
} else {
for (auto const& source : this->GetAllConfigSources()) {
if (source.Source->GetCustomCommand() != nullptr) {
sideEffects.insert(this);
break;
}
}
}
}
void cmGeneratorTarget::AppendLanguageSideEffects(
std::map<std::string, std::set<cmGeneratorTarget const*>>& sideEffects) const
{
static const std::set<cm::string_view> LANGS_WITH_NO_SIDE_EFFECTS = {
"C"_s, "CXX"_s, "OBJC"_s, "OBJCXX"_s, "ASM"_s, "CUDA"_s,
};
for (auto const& lang : this->GetAllConfigCompileLanguages()) {
if (!LANGS_WITH_NO_SIDE_EFFECTS.count(lang)) {
sideEffects[lang].insert(this);
}
}
}
bool cmGeneratorTarget::IsInBuildSystem() const
{
if (this->IsImported()) {
+6
View File
@@ -55,6 +55,12 @@ public:
std::vector<cmCustomCommand> const& GetPreLinkCommands() const;
std::vector<cmCustomCommand> const& GetPostBuildCommands() const;
void AppendCustomCommandSideEffects(
std::set<cmGeneratorTarget const*>& sideEffects) const;
void AppendLanguageSideEffects(
std::map<std::string, std::set<cmGeneratorTarget const*>>& sideEffects)
const;
#define DECLARE_TARGET_POLICY(POLICY) \
cmPolicies::PolicyStatus GetPolicyStatus##POLICY() const \
{ \
+1
View File
@@ -373,6 +373,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
initProp("VS_JUST_MY_CODE_DEBUGGING");
initProp("DISABLE_PRECOMPILE_HEADERS");
initProp("UNITY_BUILD");
initProp("OPTIMIZE_DEPENDENCIES");
initPropValue("UNITY_BUILD_BATCH_SIZE", "8");
initPropValue("UNITY_BUILD_MODE", "BATCH");
initPropValue("PCH_WARN_INVALID", "ON");