]> git.tdb.fi Git - builder.git/blob - source/target.cpp
Refactor build graph into its own class
[builder.git] / source / target.cpp
1 #include <msp/fs/stat.h>
2 #include <msp/fs/utils.h>
3 #include <msp/strings/format.h>
4 #include "builder.h"
5 #include "filetarget.h"
6 #include "sourcepackage.h"
7 #include "target.h"
8 #include "task.h"
9 #include "tool.h"
10
11 using namespace std;
12 using namespace Msp;
13
14 Target::Target(Builder &b, const string &n):
15         builder(b),
16         package(0),
17         component(0),
18         name(n),
19         tool(0),
20         state(INIT),
21         primary_target(0)
22 {
23         builder.get_build_graph().add_target(this);
24 }
25
26 void Target::add_dependency(Target &dep)
27 {
28         if(&dep==this)
29                 throw invalid_argument("Target::add_depend");
30         depends.push_back(&dep);
31         if(state>PREPARING)
32                 dep.signal_bubble_rebuild.connect(sigc::mem_fun(this, &Target::check_rebuild));
33 }
34
35 void Target::add_side_effect(Target &se)
36 {
37         side_effects.push_back(&se);
38         se.add_dependency(*this);
39         if(tool)
40                 se.set_tool(*tool);
41         se.primary_target = this;
42 }
43
44 Target *Target::get_buildable_target()
45 {
46         if(primary_target)
47                 return primary_target->get_buildable_target();
48         if(!needs_rebuild())
49                 return 0;
50
51         bool self_ok = state!=BUILDING;
52         for(Dependencies::iterator i=depends.begin(); i!=depends.end(); ++i)
53         {
54                 Target *tgt = (*i)->get_buildable_target();
55                 if(tgt)
56                         return tgt;
57                 else if((*i)->needs_rebuild())
58                         self_ok = false;
59         }
60
61         if(self_ok)
62                 return this;
63
64         return 0;
65 }
66
67 void Target::set_tool(const Tool &t)
68 {
69         tool = &t;
70         for(Dependencies::const_iterator i=side_effects.begin(); i!=side_effects.end(); ++i)
71                 (*i)->set_tool(t);
72 }
73
74 void Target::force_rebuild()
75 {
76         if(!is_buildable())
77                 throw logic_error("Target::force_rebuild");
78         mark_rebuild("Forced rebuild");
79 }
80
81 void Target::mark_rebuild(const string &reason)
82 {
83         if(reason.empty())
84                 throw invalid_argument("No reason given for rebuilding "+name);
85
86         state = REBUILD;
87         rebuild_reason = reason;
88
89         builder.get_logger().log("rebuild", format("Rebuilding %s: %s", name, reason));
90
91         signal_bubble_rebuild.emit();
92 }
93
94 void Target::prepare()
95 {
96         if(state>PREPARING)
97                 return;
98         if(state==PREPARING)
99         {
100                 builder.problem((package ? package->get_name() : string()), "Dependency cycle detected at "+name);
101                 return;
102         }
103
104         state = PREPARING;
105         find_dependencies();
106         if(tool)
107         {
108                 if(FileTarget *tool_exe = tool->get_executable())
109                         add_dependency(*tool_exe);
110         }
111
112         for(Dependencies::iterator i=depends.begin(); i!=depends.end(); ++i)
113                 (*i)->prepare();
114
115         check_rebuild();
116         if(state==PREPARING)
117                 state = UPTODATE;
118
119         for(Dependencies::iterator i=depends.begin(); i!=depends.end(); ++i)
120                 (*i)->signal_bubble_rebuild.connect(sigc::mem_fun(this, &Target::check_rebuild));
121 }
122
123 Task *Target::build()
124 {
125         if(!tool)
126         {
127                 // This special case is needed for VirtualTargets
128                 state = UPTODATE;
129                 return 0;
130         }
131
132         Task *task = tool->run(*this);
133         task->signal_finished.connect(sigc::mem_fun(this, &Target::build_finished));
134         state = BUILDING;
135
136         return task;
137 }
138
139 void Target::build_finished(bool success)
140 {
141         state = UPTODATE;
142         if(success)
143         {
144                 modified();
145                 for(Dependencies::const_iterator i=side_effects.begin(); i!=side_effects.end(); ++i)
146                         (*i)->build_finished(success);
147         }
148 }