]> git.tdb.fi Git - builder.git/blob - source/analyzer.cpp
Add comments
[builder.git] / source / analyzer.cpp
1 #include <iomanip>
2 #include <iostream>
3 #include <sstream>
4 #include <msp/path/path.h>
5 #include "analyzer.h"
6 #include "builder.h"
7 #include "install.h"
8 #include "objectfile.h"
9 #include "package.h"
10 #include "target.h"
11
12 using namespace std;
13 using namespace Msp;
14
15 Analyzer::Analyzer(Builder &b):
16         builder(b),
17         mode(DEPS),
18         max_depth(0),
19         full_paths(false)
20 { }
21
22 /**
23 Performs the analysis and prints out the resulting dependency tree.
24 */
25 void Analyzer::analyze()
26 {
27         TableRow row;
28         row.push_back("Name");
29         row.push_back("Package");
30         row.push_back("Type");
31         row.push_back("Rebuild");
32         table.push_back(row);
33         
34         build_depend_table(*builder.get_target("cmdline"), 0);
35
36         print_table();
37 }
38
39 /**
40 Adds rows to the table for the given target and it' dependencies.
41
42 @param   tgt    Target to be processed
43 @param   depth  Recursion level of the target (top level is 0)
44 */
45 void Analyzer::build_depend_table(Target &tgt, unsigned depth)
46 {
47         if(mode!=REBUILD && mode!=ALLDEPS)
48         {
49                 // Skip trivial targets
50                 if(dynamic_cast<ObjectFile *>(&tgt))
51                         return build_depend_table(*tgt.get_depends().front(), depth);
52                 else if(dynamic_cast<Install *>(&tgt))
53                         return build_depend_table(*tgt.get_depends().front(), depth);
54         }
55         else if(mode==REBUILD && !tgt.get_rebuild())
56                 /* All targets that depend on to-be-built targets will be rebuilt
57                    themselves, so we cn stop here. */
58                 return;
59         
60         TableRow row;
61
62         string fn;
63         if(full_paths)
64                 fn=tgt.get_name();
65         else
66                 fn=Path::Path(tgt.get_name())[-1];
67         row.push_back(string(depth*2, ' ')+fn);
68
69         const Package *pkg=tgt.get_package();
70         if(pkg)
71                 row.push_back(pkg->get_name());
72         else
73                 row.push_back("");
74         
75         row.push_back(tgt.get_type());
76         
77         if(tgt.get_rebuild())
78         {
79                 if(tgt.get_rebuild_reason().empty())
80                         row.push_back("Yes (no reason)");
81                 else
82                         row.push_back(tgt.get_rebuild_reason());
83         }
84
85         table.push_back(row);
86
87         if(!max_depth || depth<max_depth-1)
88         {
89                 const TargetList &depends=tgt.get_depends();
90                 //XXX If we want to sort the targets, we need to take the value of full_paths into account
91                 //depends.sort(target_order);
92                 for(TargetList::const_iterator i=depends.begin(); i!=depends.end(); ++i)
93                         build_depend_table(**i, depth+1);
94         }
95 }
96
97 /**
98 Prints out the table that resulted from the analysis.
99 */
100 void Analyzer::print_table() const
101 {
102         vector<unsigned> col_width;
103
104         // Determine column widths
105         for(Table::const_iterator i=table.begin(); i!=table.end(); ++i)
106         {
107                 if(col_width.size()<i->size())
108                         col_width.resize(i->size(), 0);
109                 for(unsigned j=0; j<i->size(); ++j)
110                         col_width[j]=max(col_width[j], (*i)[j].size());
111         }
112
113         for(Table::const_iterator i=table.begin(); i!=table.end(); ++i)
114         {
115                 ostringstream ss;
116                 ss<<left;
117                 for(unsigned j=0; j<i->size(); ++j)
118                 {
119                         if(j>0)
120                                 ss<<"  ";
121                         ss<<setw(col_width[j])<<(*i)[j];
122                 }
123                 cout<<ss.str()<<'\n';
124         }
125 }
126
127 bool Analyzer::target_order(Target *t1, Target *t2)
128 { return t1->get_name()<t2->get_name(); }