aboutsummaryrefslogtreecommitdiff
path: root/build2/b.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-03-16 10:37:46 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-03-16 18:15:18 +0200
commitf57ec74251b31cc532dc095801c1da17a7d8e0ac (patch)
tree16891832c41ab1946213001a76451dcd4dff770e /build2/b.cxx
parentece4003beebd23082a5fd7a324de40c5572161d1 (diff)
Add ability for meta-operation to preprocess buildspec
Diffstat (limited to 'build2/b.cxx')
-rw-r--r--build2/b.cxx114
1 files changed, 74 insertions, 40 deletions
diff --git a/build2/b.cxx b/build2/b.cxx
index d247958..6e5aef9 100644
--- a/build2/b.cxx
+++ b/build2/b.cxx
@@ -349,22 +349,20 @@ main (int argc, char* argv[])
// If not NULL, then lifted points to the operation that has been "lifted"
// to the meta-operaion (see the logic below for details). Skip is the
- // position of the next operation. Dirty indicated whether we managed to
- // execute anything before lifting an operation.
+ // position of the next operation.
//
opspec* lifted (nullptr);
size_t skip (0);
- bool dirty (false); // We already (re)set for the first run.
+
+ // The dirty flag indicated whether we managed to execute anything before
+ // lifting an operation.
+ //
+ bool dirty (false); // Already (re)set for the first run.
for (auto mit (bspec.begin ()); mit != bspec.end (); )
{
vector_view<opspec> opspecs;
- const string& mname (lifted == nullptr ? mit->name : lifted->name);
- const values& mparams (lifted == nullptr ? mit->params : lifted->params);
-
- current_mname = &mname;
-
if (lifted == nullptr)
{
metaopspec& ms (*mit);
@@ -402,9 +400,36 @@ main (int argc, char* argv[])
dirty = false;
}
+ const path p ("<buildspec>");
+ const location l (&p, 0, 0); //@@ TODO
+
meta_operation_id mid (0); // Not yet translated.
const meta_operation_info* mif (nullptr);
+ // See if this meta-operation wants to pre-process the opspecs. Note
+ // that this functionality can only be used for build-in meta-operations
+ // that were explicitly specified on the command line (so cannot be used
+ // for perform) and that will be lifted early (see below).
+ //
+ values& mparams (lifted == nullptr ? mit->params : lifted->params);
+ {
+ const string& mname (lifted == nullptr ? mit->name : lifted->name);
+ current_mname = &mname;
+
+ if (!mname.empty ())
+ {
+ if (meta_operation_id m = meta_operation_table.find (mname))
+ {
+ // Can modify params, opspec, change meta-operation name.
+ //
+ if (auto f = meta_operation_table[m].process)
+ current_mname = &f (mparams, opspecs, lifted != nullptr, l);
+ }
+ }
+ }
+
+ const string& mname (*current_mname);
+
for (auto oit (opspecs.begin ()); oit != opspecs.end (); ++oit)
{
opspec& os (*oit);
@@ -422,9 +447,6 @@ main (int argc, char* argv[])
if (os.empty ()) // Default target: dir{}.
os.push_back (targetspec (name ("dir", string ())));
- const path p ("<buildspec>");
- const location l (&p, 0, 0); //@@ TODO
-
operation_id oid (0); // Not yet translated.
const operation_info* oif (nullptr);
@@ -434,14 +456,42 @@ main (int argc, char* argv[])
operation_id post_oid (0);
const operation_info* post_oif (nullptr);
+ // Return true if this operation is lifted.
+ //
+ auto lift = [&oname, &mname, &os, &mit, &lifted, &skip, &l, &trace] ()
+ {
+ meta_operation_id m (meta_operation_table.find (oname));
+
+ if (m != 0)
+ {
+ if (!mname.empty ())
+ fail (l) << "nested meta-operation " << mname << '(' << oname << ')';
+
+ l5 ([&]{trace << "lifting operation " << oname
+ << ", id " << uint16_t (m);});
+
+ lifted = &os;
+ skip = lifted - mit->data () + 1;
+ }
+
+ return m != 0;
+ };
+
// We do meta-operation and operation batches sequentially (no
// parallelism). But multiple targets in an operation batch can be
// done in parallel.
- // First bootstrap projects for all the target so that all the
- // variable overrides are set (if we also load/search/match in the
- // same loop then we may end up loading a project (via import) before
- // this happends.
+ // First see if we can lift this operation early by checking if it
+ // is one of the built-in meta-operations. This is important to make
+ // sure we pre-process the opspec before loading anything.
+ //
+ if (!oname.empty () && lift ())
+ break;
+
+ // Next bootstrap projects for all the target so that all the variable
+ // overrides are set (if we also load/search/match in the same loop
+ // then we may end up loading a project (via import) before this
+ // happends.
//
for (targetspec& ts: os)
{
@@ -720,28 +770,12 @@ main (int argc, char* argv[])
// known.
//
{
+ if (!oname.empty () && lift ())
+ break; // Out of targetspec loop.
+
meta_operation_id m (0);
operation_id o (0);
- if (!oname.empty ())
- {
- m = meta_operation_table.find (oname);
-
- if (m != 0)
- {
- if (!mname.empty ())
- fail (l) << "nested meta-operation " << mname
- << '(' << oname << ')';
-
- l5 ([&]{trace << "lifting operation " << oname
- << ", id " << uint16_t (m);});
-
- lifted = &os;
- skip = lifted - mit->data () + 1;
- break; // Out of targetspec loop.
- }
- }
-
if (!mname.empty ())
{
m = meta_operation_table.find (mname);
@@ -779,14 +813,14 @@ main (int argc, char* argv[])
}
}
- // The default meta-operation is perform. The default
- // operation is assigned by the meta-operation below.
+ // The default meta-operation is perform. The default operation is
+ // assigned by the meta-operation below.
//
if (m == 0)
m = perform_id;
- // If this is the first target in the meta-operation batch,
- // then set the batch meta-operation id.
+ // If this is the first target in the meta-operation batch, then
+ // set the batch meta-operation id.
//
if (mid == 0)
{
@@ -795,7 +829,7 @@ main (int argc, char* argv[])
if (mif == nullptr)
fail (l) << "target " << tn << " does not support meta-"
- << "operation " << meta_operation_table[m];
+ << "operation " << meta_operation_table[m].name;
l5 ([&]{trace << "start meta-operation batch " << mif->name
<< ", id " << static_cast<uint16_t> (mid);});
@@ -819,7 +853,7 @@ main (int argc, char* argv[])
if (mi == nullptr)
fail (l) << "target " << tn << " does not support meta-"
- << "operation " << meta_operation_table[mid];
+ << "operation " << meta_operation_table[mid].name;
if (mi != mif)
fail (l) << "different implementations of meta-operation "