aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/algorithm29
-rw-r--r--build2/algorithm.cxx16
-rw-r--r--build2/algorithm.ixx31
-rw-r--r--build2/test/init.cxx3
-rw-r--r--build2/test/rule10
-rw-r--r--build2/test/rule.cxx74
-rw-r--r--old-tests/test/generated/build/bootstrap.build6
7 files changed, 102 insertions, 67 deletions
diff --git a/build2/algorithm b/build2/algorithm
index 4c12148..8d8889d 100644
--- a/build2/algorithm
+++ b/build2/algorithm
@@ -45,7 +45,8 @@ namespace build2
const dir_path& out,
const string& name,
const string* ext,
- scope*);
+ scope*,
+ const string* proj = nullptr);
// As above but specify the target type as template argument.
//
@@ -57,32 +58,30 @@ namespace build2
const string* ext,
scope*);
- // Search for a target identified by the name. The semantics
- // is "as if" we first created a prerequisite based on this
- // name in exactly the same way as the parser would and then
- // searched based on this prerequisite.
+ // Search for a target identified by the name. The semantics is "as if" we
+ // first created a prerequisite based on this name in exactly the same way
+ // as the parser would and then searched based on this prerequisite.
//
target&
search (name, scope&);
- // Match and apply a rule to the action/target with ambiguity
- // detection. Increment the target's dependents count, which
- // means that you should call this function with the intent
- // to also call execute(). In case of optimizations that would
- // avoid calling execute(), call unmatch() to indicate this.
+ // Match and apply a rule to the action/target with ambiguity detection.
+ // Increment the target's dependents count, which means that you should call
+ // this function with the intent to also call execute(). In case of
+ // optimizations that would avoid calling execute(), call unmatch() to
+ // indicate this.
//
void
match (action, target&);
- // Note that calling this function only makes sense if the
- // target itself doesn't have its own dependents.
+ // Note that calling this function only makes sense if the target itself
+ // doesn't have its own dependents.
//
void
unmatch (action, target&);
- // Match (but do not apply) a rule to the action/target with
- // ambiguity detection. Note that this function does not touch
- // the dependents count.
+ // Match (but do not apply) a rule to the action/target with ambiguity
+ // detection. Note that this function does not touch the dependents count.
//
void
match_only (action, target&);
diff --git a/build2/algorithm.cxx b/build2/algorithm.cxx
index dbdf81c..7a3b773 100644
--- a/build2/algorithm.cxx
+++ b/build2/algorithm.cxx
@@ -49,7 +49,7 @@ namespace build2
// @@ OUT: for now we assume the prerequisite's out is undetermined.
// Would need to pass a pair of names.
//
- return search (*tt, n.dir, dir_path (), n.value, e, &s);
+ return search (*tt, n.dir, dir_path (), n.value, e, &s, n.proj);
}
pair<const rule*, match_result>
@@ -275,15 +275,13 @@ namespace build2
}
void
- search_and_match_prerequisites (action a, target& t, const dir_path& d)
+ search_and_match_prerequisites (action a, target& t, scope* s)
{
- const bool e (d.empty ());
-
for (prerequisite p: group_prerequisites (t))
{
target& pt (search (p));
- if (e || pt.dir.sub (d))
+ if (s == nullptr || pt.in (*s))
{
match (a, pt);
t.prerequisite_targets.push_back (&pt);
@@ -292,17 +290,13 @@ namespace build2
}
void
- search_and_match_prerequisite_members (action a,
- target& t,
- const dir_path& d)
+ search_and_match_prerequisite_members (action a, target& t, scope* s)
{
- const bool e (d.empty ());
-
for (prerequisite_member p: group_prerequisite_members (a, t))
{
target& pt (p.search ());
- if (e || pt.dir.sub (d))
+ if (s == nullptr || pt.in (*s))
{
match (a, pt);
t.prerequisite_targets.push_back (&pt);
diff --git a/build2/algorithm.ixx b/build2/algorithm.ixx
index b2c4941..ac81dbe 100644
--- a/build2/algorithm.ixx
+++ b/build2/algorithm.ixx
@@ -31,10 +31,11 @@ namespace build2
const dir_path& out,
const string& name,
const string* ext,
- scope* scope)
+ scope* scope,
+ const string* proj)
{
return search (
- prerequisite_key {nullptr, {&type, &dir, &out, &name, ext}, scope});
+ prerequisite_key {proj, {&type, &dir, &out, &name, ext}, scope});
}
template <typename T>
@@ -99,28 +100,44 @@ namespace build2
return r.members != nullptr ? r : resolve_group_members_impl (a, g);
}
+ void
+ search_and_match_prerequisites (action, target&, scope*);
+
+ void
+ search_and_match_prerequisite_members (action, target&, scope*);
+
inline void
search_and_match_prerequisites (action a, target& t)
{
search_and_match_prerequisites (
a,
t,
- (a.operation () != clean_id
- ? dir_path ()
- : t.root_scope ().out_path ()));
+ (a.operation () != clean_id ? nullptr : &t.root_scope ()));
}
inline void
search_and_match_prerequisite_members (action a, target& t)
{
if (a.operation () != clean_id)
- search_and_match_prerequisite_members (a, t, dir_path ());
+ search_and_match_prerequisite_members (a, t, nullptr);
else
// Note that here we don't iterate over members even for see-
// through groups since the group target should clean eveything
// up. A bit of an optimization.
//
- search_and_match_prerequisites (a, t, t.root_scope ().out_path ());
+ search_and_match_prerequisites (a, t, &t.root_scope ());
+ }
+
+ inline void
+ search_and_match_prerequisites (action a, target& t, scope& s)
+ {
+ search_and_match_prerequisites (a, t, &s);
+ }
+
+ inline void
+ search_and_match_prerequisite_members (action a, target& t, scope& s)
+ {
+ search_and_match_prerequisite_members (a, t, &s);
}
target_state
diff --git a/build2/test/init.cxx b/build2/test/init.cxx
index 098718b..21a6612 100644
--- a/build2/test/init.cxx
+++ b/build2/test/init.cxx
@@ -21,6 +21,7 @@ namespace build2
namespace test
{
static rule rule_;
+ static alias_rule alias_rule_;
void
boot (scope& rs, const location&, unique_ptr<module_base>&)
@@ -105,7 +106,7 @@ namespace build2
// Register our test running rule.
//
r.insert<target> (perform_test_id, "test", rule_);
- r.insert<alias> (perform_test_id, "test", rule_); // Override generic.
+ r.insert<alias> (perform_test_id, "test", alias_rule_);
// Register our rule for the dist meta-operation. We need to do this
// because we may have ad hoc prerequisites (test input/output files)
diff --git a/build2/test/rule b/build2/test/rule
index b915ea7..d1790e0 100644
--- a/build2/test/rule
+++ b/build2/test/rule
@@ -30,6 +30,16 @@ namespace build2
static target_state
perform_test (action, target&);
};
+
+ class alias_rule: public rule
+ {
+ public:
+ virtual recipe
+ apply (action, target&) const override;
+
+ static target_state
+ perform_test (action, target&);
+ };
}
}
diff --git a/build2/test/rule.cxx b/build2/test/rule.cxx
index a8adb9e..d313925 100644
--- a/build2/test/rule.cxx
+++ b/build2/test/rule.cxx
@@ -147,47 +147,44 @@ namespace build2
return mr;
}
- recipe rule::
+ recipe alias_rule::
apply (action a, target& t) const
{
- tracer trace ("test::rule::apply");
-
match_data md (move (t.data<match_data> ()));
t.clear_data (); // In case delegated-to rule also uses aux storage.
- // The alias case is special so handle it first.
+ // We can only test an alias via a testscript, not a simple test.
//
- if (t.is_a<alias> ())
- {
- // We can only test an alias via a testscript, not a simple test.
- //
- assert (!md.test || md.script);
+ assert (!md.test || md.script);
- // Find the actual alias rule.
- //
- recipe d (match_delegate (a, t, *this).first);
+ // If this is the update pre-operation then simply redirect to the
+ // standard alias rule.
+ //
+ if (a.operation () == update_id)
+ return match_delegate (a, t, *this).first;
+
+ // For the test operation we have to implement our own search and match
+ // because we need to ignore prerequisites that are outside of our
+ // project. They can be from projects that don't use the test module
+ // (and thus won't have a suitable rule). Or they can be from no project
+ // at all (e.g., installed). Also, generally, not testing stuff that's
+ // not ours seems right. Note that we still want to make sure they are
+ // up to date (via the above delegate) since our tests might use them.
+ //
+ search_and_match_prerequisites (a, t, t.root_scope ());
- // If not a test or this is the update pre-operation then simply
- // redirect to the alias rule.
- //
- if (!md.test || a.operation () == update_id)
- return d;
+ // If not a test then also redirect to the alias rule.
+ //
+ return md.test ? perform_test : default_recipe;
+ }
- // Otherwise, we have to combine the two recipes. Note that we will
- // reuse the prerequisite_targets prepared by the alias rule.
- //
- // Note: this most likely won't fit the small object optimization. We
- // could check if the target is a function pointer (which it will most
- // likely be) and return an optimized lambda in this case.
- //
- return [dr = move (d)] (action a, target& t) -> target_state
- {
- // Run the alias recipe first then the test.
- //
- target_state r (execute_delegate (dr, a, t));
- return r |= perform_script (a, t);
- };
- }
+ recipe rule::
+ apply (action a, target& t) const
+ {
+ tracer trace ("test::rule::apply");
+
+ match_data md (move (t.data<match_data> ()));
+ t.clear_data (); // In case delegated-to rule also uses aux storage.
if (!md.test)
return noop_recipe;
@@ -593,5 +590,18 @@ namespace build2
return target_state::changed;
}
+
+ target_state alias_rule::
+ perform_test (action a, target& t)
+ {
+ // Run the alias recipe first then the test.
+ //
+ target_state r (execute_prerequisites (a, t));
+
+ // Note that we reuse the prerequisite_targets prepared by the standard
+ // search and match.
+ //
+ return r |= perform_script (a, t);
+ }
}
}
diff --git a/old-tests/test/generated/build/bootstrap.build b/old-tests/test/generated/build/bootstrap.build
index 5428eb8..1b04c1d 100644
--- a/old-tests/test/generated/build/bootstrap.build
+++ b/old-tests/test/generated/build/bootstrap.build
@@ -1,4 +1,8 @@
-project = test-generated
+project = generated
amalgamation = # Disabled.
+
+dist.package = $project
+
using config
using test
+using dist