aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-11-20 13:11:59 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-11-20 18:29:45 +0200
commit9964a9aca03b38c2959994e0fdc91014da252cb8 (patch)
tree4c263c8f9ee422de9f27aecdb05a040ee116ddae
parent4184f61e2b795dd4c4b4a974a890bdaf98906b82 (diff)
Implement dump directive
It can be used to print (to stderr) a human-readable representation of the current scope or a list of targets. For example: dump # Dump current scope. dump lib{foo} details/exe{bar} # Dump two targets. This is primarily useful for debugging as well as to write build system tests.
-rw-r--r--build2/dump.cxx61
-rw-r--r--build2/dump.hxx13
-rw-r--r--build2/parser.cxx109
-rw-r--r--build2/parser.hxx3
4 files changed, 162 insertions, 24 deletions
diff --git a/build2/dump.cxx b/build2/dump.cxx
index ab2e73f..7e2676d 100644
--- a/build2/dump.cxx
+++ b/build2/dump.cxx
@@ -184,16 +184,27 @@ namespace build2
}
static void
- dump_target (ostream& os, string& ind, const target& t, const scope& s)
+ dump_target (ostream& os,
+ string& ind,
+ const target& t,
+ const scope& s,
+ bool relative)
{
- // Print the target and its prerequisites relative to the scope. To achieve
- // this we are going to temporarily lower the stream verbosity to level 1.
- // The drawback of doing this is that we also lower the verbosity of
- // extension printing (it wouldn't have been bad at all to get 'foo.?' for
- // unassigned and 'foo.' for empty).
+ // If requested, print the target and its prerequisites relative to the
+ // scope. To achieve this we are going to temporarily lower the stream
+ // verbosity to level 1. The drawback of doing this is that we also lower
+ // the verbosity of extension printing (it wouldn't have been bad at all
+ // to get 'foo.?' for unassigned and 'foo.' for empty).
//
- uint16_t sv (stream_verb (os));
- stream_verb (os, 1);
+ // @@ Actually, all those foo.? look rather hairy...
+ // @@ Can't we change level to a bit mask?
+ //
+ uint16_t sv;
+ if (relative)
+ {
+ sv = stream_verb (os);
+ stream_verb (os, 1);
+ }
os << ind << t;
@@ -234,7 +245,8 @@ namespace build2
}
}
- stream_verb (os, sv); // We want variable values in full.
+ if (relative)
+ stream_verb (os, sv); // We want variable values in full.
// Print target-specific variables.
//
@@ -265,7 +277,10 @@ namespace build2
if (d.empty ())
os << ind << dir_path::traits::directory_separator;
else
- os << ind << relative (d);
+ {
+ dir_path rd (relative (d));
+ os << ind << (rd.empty () ? dir_path (".") : rd);
+ }
os << ":" << endl << ind << '{';
@@ -329,7 +344,7 @@ namespace build2
}
os << endl;
- dump_target (os, ind, t, p);
+ dump_target (os, ind, t, p, true /* relative */);
}
ind.resize (ind.size () - 2);
@@ -346,11 +361,33 @@ namespace build2
assert (&i->second == global_scope);
// We don't lock diag_stream here as dump() is supposed to be called from
- // the main thread prior to any other threads being spawned.
+ // the main thread prior/after to any other threads being spawned.
//
string ind;
ostream& os (*diag_stream);
dump_scope (os, ind, i);
os << endl;
}
+
+ void
+ dump (const scope& s, const char* cind)
+ {
+ const scope_map_base& m (scopes); // Iterator interface.
+ auto i (m.find (s.out_path ()));
+ assert (i != m.end () && &i->second == &s);
+
+ string ind (cind);
+ ostream& os (*diag_stream);
+ dump_scope (os, ind, i);
+ os << endl;
+ }
+
+ void
+ dump (const target& t, const char* cind)
+ {
+ string ind (cind);
+ ostream& os (*diag_stream);
+ dump_target (os, ind, t, t.base_scope (), false /* relative */);
+ os << endl;
+ }
}
diff --git a/build2/dump.hxx b/build2/dump.hxx
index e456540..8330708 100644
--- a/build2/dump.hxx
+++ b/build2/dump.hxx
@@ -8,14 +8,21 @@
#include <build2/types.hxx>
#include <build2/utility.hxx>
-#include <build2/operation.hxx>
-
namespace build2
{
- // Dump the state pertaining to the current action.
+ class scope;
+ class target;
+
+ // Dump the build state to diag_stream.
//
void
dump ();
+
+ void
+ dump (const scope&, const char* ind = "");
+
+ void
+ dump (const target&, const char* ind = "");
}
#endif // BUILD2_DUMP_HXX
diff --git a/build2/parser.cxx b/build2/parser.cxx
index 1863f67..7c8695a 100644
--- a/build2/parser.cxx
+++ b/build2/parser.cxx
@@ -9,6 +9,7 @@
#include <libbutl/filesystem.mxx> // path_search(), path_match()
+#include <build2/dump.hxx>
#include <build2/file.hxx>
#include <build2/scope.hxx>
#include <build2/module.hxx>
@@ -112,6 +113,40 @@ namespace build2
tracer& tr)
: p_ (&p), t_ (p.target_)
{
+ // Find or insert.
+ //
+ auto r (process_target (p, n, o, loc));
+ p.target_ = &targets.insert (*r.first, // target type
+ move (n.dir),
+ move (o.dir),
+ move (n.value),
+ move (r.second), // extension
+ implied,
+ tr).first;
+ }
+
+ static const target*
+ find_target (parser& p,
+ name& n, // If n.pair, then o is out dir.
+ name& o,
+ const location& loc,
+ tracer& tr)
+ {
+ auto r (process_target (p, n, o, loc));
+ return targets.find (*r.first, // target type
+ n.dir,
+ o.dir,
+ n.value,
+ r.second, // extension
+ tr);
+ }
+
+ static pair<const target_type*, optional<string>>
+ process_target (parser& p,
+ name& n, // If n.pair, then o is out dir.
+ name& o,
+ const location& loc)
+ {
optional<string> e;
const target_type* ti (p.scope_->find_target_type (n, e));
@@ -148,16 +183,9 @@ namespace build2
out = o.dir.relative () ? od / o.dir : move (o.dir);
out.normalize ();
}
+ o.dir = move (out); // Result.
- // Find or insert.
- //
- p.target_ = &targets.insert (*ti,
- move (d),
- move (out),
- move (n.value),
- move (e),
- implied,
- tr).first;
+ return make_pair (ti, move (e));
}
~enter_target ()
@@ -348,6 +376,10 @@ namespace build2
{
f = &parser::parse_diag;
}
+ else if (n == "dump")
+ {
+ f = &parser::parse_dump;
+ }
else if (n == "source")
{
f = &parser::parse_source;
@@ -1823,6 +1855,65 @@ namespace build2
next (t, tt); // Swallow newline.
}
+ void parser::
+ parse_dump (token& t, type& tt)
+ {
+ // dump [<target>...]
+ //
+ // If there are no targets, then we dump the current scope.
+ //
+ tracer trace ("parser::parse_dump", &path_);
+
+ const location l (get_location (t));
+ next (t, tt);
+ names ns (tt != type::newline && tt != type::eos
+ ? parse_names (t, tt, pattern_mode::ignore)
+ : names ());
+
+ text (l) << "dump:";
+
+ // Dump directly into diag_stream.
+ //
+ ostream& os (*diag_stream);
+
+ // Print directories as absolute.
+ //
+ const dir_path* orb (relative_base);
+ relative_base = &empty_dir_path;
+
+ if (ns.empty ())
+ {
+ if (scope_ != nullptr)
+ dump (*scope_, " "); // Indent two spaces.
+ else
+ os << " <no current scope>" << endl;
+ }
+ else
+ {
+ for (auto i (ns.begin ()), e (ns.end ()); i != e; ++i)
+ {
+ name& n (*i);
+ name o (n.pair ? move (*++i) : name ());
+
+ const target* t (enter_target::find_target (*this, n, o, l, trace));
+
+ if (t != nullptr)
+ dump (*t, " "); // Indent two spaces.
+ else
+ {
+ os << " <no target " << n;
+ if (n.pair && !o.dir.empty ()) os << '@' << o.dir;
+ os << '>' << endl;
+ }
+ }
+ }
+
+ relative_base = orb;
+
+ if (tt != type::eos)
+ next (t, tt); // Swallow newline.
+ }
+
string parser::
parse_variable_name (names&& ns, const location& l)
{
diff --git a/build2/parser.hxx b/build2/parser.hxx
index ce9ad2f..3c51801 100644
--- a/build2/parser.hxx
+++ b/build2/parser.hxx
@@ -85,6 +85,9 @@ namespace build2
parse_diag (token&, token_type&);
void
+ parse_dump (token&, token_type&);
+
+ void
parse_source (token&, token_type&);
void