]> git.tdb.fi Git - builder.git/blob - source/target.cpp
c9c23ad9116165297d602978b9be04c13f902530
[builder.git] / source / target.cpp
1 /* $Id$
2
3 This file is part of builder
4 Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <msp/path/utils.h>
9 #include <msp/time/utils.h>
10 #include "action.h"
11 #include "builder.h"
12 #include "package.h"
13 #include "target.h"
14
15 using namespace std;
16 using namespace Msp;
17
18 /**
19 Tries to locate a target that will help getting this target built.  If all
20 dependencies are up-to-date, returns this target.  If there are no targets
21 ready to be built (maybe because they are being built right now), returns 0.
22 */
23 Target *Target::get_buildable_target()
24 {
25         if(!rebuild)
26                 return 0;
27
28         bool self_ok=!building;
29         for(TargetList::iterator i=depends.begin(); i!=depends.end(); ++i)
30         {
31                 Target *tgt=(*i)->get_buildable_target();
32                 if(tgt)
33                         return tgt;
34                 else if((*i)->get_rebuild())
35                         self_ok=false;
36         }
37
38         if(self_ok)
39                 return this;
40
41         return 0;
42 }
43
44 void Target::add_depend(Target *dep)
45 {
46         if(dep==this)
47                 throw InvalidParameterValue("A target can't depend on itself");
48         depends.push_back(dep);
49         dep->rdepends.push_back(this);
50 }
51
52 /**
53 Prepares the target by recursively preparing dependencies, then checking
54 whether rebuilding is needed.  A flag is used to prevent unnecessary
55 executions.
56 */
57 void Target::prepare()
58 {
59         if(prepared)
60                 return;
61
62         prepared=true;
63         for(TargetList::iterator i=depends.begin(); i!=depends.end(); ++i)
64                 (*i)->prepare();
65
66         check_rebuild();
67
68 }
69
70 /**
71 Returns the number of targets that need to be rebuilt in order to get this
72 target up-to-date.
73 */
74 unsigned Target::count_rebuild()
75 {
76         if(counted)
77                 return 0;
78
79         counted=true;
80         unsigned count=rebuild;
81         for(TargetList::iterator i=depends.begin(); i!=depends.end(); ++i)
82                 count+=(*i)->count_rebuild();
83         return count;
84 }
85
86 /**
87 Changes the mtime of the target to the current time.
88 */
89 void Target::touch()
90 {
91         mtime=Time::now();
92 }
93
94 Target::Target(Builder &b, const Package *p, const string &n):
95         builder(b),
96         package(p),
97         name(n),
98         buildable(false),
99         building(false),
100         rebuild(false),
101         deps_ready(false),
102         prepared(false),
103         counted(false)
104 {
105         builder.add_target(this);
106
107         struct stat st;
108         if(!Path::stat(name, st))
109                 mtime=Time::TimeStamp::from_unixtime(st.st_mtime);
110 }
111
112 void Target::mark_rebuild(const std::string &reason)
113 {
114         rebuild=true;
115         rebuild_reason=reason;
116 }
117
118 /**
119 Checks if this target needs to be rebuilt and why.
120 */
121 void Target::check_rebuild()
122 {
123         if(!buildable)
124                 return;
125
126         if(builder.get_build_all())
127                 mark_rebuild("Rebuilding everything");
128         else if(!mtime)
129                 mark_rebuild("Does not exist");
130         else
131         {
132                 for(TargetList::iterator i=depends.begin(); (i!=depends.end() && !rebuild); ++i)
133                 {
134                         if((*i)->get_mtime()>mtime)
135                                 mark_rebuild(Path::basename((*i)->get_name())+" has changed");
136                         else if((*i)->get_rebuild())
137                                 mark_rebuild(Path::basename((*i)->get_name())+" needs rebuilding");
138                 }
139         }
140         if(!rebuild && package && package->get_config().get_mtime()>mtime)
141                 mark_rebuild("Package options changed");
142 }
143
144 /**
145 Hooks the target up with the given action, then returns it.  This should be
146 called from the public build() function of buildable targets.
147 */
148 Action *Target::build(Action *action)
149 {
150         building=true;
151         action->signal_done.connect(sigc::mem_fun(this, &Target::build_done));
152         return action;
153 }
154
155 /**
156 Handles for the build_done signal of Action.
157 */
158 void Target::build_done()
159 {
160         building=false;
161         rebuild=false;
162 }