X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Flib%2Ftarget.cpp;h=0d823eef6618814c01043f9a71805b562ccad536;hb=HEAD;hp=d1aaf73be578c3836b48cf251536a4a4d446612b;hpb=b0438fd2d85d6937b67db38c6138b0783962d8b2;p=builder.git diff --git a/source/lib/target.cpp b/source/lib/target.cpp index d1aaf73..0d823ee 100644 --- a/source/lib/target.cpp +++ b/source/lib/target.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "builder.h" #include "filetarget.h" #include "sourcepackage.h" @@ -11,6 +12,8 @@ using namespace std; using namespace Msp; +vector Target::prepare_stack; + Target::Target(Builder &b, const string &n): builder(b), name(n) @@ -45,6 +48,50 @@ void Target::add_side_effect(Target &se) se.signal_bubble_rebuild.connect(sigc::mem_fun(this, &Target::check_rebuild)); } +bool Target::find_transitive_dependencies() +{ + vector 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 &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) @@ -67,7 +114,16 @@ Target *Target::get_buildable_target() } if(self_ok) + { + if(rescan_trans_deps) + { + rescan_trans_deps = false; + if(find_transitive_dependencies()) + return get_buildable_target(); + } + return this; + } return 0; } @@ -118,12 +174,26 @@ void Target::prepare() 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. */ @@ -133,6 +203,7 @@ void Target::prepare() tool->prepare(); find_dependencies(); + find_transitive_dependencies(); bool broken = !problems.empty(); if(tool)