aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-01-23 11:14:05 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-01-23 11:14:05 +0200
commitdb0edaafe15831ba6fa9c2109da37942506c62b1 (patch)
tree320dfcbf16b553c162cd079d633f16b6054b9740
parent19c37866524f60a7710b256dd13bf1da9f8cff16 (diff)
Cleanup absolute/relative path diagnostics by introducing stream verbosity
-rw-r--r--build2/b.cxx7
-rw-r--r--build2/context49
-rw-r--r--build2/context.cxx25
-rw-r--r--build2/diagnostics150
-rw-r--r--build2/diagnostics.cxx19
-rw-r--r--build2/file.cxx6
-rw-r--r--build2/lexer8
-rw-r--r--build2/lexer.cxx2
-rw-r--r--build2/parser9
-rw-r--r--build2/parser.cxx26
-rw-r--r--build2/path-io.cxx6
-rw-r--r--build2/prerequisite.cxx22
-rw-r--r--build2/spec.cxx16
-rw-r--r--build2/target.cxx12
-rw-r--r--build2/types13
15 files changed, 212 insertions, 158 deletions
diff --git a/build2/b.cxx b/build2/b.cxx
index cc87cec..c6a118e 100644
--- a/build2/b.cxx
+++ b/build2/b.cxx
@@ -151,7 +151,7 @@ main (int argc, char* argv[])
istringstream is (s);
is.exceptions (istringstream::failbit | istringstream::badbit);
- lexer l (is, "<cmdline>");
+ lexer l (is, path ("<cmdline>"));
token t (l.next ());
if (t.type == token_type::eos)
@@ -202,7 +202,7 @@ main (int argc, char* argv[])
is.exceptions (istringstream::failbit | istringstream::badbit);
parser p;
- bspec = p.parse_buildspec (is, "<buildspec>");
+ bspec = p.parse_buildspec (is, path ("<buildspec>"));
}
catch (const istringstream::failure&)
{
@@ -227,7 +227,8 @@ main (int argc, char* argv[])
for (opspec& os: ms)
{
- const location l ("<buildspec>", 1, 0); //@@ TODO
+ const path p ("<buildspec>");
+ const location l (&p, 1, 0); //@@ TODO
if (os.empty ()) // Default target: dir{}.
os.push_back (targetspec (name ("dir", string ())));
diff --git a/build2/context b/build2/context
index 7bae8c3..e2732db 100644
--- a/build2/context
+++ b/build2/context
@@ -23,7 +23,6 @@ namespace build2
extern dir_path work;
extern dir_path home;
- extern string_pool path_pool;
extern string_pool extension_pool;
extern string_pool project_name_pool;
@@ -146,18 +145,52 @@ namespace build2
diag_relative (const dir_path&, bool current = true);
// Action phrases, e.g., "configure update exe{foo}", "updating exe{foo}",
- // and "updating exe{foo} is configured".
+ // and "updating exe{foo} is configured". Use like this:
+ //
+ // info << "while " << diag_doing (a, t);
//
class target;
- std::string
- diag_do (const action&, const target&);
+ struct diag_phrase
+ {
+ const action& a;
+ const target& t;
+ void (*f) (ostream&, const action&, const target&);
+ };
- std::string
- diag_doing (const action&, const target&);
+ inline ostream&
+ operator<< (ostream& os, const diag_phrase& p)
+ {
+ p.f (os, p.a, p.t);
+ return os;
+ }
- std::string
- diag_done (const action&, const target&);
+ void
+ diag_do (ostream&, const action&, const target&);
+
+ inline diag_phrase
+ diag_do (const action& a, const target& t)
+ {
+ return diag_phrase {a, t, &diag_do};
+ }
+
+ void
+ diag_doing (ostream&, const action&, const target&);
+
+ inline diag_phrase
+ diag_doing (const action& a, const target& t)
+ {
+ return diag_phrase {a, t, &diag_doing};
+ }
+
+ void
+ diag_done (ostream&, const action&, const target&);
+
+ inline diag_phrase
+ diag_done (const action& a, const target& t)
+ {
+ return diag_phrase {a, t, &diag_done};
+ }
}
#include <build2/context.txx>
diff --git a/build2/context.cxx b/build2/context.cxx
index 0579545..87a6d71 100644
--- a/build2/context.cxx
+++ b/build2/context.cxx
@@ -5,7 +5,6 @@
#include <build2/context>
#include <ostream>
-#include <sstream>
#include <cassert>
#include <system_error>
@@ -22,7 +21,6 @@ namespace build2
dir_path work;
dir_path home;
- string_pool path_pool;
string_pool extension_pool;
string_pool project_name_pool;
@@ -35,7 +33,6 @@ namespace build2
void
reset ()
{
- path_pool.clear ();
extension_pool.clear ();
project_name_pool.clear ();
@@ -299,15 +296,13 @@ namespace build2
// diag_do(), etc.
//
- string
- diag_do (const action&, const target& t)
+ void
+ diag_do (ostream& os, const action&, const target& t)
{
const meta_operation_info& m (*current_mif);
const operation_info& io (*current_inner_oif);
const operation_info* oo (current_outer_oif);
- ostringstream os;
-
// perform(update(x)) -> "update x"
// configure(update(x)) -> "configure updating x"
//
@@ -325,18 +320,15 @@ namespace build2
os << "(for " << oo->name << ") ";
os << t;
- return os.str ();
}
- string
- diag_doing (const action&, const target& t)
+ void
+ diag_doing (ostream& os, const action&, const target& t)
{
const meta_operation_info& m (*current_mif);
const operation_info& io (*current_inner_oif);
const operation_info* oo (current_outer_oif);
- ostringstream os;
-
// perform(update(x)) -> "updating x"
// configure(update(x)) -> "configuring updating x"
//
@@ -350,18 +342,15 @@ namespace build2
os << "(for " << oo->name << ") ";
os << t;
- return os.str ();
}
- string
- diag_done (const action&, const target& t)
+ void
+ diag_done (ostream& os, const action&, const target& t)
{
const meta_operation_info& m (*current_mif);
const operation_info& io (*current_inner_oif);
const operation_info* oo (current_outer_oif);
- ostringstream os;
-
// perform(update(x)) -> "x is up to date"
// configure(update(x)) -> "updating x is configured"
//
@@ -385,7 +374,5 @@ namespace build2
os << t << " " << m.name_done;
}
-
- return os.str ();
}
}
diff --git a/build2/diagnostics b/build2/diagnostics
index 4aef6dd..27c71fa 100644
--- a/build2/diagnostics
+++ b/build2/diagnostics
@@ -28,17 +28,6 @@ namespace build2
//
class failed: public std::exception {};
- // Flag that indicates whether paths should be inserted relative
- // into this stream.
- //
- extern const int relative_index;
-
- inline bool
- relative (std::ostream& os) {return os.iword (relative_index);}
-
- inline void
- relative (std::ostream& os, bool v) {os.iword (relative_index) = v ? 1 : 0;}
-
// Print process commmand line. If the number of elements is specified
// (or the second version is used), then it will print the piped multi-
// process command line, if present. In this case, the expected format
@@ -67,7 +56,7 @@ namespace build2
print_process (args.data (), args.size ());
}
- // Verbosity level.
+ // Program verbosity level (-v/--verbose).
//
// 0 - disabled
// 1 - high-level information messages
@@ -79,7 +68,7 @@ namespace build2
//
// While uint8 is more than enough, use uint16 for the ease of printing.
//
- extern std::uint16_t verb;
+ extern uint16_t verb;
template <typename F> inline void level1 (const F& f) {if (verb >= 1) f ();}
template <typename F> inline void level2 (const F& f) {if (verb >= 2) f ();}
@@ -88,6 +77,46 @@ namespace build2
template <typename F> inline void level5 (const F& f) {if (verb >= 5) f ();}
template <typename F> inline void level6 (const F& f) {if (verb >= 6) f ();}
+ // Stream verbosity level. It is determined by the diagnostic type (e.g.,
+ // trace always has maximum verbosity) as well as the program verbosity. It
+ // is used to decide whether to print relative/absolute paths, and default
+ // target extensions.
+ //
+ // 0 - minimum
+ // 1 - intermediate
+ // 2 - maximum
+ //
+ // Currently we have the following program to stream verbosity mapping:
+ //
+ // fail/error/warn/info <2:0 2:1 >2:2
+ // trace *:2
+ //
+ // A stream that hasn't been (yet) assigned any verbosity explicitly (e.g.,
+ // ostringstream) defaults to maximum.
+ //
+ const uint16_t stream_verb_min = 0;
+ const uint16_t stream_verb_max = 2;
+
+ // Default program to stream verbosity mapping, as outlined above.
+ //
+ inline uint16_t
+ stream_verb_map () {return verb < 2 ? 0 : (verb > 2 ? 2 : 1);}
+
+ extern const int stream_verb_index;
+
+ inline uint16_t
+ stream_verb (std::ostream& os)
+ {
+ uint16_t v (static_cast<uint16_t> (os.iword (stream_verb_index)));
+ return v == 0 ? stream_verb_max : v - 1;
+ }
+
+ inline void
+ stream_verb (std::ostream& os, uint16_t v)
+ {
+ os.iword (stream_verb_index) = static_cast<long> (v + 1);
+ }
+
// Diagnostic facility, base infrastructure (potentially reusable).
//
extern std::ostream* diag_stream;
@@ -159,7 +188,7 @@ namespace build2
if (!empty_)
{
- assert (false); //@@ Relative flag will not be transferred.
+ assert (false); //@@ Stream verbosity will not be transferred.
os_ << r.os_.str ();
r.empty_ = true;
@@ -243,8 +272,8 @@ namespace build2
struct simple_prologue_base
{
explicit
- simple_prologue_base (const char* type, const char* name, bool rel)
- : type_ (type), name_ (name), relative_ (rel) {}
+ simple_prologue_base (const char* type, const char* name, uint16_t sverb)
+ : type_ (type), name_ (name), sverb_ (sverb) {}
void
operator() (const diag_record& r) const;
@@ -252,18 +281,20 @@ namespace build2
private:
const char* type_;
const char* name_;
- const bool relative_;
+ const uint16_t sverb_;
};
typedef diag_prologue<simple_prologue_base> simple_prologue;
class location
{
public:
- location () {}
- location (const char* f, std::uint64_t l, std::uint64_t c)
+ // Note that location maintains a shallow reference to path.
+ //
+ location (): file (nullptr), line (0), column (0) {}
+ location (const path* f, std::uint64_t l, std::uint64_t c)
: file (f), line (l), column (c) {}
- const char* file;
+ const path* file;
std::uint64_t line;
std::uint64_t column;
};
@@ -273,8 +304,8 @@ namespace build2
location_prologue_base (const char* type,
const char* name,
const location& l,
- bool rel)
- : type_ (type), name_ (name), loc_ (l), relative_ (rel) {}
+ uint16_t sverb)
+ : type_ (type), name_ (name), loc_ (l), sverb_ (sverb) {}
void
operator() (const diag_record& r) const;
@@ -283,68 +314,55 @@ namespace build2
const char* type_;
const char* name_;
const location loc_;
- const bool relative_;
+ const uint16_t sverb_;
};
typedef diag_prologue<location_prologue_base> location_prologue;
- // Here is the absolute/relative path rationale: we want it absolute
- // in the error/warning/info streams to give the user the complete
- // picture. But in the text stream (e.g., command lines), we print
- // relative unless verbosity is greater than 1.
- //
struct basic_mark_base
{
explicit
- basic_mark_base (const char* type,
+ basic_mark_base (uint16_t (*sverb) (),
+ const char* type,
const char* name = nullptr,
- const void* data = nullptr)
- : type_ (type), name_ (name), data_ (data) {}
+ const void* data = nullptr,
+ diag_epilogue epilogue = nullptr)
+ : sverb_ (sverb),
+ type_ (type), name_ (name), data_ (data),
+ epilogue_ (epilogue) {}
simple_prologue
operator() () const
{
- return simple_prologue (type_, name_, false);
+ return simple_prologue (epilogue_, type_, name_, sverb_ ());
}
location_prologue
operator() (const location& l) const
{
- return location_prologue (type_, name_, l, false);
+ return location_prologue (epilogue_, type_, name_, l, sverb_ ());
}
template <typename L>
location_prologue
operator() (const L& l) const
{
- return location_prologue (type_, name_, get_location (l, data_), false);
+ return location_prologue (
+ epilogue_, type_, name_, get_location (l, data_), sverb_ ());
}
protected:
+ uint16_t (*sverb_) ();
const char* type_;
const char* name_;
const void* data_;
+ const diag_epilogue epilogue_;
};
typedef diag_mark<basic_mark_base> basic_mark;
extern const basic_mark error;
extern const basic_mark warn;
extern const basic_mark info;
-
- // text
- //
- struct text_mark_base: basic_mark_base
- {
- text_mark_base (): basic_mark_base (nullptr) {}
-
- simple_prologue
- operator() () const
- {
- return simple_prologue (type_, name_, verb <= 1);
- }
- };
- typedef diag_mark<text_mark_base> text_mark;
-
- extern const text_mark text;
+ extern const basic_mark text;
// trace
//
@@ -352,7 +370,8 @@ namespace build2
{
explicit
trace_mark_base (const char* name, const void* data = nullptr)
- : basic_mark_base ("trace", name, data) {}
+ : basic_mark_base ([]() {return stream_verb_max;}, "trace", name, data)
+ {}
};
typedef diag_mark<trace_mark_base> trace_mark;
@@ -361,36 +380,15 @@ namespace build2
// fail
//
template <typename E>
- struct fail_mark_base
+ struct fail_mark_base: basic_mark_base
{
explicit
- fail_mark_base (const void* data = nullptr): data_ (data) {}
-
- simple_prologue
- operator() () const
- {
- return simple_prologue (&epilogue, "error", nullptr, false);
- }
-
- location_prologue
- operator() (const location& l) const
- {
- return location_prologue (&epilogue, "error", nullptr, l, false);
- }
-
- template <typename L>
- location_prologue
- operator() (const L& l) const
- {
- return location_prologue (
- &epilogue, "error", nullptr, get_location (l, data_), false);
- }
+ fail_mark_base (const void* data = nullptr)
+ : basic_mark_base (&stream_verb_map, "error", nullptr, data, &epilogue)
+ {}
static void
epilogue (const diag_record&) {throw E ();}
-
- private:
- const void* data_;
};
template <typename E>
diff --git a/build2/diagnostics.cxx b/build2/diagnostics.cxx
index 50e4578..fb108dc 100644
--- a/build2/diagnostics.cxx
+++ b/build2/diagnostics.cxx
@@ -13,9 +13,9 @@ using namespace std;
namespace build2
{
- // Relative stream.
+ // Stream verbosity.
//
- const int relative_index = ostream::xalloc ();
+ const int stream_verb_index = ostream::xalloc ();
void
print_process (const char* const* args, size_t n)
@@ -94,7 +94,7 @@ namespace build2
void simple_prologue_base::
operator() (const diag_record& r) const
{
- relative (r.os_, relative_);
+ stream_verb (r.os_, sverb_);
if (type_ != nullptr)
r << type_ << ": ";
@@ -106,9 +106,9 @@ namespace build2
void location_prologue_base::
operator() (const diag_record& r) const
{
- relative (r.os_, relative_);
+ stream_verb (r.os_, sverb_);
- r << loc_.file << ':' << loc_.line << ':' << loc_.column << ": ";
+ r << *loc_.file << ':' << loc_.line << ':' << loc_.column << ": ";
if (type_ != nullptr)
r << type_ << ": ";
@@ -117,9 +117,10 @@ namespace build2
r << name_ << ": ";
}
- const basic_mark error ("error");
- const basic_mark warn ("warning");
- const basic_mark info ("info");
- const text_mark text;
+ const basic_mark error (&stream_verb_map, "error");
+ const basic_mark warn (&stream_verb_map, "warning");
+ const basic_mark info (&stream_verb_map, "info");
+ const basic_mark text (&stream_verb_map, nullptr);
+
const fail_mark<failed> fail;
}
diff --git a/build2/file.cxx b/build2/file.cxx
index 68b655e..9a5ab80 100644
--- a/build2/file.cxx
+++ b/build2/file.cxx
@@ -275,9 +275,7 @@ namespace build2
ifs.exceptions (ifstream::failbit | ifstream::badbit);
- path rbf (diag_relative (bf));
-
- lexer lex (ifs, rbf.string ());
+ lexer lex (ifs, bf);
token t (lex.next ());
token_type tt;
@@ -286,7 +284,7 @@ namespace build2
tt != token_type::prepend &&
tt != token_type::append))
{
- error << "variable '" << var << "' expected as first line in " << rbf;
+ error << "variable '" << var << "' expected as first line in " << bf;
throw failed (); // Suppress "used uninitialized" warning.
}
diff --git a/build2/lexer b/build2/lexer
index 69ca0a8..06f2b24 100644
--- a/build2/lexer
+++ b/build2/lexer
@@ -44,14 +44,14 @@ namespace build2
{
public:
lexer (std::istream& is,
- const std::string& name,
+ const path& name,
void (*processor) (token&, const lexer&) = nullptr)
: char_scanner (is), fail (name), processor_ (processor), sep_ (false)
{
mode_.push (lexer_mode::normal);
}
- const std::string&
+ const path&
name () const {return fail.name_;}
// Note: sets mode for the next token. If mode is pairs, then
@@ -115,12 +115,12 @@ namespace build2
private:
struct fail_mark_base: build2::fail_mark_base<failed>
{
- fail_mark_base (const std::string& n): name_ (n) {}
+ fail_mark_base (const path& n): name_ (n) {}
location_prologue
operator() (const xchar&) const;
- std::string name_;
+ path name_;
};
typedef diag_mark<fail_mark_base> fail_mark;
diff --git a/build2/lexer.cxx b/build2/lexer.cxx
index da3d64e..c73017e 100644
--- a/build2/lexer.cxx
+++ b/build2/lexer.cxx
@@ -458,6 +458,6 @@ namespace build2
operator() (const xchar& c) const
{
return build2::fail_mark_base<failed>::operator() (
- location (name_.c_str (), c.line, c.column));
+ location (&name_, c.line, c.column));
}
}
diff --git a/build2/parser b/build2/parser
index a379bd7..ae3add9 100644
--- a/build2/parser
+++ b/build2/parser
@@ -36,13 +36,14 @@ namespace build2
// Issue diagnostics and throw failed in case of an error.
//
void
- parse_buildfile (std::istream&, const path&, scope& root, scope& base);
+ parse_buildfile (std::istream&, const path& name,
+ scope& root, scope& base);
buildspec
- parse_buildspec (std::istream&, const std::string& name);
+ parse_buildspec (std::istream&, const path& name);
token
- parse_variable (lexer&, scope&, std::string name, token_type kind);
+ parse_variable (lexer&, scope&, std::string var_name, token_type kind);
names_type
parse_export_stub (std::istream& is, const path& p, scope& r, scope& b)
@@ -285,7 +286,7 @@ namespace build2
protected:
bool boot_;
- const std::string* path_; // Path processed by diag_relative() and pooled.
+ const path* path_; // Current path.
lexer* lexer_;
target* target_; // Current target, if any.
scope* scope_; // Current base scope (out_base).
diff --git a/build2/parser.cxx b/build2/parser.cxx
index 187c47e..7e07834 100644
--- a/build2/parser.cxx
+++ b/build2/parser.cxx
@@ -39,7 +39,7 @@ namespace build2
{
enter_buildfile (p);
- path_ = &path_pool.find (diag_relative (p)); // Relative to work.
+ path_ = &p;
lexer l (is, *path_);
lexer_ = &l;
@@ -63,14 +63,14 @@ namespace build2
token parser::
parse_variable (lexer& l, scope& s, string name, type kind)
{
- path_ = &l.name (); // Note: not pooled.
+ path_ = &l.name ();
lexer_ = &l;
target_ = nullptr;
scope_ = &s;
type tt;
token t (type::eos, false, 0, 0);
- variable (t, tt, name, kind);
+ variable (t, tt, move (name), kind);
return t;
}
@@ -539,8 +539,8 @@ namespace build2
enter_buildfile (p);
- const string* op (path_);
- path_ = &path_pool.find (diag_relative (p)); // Relative to work.
+ const path* op (path_);
+ path_ = &p;
lexer l (ifs, *path_);
lexer* ol (lexer_);
@@ -675,8 +675,8 @@ namespace build2
enter_buildfile (p);
- const string* op (path_);
- path_ = &path_pool.find (diag_relative (p)); // Relative to work.
+ const path* op (path_);
+ path_ = &p;
lexer l (ifs, *path_);
lexer* ol (lexer_);
@@ -1899,11 +1899,11 @@ namespace build2
}
buildspec parser::
- parse_buildspec (istream& is, const std::string& name)
+ parse_buildspec (istream& is, const path& name)
{
- path_ = &name; // Note: caller pools.
+ path_ = &name;
- lexer l (is, name, &paren_processor);
+ lexer l (is, *path_, &paren_processor);
lexer_ = &l;
target_ = nullptr;
scope_ = root_ = global_scope;
@@ -2232,8 +2232,8 @@ namespace build2
static location
get_location (const token& t, const void* data)
{
- assert (data != nullptr);
- const string& p (**static_cast<const string* const*> (data));
- return location (p.c_str (), t.line, t.column);
+ assert (data != nullptr); // &parser::path_
+ const path* p (*static_cast<const path* const*> (data));
+ return location (p, t.line, t.column);
}
}
diff --git a/build2/path-io.cxx b/build2/path-io.cxx
index 81b981b..845b0a3 100644
--- a/build2/path-io.cxx
+++ b/build2/path-io.cxx
@@ -16,14 +16,14 @@ namespace build2
ostream&
operator<< (ostream& os, const path& p)
{
- return os << (relative (os) ? diag_relative (p) : p.string ());
+ return os << (stream_verb (os) < 2 ? diag_relative (p) : p.string ());
}
ostream&
operator<< (ostream& os, const dir_path& d)
{
- if (relative (os))
- os << diag_relative (d);
+ if (stream_verb (os) < 2)
+ os << diag_relative (d); // Adds trailing '/'.
else
{
const string& s (d.string ());
diff --git a/build2/prerequisite.cxx b/build2/prerequisite.cxx
index 2192abe..fb432eb 100644
--- a/build2/prerequisite.cxx
+++ b/build2/prerequisite.cxx
@@ -22,16 +22,26 @@ namespace build2
{
if (pk.proj != nullptr)
os << *pk.proj << '%';
-
- // Don't print scope if we are project-qualified or the
- // prerequisite's directory is absolute. In both these
- // cases the scope is not used to resolve it to target.
+ //
+ // Don't print scope if we are project-qualified or the prerequisite's
+ // directory is absolute. In both these cases the scope is not used to
+ // resolve it to target.
//
else if (!pk.tk.dir->absolute ())
{
- string s (diag_relative (pk.scope->out_path (), false));
+ // Avoid printing './' in './:...', similar to what we do for the
+ // directory in target_key.
+ //
+ const dir_path& s (pk.scope->out_path ());
+
+ if (stream_verb (os) < 2)
+ {
+ const string& r (diag_relative (s, false));
- if (!s.empty ())
+ if (!r.empty ())
+ os << r << ':';
+ }
+ else
os << s << ':';
}
diff --git a/build2/spec.cxx b/build2/spec.cxx
index 89ed9c8..3f02d87 100644
--- a/build2/spec.cxx
+++ b/build2/spec.cxx
@@ -18,10 +18,18 @@ namespace build2
{
if (!s.src_base.empty ())
{
- string d (diag_relative (s.src_base, false));
-
- if (!d.empty ())
- os << d << '@';
+ // Avoid printing './' in './@...', similar to what we do for the
+ // {target,prerequisite}_key.
+ //
+ if (stream_verb (os) < 2)
+ {
+ const string& r (diag_relative (s.src_base, false));
+
+ if (!r.empty ())
+ os << r << '@';
+ }
+ else
+ os << s.src_base << '@';
}
os << s.name;
diff --git a/build2/target.cxx b/build2/target.cxx
index 0dcf959..43c6a41 100644
--- a/build2/target.cxx
+++ b/build2/target.cxx
@@ -254,10 +254,16 @@ namespace build2
// inside {}, e.g., dir{bar/}, not bar/dir{}.
//
bool n (!k.name->empty ());
- string d (diag_relative (*k.dir, false));
if (n)
- os << d;
+ {
+ // Avoid printing './' in './{...}'
+ //
+ if (stream_verb (os) < 2)
+ os << diag_relative (*k.dir, false);
+ else
+ os << *k.dir;
+ }
os << k.type->name << '{';
@@ -269,7 +275,7 @@ namespace build2
os << '.' << *k.ext;
}
else
- os << d;
+ os << *k.dir;
os << '}';
diff --git a/build2/types b/build2/types
index 407a3b5..35aaa58 100644
--- a/build2/types
+++ b/build2/types
@@ -5,11 +5,13 @@
#ifndef BUILD2_TYPES
#define BUILD2_TYPES
+#include <iosfwd> // ostream
#include <vector>
#include <string>
#include <utility> // pair
#include <memory> // unique_ptr, shared_ptr
#include <cstddef> // size_t
+#include <cstdint> // uint{8,16,32,64}_t
#include <functional> // reference_wrapper
#include <butl/path>
@@ -21,8 +23,13 @@ namespace build2
{
// Commonly-used types.
//
- using std::pair;
+ using std::uint8_t;
+ using std::uint16_t;
+ using std::uint32_t;
+ using std::uint64_t;
using std::size_t;
+
+ using std::pair;
using std::string;
using std::unique_ptr;
using std::shared_ptr;
@@ -32,6 +39,10 @@ namespace build2
using strings = vector<string>;
using cstrings = vector<const char*>;
+ // <iosfwd>
+ //
+ using std::ostream;
+
// <butl/path>
//
using butl::path;