aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2021-08-04 06:45:02 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2021-08-04 06:45:02 +0200
commitea57c514dc169afb3ece21ff2e4c1d2ab0c47d6a (patch)
treee71ca9c5adf25aabb7ddb6a5e887415ecbfb36c0
parente767684a3462059852f7067a2297b1e18fdb3137 (diff)
Take into account file-base'ness in ad hoc buildscript recipes
-rw-r--r--libbuild2/adhoc-rule-buildscript.cxx27
-rw-r--r--libbuild2/adhoc-rule-buildscript.hxx13
-rw-r--r--libbuild2/adhoc-rule-cxx.cxx2
-rw-r--r--libbuild2/adhoc-rule-cxx.hxx5
-rw-r--r--libbuild2/build/script/parser.cxx10
-rw-r--r--libbuild2/build/script/parser.hxx12
-rw-r--r--libbuild2/build/script/parser.test.cxx2
-rw-r--r--libbuild2/parser.cxx12
-rw-r--r--libbuild2/parser.hxx1
-rw-r--r--libbuild2/rule.hxx11
10 files changed, 76 insertions, 19 deletions
diff --git a/libbuild2/adhoc-rule-buildscript.cxx b/libbuild2/adhoc-rule-buildscript.cxx
index c715ff2..61b4cb2 100644
--- a/libbuild2/adhoc-rule-buildscript.cxx
+++ b/libbuild2/adhoc-rule-buildscript.cxx
@@ -23,7 +23,10 @@ using namespace std;
namespace build2
{
bool adhoc_buildscript_rule::
- recipe_text (const scope& s, string&& t, attributes& as)
+ recipe_text (const scope& s,
+ const target_type& tt,
+ string&& t,
+ attributes& as)
{
// Handle and erase recipe-specific attributes.
//
@@ -52,11 +55,12 @@ namespace build2
}
checksum = sha256 (t).string ();
+ ttype = &tt;
istringstream is (move (t));
build::script::parser p (s.ctx);
- script = p.pre_parse (s, actions,
+ script = p.pre_parse (s, tt, actions,
is, loc.file, loc.line + 1,
move (diag), as.loc);
@@ -109,6 +113,25 @@ namespace build2
perform_update_id) != actions.end ();
}
+ bool adhoc_buildscript_rule::
+ match (action a, target& t, const string& h, match_extra& me) const
+ {
+ // We pre-parsed the script with the assumption it will be used on a
+ // non/file-based target. Note that this should not be possible with
+ // patterns.
+ //
+ if (pattern == nullptr)
+ {
+ if ((t.is_a<file> () != nullptr) != ttype->is_a<file> ())
+ {
+ fail (loc) << "incompatible target types used with shared recipe" <<
+ info << "all targets must be file-based or non-file-based";
+ }
+ }
+
+ return adhoc_rule::match (a, t, h, me);
+ }
+
recipe adhoc_buildscript_rule::
apply (action a, target& t, match_extra& me) const
{
diff --git a/libbuild2/adhoc-rule-buildscript.hxx b/libbuild2/adhoc-rule-buildscript.hxx
index 748a4c4..7f9c10a 100644
--- a/libbuild2/adhoc-rule-buildscript.hxx
+++ b/libbuild2/adhoc-rule-buildscript.hxx
@@ -25,6 +25,9 @@ namespace build2
virtual bool
reverse_fallback (action, const target_type&) const override;
+ virtual bool
+ match (action, target&, const string&, match_extra&) const override;
+
virtual recipe
apply (action, target&, match_extra&) const override;
@@ -42,7 +45,10 @@ namespace build2
: adhoc_rule (move (n), l, b) {}
virtual bool
- recipe_text (const scope&, string&&, attributes&) override;
+ recipe_text (const scope&,
+ const target_type&,
+ string&&,
+ attributes&) override;
virtual void
dump_attributes (ostream&) const override;
@@ -53,8 +59,9 @@ namespace build2
public:
using script_type = build::script::script;
- script_type script;
- string checksum; // Script text hash.
+ script_type script;
+ string checksum; // Script text hash.
+ const target_type* ttype; // First target/pattern type.
};
}
diff --git a/libbuild2/adhoc-rule-cxx.cxx b/libbuild2/adhoc-rule-cxx.cxx
index 83eeee0..83029ca 100644
--- a/libbuild2/adhoc-rule-cxx.cxx
+++ b/libbuild2/adhoc-rule-cxx.cxx
@@ -40,7 +40,7 @@ namespace build2
}
bool adhoc_cxx_rule::
- recipe_text (const scope&, string&& t, attributes&)
+ recipe_text (const scope&, const target_type&, string&& t, attributes&)
{
code = move (t);
return true;
diff --git a/libbuild2/adhoc-rule-cxx.hxx b/libbuild2/adhoc-rule-cxx.hxx
index 0ca6038..466c0e5 100644
--- a/libbuild2/adhoc-rule-cxx.hxx
+++ b/libbuild2/adhoc-rule-cxx.hxx
@@ -72,7 +72,10 @@ namespace build2
optional<string> sep);
virtual bool
- recipe_text (const scope&, string&&, attributes&) override;
+ recipe_text (const scope&,
+ const target_type&,
+ string&&,
+ attributes&) override;
virtual
~adhoc_cxx_rule () override;
diff --git a/libbuild2/build/script/parser.cxx b/libbuild2/build/script/parser.cxx
index b602880..43ec0d5 100644
--- a/libbuild2/build/script/parser.cxx
+++ b/libbuild2/build/script/parser.cxx
@@ -28,6 +28,7 @@ namespace build2
script parser::
pre_parse (const scope& bs,
+ const target_type& tt,
const small_vector<action, 1>& as,
istream& is, const path_name& pn, uint64_t line,
optional<string> diag, const location& diag_loc)
@@ -48,6 +49,7 @@ namespace build2
pbase_ = scope_->src_path_;
+ file_based_ = tt.is_a<file> ();
perform_update_ = find (as.begin (), as.end (), perform_update_id) !=
as.end ();
@@ -454,7 +456,7 @@ namespace build2
verify ();
// Verify that depdb is not used for anything other than
- // performing update.
+ // performing update on a file-based target.
//
assert (actions_ != nullptr);
@@ -466,6 +468,10 @@ namespace build2
<< ' ' << ctx.operation_table[a.operation ()];
}
+ if (!file_based_)
+ fail (l) << "'depdb' builtin can only be used for file-based "
+ << "targets";
+
if (diag_line_)
fail (diag_line_->second)
<< "'diag' builtin call before 'depdb' call" <<
@@ -1215,7 +1221,7 @@ namespace build2
void parser::
lookup_function (string&& name, const location& loc)
{
- if (perform_update_ && !impure_func_)
+ if (perform_update_ && file_based_ && !impure_func_)
{
const function_overloads* f (ctx.functions.find (name));
diff --git a/libbuild2/build/script/parser.hxx b/libbuild2/build/script/parser.hxx
index 948c381..e744c08 100644
--- a/libbuild2/build/script/parser.hxx
+++ b/libbuild2/build/script/parser.hxx
@@ -46,7 +46,9 @@ namespace build2
// we will end up with mismatching diagnostics.
//
script
- pre_parse (const scope&, const small_vector<action, 1>&,
+ pre_parse (const scope&,
+ const target_type&,
+ const small_vector<action, 1>&,
istream&, const path_name&, uint64_t line,
optional<string> diag_name, const location& diag_loc);
@@ -156,9 +158,11 @@ namespace build2
script* script_;
const small_vector<action, 1>* actions_; // Non-NULL during pre-parse.
- // True if performing update is one of the actions. Only set for the
- // pre-parse mode.
+ // True if this script is for file-based targets and performing update
+ // is one of the actions, respectively. Only set for the pre-parse
+ // mode.
//
+ bool file_based_;
bool perform_update_;
// Current low-verbosity script diagnostics and its weight.
@@ -220,7 +224,7 @@ namespace build2
lines depdb_preamble_; // Note: excludes 'depdb clear'.
// If present, the first impure function called in the body of the
- // script that performs update.
+ // script that performs update of a file-based target.
//
// Note that during the line pre-parsing we cannot tell if this is a
// body or depdb preamble line. Thus, if we encounter an impure
diff --git a/libbuild2/build/script/parser.test.cxx b/libbuild2/build/script/parser.test.cxx
index c9356a8..da23564 100644
--- a/libbuild2/build/script/parser.test.cxx
+++ b/libbuild2/build/script/parser.test.cxx
@@ -208,7 +208,7 @@ namespace build2
parser p (ctx);
path_name nm ("buildfile");
- script s (p.pre_parse (tt.base_scope (), acts,
+ script s (p.pre_parse (tt.base_scope (), tt.type (), acts,
cin, nm,
11 /* line */,
(m != mode::diag
diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx
index a6f6ae6..076bcf5 100644
--- a/libbuild2/parser.cxx
+++ b/libbuild2/parser.cxx
@@ -1104,7 +1104,7 @@ namespace build2
if (tt == type::percent || tt == type::multi_lcbrace)
{
small_vector<shared_ptr<adhoc_rule>, 1> recipes;
- parse_recipe (t, tt, token (t), recipes, rn);
+ parse_recipe (t, tt, token (t), recipes, ttype, rn);
for (shared_ptr<adhoc_rule>& pr: recipes)
{
@@ -1533,6 +1533,7 @@ namespace build2
parse_recipe (token& t, type& tt,
const token& start,
small_vector<shared_ptr<adhoc_rule>, 1>& recipes,
+ const target_type* ttype,
const string& name)
{
// Parse a recipe chain.
@@ -1581,6 +1582,7 @@ namespace build2
struct data
{
+ const target_type* ttype;
const string& name;
small_vector<shared_ptr<adhoc_rule>, 1>& recipes;
bool first;
@@ -1589,7 +1591,7 @@ namespace build2
attributes& as;
buildspec& bs;
const location& bsloc;
- } d {name, recipes, first, clean, i, as, bs, bsloc};
+ } d {ttype, name, recipes, first, clean, i, as, bs, bsloc};
// Note that this function must be called at most once per iteration.
//
@@ -1797,7 +1799,11 @@ namespace build2
// Set the recipe text.
//
- if (ar.recipe_text (*scope_, move (t.value), d.as))
+ if (ar.recipe_text (
+ *scope_,
+ d.ttype != nullptr ? *d.ttype : target_->type (),
+ move (t.value),
+ d.as))
d.clean = true;
// Verify we have no unhandled attributes.
diff --git a/libbuild2/parser.hxx b/libbuild2/parser.hxx
index 1095eeb..bc5bf4b 100644
--- a/libbuild2/parser.hxx
+++ b/libbuild2/parser.hxx
@@ -139,6 +139,7 @@ namespace build2
parse_recipe (token&, token_type&,
const token&,
small_vector<shared_ptr<adhoc_rule>, 1>&,
+ const target_type* = nullptr,
const string& = {});
// Ad hoc target names inside < ... >.
diff --git a/libbuild2/rule.hxx b/libbuild2/rule.hxx
index ad6b51c..3eb7775 100644
--- a/libbuild2/rule.hxx
+++ b/libbuild2/rule.hxx
@@ -173,13 +173,20 @@ namespace build2
// Set the rule text, handle any recipe-specific attributes, and return
// true if the recipe builds anything in the build/recipes/ directory and
- // therefore requires cleanup. Scope is the scope of the recipe.
+ // therefore requires cleanup.
+ //
+ // Scope is the scope of the recipe and target type is the type of the
+ // first target (for ad hoc recipe) or primary group member type (for ad
+ // hoc pattern rule). The idea is that an implementation may make certain
+ // assumptions based on the first target type (e.g., file vs non-file
+ // based) in which case it should also enforce (e.g., in match()) that any
+ // other targets that share this recipe are also of suitable type.
//
// Note also that this function is called after the actions member has
// been populated.
//
virtual bool
- recipe_text (const scope&, string&&, attributes&) = 0;
+ recipe_text (const scope&, const target_type&, string&&, attributes&) = 0;
public:
// Some of the operations come in compensating pairs, such as update and