aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-02-07 15:48:50 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-02-07 16:52:55 +0200
commit968d8a7acd6c23078a3ea6936c03be0b45523227 (patch)
treed7da843d0961b649ff93f6f299b9ce65b1255003
parent378b2598a305d4e332e52460ca89dd867546a58b (diff)
Add support for update-for-{test,install} operation aliases
-rw-r--r--build2/b.cxx79
-rw-r--r--build2/config/init.cxx4
-rw-r--r--build2/config/operation.cxx2
-rw-r--r--build2/context.cxx16
-rw-r--r--build2/context.hxx8
-rw-r--r--build2/dist/operation.cxx32
-rw-r--r--build2/install/init.cxx7
-rw-r--r--build2/install/operation.cxx18
-rw-r--r--build2/install/operation.hxx1
-rw-r--r--build2/operation.cxx10
-rw-r--r--build2/operation.hxx39
-rw-r--r--build2/parser.cxx4
-rw-r--r--build2/test/init.cxx3
-rw-r--r--build2/test/operation.cxx17
-rw-r--r--build2/test/operation.hxx1
-rw-r--r--build2/test/rule.cxx2
16 files changed, 165 insertions, 78 deletions
diff --git a/build2/b.cxx b/build2/b.cxx
index b827470..6d681cd 100644
--- a/build2/b.cxx
+++ b/build2/b.cxx
@@ -577,23 +577,22 @@ main (int argc, char* argv[])
//
values& mparams (lifted == nullptr ? mit->params : lifted->params);
{
- const string& mname (lifted == nullptr ? mit->name : lifted->name);
- current_mname = &mname;
+ current_mname = (lifted == nullptr ? mit->name : lifted->name);
- if (!mname.empty ())
+ if (!current_mname.empty ())
{
- if (meta_operation_id m = meta_operation_table.find (mname))
+ if (meta_operation_id m = meta_operation_table.find (current_mname))
{
// Can modify params, opspec, change meta-operation name.
//
if (auto f = meta_operation_table[m].process)
- current_mname = &f (
+ current_mname = f (
var_ovs, mparams, opspecs, lifted != nullptr, l);
}
}
}
- const string& mname (*current_mname);
+ const string& mname (current_mname);
for (auto oit (opspecs.begin ()); oit != opspecs.end (); ++oit)
{
@@ -601,38 +600,39 @@ main (int argc, char* argv[])
// A lifted meta-operation will always have default operation.
//
- const string& oname (lifted == nullptr ? os.name : string ());
+ current_oname = (lifted == nullptr ? os.name : empty_string);
+ const string& oname (current_oname);
const values& oparams (lifted == nullptr ? os.params : values ());
- current_oname = &oname;
-
if (lifted != nullptr)
lifted = nullptr; // Clear for the next iteration.
if (os.empty ()) // Default target: dir{}.
os.push_back (targetspec (name ("dir", string ())));
- operation_id oid (0); // Not yet translated.
+ operation_id oid (0), orig_oid;
const operation_info* oif (nullptr);
+ const operation_info* outer_oif (nullptr);
- operation_id pre_oid (0);
+ operation_id pre_oid (0), orig_pre_oid;
const operation_info* pre_oif (nullptr);
- operation_id post_oid (0);
+ operation_id post_oid (0), orig_post_oid;
const operation_info* post_oif (nullptr);
// Return true if this operation is lifted.
//
- auto lift = [&oname, &mname, &os, &mit, &lifted, &skip, &l, &trace] ()
+ auto lift = [&os, &mit, &lifted, &skip, &l, &trace] ()
{
- meta_operation_id m (meta_operation_table.find (oname));
+ meta_operation_id m (meta_operation_table.find (current_oname));
if (m != 0)
{
- if (!mname.empty ())
- fail (l) << "nested meta-operation " << mname << '(' << oname << ')';
+ if (!current_mname.empty ())
+ fail (l) << "nested meta-operation " << current_mname << '('
+ << current_oname << ')';
- l5 ([&]{trace << "lifting operation " << oname
+ l5 ([&]{trace << "lifting operation " << current_oname
<< ", id " << uint16_t (m);});
lifted = &os;
@@ -991,33 +991,44 @@ main (int argc, char* argv[])
if (o == 0)
o = default_id;
+ // Before de-aliasing and/or translation (we assume in the check
+ // below that those will be the same since we've verified the
+ // meta-operation implementation is the same).
+ //
+ orig_oid = o;
+
oif = lookup (o);
l5 ([&]{trace << "start operation batch " << oif->name
- << ", id " << static_cast<uint16_t> (o);});
+ << ", id " << static_cast<uint16_t> (oif->id);});
// Allow the meta-operation to translate the operation.
//
if (mif->operation_pre != nullptr)
- oid = mif->operation_pre (mparams, o);
+ oid = mif->operation_pre (mparams, oif->id);
else // Otherwise translate default to update.
- oid = (o == default_id ? update_id : o);
+ oid = (oif->id == default_id ? update_id : oif->id);
- if (o != oid)
+ if (oif->id != oid)
{
oif = lookup (oid);
+ oid = oif->id; // De-alias.
l5 ([&]{trace << "operation translated to " << oif->name
<< ", id " << static_cast<uint16_t> (oid);});
}
+ if (oif->outer_id != 0)
+ outer_oif = lookup (oif->outer_id);
+
// Handle pre/post operations.
//
if (oif->pre != nullptr)
{
- if ((pre_oid = oif->pre (oparams, mid, l)) != 0)
+ if ((orig_pre_oid = oif->pre (oparams, mid, l)) != 0)
{
- assert (pre_oid != default_id);
- pre_oif = lookup (pre_oid);
+ assert (orig_pre_oid != default_id);
+ pre_oif = lookup (orig_pre_oid);
+ pre_oid = pre_oif->id; // De-alias.
}
}
else if (!oparams.empty ())
@@ -1026,10 +1037,11 @@ main (int argc, char* argv[])
if (oif->post != nullptr)
{
- if ((post_oid = oif->post (oparams, mid)) != 0)
+ if ((orig_post_oid = oif->post (oparams, mid)) != 0)
{
- assert (post_oid != default_id);
- post_oif = lookup (post_oid);
+ assert (orig_post_oid != default_id);
+ post_oif = lookup (orig_post_oid);
+ post_oid = post_oif->id;
}
}
}
@@ -1053,13 +1065,16 @@ main (int argc, char* argv[])
<< i->name << " in the same operation batch";
};
- check (oid, oif);
+ check (orig_oid, oif);
+
+ if (oif->outer_id != 0)
+ check (oif->outer_id, outer_oif);
if (pre_oid != 0)
- check (pre_oid, pre_oif);
+ check (orig_pre_oid, pre_oif);
if (post_oid != 0)
- check (post_oid, post_oif);
+ check (orig_post_oid, post_oif);
}
}
@@ -1246,9 +1261,9 @@ main (int argc, char* argv[])
tgs.reset ();
}
- set_current_oif (*oif);
+ set_current_oif (*oif, outer_oif);
- action a (mid, oid, 0);
+ action a (mid, oid, oif->outer_id);
{
result_printer p (tgs);
diff --git a/build2/config/init.cxx b/build2/config/init.cxx
index 35bc94c..8bbc07e 100644
--- a/build2/config/init.cxx
+++ b/build2/config/init.cxx
@@ -29,8 +29,8 @@ namespace build2
l5 ([&]{trace << "for " << rs.out_path ();});
- const string& mname (*current_mname);
- const string& oname (*current_oname);
+ const string& mname (current_mname);
+ const string& oname (current_oname);
// Only create the module if we are configuring or creating. This is a
// bit tricky since the build2 core may not yet know if this is the
diff --git a/build2/config/operation.cxx b/build2/config/operation.cxx
index fa7cb9f..d5a1565 100644
--- a/build2/config/operation.cxx
+++ b/build2/config/operation.cxx
@@ -732,7 +732,7 @@ namespace build2
fail (l) << "invalid module name: " << e.what ();
}
- current_oname = &empty_string; // Make sure valid.
+ current_oname = empty_string; // Make sure valid.
// Now handle each target in each operation spec.
//
diff --git a/build2/context.cxx b/build2/context.cxx
index 6f3abcc..e73f0a1 100644
--- a/build2/context.cxx
+++ b/build2/context.cxx
@@ -341,8 +341,8 @@ namespace build2
const char var_extension[10] = "extension";
- const string* current_mname;
- const string* current_oname;
+ string current_mname;
+ string current_oname;
const meta_operation_info* current_mif;
const operation_info* current_inner_oif;
@@ -393,8 +393,10 @@ namespace build2
operation_table.insert ("update");
operation_table.insert ("clean");
operation_table.insert ("test");
+ operation_table.insert ("update-for-test");
operation_table.insert ("install");
operation_table.insert ("uninstall");
+ operation_table.insert ("update-for-install");
// Create global scope. Note that the empty path is a prefix for any other
// path. See the comment in <libbutl/prefix-map.mxx> for details.
@@ -762,7 +764,7 @@ namespace build2
{
r = m.name_do;
- if (!io.name_doing.empty ())
+ if (io.name_doing[0] != '\0')
{
r += ' ';
r += io.name_doing;
@@ -800,7 +802,7 @@ namespace build2
if (!m.name_doing.empty ())
r = m.name_doing;
- if (!io.name_doing.empty ())
+ if (io.name_doing[0] != '\0')
{
if (!r.empty ()) r += ' ';
r += io.name_doing;
@@ -838,7 +840,7 @@ namespace build2
{
r = m.name_did;
- if (!io.name_doing.empty ())
+ if (io.name_doing[0] != '\0')
{
r += ' ';
r += io.name_doing;
@@ -877,7 +879,7 @@ namespace build2
{
os << t;
- if (!io.name_done.empty ())
+ if (io.name_done[0] != '\0')
os << ' ' << io.name_done;
if (oo != nullptr)
@@ -885,7 +887,7 @@ namespace build2
}
else
{
- if (!io.name_doing.empty ())
+ if (io.name_doing[0] != '\0')
os << io.name_doing << ' ';
if (oo != nullptr)
diff --git a/build2/context.hxx b/build2/context.hxx
index 97ba285..7702564 100644
--- a/build2/context.hxx
+++ b/build2/context.hxx
@@ -285,8 +285,8 @@ namespace build2
// lifted. The name is always for an outer operation (or meta operation
// that hasn't been recognized as such yet).
//
- extern const string* current_mname;
- extern const string* current_oname;
+ extern string current_mname;
+ extern string current_oname;
extern const meta_operation_info* current_mif;
extern const operation_info* current_inner_oif;
@@ -315,7 +315,7 @@ namespace build2
inline void
set_current_mif (const meta_operation_info& mif)
{
- current_mname = &mif.name;
+ current_mname = mif.name;
current_mif = &mif;
current_on = 0; // Reset.
}
@@ -324,7 +324,7 @@ namespace build2
set_current_oif (const operation_info& inner_oif,
const operation_info* outer_oif = nullptr)
{
- current_oname = &(outer_oif == nullptr ? inner_oif : *outer_oif).name;
+ current_oname = (outer_oif == nullptr ? inner_oif : *outer_oif).name;
current_inner_oif = &inner_oif;
current_outer_oif = outer_oif;
current_on++;
diff --git a/build2/dist/operation.cxx b/build2/dist/operation.cxx
index a378b5d..e0d1f60 100644
--- a/build2/dist/operation.cxx
+++ b/build2/dist/operation.cxx
@@ -126,15 +126,25 @@ namespace build2
{
if (const operation_info* oif = rs->operations[id])
{
+ // Skip aliases (e.g., update-for-install). In fact, one can argue
+ // the default update should be sufficient since it is assumed to
+ // update all prerequisites and we not longer support ad hoc stuff
+ // like test.input.
+ //
+ if (oif->id != id)
+ continue;
+
// Use standard (perform) match.
//
if (oif->pre != nullptr)
{
- const operation_info* poif (
- rs->operations[oif->pre (params, dist_id, loc)]);
- set_current_oif (*poif, oif);
- action a (dist_id, poif->id, oif->id);
- match (params, a, ts, true /* quiet */);
+ if (operation_id pid = oif->pre (params, dist_id, loc))
+ {
+ const operation_info* poif (rs->operations[pid]);
+ set_current_oif (*poif, oif);
+ action a (dist_id, poif->id, oif->id);
+ match (params, a, ts, true /* quiet */);
+ }
}
set_current_oif (*oif);
@@ -143,11 +153,13 @@ namespace build2
if (oif->post != nullptr)
{
- const operation_info* poif (
- rs->operations[oif->post (params, dist_id)]);
- set_current_oif (*poif, oif);
- action a (dist_id, poif->id, oif->id);
- match (params, a, ts, true /* quiet */);
+ if (operation_id pid = oif->post (params, dist_id))
+ {
+ const operation_info* poif (rs->operations[pid]);
+ set_current_oif (*poif, oif);
+ action a (dist_id, poif->id, oif->id);
+ match (params, a, ts, true /* quiet */);
+ }
}
}
}
diff --git a/build2/install/init.cxx b/build2/install/init.cxx
index 259fb07..52875d4 100644
--- a/build2/install/init.cxx
+++ b/build2/install/init.cxx
@@ -140,10 +140,11 @@ namespace build2
if (!function_family::defined ("install"))
functions ();
- // Register the install and uninstall operations.
+ // Register our operations.
//
- r.operations.insert (install_id, op_install);
- r.operations.insert (uninstall_id, op_uninstall);
+ r.operations.insert (install_id, op_install);
+ r.operations.insert (uninstall_id, op_uninstall);
+ r.operations.insert (update_for_install_id, op_update_for_install);
return false;
}
diff --git a/build2/install/operation.cxx b/build2/install/operation.cxx
index 5279b3d..be4dd2d 100644
--- a/build2/install/operation.cxx
+++ b/build2/install/operation.cxx
@@ -30,6 +30,7 @@ namespace build2
const operation_info op_install {
install_id,
+ 0,
"install",
"install",
"installing",
@@ -52,6 +53,7 @@ namespace build2
//
const operation_info op_uninstall {
uninstall_id,
+ 0,
"uninstall",
"uninstall",
"uninstalling",
@@ -62,5 +64,21 @@ namespace build2
&install_pre,
nullptr
};
+
+ // Also the explicit update-for-install operation alias.
+ //
+ const operation_info op_update_for_install {
+ update_id, // Note: not update_for_install_id.
+ install_id,
+ op_update.name,
+ op_update.name_do,
+ op_update.name_doing,
+ op_update.name_did,
+ op_update.name_done,
+ op_update.mode,
+ op_update.concurrency,
+ op_update.pre,
+ op_update.post
+ };
}
}
diff --git a/build2/install/operation.hxx b/build2/install/operation.hxx
index 0d96faf..1f3db58 100644
--- a/build2/install/operation.hxx
+++ b/build2/install/operation.hxx
@@ -16,6 +16,7 @@ namespace build2
{
extern const operation_info op_install;
extern const operation_info op_uninstall;
+ extern const operation_info op_update_for_install;
}
}
diff --git a/build2/operation.cxx b/build2/operation.cxx
index a43e20a..f262321 100644
--- a/build2/operation.cxx
+++ b/build2/operation.cxx
@@ -522,6 +522,7 @@ namespace build2
//
const operation_info op_default {
default_id,
+ 0,
"<default>",
"",
"",
@@ -533,8 +534,14 @@ namespace build2
nullptr
};
- const operation_info op_update {
+#ifndef _MSC_VER
+ constexpr
+#else
+ const
+#endif
+ operation_info op_update {
update_id,
+ 0,
"update",
"update",
"updating",
@@ -548,6 +555,7 @@ namespace build2
const operation_info op_clean {
clean_id,
+ 0,
"clean",
"clean",
"cleaning",
diff --git a/build2/operation.hxx b/build2/operation.hxx
index e79a57c..7f59783 100644
--- a/build2/operation.hxx
+++ b/build2/operation.hxx
@@ -127,12 +127,16 @@ namespace build2
// that no operation was explicitly specified by the user. If adding
// something here remember to update the man page.
//
- const operation_id default_id = 1; // Shall be first.
- const operation_id update_id = 2; // Shall be second.
- const operation_id clean_id = 3;
- const operation_id test_id = 4;
- const operation_id install_id = 5;
- const operation_id uninstall_id = 6;
+ const operation_id default_id = 1; // Shall be first.
+ const operation_id update_id = 2; // Shall be second.
+ const operation_id clean_id = 3;
+
+ const operation_id test_id = 4;
+ const operation_id update_for_test_id = 5; // update(for test) alias.
+
+ const operation_id install_id = 6;
+ const operation_id uninstall_id = 7;
+ const operation_id update_for_install_id = 8; // update(for install) alias.
const action_id perform_update_id = (perform_id << 4) | update_id;
const action_id perform_clean_id = (perform_id << 4) | clean_id;
@@ -321,10 +325,18 @@ namespace build2
// Operation info.
//
+ // NOTE: keep POD-like to ensure can be constant-initialized in order to
+ // sidestep static initialization order (relied upon in operation
+ // aliasing).
+ //
struct operation_info
{
+ // If outer_id is not 0, then use that as the outer part of the
+ // action.
+ //
const operation_id id;
- const string name;
+ const operation_id outer_id;
+ const char* name;
// Name derivatives for diagnostics. Note that unlike meta-operations,
// these can only be empty for the default operation (id 1), And
@@ -332,10 +344,10 @@ namespace build2
// have empty derivatives (failed which only target name will be
// printed).
//
- const string name_do; // E.g., [to] 'update'.
- const string name_doing; // E.g., [while] 'updating'.
- const string name_did; // E.g., [not] 'updated'.
- const string name_done; // E.g., 'is up to date'.
+ const char* name_do; // E.g., [to] 'update'.
+ const char* name_doing; // E.g., [while] 'updating'.
+ const char* name_did; // E.g., [not] 'updated'.
+ const char* name_done; // E.g., 'is up to date'.
const execution_mode mode;
@@ -346,9 +358,8 @@ namespace build2
// The first argument in all the callback is the operation parameters.
//
- // If the meta-operation expects parameters, then it should have a
- // non-NULL pre(). Failed that, any parameters will be diagnosed as
- // unexpected.
+ // If the operation expects parameters, then it should have a non-NULL
+ // pre(). Failed that, any parameters will be diagnosed as unexpected.
// If the returned operation_id's are not 0, then they are injected
// as pre/post operations for this operation. Can be NULL if unused.
diff --git a/build2/parser.cxx b/build2/parser.cxx
index 5687b0f..0c360a5 100644
--- a/build2/parser.cxx
+++ b/build2/parser.cxx
@@ -4290,12 +4290,12 @@ namespace build2
if (n.pair || !n.simple () || n.empty ())
return false;
- // C identifier.
+ // Like C identifier but with '-' instead of '_' as the delimiter.
//
for (size_t i (0); i != n.value.size (); ++i)
{
char c (n.value[i]);
- if (c != '_' && !(i != 0 ? alnum (c) : alpha (c)))
+ if (c != '-' && !(i != 0 ? alnum (c) : alpha (c)))
return false;
}
diff --git a/build2/test/init.cxx b/build2/test/init.cxx
index 556de00..6d28e9e 100644
--- a/build2/test/init.cxx
+++ b/build2/test/init.cxx
@@ -29,9 +29,10 @@ namespace build2
l5 ([&]{trace << "for " << rs.out_path ();});
- // Register the test operation.
+ // Register our operations.
//
rs.operations.insert (test_id, op_test);
+ rs.operations.insert (update_for_test_id, op_update_for_test);
// Enter module variables. Do it during boot in case they get assigned
// in bootstrap.build.
diff --git a/build2/test/operation.cxx b/build2/test/operation.cxx
index e4591e4..7c968ff 100644
--- a/build2/test/operation.cxx
+++ b/build2/test/operation.cxx
@@ -24,6 +24,7 @@ namespace build2
const operation_info op_test {
test_id,
+ 0,
"test",
"test",
"testing",
@@ -34,5 +35,21 @@ namespace build2
&test_pre,
nullptr
};
+
+ // Also the explicit update-for-test operation alias.
+ //
+ const operation_info op_update_for_test {
+ update_id, // Note: not update_for_test_id.
+ test_id,
+ op_update.name,
+ op_update.name_do,
+ op_update.name_doing,
+ op_update.name_did,
+ op_update.name_done,
+ op_update.mode,
+ op_update.concurrency,
+ op_update.pre,
+ op_update.post
+ };
}
}
diff --git a/build2/test/operation.hxx b/build2/test/operation.hxx
index 774e8d0..09739d6 100644
--- a/build2/test/operation.hxx
+++ b/build2/test/operation.hxx
@@ -15,6 +15,7 @@ namespace build2
namespace test
{
extern const operation_info op_test;
+ extern const operation_info op_update_for_test;
}
}
diff --git a/build2/test/rule.cxx b/build2/test/rule.cxx
index 86062f9..a42ceca 100644
--- a/build2/test/rule.cxx
+++ b/build2/test/rule.cxx
@@ -303,7 +303,7 @@ namespace build2
//
match_inner (a, t);
- return [pass_n, this] (action a, const target& t)
+ return [pass_n] (action a, const target& t)
{
return perform_update (a, t, pass_n);
};