1 #include <msp/core/algorithm.h>
2 #include <msp/fs/stat.h>
3 #include <msp/fs/utils.h>
4 #include <msp/strings/utils.h>
6 #include "filetarget.h"
7 #include "sourcepackage.h"
15 vector<Target *> Target::prepare_stack;
17 Target::Target(Builder &b, const string &n):
21 builder.get_build_graph().add_target(this);
24 void Target::add_dependency(Target &dep)
27 throw invalid_argument("Target::add_depend");
28 depends.push_back(&dep);
30 dep.signal_bubble_rebuild.connect(sigc::mem_fun(this, &Target::check_rebuild));
33 void Target::add_transitive_dependency(Target &dep)
36 throw invalid_argument("Target::add_transitive_dependency");
37 trans_depends.push_back(&dep);
40 void Target::add_side_effect(Target &se)
42 side_effects.push_back(&se);
45 se.primary_target = this;
46 /* Side effects are checked for rebuild after the primary target. Recheck
47 the primary if a side effect is marked for rebuild. */
48 se.signal_bubble_rebuild.connect(sigc::mem_fun(this, &Target::check_rebuild));
51 bool Target::find_transitive_dependencies()
53 vector<Target *> found_deps;
54 for(Target *d: depends)
55 if(!d->is_buildable())
56 find_transitive_dependencies(*d, found_deps);
58 bool any_added = false;
59 for(Target *d: found_deps)
60 if(!any_equals(depends, d))
64 if(d->get_real_target()->is_buildable())
65 d->signal_modified.connect([this]{ rescan_trans_deps = true; });
71 void Target::find_transitive_dependencies(Target &tgt, vector<Target *> &found_deps) const
75 Target *rtgt = tgt.get_real_target();
76 Dependencies deps_to_add = rtgt->get_transitive_dependencies();
79 for(Target *&d: deps_to_add)
80 d = resolve_transitive_dependency(tgt, *d);
83 for(Target *d: deps_to_add)
86 auto i = lower_bound(found_deps, d);
87 if(i==found_deps.end() || *i!=d)
89 found_deps.insert(i, d);
90 find_transitive_dependencies(*d, found_deps);
95 Target *Target::get_buildable_target()
98 return primary_target->get_buildable_target();
102 bool self_ok = state!=BUILDING;
103 for(Target *d: depends)
105 // Avoid infinite recursion if a target depends on its own side effect
106 if(any_equals(side_effects, d))
109 Target *tgt = d->get_buildable_target();
112 else if(d->needs_rebuild())
118 if(rescan_trans_deps)
120 rescan_trans_deps = false;
121 if(find_transitive_dependencies())
122 return get_buildable_target();
131 void Target::set_tool(Tool &t)
134 for(Target *s: side_effects)
138 void Target::collect_build_info(BuildInfo &binfo) const
141 binfo.update_from(tool->get_build_info());
143 binfo.update_from(component->get_build_info());
145 binfo.update_from(package->get_build_info());
148 void Target::force_rebuild()
151 throw logic_error("Target::force_rebuild");
152 mark_rebuild("Forced rebuild");
155 void Target::mark_rebuild(const string &reason)
158 throw invalid_argument("No reason given for rebuilding "+name);
161 rebuild_reason = reason;
163 builder.get_logger().log("rebuild", "Rebuilding %s: %s", name, reason);
165 signal_bubble_rebuild.emit();
168 void Target::prepare()
170 if(primary_target && primary_target->state<PREPARING)
171 primary_target->prepare();
177 auto i = find(prepare_stack, this);
178 if(i!=prepare_stack.end())
181 for(; i!=prepare_stack.end(); ++i)
182 append(cycle, " -> ", (*i)->name);
183 append(cycle, " -> ", name);
184 builder.get_logger().log("problems", "Dependency cycle detected: %s", cycle);
185 problems.push_back(format("Dependency cycle detected: %s", cycle));
189 builder.get_logger().log("problems", "Dependency cycle detected at %s", name);
190 problems.push_back("Dependency cycle detected");
196 PushPrepare _push(this);
198 /* Prepare existing dependencies early, because their information may be
199 needed to find other dependencies. */
200 for(Target *d: depends)
206 find_transitive_dependencies();
207 bool broken = !problems.empty();
211 if(FileTarget *tool_exe = tool->get_executable())
212 add_dependency(*tool_exe);
213 broken |= tool->is_broken();
215 // Only check package and component brokenness for buildable targets
216 broken |= (package && package->is_broken());
217 broken |= (component && component->is_broken());
220 /* Now that all dependencies are known, prepare them again. This will do
221 nothing to already prepared targets. */
222 for(Target *d: depends)
225 broken |= d->is_broken();
227 for(Target *d: trans_depends)
233 else if(state==PREPARING)
236 for(Target *d: depends)
237 d->signal_bubble_rebuild.connect(sigc::mem_fun(this, &Target::check_rebuild));
240 Task *Target::build()
243 return primary_target->build();
245 Task *task = tool->run(*this);
246 task->signal_finished.connect(sigc::mem_fun(this, &Target::build_finished));
250 for(Target *s: side_effects)
256 void Target::build_finished(bool success)
262 for(Target *s: side_effects)
263 s->build_finished(success);
264 signal_modified.emit();