From 3925bdc7708abd4387a5ffb0db60bc57098f2669 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 16 Jan 2024 08:07:04 +0200 Subject: Add add_adhoc_member_identity(), use to fix ad hoc pattern rule logic --- libbuild2/adhoc-rule-regex-pattern.cxx | 12 +++++----- libbuild2/algorithm.cxx | 43 ++++++++++++++++++++++++++++++++++ libbuild2/algorithm.hxx | 26 ++++++++++++++++++-- 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/libbuild2/adhoc-rule-regex-pattern.cxx b/libbuild2/adhoc-rule-regex-pattern.cxx index cd8c241..9101000 100644 --- a/libbuild2/adhoc-rule-regex-pattern.cxx +++ b/libbuild2/adhoc-rule-regex-pattern.cxx @@ -366,7 +366,9 @@ namespace build2 // @@ TODO: save location in constructor? // - optional ext (target::split_name (n, location ())); + location loc; + + optional ext (target::split_name (n, loc)); if (g != nullptr) { @@ -425,16 +427,14 @@ namespace build2 } else { - // @@ TODO: currently this uses type as the ad hoc member identity. - // Use inject_adhoc_group_member() variant? - // - add_adhoc_member ( + add_adhoc_member_identity ( t, e.type, move (d), dir_path (), // Always in out. move (n), - move (ext)); + move (ext), + loc); } } } diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx index df8e650..2abf391 100644 --- a/libbuild2/algorithm.cxx +++ b/libbuild2/algorithm.cxx @@ -400,6 +400,49 @@ namespace build2 return *m; }; + pair + add_adhoc_member_identity (target& t, + const target_type& tt, + dir_path dir, + dir_path out, + string n, + optional ext, + const location& loc) + { + // NOTE: see similar code in parser::enter_adhoc_members(). + + tracer trace ("add_adhoc_member_identity"); + + pair r ( + t.ctx.targets.insert_locked (tt, + move (dir), + move (out), + move (n), + move (ext), + target_decl::implied, + trace, + true /* skip_find */)); + target& m (r.first); + + // Add as an ad hoc member at the end of the chain skipping duplicates. + // + const_ptr* mp (&t.adhoc_member); + for (; *mp != nullptr; mp = &(*mp)->adhoc_member) + { + if (*mp == &m) + return {m, false}; + } + + if (!r.second) + fail (loc) << "target " << m << " already exists and cannot be made " + << "ad hoc member of group " << t; + + m.group = &t; + *mp = &m; + + return {m, true}; + } + static bool trace_target (const target& t, const vector& ns) { diff --git a/libbuild2/algorithm.hxx b/libbuild2/algorithm.hxx index 2c57b74..dd5d367 100644 --- a/libbuild2/algorithm.hxx +++ b/libbuild2/algorithm.hxx @@ -274,11 +274,15 @@ namespace build2 // // Note that here and in find_adhoc_member() below (as well as in // perform_clean_extra()) we use target type (as opposed to, say, type and - // name) as the member's identity. This fits our current needs where every + // name) as the member's identity. This fits common needs where every // (rule-managed) ad hoc member has a unique target type and we have no need // for multiple members of the same type. This also allows us to support // things like changing the ad hoc member name by declaring it in a - // buildfile. + // buildfile. However, if this semantics is not appropriate, use the + // add_adhoc_member_identity() version below. + // + // Note that the current implementation asserts if the member target already + // exists but is not already a member. // LIBBUILD2_SYMEXPORT target& add_adhoc_member (target&, @@ -309,6 +313,24 @@ namespace build2 return add_adhoc_member (g, T::static_type, e); } + // Add an ad hoc member using the member identity (as opposed to only its + // type as in add_adhoc_member() above) to suppress diplicates. See also + // dyndep::inject_adhoc_group_member(). + // + // Return the member target as well as an indication of whether it was added + // or was already a member. Fail if the member target already exists but is + // not a member since it's not possible to make it a member in an MT-safe + // manner. + // + LIBBUILD2_SYMEXPORT pair + add_adhoc_member_identity (target&, + const target_type&, + dir_path dir, + dir_path out, + string name, + optional ext, + const location& = location ()); + // Find an ad hoc member of the specified target type returning NULL if not // found. // -- cgit v1.1