From af55babfc0c01abbd0a074b0d2ed86598d6bf628 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 1 Dec 2022 10:01:24 +0200 Subject: Fix corner case in distributing via obj{}, libul{} groups --- libbuild2/bin/init.cxx | 12 ++++++++ libbuild2/bin/rule.cxx | 71 +++++++++++++++++++++++++++++++++++++++++++++++- libbuild2/bin/rule.hxx | 14 ++++++++-- libbuild2/bin/target.hxx | 8 ++++++ 4 files changed, 102 insertions(+), 3 deletions(-) diff --git a/libbuild2/bin/init.cxx b/libbuild2/bin/init.cxx index d7c5b5a..78119cb 100644 --- a/libbuild2/bin/init.cxx +++ b/libbuild2/bin/init.cxx @@ -605,6 +605,18 @@ namespace build2 if (rs.find_module ("dist")) { + // Note that without custom dist rules in setups along the follwing + // lines the source file will be unreachable by dist: + // + // lib{foo}: obj{foo} + // obja{foo}: cxx{foo} + // objs{foo}: cxx{foo} + // + r.insert (dist_id, 0, "bin.obj", obj_); + r.insert (dist_id, 0, "bin.bmi", obj_); + r.insert (dist_id, 0, "bin.hbmi", obj_); + r.insert (dist_id, 0, "bin.libul", libul_); + r.insert (dist_id, 0, "bin.lib", lib_); } } diff --git a/libbuild2/bin/rule.cxx b/libbuild2/bin/rule.cxx index 27c9b4b..c7147bf 100644 --- a/libbuild2/bin/rule.cxx +++ b/libbuild2/bin/rule.cxx @@ -17,11 +17,29 @@ namespace build2 { namespace bin { + // Search for an existing (declared real) member and match it if found. + // + static void + dist_match (action a, target& t, const target_type& tt) + { + if (const target* m = search_existing (t.ctx, tt, t.dir, t.out, t.name)) + { + // Only a real target declaration can have prerequisites (which is + // the reason we are doing this). + // + if (m->decl == target_decl::real) + match_sync (a, *m); + } + } + // obj_rule // bool obj_rule:: match (action a, target& t) const { + if (a.meta_operation () == dist_id) + return true; + const char* n (t.dynamic_type->name); // Ignore derived type. fail << diag_doing (a, t) << " target group" << @@ -30,7 +48,43 @@ namespace build2 } recipe obj_rule:: - apply (action, target&) const {return empty_recipe;} + apply (action a, target& t) const + { + // We only get here for dist. + // + const target_type* ett (nullptr); + const target_type* att (nullptr); + const target_type* stt (nullptr); + + if (t.is_a ()) + { + ett = &obje::static_type; + att = &obja::static_type; + stt = &objs::static_type; + } + else if (t.is_a ()) + { + ett = &bmie::static_type; + att = &bmia::static_type; + stt = &bmis::static_type; + } + else if (t.is_a ()) + { + ett = &hbmie::static_type; + att = &hbmia::static_type; + stt = &hbmis::static_type; + } + else + assert (false); + + dist_match (a, t, *ett); + dist_match (a, t, *att); + dist_match (a, t, *stt); + + // Delegate to the default dist rule to match prerequisites. + // + return dist::rule::apply (a, t); + } // libul_rule // @@ -43,6 +97,16 @@ namespace build2 recipe libul_rule:: apply (action a, target& t) const { + if (a.meta_operation () == dist_id) + { + dist_match (a, t, libua::static_type); + dist_match (a, t, libus::static_type); + + // Delegate to the default dist rule to match prerequisites. + // + return dist::rule::apply (a, t); + } + // Pick one of the members. First looking for the one already matched. // const target* m (nullptr); @@ -113,6 +177,11 @@ namespace build2 // The whole logic is pretty much as if we had our two group members as // our prerequisites. // + // Note also that unlike the obj and libul rules above, we don't need to + // delegate to the default dist rule since any group prerequisites will be + // matched by one of the members (the key difference here is that unlike + // those rules, we insert and match members unconditionally). + // bool lib_rule:: match (action a, target& xt) const { diff --git a/libbuild2/bin/rule.hxx b/libbuild2/bin/rule.hxx index b403433..9dd1d14 100644 --- a/libbuild2/bin/rule.hxx +++ b/libbuild2/bin/rule.hxx @@ -9,6 +9,8 @@ #include +#include + #include namespace build2 @@ -18,7 +20,10 @@ namespace build2 // "Fail rule" for obj{} and [h]bmi{} that issues diagnostics if someone // tries to build these groups directly. // - class obj_rule: public simple_rule + // Note that for dist it acts as a pass-through to all existing (declared) + // members. + // + class obj_rule: public dist::rule { public: obj_rule () {} @@ -39,7 +44,10 @@ namespace build2 // falling back to making our own based on bin.lib and bin.exe.lib. Note // that for update this rule always returns target_state::unchanged. // - class libul_rule: public simple_rule + // Note also that for dist it acts as a pass-through to all existing + // (declared) members. + // + class libul_rule: public dist::rule { public: explicit @@ -54,6 +62,8 @@ namespace build2 // Pass-through to group members rule, similar to alias. // + // Note that for dist it always passes to both members. + // class LIBBUILD2_BIN_SYMEXPORT lib_rule: public simple_rule { public: diff --git a/libbuild2/bin/target.hxx b/libbuild2/bin/target.hxx index 3ecabce..9685e39 100644 --- a/libbuild2/bin/target.hxx +++ b/libbuild2/bin/target.hxx @@ -71,6 +71,8 @@ namespace build2 static const target_type static_type; }; + // Note: this is a "choice" target group. + // class LIBBUILD2_BIN_SYMEXPORT obj: public target { public: @@ -219,6 +221,8 @@ namespace build2 static const target_type static_type; }; + // Note: this is a "choice" target group (similar to obj{}). + // class LIBBUILD2_BIN_SYMEXPORT bmi: public target { public: @@ -232,6 +236,8 @@ namespace build2 static const target_type static_type; }; + // Note: this is a "choice" target group (similar to bmi{} and obj{}). + // class LIBBUILD2_BIN_SYMEXPORT hbmi: public target { public: @@ -340,6 +346,8 @@ namespace build2 static const target_type static_type; }; + // Note: this is a "choice" target group. + // // @@ Ideally this shouldn't derive from mtime_target (via libx). Maybe // get rid of libx? // -- cgit v1.1