aboutsummaryrefslogtreecommitdiff
path: root/build2/operation.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'build2/operation.cxx')
-rw-r--r--build2/operation.cxx232
1 files changed, 232 insertions, 0 deletions
diff --git a/build2/operation.cxx b/build2/operation.cxx
new file mode 100644
index 0000000..f4eae64
--- /dev/null
+++ b/build2/operation.cxx
@@ -0,0 +1,232 @@
+// file : build2/operation.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <build2/operation>
+
+#include <vector>
+#include <ostream>
+#include <cassert>
+#include <functional> // reference_wrapper
+
+#include <butl/utility> // reverse_iterate
+
+#include <build2/scope>
+#include <build2/target>
+#include <build2/file>
+#include <build2/algorithm>
+#include <build2/diagnostics>
+#include <build2/dump>
+
+using namespace std;
+using namespace butl;
+
+namespace build2
+{
+ // action
+ //
+ ostream&
+ operator<< (ostream& os, action a)
+ {
+ uint16_t
+ m (a.meta_operation ()),
+ i (a.operation ()),
+ o (a.outer_operation ());
+
+ os << '(' << m << ',';
+
+ if (o != 0)
+ os << o << '(';
+
+ os << i;
+
+ if (o != 0)
+ os << ')';
+
+ os << ')';
+
+ return os;
+ }
+
+ // perform
+ //
+ void
+ load (const path& bf,
+ scope& root,
+ const dir_path& out_base,
+ const dir_path& src_base,
+ const location&)
+ {
+ // Load project's root[-pre].build.
+ //
+ load_root_pre (root);
+
+ // Create the base scope. Note that its existence doesn't
+ // mean it was already setup as a base scope; it can be the
+ // same as root.
+ //
+ auto i (scopes.insert (out_base, nullptr, true, false));
+ scope& base (setup_base (i, out_base, src_base));
+
+ // Load the buildfile unless it has already been loaded.
+ //
+ source_once (bf, root, base, root);
+ }
+
+ void
+ search (scope&,
+ const target_key& tk,
+ const location& l,
+ action_targets& ts)
+ {
+ tracer trace ("search");
+
+ auto i (targets.find (tk, trace));
+ if (i == targets.end ())
+ fail (l) << "unknown target " << tk;
+
+ ts.push_back (i->get ());
+ }
+
+ void
+ match (action a, action_targets& ts)
+ {
+ tracer trace ("match");
+
+ if (verb >= 6)
+ dump (a);
+
+ for (void* vt: ts)
+ {
+ target& t (*static_cast<target*> (vt));
+ level5 ([&]{trace << "matching " << t;});
+ match (a, t);
+ }
+
+ if (verb >= 6)
+ dump (a);
+ }
+
+ void
+ execute (action a, const action_targets& ts, bool quiet)
+ {
+ tracer trace ("execute");
+
+ // Execute collecting postponed targets (to be re-examined later).
+ // Do it in reverse order if the execution mode is 'last'.
+ //
+ vector<reference_wrapper<target>> psp;
+
+ auto body (
+ [a, quiet, &psp, &trace] (void* v)
+ {
+ target& t (*static_cast<target*> (v));
+
+ level5 ([&]{trace << diag_doing (a, t);});
+
+ switch (execute (a, t))
+ {
+ case target_state::unchanged:
+ {
+ if (!quiet)
+ info << diag_done (a, t);
+ break;
+ }
+ case target_state::postponed:
+ psp.push_back (t);
+ break;
+ case target_state::changed:
+ break;
+ case target_state::failed:
+ //@@ This could probably happen in a parallel build.
+ default:
+ assert (false);
+ }
+ });
+
+ if (current_mode == execution_mode::first)
+ for (void* v: ts) body (v);
+ else
+ for (void* v: reverse_iterate (ts)) body (v);
+
+ // We should have executed every target that we matched.
+ //
+ assert (dependency_count == 0);
+
+ // Re-examine postponed targets. This is the only reliable way to
+ // find out whether the target has changed.
+ //
+ for (target& t: psp)
+ {
+ switch (execute (a, t))
+ {
+ case target_state::unchanged:
+ {
+ if (!quiet)
+ info << diag_done (a, t);
+ break;
+ }
+ case target_state::changed:
+ break;
+ case target_state::postponed:
+ assert (false);
+ case target_state::failed:
+ //@@ This could probably happen in a parallel build.
+ default:
+ assert (false);
+ }
+ }
+ }
+
+ meta_operation_info perform {
+ "perform",
+ "",
+ "",
+ "",
+ nullptr, // meta-operation pre
+ nullptr, // operation pre
+ &load,
+ &search,
+ &match,
+ &execute,
+ nullptr, // operation post
+ nullptr // meta-operation post
+ };
+
+ // operations
+ //
+ operation_info default_ {
+ "<default>",
+ "",
+ "",
+ "",
+ execution_mode::first,
+ nullptr,
+ nullptr
+ };
+
+ operation_info update {
+ "update",
+ "update",
+ "updating",
+ "is up to date",
+ execution_mode::first,
+ nullptr,
+ nullptr
+ };
+
+ operation_info clean {
+ "clean",
+ "clean",
+ "cleaning",
+ "is clean",
+ execution_mode::last,
+ nullptr,
+ nullptr
+ };
+
+ // Tables.
+ //
+ string_table<meta_operation_id> meta_operation_table;
+ string_table<operation_id> operation_table;
+}