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