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