]> git.tdb.fi Git - builder.git/blob - source/analyzer.cpp
Convert all list containers to vectors
[builder.git] / source / analyzer.cpp
1 #include <msp/core/algorithm.h>
2 #include <msp/fs/utils.h>
3 #include <msp/io/print.h>
4 #include "analyzer.h"
5 #include "builder.h"
6 #include "buildgraph.h"
7 #include "objectfile.h"
8 #include "sourcefile.h"
9 #include "sourcepackage.h"
10 #include "target.h"
11 #include "tool.h"
12
13 using namespace std;
14 using namespace Msp;
15
16 Analyzer::Analyzer(Builder &b):
17         builder(b),
18         mode(DEPS),
19         max_depth(0),
20         full_paths(false)
21 { }
22
23 void Analyzer::analyze()
24 {
25         if(mode==RDEPS)
26         {
27                 rdepends.clear();
28                 for(const auto &kvp: builder.get_build_graph().get_targets())
29                 {
30                         for(Target *d: kvp.second->get_dependencies())
31                                 rdepends[d].insert(kvp.second);
32                         for(Target *d: kvp.second->get_transitive_dependencies())
33                                 rdepends[d].insert(kvp.second);
34                 }
35         }
36
37         table.clear();
38
39         TableRow row;
40         row.push_back("Name");
41         row.push_back("Package");
42         row.push_back("Type");
43         row.push_back("Tool");
44         row.push_back("Rebuild");
45         table.push_back(row);
46         
47         Target &goals = builder.get_build_graph().get_goals();
48         if(mode==RDEPS)
49         {
50                 for(Target *d: goals.get_dependencies())
51                         build_depend_table(*d, 0);
52         }
53         else
54                 build_depend_table(goals, 0);
55
56         print_table();
57 }
58
59 void Analyzer::build_depend_table(Target &tgt, unsigned depth)
60 {
61         Target *real = tgt.get_real_target();
62         if(mode==DEPS)
63         {
64                 // Skip trivial targets
65                 if(real!=&tgt)
66                         return build_depend_table(*real, depth);
67                 if(const ObjectFile *obj = dynamic_cast<const ObjectFile *>(&tgt))
68                         return build_depend_table(obj->get_source(), depth);
69         }
70         else if(mode==REBUILD && !tgt.needs_rebuild())
71                 /* All targets that depend on to-be-built targets will be rebuilt
72                 themselves, so we can stop here. */
73                 return;
74         
75         TableRow row;
76
77         string name;
78         const FileTarget *ft = dynamic_cast<const FileTarget *>(&tgt);
79         if(full_paths && ft)
80                 name = ft->get_path().str();
81         else
82                 name = tgt.get_name();
83         row.push_back(string(depth*2, ' ')+name);
84
85         const Package *pkg = tgt.get_package();
86         if(pkg)
87                 row.push_back(pkg->get_name());
88         else
89                 row.push_back("");
90         
91         row.push_back(tgt.get_type());
92         const Tool *tool = tgt.get_tool();
93         if(tool)
94                 row.push_back(tool->get_tag());
95         else
96                 row.push_back("");
97
98         if(tgt.needs_rebuild())
99                 row.push_back(tgt.get_rebuild_reason());
100
101         table.push_back(row);
102
103         if(!max_depth || depth<max_depth-1)
104         {
105                 Target::Dependencies depends;
106                 if(mode==RDEPS)
107                 {
108                         const set<Target *> &rdeps = rdepends[&tgt];
109                         depends.assign(rdeps.begin(), rdeps.end());
110                 }
111                 else
112                 {
113                         depends = tgt.get_dependencies();
114                         const Target::Dependencies &tdeps = tgt.get_transitive_dependencies();
115                         depends.insert(depends.end(), tdeps.begin(), tdeps.end());
116                 }
117
118                 sort(depends, (full_paths ? target_order_full : target_order));
119
120                 for(Target *d: depends)
121                         build_depend_table(*d, depth+1);
122         }
123 }
124
125 void Analyzer::print_table() const
126 {
127         vector<string::size_type> col_width;
128
129         // Determine column widths
130         for(const vector<string> &r: table)
131         {
132                 if(col_width.size()<r.size())
133                         col_width.resize(r.size(), 0);
134                 for(unsigned j=0; j<r.size(); ++j)
135                         col_width[j] = max(col_width[j], r[j].size());
136         }
137
138         for(const vector<string> &r: table)
139         {
140                 string line;
141                 for(unsigned j=0; j<r.size(); ++j)
142                 {
143                         if(j>0)
144                                 line += "  ";
145                         line += lexical_cast<string>(r[j], Fmt("%-s").width(col_width[j]));
146                 }
147                 IO::print("%s\n", line);
148         }
149 }
150
151 bool Analyzer::target_order(const Target *t1, const Target *t2)
152 {
153         return t1->get_name()<t2->get_name();
154 }
155
156 bool Analyzer::target_order_full(const Target *t1, const Target *t2)
157 {
158         const FileTarget *ft1 = dynamic_cast<const FileTarget *>(t1);
159         const FileTarget *ft2 = dynamic_cast<const FileTarget *>(t2);
160         if(!ft1)
161         {
162                 if(ft2)
163                         return true;
164                 return target_order(t1, t2);
165         }
166         else if(!ft2)
167                 return false;
168         return ft1->get_path().str()<ft2->get_path().str();
169 }