#include <msp/core/algorithm.h>
#include <msp/fs/stat.h>
#include <msp/fs/utils.h>
+#include <msp/strings/utils.h>
#include "builder.h"
#include "filetarget.h"
#include "sourcepackage.h"
using namespace std;
using namespace Msp;
+vector<Target *> Target::prepare_stack;
+
Target::Target(Builder &b, const string &n):
builder(b),
name(n)
se.signal_bubble_rebuild.connect(sigc::mem_fun(this, &Target::check_rebuild));
}
+bool Target::find_transitive_dependencies()
+{
+ vector<Target *> found_deps;
+ for(Target *d: depends)
+ if(!d->is_buildable())
+ find_transitive_dependencies(*d, found_deps);
+
+ bool any_added = false;
+ for(Target *d: found_deps)
+ if(!any_equals(depends, d))
+ {
+ any_added = true;
+ add_dependency(*d);
+ if(d->get_real_target()->is_buildable())
+ d->signal_modified.connect([this]{ rescan_trans_deps = true; });
+ }
+
+ return any_added;
+}
+
+void Target::find_transitive_dependencies(Target &tgt, vector<Target *> &found_deps) const
+{
+ tgt.prepare();
+
+ Target *rtgt = tgt.get_real_target();
+ Dependencies deps_to_add = rtgt->get_transitive_dependencies();
+ if(rtgt!=&tgt)
+ {
+ for(Target *&d: deps_to_add)
+ d = resolve_transitive_dependency(tgt, *d);
+ }
+
+ for(Target *d: deps_to_add)
+ if(d)
+ {
+ auto i = lower_bound(found_deps, d);
+ if(i==found_deps.end() || *i!=d)
+ {
+ found_deps.insert(i, d);
+ find_transitive_dependencies(*d, found_deps);
+ }
+ }
+}
+
Target *Target::get_buildable_target()
{
if(primary_target)
}
if(self_ok)
+ {
+ if(rescan_trans_deps)
+ {
+ rescan_trans_deps = false;
+ if(find_transitive_dependencies())
+ return get_buildable_target();
+ }
+
return this;
+ }
return 0;
}
void Target::prepare()
{
+ if(primary_target && primary_target->state<PREPARING)
+ primary_target->prepare();
+
if(state>PREPARING)
return;
if(state==PREPARING)
{
- builder.get_logger().log("problems", "Dependency cycle detected at %s", name);
- problems.push_back("Dependency cycle detected");
+ auto i = find(prepare_stack, this);
+ if(i!=prepare_stack.end())
+ {
+ string cycle;
+ for(; i!=prepare_stack.end(); ++i)
+ append(cycle, " -> ", (*i)->name);
+ append(cycle, " -> ", name);
+ builder.get_logger().log("problems", "Dependency cycle detected: %s", cycle);
+ problems.push_back(format("Dependency cycle detected: %s", cycle));
+ }
+ else
+ {
+ builder.get_logger().log("problems", "Dependency cycle detected at %s", name);
+ problems.push_back("Dependency cycle detected");
+ }
state = BROKEN;
return;
}
+ PushPrepare _push(this);
state = PREPARING;
/* Prepare existing dependencies early, because their information may be
needed to find other dependencies. */
tool->prepare();
find_dependencies();
+ find_transitive_dependencies();
bool broken = !problems.empty();
if(tool)