aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/build
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2023-05-30 05:51:23 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2023-05-30 11:23:09 +0200
commitde2daaa41ec6064181e6b9e73a34c32cd0008242 (patch)
tree4978e5c28aae5ffbff3198e7fda54903ac09f92b /libbuild2/build
parent74b8dd5bf57dd351b844c6fe407c60f18043d597 (diff)
Store dynamic group member types in depdb, use in clean
Diffstat (limited to 'libbuild2/build')
-rw-r--r--libbuild2/build/script/parser.cxx85
-rw-r--r--libbuild2/build/script/parser.hxx20
2 files changed, 89 insertions, 16 deletions
diff --git a/libbuild2/build/script/parser.cxx b/libbuild2/build/script/parser.cxx
index c6eb9cd..3814305 100644
--- a/libbuild2/build/script/parser.cxx
+++ b/libbuild2/build/script/parser.cxx
@@ -1291,7 +1291,7 @@ namespace build2
environment& e, const script& s, runner& r,
lines_iterator begin, lines_iterator end,
depdb& dd,
- paths* dyn_targets,
+ dynamic_targets* dyn_targets,
bool* update,
optional<timestamp> mt,
bool* deferred_failure,
@@ -1320,7 +1320,7 @@ namespace build2
const script& scr;
depdb& dd;
- paths* dyn_targets;
+ dynamic_targets* dyn_targets;
bool* update;
bool* deferred_failure;
optional<timestamp> mt;
@@ -1647,7 +1647,7 @@ namespace build2
size_t li, const location& ll,
action a, const scope& bs, target& t,
depdb& dd,
- paths& dyn_targets,
+ dynamic_targets& dyn_targets,
bool& update,
timestamp mt,
bool& deferred_failure,
@@ -2647,10 +2647,25 @@ namespace build2
break;
}
- if (l->empty ()) // Done with target.
+ if (l->empty ()) // Done with targets.
break;
- dyn_targets.push_back (path (move (*l)));
+ // Split into type and path (see below for background).
+ //
+ size_t p (l->find (' '));
+ if (p == string::npos || // Invalid format.
+ p == 0 || // Empty type.
+ p + 1 == l->size ()) // Empty path.
+ {
+ dd.write (); // Invalidate this line.
+ restart = true;
+ break;
+ }
+
+ string t (*l, 0, p);
+ l->erase (0, p + 1);
+
+ dyn_targets.emplace_back (move (t), path (move (*l)));
}
}
@@ -2861,7 +2876,9 @@ namespace build2
<< "directory " << rs.out_path ();
}
- dyn_targets.push_back (move (f));
+ // Note: type is resolved later.
+ //
+ dyn_targets.emplace_back (string (), move (f));
}
continue;
@@ -2969,7 +2986,9 @@ namespace build2
<< rs.out_path ();
}
- dyn_targets.push_back (move (f));
+ // Note: type is resolved later.
+ //
+ dyn_targets.emplace_back (string (), move (f));
}
else
{
@@ -3099,11 +3118,23 @@ namespace build2
};
}
- for (const path& f: dyn_targets)
+ // Unlike for prerequisites, for targets we store in depdb both the
+ // resolved target type and path. The target type is used in clean
+ // (see adhoc_rule_buildscript::apply()) where we cannot easily get
+ // hold of all the dyndep options to map the path to target type.
+ // So the format of the target line is:
+ //
+ // <type> <path>
+ //
+ string l; // Reuse the buffer.
+ for (dynamic_target& dt: dyn_targets)
{
+ const path& f (dt.path);
+
// Note that this logic should be consistent with what we have in
// adhoc_buildscript_rule::apply() for perform_clean.
//
+ const build2::file* ft (nullptr);
if (g != nullptr)
{
pair<const build2::file&, bool> r (
@@ -3117,12 +3148,17 @@ namespace build2
// each update.
//
if (!r.second)
+ {
+ dt.type.clear (); // Static indicator.
continue;
+ }
+
+ ft = &r.first;
// Note: we only currently support dynamic file members so it
// will be file if first.
//
- g->members.push_back (&r.first);
+ g->members.push_back (ft);
}
else
{
@@ -3137,14 +3173,41 @@ namespace build2
// already a member (think `b update && b clean update`).
//
if (!r.second && r.first.decl == target_decl::real)
+ {
+ dt.type.clear (); // Static indicator.
continue;
+ }
+
+ ft = &r.first;
if (dts)
- dts->push_back (&r.first);
+ dts->push_back (ft);
+ }
+
+ const char* tn (ft->type ().name);
+
+ if (dt.type.empty ())
+ dt.type = tn;
+ else if (dt.type != tn)
+ {
+ // This can, for example, happen if the user changed the
+ // extension to target type mapping. Say swapped extension
+ // variable values of two target types.
+ //
+ fail << "mapping of " << what_tgt << " target path " << f
+ << " to target type has changed" <<
+ info << "previously mapped to " << dt.type << "{}" <<
+ info << "now mapped to " << tn << "{}" <<
+ info << "perform from scratch rebuild of " << t;
}
if (!cache)
- dd.expect (f);
+ {
+ l = dt.type;
+ l += ' ';
+ l += f.string ();
+ dd.expect (l);
+ }
}
// Add the dynamic targets terminating blank line.
diff --git a/libbuild2/build/script/parser.hxx b/libbuild2/build/script/parser.hxx
index f975194..ce550fc 100644
--- a/libbuild2/build/script/parser.hxx
+++ b/libbuild2/build/script/parser.hxx
@@ -121,12 +121,20 @@ namespace build2
dd);
}
+ struct dynamic_target
+ {
+ string type; // Target type name (absent if static member).
+ build2::path path;
+ };
+
+ using dynamic_targets = vector<dynamic_target>;
+
void
execute_depdb_preamble_dyndep (
action a, const scope& base, target& t,
environment& e, const script& s, runner& r,
depdb& dd,
- paths& dyn_targets,
+ dynamic_targets& dyn_targets,
bool& update, timestamp mt, bool& deferred_failure)
{
exec_depdb_preamble (
@@ -162,11 +170,13 @@ namespace build2
environment& e, const script& s, runner& r,
depdb& dd, bool& update, timestamp mt)
{
+ // Dummies.
+ //
// This is getting a bit ugly (we also don't really need to pass
// depdb here). One day we will find a better way...
//
- paths dyn_targets;
- bool deferred_failure; // Dymmy.
+ dynamic_targets dyn_targets;
+ bool deferred_failure;
dyndep_byproduct v;
exec_depdb_preamble (
@@ -228,7 +238,7 @@ namespace build2
environment&, const script&, runner&,
lines_iterator begin, lines_iterator end,
depdb&,
- paths* dyn_targets = nullptr,
+ dynamic_targets* dyn_targets = nullptr,
bool* update = nullptr,
optional<timestamp> mt = nullopt,
bool* deferred_failure = nullptr,
@@ -241,7 +251,7 @@ namespace build2
size_t line_index, const location&,
action, const scope& base, target&,
depdb&,
- paths& dyn_targets,
+ dynamic_targets& dyn_targets,
bool& update,
timestamp,
bool& deferred_failure,