aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-02-24 08:27:04 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-02-24 08:27:04 +0200
commitfdb050b4b1b966683ff00dd14b268fe395492358 (patch)
treeb4da8e293eef9d8682c14cf64f2ed25cc1cc75ab
parent52925684387496e83425c79f74b29a91943466a7 (diff)
Use prefix_map for scopes, establish root scope
-rw-r--r--build/b.cxx10
-rw-r--r--build/context3
-rw-r--r--build/context.cxx2
-rw-r--r--build/parser.cxx25
-rw-r--r--build/path-map77
-rw-r--r--build/path.txx2
-rw-r--r--build/prefix-map1
-rw-r--r--build/prerequisite.cxx4
-rw-r--r--build/scope7
-rw-r--r--build/target.cxx2
-rw-r--r--build/utility1
11 files changed, 120 insertions, 14 deletions
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 <build/path-map> 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 <build/path>
+#include <build/prefix-map>
+
+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 <typename C>
+ struct compare_prefix<basic_path<C>>: compare_prefix<std::basic_string<C>>
+ {
+ typedef basic_path<C> K;
+
+ typedef C char_type;
+ typedef std::basic_string<C> string_type;
+ typedef compare_prefix<std::basic_string<C>> 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 <typename T>
+ using path_map = prefix_map<path, T, path::traits::directory_separator>;
+}
+
+#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<C>& basic_path<C>::
operator/= (basic_path<C> const& r)
{
- if (r.absolute ())
+ if (r.absolute () && !path_.empty ()) // Allow ('' / '/foo').
throw invalid_basic_path<C> (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 <map>
-
#include <build/path>
+#include <build/path-map>
#include <build/prerequisite>
namespace build
@@ -23,7 +22,7 @@ namespace build
private:
friend class scope_map;
- typedef std::map<path_type, scope>::const_iterator iterator;
+ typedef path_map<scope>::const_iterator iterator;
scope () = default;
@@ -37,7 +36,7 @@ namespace build
iterator i_;
};
- class scope_map: std::map<path, scope>
+ class scope_map: path_map<scope>
{
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 <exception>
#include <unordered_set>
-
namespace build
{
struct compare_c_string