aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/adhoc-rule-cxx.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/adhoc-rule-cxx.cxx')
-rw-r--r--libbuild2/adhoc-rule-cxx.cxx109
1 files changed, 98 insertions, 11 deletions
diff --git a/libbuild2/adhoc-rule-cxx.cxx b/libbuild2/adhoc-rule-cxx.cxx
index dc795df..8a91809 100644
--- a/libbuild2/adhoc-rule-cxx.cxx
+++ b/libbuild2/adhoc-rule-cxx.cxx
@@ -25,6 +25,13 @@ namespace build2
return true;
}
+ recipe cxx_rule_v1::
+ apply (action, target&) const
+ {
+ assert (false); // This (or the match_extra version) must be overriden.
+ return empty_recipe;
+ }
+
// adhoc_cxx_rule
//
adhoc_cxx_rule::
@@ -95,8 +102,10 @@ namespace build2
load_module_library (const path& lib, const string& sym, string& err);
bool adhoc_cxx_rule::
- match (action a, target& t, const string& hint, match_extra& me) const
+ match (action a, target& xt, const string& hint, match_extra& me) const
{
+ const target& t (xt); // See adhoc_rule::match() for background.
+
if (pattern != nullptr && !pattern->match (a, t, hint, me))
return false;
@@ -302,9 +311,9 @@ namespace build2
//
auto_thread_env penv (nullptr);
context& ctx (*t.ctx.module_context);
- scheduler::phase_guard pg (ctx.sched);
+ scheduler::phase_guard pg (*ctx.sched);
- const uint16_t verbosity (3); // Project creation command verbosity.
+ uint16_t verbosity (3); // Project creation command verbosity.
// Project and location signatures.
//
@@ -326,6 +335,17 @@ namespace build2
if (!create && (create = !check_sig (bf, psig)))
rmdir_r (ctx, pd, false, verbosity); // Never dry-run.
+ auto diag = [verbosity] (const path& f)
+ {
+ if (verb >= verbosity)
+ {
+ if (verb >= 2)
+ text << "cat >" << f;
+ else if (verb)
+ print_diag ("save", f);
+ }
+ };
+
path of;
ofdstream ofs;
@@ -338,6 +358,46 @@ namespace build2
// This way the configuration will be always in sync with ~build2
// and we can update the recipe manually (e.g., for debugging).
//
+ // Should we use ~build2 or ~build2-no-warnings? This case is similar
+ // to private host/module configurations in that the user doesn't have
+ // any control over the options used, etc. So it would be natural to
+ // use the no-warnings variant. However, unlike with tools/modules
+ // which can be configured in a user-created configuration (and which
+ // will normally be the case during development), for recipes it's
+ // always this automatically-create configuration. It feels like the
+ // best we can do is use ~build2-no-warnings by default but switch to
+ // ~build2 if the project is configured for development
+ // (config.<project>.develop).
+ //
+ string cfg;
+ {
+ const project_name& pn (named_project (rs));
+
+ if (!pn.empty ())
+ {
+ string var ("config." + pn.variable () + ".develop");
+
+ if (lookup l = rs[var])
+ {
+ // The value could be untyped if the project didn't declare this
+ // variable. Let's handle that case gracefully.
+ //
+ try
+ {
+ if (convert<bool> (*l))
+ cfg = "~build2";
+ }
+ catch (const invalid_argument& e)
+ {
+ fail << "invalid " << var << " value: " << e;
+ }
+ }
+ }
+
+ if (cfg.empty ())
+ cfg = "~build2-no-warnings";
+ }
+
create_project (
pd,
dir_path (), /* amalgamation */
@@ -346,7 +406,7 @@ namespace build2
{"cxx."}, /* root_modules */
"", /* root_post */
string ("config"), /* config_module */
- string ("config.config.load = ~build2"), /* config_file */
+ "config.config.load = " + cfg, /* config_file */
false, /* buildfile */
"build2 core", /* who */
verbosity); /* verbosity */
@@ -356,8 +416,7 @@ namespace build2
//
of = path (pd / "rule.cxx");
- if (verb >= verbosity)
- text << (verb >= 2 ? "cat >" : "save ") << of;
+ diag (of);
ofs.open (of);
@@ -377,6 +436,8 @@ namespace build2
<< "#include <libbuild2/depdb.hxx>" << '\n'
<< "#include <libbuild2/scope.hxx>" << '\n'
<< "#include <libbuild2/target.hxx>" << '\n'
+ << "#include <libbuild2/recipe.hxx>" << '\n'
+ << "#include <libbuild2/dyndep.hxx>" << '\n'
<< "#include <libbuild2/context.hxx>" << '\n'
<< "#include <libbuild2/variable.hxx>" << '\n'
<< "#include <libbuild2/algorithm.hxx>" << '\n'
@@ -486,8 +547,7 @@ namespace build2
//
of = bf;
- if (verb >= verbosity)
- text << (verb >= 2 ? "cat >" : "save ") << of;
+ diag (of);
ofs.open (of);
@@ -559,8 +619,7 @@ namespace build2
entry_time et (file_time (of));
- if (verb >= verbosity)
- text << (verb >= 2 ? "cat >" : "save ") << of;
+ diag (of);
ofs.open (of);
@@ -665,13 +724,41 @@ namespace build2
}
}
- return impl->match (a, t, hint, me);
+ return impl->match (a, xt, hint, me);
}
#endif // BUILD2_BOOTSTRAP || LIBBUILD2_STATIC_BUILD
recipe adhoc_cxx_rule::
apply (action a, target& t, match_extra& me) const
{
+ // Handle matching explicit group member (see adhoc_rule::match() for
+ // background).
+ //
+ if (const group* g = (t.group != nullptr
+ ? t.group->is_a<group> ()
+ : nullptr))
+ {
+ // @@ Hm, this looks very similar to how we handle ad hoc group members.
+ // Shouldn't impl be given a chance to translate options or some
+ // such?
+ //
+ match_sync (a, *g, 0 /* options */);
+ return group_recipe; // Execute the group's recipe.
+ }
+
+ // Note that while we probably could call pattern's apply_group_members()
+ // here, apply_group_prerequisites() is normally called after adding
+ // prerequisites but before matching, which can only be done from the
+ // rule's implementation. Also, for apply_group_members(), there is the
+ // explicit group special case which may also require custom logic.
+ // So it feels best to leave both to the implementation.
+
return impl.load (memory_order_relaxed)->apply (a, t, me);
}
+
+ void adhoc_cxx_rule::
+ reapply (action a, target& t, match_extra& me) const
+ {
+ return impl.load (memory_order_relaxed)->reapply (a, t, me);
+ }
}