From fdb050b4b1b966683ff00dd14b268fe395492358 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 24 Feb 2015 08:27:04 +0200 Subject: Use prefix_map for scopes, establish root scope --- build/b.cxx | 10 +++++++ build/context | 3 ++ build/context.cxx | 2 ++ build/parser.cxx | 25 ++++++++++++---- build/path-map | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++ build/path.txx | 2 +- build/prefix-map | 1 + build/prerequisite.cxx | 4 +-- build/scope | 7 ++--- build/target.cxx | 2 +- build/utility | 1 - 11 files changed, 120 insertions(+), 14 deletions(-) create mode 100644 build/path-map (limited to 'build') diff --git a/build/b.cxx b/build/b.cxx index 05dac4c..492fdea 100644 --- a/build/b.cxx +++ b/build/b.cxx @@ -152,6 +152,16 @@ main (int argc, char* argv[]) trace << "src_root: " << src_root.string (); } + // Create root scope. For Win32 we use the empty path since there + // is no such "real" root path. On POSIX, however, this is a real + // path. See the comment in for details. + // +#ifdef _WIN32 + root_scope = &scopes[path ()]; +#else + root_scope = &scopes[path ("/")]; +#endif + // Parse buildfile. // path bf ("buildfile"); diff --git a/build/context b/build/context index c177603..4f5b029 100644 --- a/build/context +++ b/build/context @@ -21,6 +21,9 @@ namespace build extern path src_base; extern path out_base; + class scope; + extern scope* root_scope; + // Return the src/out directory corresponding to the given out/src. The // passed directory should be a sub-directory of out/src_root. // diff --git a/build/context.cxx b/build/context.cxx index 79753ec..a298d41 100644 --- a/build/context.cxx +++ b/build/context.cxx @@ -20,6 +20,8 @@ namespace build path src_base; path out_base; + scope* root_scope; + path src_out (const path& o) { diff --git a/build/parser.cxx b/build/parser.cxx index 5102c60..9ebf8d3 100644 --- a/build/parser.cxx +++ b/build/parser.cxx @@ -158,8 +158,15 @@ namespace build if (dir) { scope& prev (*scope_); - path p (tns[0].name); + // On Win32 translate the root path to the special empty path. + // Search for root_scope for details. + // +#ifdef _WIN32 + path p (tns[0].name != "/" ? path (tns[0].name) : path ()); +#else + path p (tns[0].name); +#endif if (p.relative ()) p = prev.path () / p; @@ -197,9 +204,14 @@ namespace build // Dependency declaration. // - if (tt == type::name || tt == type::lcbrace || tt == type::newline) + if (tt == type::name || + tt == type::lcbrace || + tt == type::newline || + tt == type::eos) { - names_type pns (tt != type::newline ? names (t, tt) : names_type ()); + names_type pns (tt != type::newline && tt != type::eos + ? names (t, tt) + : names_type ()); // Prepare the prerequisite list. // @@ -224,7 +236,7 @@ namespace build n = move (pn.name); // NOTE: steal! else { - d /= path (pn.name, i); + d /= path (pn.name, i != 0 ? i : 1); // Special case: "/". n.assign (pn.name, i + 1, string::npos); } @@ -292,7 +304,7 @@ namespace build n = move (tn.name); // NOTE: steal! else { - d /= path (tn.name, i); + d /= path (tn.name, i != 0 ? i : 1); // Special case: "/". n.assign (tn.name, i + 1, string::npos); } @@ -630,7 +642,10 @@ namespace build peek () { if (!peeked_) + { peek_ = lexer_->next (); + peeked_ = true; + } return peek_.type (); } diff --git a/build/path-map b/build/path-map new file mode 100644 index 0000000..c422dde --- /dev/null +++ b/build/path-map @@ -0,0 +1,77 @@ +// file : build/path-map -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#ifndef BUILD_PATH_MAP +#define BUILD_PATH_MAP + +#include +#include + +namespace build +{ + // prefix_map for paths + // + // The paths should be normalized. + // + // Note that the path's representation of POSIX root ('/') is + // inconsistent in that we have a trailing delimiter at the end of + // the path (its "proper" representation would have been an empty + // string but that would have clashed with empty paths). To work + // around this snag, this implementation, during key comparison, + // detects '/' and treats it as empty. Note that the map will + // still store the key as you have first inserted it. So if you + // want a particular representation, pre-populate the map with + // it. + // + template + struct compare_prefix>: compare_prefix> + { + typedef basic_path K; + + typedef C char_type; + typedef std::basic_string string_type; + typedef compare_prefix> base; + + explicit + compare_prefix (C d): base (d) {} + + bool + operator() (const K& x, const K& y) const + { + const auto& xs (x.string ()); + const auto& ys (y.string ()); + +#ifdef _WIN32 + return base::compare (xs.c_str (), + xs.size (), + ys.c_str (), + ys.size ()) < 0; +#else + return base::compare (xs.c_str (), + x.root () ? 0 : xs.size (), + ys.c_str (), + y.root () ? 0 : ys.size ()) < 0; +#endif + } + + bool + prefix (const K& p, const K& k) const + { + const auto& ps (p.string ()); + const auto& ks (k.string ()); + +#ifdef _WIN32 + return base::prefix (ps, ks); +#else + return base::prefix (p.root () ? string_type () : ps, + k.root () ? string_type () : ks); +#endif + } + }; + + template + using path_map = prefix_map; +} + +#endif // BUILD_PATH_MAP diff --git a/build/path.txx b/build/path.txx index 881dc17..5fbabbd 100644 --- a/build/path.txx +++ b/build/path.txx @@ -58,7 +58,7 @@ namespace build basic_path& basic_path:: operator/= (basic_path const& r) { - if (r.absolute ()) + if (r.absolute () && !path_.empty ()) // Allow ('' / '/foo'). throw invalid_basic_path (r.path_); if (path_.empty () || r.path_.empty ()) diff --git a/build/prefix-map b/build/prefix-map index a385ca8..1b00337 100644 --- a/build/prefix-map +++ b/build/prefix-map @@ -44,6 +44,7 @@ namespace build p.c_str (), pn, k.c_str (), pn == k.size () ? pn : pn + 1) == 0; } + protected: int compare (const C* x, size_type xn, const C* y, size_type yn) const diff --git a/build/prerequisite.cxx b/build/prerequisite.cxx index debafe6..f2c72e5 100644 --- a/build/prerequisite.cxx +++ b/build/prerequisite.cxx @@ -30,7 +30,7 @@ namespace build { string s (diag_relative_work (p.scope.path ())); - if (!s.empty ()) + if (!s.empty () && s.back () != path::traits::directory_separator) os << s << path::traits::directory_separator << ": "; } @@ -40,7 +40,7 @@ namespace build { string s (diag_relative_work (p.dir)); - if (!s.empty ()) + if (!s.empty () && s.back () != path::traits::directory_separator) os << s << path::traits::directory_separator; } diff --git a/build/scope b/build/scope index 760fc03..58f7933 100644 --- a/build/scope +++ b/build/scope @@ -5,9 +5,8 @@ #ifndef BUILD_SCOPE #define BUILD_SCOPE -#include - #include +#include #include namespace build @@ -23,7 +22,7 @@ namespace build private: friend class scope_map; - typedef std::map::const_iterator iterator; + typedef path_map::const_iterator iterator; scope () = default; @@ -37,7 +36,7 @@ namespace build iterator i_; }; - class scope_map: std::map + class scope_map: path_map { public: scope& diff --git a/build/target.cxx b/build/target.cxx index 235ceef..bb578c1 100644 --- a/build/target.cxx +++ b/build/target.cxx @@ -33,7 +33,7 @@ namespace build { os << s; - if (!t.name.empty ()) + if (!t.name.empty () && s.back () != path::traits::directory_separator) os << path::traits::directory_separator; } } diff --git a/build/utility b/build/utility index 5523e8b..f429598 100644 --- a/build/utility +++ b/build/utility @@ -12,7 +12,6 @@ #include #include - namespace build { struct compare_c_string -- cgit v1.1