From 5035f4ef68922ac758b1e4734e67d73c9228010b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 22 Aug 2019 14:38:57 +0200 Subject: Introduce notion of build context All non-const global state is now in class context and we can now have multiple independent builds going on at the same time. --- libbuild2/target.cxx | 108 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 69 insertions(+), 39 deletions(-) (limited to 'libbuild2/target.cxx') diff --git a/libbuild2/target.cxx b/libbuild2/target.cxx index c823e85..dbca6cd 100644 --- a/libbuild2/target.cxx +++ b/libbuild2/target.cxx @@ -67,7 +67,7 @@ namespace build2 const string& target:: ext (string v) { - ulock l (targets.mutex_); + ulock l (ctx.targets.mutex_); // Once the extension is set, it is immutable. However, it is possible // that someone has already "branded" this target with a different @@ -102,7 +102,7 @@ namespace build2 // If this target is from the src tree, use its out directory to find // the scope. // - return scopes.find (out_dir ()); + return ctx.scopes.find (out_dir ()); } const scope& target:: @@ -290,10 +290,36 @@ namespace build2 } } - // target_set + // include() // - target_set targets; + include_type + include_impl (action a, + const target& t, + const string& v, + const prerequisite& p, + const target* m) + { + context& ctx (t.ctx); + + include_type r (false); + + if (v == "false") r = include_type::excluded; + else if (v == "adhoc") r = include_type::adhoc; + else if (v == "true") r = include_type::normal; + else + fail << "invalid " << ctx.var_include->name << " variable value " + << "'" << v << "' specified for prerequisite " << p; + + // Call the meta-operation override, if any (currently used by dist). + // + if (auto f = ctx.current_mif->include) + r = f (a, t, prerequisite_member {p, m}, r); + return r; + } + + // target_set + // const target* target_set:: find (const target_key& k, tracer& trace) const { @@ -367,14 +393,14 @@ namespace build2 // We sometimes call insert() even if we expect to find an existing // target in order to keep the same code (see cc/search_library()). // - assert (phase != run_phase::execute); + assert (ctx.phase != run_phase::execute); optional e ( tt.fixed_extension != nullptr ? string (tt.fixed_extension (tk, nullptr /* root scope */)) : move (tk.ext)); - t = tt.factory (tt, move (dir), move (out), move (name)); + t = tt.factory (ctx, tt, move (dir), move (out), move (name)); // Re-lock for exclusive access. In the meantime, someone could have // inserted this target so emplace() below could return false, in which @@ -392,8 +418,8 @@ namespace build2 { t->ext_ = &i->first.ext; t->implied = implied; - t->state.data[0].target_ = t; - t->state.data[1].target_ = t; + t->state.inner.target_ = t; + t->state.outer.target_ = t; return pair (*t, move (ul)); } @@ -432,7 +458,7 @@ namespace build2 { // The implied flag can only be cleared during the load phase. // - assert (phase == run_phase::load); + assert (ctx.phase == run_phase::load); // Clear the implied flag. // @@ -538,7 +564,7 @@ namespace build2 // const mtime_target* t (this); - switch (phase) + switch (ctx.phase) { case run_phase::load: break; case run_phase::match: @@ -546,10 +572,11 @@ namespace build2 // Similar logic to matched_state_impl(). // const opstate& s (state[action () /* inner */]); - size_t o (s.task_count.load (memory_order_relaxed) - // Synchronized. - target::count_base ()); - if (o != target::offset_applied && o != target::offset_executed) + // Note: already synchronized. + size_t o (s.task_count.load (memory_order_relaxed) - ctx.count_base ()); + + if (o != offset_applied && o != offset_executed) break; } // Fall through. @@ -658,25 +685,25 @@ namespace build2 // const target* - target_search (const target&, const prerequisite_key& pk) + target_search (const target& t, const prerequisite_key& pk) { // The default behavior is to look for an existing target in the // prerequisite's directory scope. // - return search_existing_target (pk); + return search_existing_target (t.ctx, pk); } const target* - file_search (const target&, const prerequisite_key& pk) + file_search (const target& t, const prerequisite_key& pk) { // First see if there is an existing target. // - if (const target* t = search_existing_target (pk)) - return t; + if (const target* e = search_existing_target (t.ctx, pk)) + return e; // Then look for an existing file in the src tree. // - return search_existing_file (pk); + return search_existing_file (t.ctx, pk); } void @@ -753,17 +780,17 @@ namespace build2 }; static const target* - alias_search (const target&, const prerequisite_key& pk) + alias_search (const target& t, const prerequisite_key& pk) { // For an alias we don't want to silently create a target since it will do // nothing and it most likely not what the user intended. // - const target* t (search_existing_target (pk)); + const target* e (search_existing_target (t.ctx, pk)); - if (t == nullptr || t->implied) + if (e == nullptr || e->implied) fail << "no explicit target for " << pk; - return t; + return e; } const target_type alias::static_type @@ -847,16 +874,16 @@ namespace build2 } static const target* - dir_search (const target&, const prerequisite_key& pk) + dir_search (const target& t, const prerequisite_key& pk) { tracer trace ("dir_search"); // The first step is like in search_alias(): looks for an existing target. // - const target* t (search_existing_target (pk)); + const target* e (search_existing_target (t.ctx, pk)); - if (t != nullptr && !t->implied) - return t; + if (e != nullptr && !e->implied) + return e; // If not found (or is implied), then try to load the corresponding // buildfile (which would normally define this target). Failed that, see @@ -895,20 +922,20 @@ namespace build2 // bool retest (false); - assert (phase == run_phase::match); + assert (t.ctx.phase == run_phase::match); { // Switch the phase to load. // - phase_switch ps (run_phase::load); + phase_switch ps (t.ctx, run_phase::load); // This is subtle: while we were fussing around another thread may // have loaded the buildfile. So re-test now that we are in exclusive // phase. // - if (t == nullptr) - t = search_existing_target (pk); + if (e == nullptr) + e = search_existing_target (t.ctx, pk); - if (t != nullptr && !t->implied) + if (e != nullptr && !e->implied) retest = true; else { @@ -933,23 +960,23 @@ namespace build2 } else if (exists (src_base)) { - t = dir::search_implied (base, pk, trace); - retest = (t != nullptr); + e = dir::search_implied (base, pk, trace); + retest = (e != nullptr); } } } } - assert (phase == run_phase::match); + assert (t.ctx.phase == run_phase::match); // If we loaded/implied the buildfile, examine the target again. // if (retest) { - if (t == nullptr) - t = search_existing_target (pk); + if (e == nullptr) + e = search_existing_target (t.ctx, pk); - if (t != nullptr && !t->implied) - return t; + if (e != nullptr && !e->implied) + return e; } } @@ -1100,7 +1127,10 @@ namespace build2 // Note: we are guaranteed the scope is never NULL for prerequisites // (where out/dir could be relative and none of this will work). // + // @@ CTX TODO +#if 0 root = scopes.find (tk.out->empty () ? *tk.dir : *tk.out).root_scope (); +#endif if (root == nullptr || root->root_extra == nullptr) fail << "unable to determine extension for buildfile target " << tk; -- cgit v1.1