diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2015-04-13 15:50:17 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2015-04-13 15:50:17 +0200 |
commit | ace1743f7f78bb13f99553d6e97ad1beecf1ba99 (patch) | |
tree | 595bc9dad989e44f4be9a67e351219f3248dc5f0 | |
parent | 534f9d8db025d58c9ce23f3b81a37e8c34386a27 (diff) |
Add separate type to represent directory paths
43 files changed, 606 insertions, 533 deletions
diff --git a/build/algorithm b/build/algorithm index c056d57..7d2c226 100644 --- a/build/algorithm +++ b/build/algorithm @@ -35,7 +35,7 @@ namespace build // in the same or a subdirectory of dir. // void - search_and_match (action, target&, const path& dir); + search_and_match (action, target&, const dir_path& dir); // Inject dependency on the parent directory fsdir{}, unless it is // the project's out_root (or is outside of any project; think, for diff --git a/build/algorithm.cxx b/build/algorithm.cxx index 3fc2e92..7675b0c 100644 --- a/build/algorithm.cxx +++ b/build/algorithm.cxx @@ -155,7 +155,7 @@ namespace build } void - search_and_match (action a, target& t, const path& d) + search_and_match (action a, target& t, const dir_path& d) { for (prerequisite& p: t.prerequisites) { @@ -177,12 +177,12 @@ namespace build if (scope* rs = s.root_scope ()) // Could be outside any project. { - const path& out_root (rs->path ()); + const dir_path& out_root (rs->path ()); // If t is a directory (name is empty), say foo/bar/, then // t is bar and its parent directory is foo/. // - const path& d (t.name.empty () ? t.dir.directory () : t.dir); + const dir_path& d (t.name.empty () ? t.dir.directory () : t.dir); if (d.sub (out_root) && d != out_root) { diff --git a/build/b.cxx b/build/b.cxx index 8d2ca47..e53844c 100644 --- a/build/b.cxx +++ b/build/b.cxx @@ -47,33 +47,33 @@ namespace build // based on the presence of known special files. Return empty // path if not found. // - path - find_src_root (const path& b) + dir_path + find_src_root (const dir_path& b) { - for (path d (b); !d.root () && d != home; d = d.directory ()) + for (dir_path d (b); !d.root () && d != home; d = d.directory ()) { if (is_src_root (d)) return d; } - return path (); + return dir_path (); } // The same but for out. Note that we also check whether a // directory happens to be src_root, in case this is an in- // tree build. // - path - find_out_root (const path& b, bool& src) + dir_path + find_out_root (const dir_path& b, bool& src) { - for (path d (b); !d.root () && d != home; d = d.directory ()) + for (dir_path d (b); !d.root () && d != home; d = d.directory ()) { if ((src = is_src_root (d)) || is_out_root (d)) return d; } src = false; - return path (); + return dir_path (); } } @@ -179,10 +179,10 @@ main (int argc, char* argv[]) // Figure out work and home directories. // - work = path::current (); + work = dir_path::current (); if (const char* h = getenv ("HOME")) - home = path (h); + home = dir_path (h); else { struct passwd* pw (getpwuid (getuid ())); @@ -193,13 +193,13 @@ main (int argc, char* argv[]) fail << "unable to determine home directory: " << msg; } - home = path (pw->pw_dir); + home = dir_path (pw->pw_dir); } if (verb >= 4) { - trace << "work dir: " << work.string (); - trace << "home dir: " << home.string (); + trace << "work dir: " << work; + trace << "home dir: " << home; } // Initialize the dependency state. @@ -293,7 +293,7 @@ main (int argc, char* argv[]) const location l ("<buildspec>", 1, 0); //@@ TODO if (os.empty ()) // Default target: dir{}. - os.push_back (targetspec (name ("dir", path (), string ()))); + os.push_back (targetspec (name ("dir", dir_path (), string ()))); operation_id oid (0); // Not yet translated. const operation_info* oif (nullptr); @@ -332,7 +332,7 @@ main (int argc, char* argv[]) // value has a directory prefix. This has a good balance of // control and the expected result in most cases. // - path out_base (tn.dir); + dir_path out_base (tn.dir); if (out_base.empty ()) { const string& v (tn.value); @@ -342,7 +342,7 @@ main (int argc, char* argv[]) // This code must be consistent with target_type_map::find(). // if (v.empty () || v == "." || v == ".." || tn.type == "dir") - out_base = path (v); + out_base = dir_path (v); else { // See if there is a directory part in value. We cannot @@ -352,7 +352,7 @@ main (int argc, char* argv[]) path::size_type i (path::traits::rfind_separator (v)); if (i != string::npos) - out_base = path (v, i != 0 ? i : 1); // Special case: "/". + out_base = dir_path (v, i != 0 ? i : 1); // Special case: "/". } } @@ -368,10 +368,10 @@ main (int argc, char* argv[]) // diagnostics for such cases. // bool guessing (false); - path src_root; - path out_root; + dir_path src_root; + dir_path out_root; - path& src_base (ts.src_base); // Update it in buildspec. + dir_path& src_base (ts.src_base); // Update it in buildspec. if (!src_base.empty ()) { @@ -427,9 +427,9 @@ main (int argc, char* argv[]) catch (const invalid_path&) { fail << "out_base directory suffix does not match src_base" - << info << "src_base is " << src_base.string () - << info << "src_root is " << src_root.string () - << info << "out_base is " << out_base.string () + << info << "src_base is " << src_base + << info << "src_root is " << src_root + << info << "out_base is " << out_base << info << "consider explicitly specifying src_base " << "for " << tn; } @@ -470,7 +470,7 @@ main (int argc, char* argv[]) // If we also have src_root specified by the user, make // sure they match. // - const path& p (v.as<const path&> ()); + const dir_path& p (v.as<const dir_path&> ()); if (src_root.empty ()) src_root = p; @@ -503,7 +503,7 @@ main (int argc, char* argv[]) v = src_root; } - rs.src_path_ = &v.as<const path&> (); + rs.src_path_ = &v.as<const dir_path&> (); } // At this stage we should have both roots and out_base figured @@ -719,10 +719,10 @@ main (int argc, char* argv[]) if (verb >= 4) { trace << "target " << tn << ':'; - trace << " out_base: " << out_base.string (); - trace << " src_base: " << src_base.string (); - trace << " out_root: " << out_root.string (); - trace << " src_root: " << src_root.string (); + trace << " out_base: " << out_base; + trace << " src_base: " << src_base; + trace << " out_root: " << out_root; + trace << " src_root: " << src_root; } path bf (src_base / path ("buildfile")); @@ -753,7 +753,7 @@ main (int argc, char* argv[]) // If the directory is relative, assume it is relative to work // (must be consistent with how we derived out_base above). // - path& d (tn.dir); + dir_path& d (tn.dir); if (d.relative ()) d = work / d; diff --git a/build/config/module.cxx b/build/config/module.cxx index 59fbb1f..9ed0cec 100644 --- a/build/config/module.cxx +++ b/build/config/module.cxx @@ -36,8 +36,8 @@ namespace build if (&root != &base) fail (l) << "config module must be initialized in project root scope"; - const path& out_root (root.path ()); - level4 ([&]{trace << "for " << out_root << '/';}); + const dir_path& out_root (root.path ()); + level4 ([&]{trace << "for " << out_root;}); // Register meta-operations. // diff --git a/build/config/operation.cxx b/build/config/operation.cxx index 85d0d07..14f2a0a 100644 --- a/build/config/operation.cxx +++ b/build/config/operation.cxx @@ -18,8 +18,8 @@ namespace build { namespace config { - static const path build_dir ("build"); - static const path bootstrap_dir ("build/bootstrap"); + static const dir_path build_dir ("build"); + static const dir_path bootstrap_dir ("build/bootstrap"); static const path config_file ("build/config.build"); static const path src_root_file ("build/bootstrap/src-root.build"); @@ -36,7 +36,7 @@ namespace build } static void - save_src_root (const path& out_root, const path& src_root) + save_src_root (const dir_path& out_root, const dir_path& src_root) { path f (out_root / src_root_file); @@ -57,7 +57,7 @@ namespace build // ofs << "# Created automatically by the config module." << endl << "#" << endl - << "src_root = " << src_root.string () << '/' << endl; + << "src_root = " << src_root << endl; } catch (const ios_base::failure&) { @@ -68,7 +68,7 @@ namespace build static void save_config (scope& root) { - const path& out_root (root.path ()); + const dir_path& out_root (root.path ()); path f (out_root / config_file); if (verb >= 1) @@ -90,7 +90,7 @@ namespace build if (auto v = root.ro_variables ()["amalgamation"]) { - const path& d (v.as<const path&> ()); + const dir_path& d (v.as<const dir_path&> ()); ofs << "# Base configuration inherited from " << d << "/ ." << endl << "#" << endl; @@ -144,8 +144,8 @@ namespace build { tracer trace ("configure_project"); - const path& out_root (root.path ()); - const path& src_root (root.src_path ()); + const dir_path& out_root (root.path ()); + const dir_path& src_root (root.src_path ()); // Make sure the directories exist. // @@ -182,7 +182,7 @@ namespace build { for (const name& n: v.as<const list_value&> ()) { - path out_nroot (out_root / n.dir); + dir_path out_nroot (out_root / n.dir); scope& nroot (scopes.find (out_nroot)); // @@ Strictly speaking we need to check whether the config @@ -239,8 +239,8 @@ namespace build static void disfigure_load (const path& bf, scope&, - const path&, - const path&, + const dir_path&, + const dir_path&, const location&) { tracer trace ("disfigure_load"); @@ -266,8 +266,8 @@ namespace build bool m (false); // Keep track of whether we actually did anything. - const path& out_root (root.path ()); - const path& src_root (root.src_path ()); + const dir_path& out_root (root.path ()); + const dir_path& src_root (root.src_path ()); // Disfigure subprojects. Since we don't load buildfiles during // disfigure, we do it for all known subprojects. @@ -278,15 +278,16 @@ namespace build { // Create and bootstrap subproject's root scope. // - path out_nroot (out_root / n.dir); - path src_nroot (src_root / n.dir); + dir_path out_nroot (out_root / n.dir); + dir_path src_nroot (src_root / n.dir); scope& nroot (create_root (out_nroot, src_nroot)); bootstrap_out (nroot); // Check if the bootstrap process changed src_root. // - const path& p (nroot.variables["src_root"].as<const path&> ()); + const dir_path& p ( + nroot.variables["src_root"].as<const dir_path&> ()); if (src_nroot != p) fail << "bootstrapped src_root " << p << " does not match " diff --git a/build/context b/build/context index 39e00e7..0e28472 100644 --- a/build/context +++ b/build/context @@ -18,8 +18,8 @@ namespace build class scope; class file; - extern path work; - extern path home; + extern dir_path work; + extern dir_path home; // Current action (meta/operation). // @@ -54,7 +54,7 @@ namespace build // important. See the fsdir{} rule for details. // fs_status<mkdir_status> - mkdir (const path&); + mkdir (const dir_path&); // Remove the file and print the standard diagnostics. The second // argument is only used in diagnostics, to print the target name. @@ -72,39 +72,42 @@ namespace build // template <typename T> fs_status<rmdir_status> - rmdir (const path&, const T& target); + rmdir (const dir_path&, const T& target); inline fs_status<rmdir_status> - rmdir (const path& d) {return rmdir (d, d);} + rmdir (const dir_path& d) {return rmdir (d, d);} // Return the src/out directory corresponding to the given out/src. The // passed directory should be a sub-directory of out/src_root. // - path - src_out (const path& out, scope&); + dir_path + src_out (const dir_path& out, scope&); - path - src_out (const path& out, const path& out_root, const path& src_root); + dir_path + src_out (const dir_path& out, + const dir_path& out_root, const dir_path& src_root); - path - out_src (const path& src, scope&); + dir_path + out_src (const dir_path& src, scope&); - path - out_src (const path& src, const path& out_root, const path& src_root); + dir_path + out_src (const dir_path& src, + const dir_path& out_root, const dir_path& src_root); // If possible and beneficial, translate an absolute, normalized path // into relative to the relative_base directory, which is normally // work. // - path - relative (const path&); + template <typename K> + basic_path<char, K> + relative (const basic_path<char, K>&); // By default this points to work. Setting this to something else // should only be done in tightly controlled, non-parallel // situations (see dump). If base is empty, then relative() // returns the original path. // - extern const path* relative_base; + extern const dir_path* relative_base; } #include <build/context.txx> diff --git a/build/context.cxx b/build/context.cxx index 7303e7d..d87ce11 100644 --- a/build/context.cxx +++ b/build/context.cxx @@ -15,8 +15,8 @@ using namespace std; namespace build { - path work; - path home; + dir_path work; + dir_path home; const meta_operation_info* current_mif; const operation_info* current_oif; @@ -35,9 +35,9 @@ namespace build // See the comment in <build/path-map> for details. // #ifdef _WIN32 - global_scope = &scopes[path ()]; + global_scope = &scopes[dir_path ()]; #else - global_scope = &scopes[path ("/")]; + global_scope = &scopes[dir_path ("/")]; #endif global_scope->variables["work"] = work; @@ -45,7 +45,7 @@ namespace build } fs_status<mkdir_status> - mkdir (const path& d) + mkdir (const dir_path& d) { // We don't want to print the command if the directory already // exists. This makes the below code a bit ugly. @@ -78,68 +78,35 @@ namespace build return ms; } - path - src_out (const path& out, scope& s) + dir_path + src_out (const dir_path& out, scope& s) { scope& rs (*s.root_scope ()); return src_out (out, rs.path (), rs.src_path ()); } - path - out_src (const path& src, scope& s) + dir_path + out_src (const dir_path& src, scope& s) { scope& rs (*s.root_scope ()); return out_src (src, rs.path (), rs.src_path ()); } - path - src_out (const path& o, const path& out_root, const path& src_root) + dir_path + src_out (const dir_path& o, + const dir_path& out_root, const dir_path& src_root) { assert (o.sub (out_root)); return src_root / o.leaf (out_root); } - path - out_src (const path& s, const path& out_root, const path& src_root) + dir_path + out_src (const dir_path& s, + const dir_path& out_root, const dir_path& src_root) { assert (s.sub (src_root)); return out_root / s.leaf (src_root); } - const path* relative_base = &work; - - path - relative (const path& p) - { - const path& b (*relative_base); - - if (b.empty ()) - return p; - - if (p.sub (b)) - return p.leaf (b); - - // If base is a sub-path of {src,out}_root and this path is also a - // sub-path of it, then use '..' to form a relative path. - // - // Don't think this is a good heuristic. For example, why shouldn't - // we display paths from imported projects as relative if they are - // more readable than absolute? - // - /* - if ((work.sub (src_root) && p.sub (src_root)) || - (work.sub (out_root) && p.sub (out_root))) - return p.relative (work); - */ - - if (p.root_directory () == b.root_directory ()) - { - path r (p.relative (b)); - - if (r.string ().size () < p.string ().size ()) - return r; - } - - return p; - } + const dir_path* relative_base = &work; } diff --git a/build/context.txx b/build/context.txx index 53081b1..218c65e 100644 --- a/build/context.txx +++ b/build/context.txx @@ -46,7 +46,7 @@ namespace build template <typename T> fs_status<rmdir_status> - rmdir (const path& d, const T& t) + rmdir (const dir_path& d, const T& t) { bool w (d == work); // Don't try to remove working directory. rmdir_status rs; @@ -97,4 +97,42 @@ namespace build return rs; } + + template <typename K> + basic_path<char, K> + relative (const basic_path<char, K>& p) + { + typedef basic_path<char, K> path; + + const dir_path& b (*relative_base); + + if (b.empty ()) + return p; + + if (p.sub (b)) + return p.leaf (b); + + // If base is a sub-path of {src,out}_root and this path is also a + // sub-path of it, then use '..' to form a relative path. + // + // Don't think this is a good heuristic. For example, why shouldn't + // we display paths from imported projects as relative if they are + // more readable than absolute? + // + /* + if ((work.sub (src_root) && p.sub (src_root)) || + (work.sub (out_root) && p.sub (out_root))) + return p.relative (work); + */ + + if (p.root_directory () == b.root_directory ()) + { + path r (p.relative (b)); + + if (r.string ().size () < p.string ().size ()) + return r; + } + + return p; + } } diff --git a/build/cxx/module.cxx b/build/cxx/module.cxx index e29d311..3c9a4b6 100644 --- a/build/cxx/module.cxx +++ b/build/cxx/module.cxx @@ -33,8 +33,8 @@ namespace build //@@ TODO: need to register target types, rules here instead of main(). - const path& out_root (root.path ()); - level4 ([&]{trace << "for " << out_root << '/';}); + const dir_path& out_root (root.path ()); + level4 ([&]{trace << "for " << out_root;}); // Configure. // diff --git a/build/cxx/rule.cxx b/build/cxx/rule.cxx index b4cfb1c..d8a7190 100644 --- a/build/cxx/rule.cxx +++ b/build/cxx/rule.cxx @@ -270,7 +270,7 @@ namespace build // extension rather than NULL (which would signify that the // extension needs to be added). // - path d (f.directory ()); + dir_path d (f.directory ()); string n (f.leaf ().base ().string ()); const char* es (f.extension ()); const string* e (&extension_pool.find (es != nullptr ? es : "")); @@ -471,8 +471,8 @@ namespace build // We may need the project roots for rule chaining (see below). // We will resolve them lazily only if needed. // - const path* out_root (nullptr); - const path* src_root (nullptr); + const dir_path* out_root (nullptr); + const dir_path* src_root (nullptr); // Process prerequisites: do rule chaining for C and C++ source // files as well as search and match. @@ -516,7 +516,7 @@ namespace build // c(xx){} directory is most likely under src_root, it is also // possible it is under out_root (e.g., generated source). // - path d; + dir_path d; if (cp.dir.relative () || cp.dir.sub (*out_root)) d = cp.dir; else diff --git a/build/diagnostics b/build/diagnostics index 3ec80a3..09adaca 100644 --- a/build/diagnostics +++ b/build/diagnostics @@ -14,7 +14,8 @@ #include <exception> #include <type_traits> -#include <build/path> // <build/path-io> included at the end. +#include <build/path> +#include <build/path-io> namespace build { @@ -24,12 +25,17 @@ namespace build class failed: public std::exception {}; // In addition to calling relative(), this function also uses shorter - // notations such as '~/'. If the path is the same as base, it returns - // '.'. + // notations such as '~/'. // std::string diag_relative (const path&); + // As above but also adds trailing '/'. If the path is the same as + // base, returns "./" if current is true and empty string otherwise. + // + std::string + diag_relative (const dir_path&, bool current = true); + // Action phrases, e.g., "configure update exe{foo}", "updating exe{foo}", // and "updating exe{foo} already configured". // @@ -357,6 +363,4 @@ namespace build extern const fail_mark<failed> fail; } -#include <build/path-io> - #endif // BUILD_DIAGNOSTICS diff --git a/build/diagnostics.cxx b/build/diagnostics.cxx index 2fad0d3..bc157ed 100644 --- a/build/diagnostics.cxx +++ b/build/diagnostics.cxx @@ -57,6 +57,24 @@ namespace build return p.string (); } + string + diag_relative (const dir_path& d, bool cur) + { + string r (diag_relative (static_cast<const path&> (d))); + + // Translate "." to empty. + // + if (!cur && d.absolute () && r == ".") + r.clear (); + + // Add trailing '/'. + // + if (!r.empty () && !dir_path::traits::is_separator (r.back ())) + r += '/'; + + return r; + } + // diag_do(), etc. // string diff --git a/build/dump.cxx b/build/dump.cxx index 05ec679..b41e489 100644 --- a/build/dump.cxx +++ b/build/dump.cxx @@ -25,7 +25,12 @@ namespace build for (const prerequisite& p: t.prerequisites) { - os << ' ' << p; + os << ' '; + + if (p.target != nullptr) + os << *p.target; + else + os << p; } } @@ -36,15 +41,14 @@ namespace build string& ind, set<const target*>& rts) { - string d (relative (p.path ()).string ()); - - if (d.back () != path::traits::directory_separator) - d += '/'; - - os << ind << d << ":" << endl + // We don't want the extra notations (e.g., ~/) provided by + // diag_relative() since we want the path to be relative to + // the outer scope. + // + os << ind << relative (p.path ()) << ":" << endl << ind << '{'; - const path* orb (relative_base); + const dir_path* orb (relative_base); relative_base = &p.path (); ind += " "; @@ -14,10 +14,10 @@ namespace build struct location; bool - is_src_root (const path&); + is_src_root (const dir_path&); bool - is_out_root (const path&); + is_out_root (const dir_path&); void source (const path& buildfile, scope& root, scope& base); @@ -37,7 +37,7 @@ namespace build // passed src_root value is not empty. // scope& - create_root (const path& out_root, const path& src_root); + create_root (const dir_path& out_root, const dir_path& src_root); // Bootstrap the project's root scope, the out part. // @@ -61,7 +61,7 @@ namespace build // none were created. Loading is done by load_root_pre() below. // scope& - create_bootstrap_inner (scope& root, const path& out_base); + create_bootstrap_inner (scope& root, const dir_path& out_base); // Load project's root[-pre].build unless already loaded. Also // make sure all outer root scopes are loaded prior to loading diff --git a/build/file.cxx b/build/file.cxx index 70a5ed8..faffce5 100644 --- a/build/file.cxx +++ b/build/file.cxx @@ -16,14 +16,14 @@ using namespace std; namespace build { bool - is_src_root (const path& d) + is_src_root (const dir_path& d) { return file_exists (d / path ("build/bootstrap.build")) || file_exists (d / path ("build/root.build")); } bool - is_out_root (const path& d) + is_out_root (const dir_path& d) { return file_exists (d / path ("build/bootstrap/src-root.build")); } @@ -67,7 +67,7 @@ namespace build } scope& - create_root (const path& out_root, const path& src_root) + create_root (const dir_path& out_root, const dir_path& src_root) { scope& rs (scopes.insert (out_root, true).first); @@ -96,7 +96,7 @@ namespace build v = out_root; else { - const path& p (v.as<const path&> ()); + const dir_path& p (v.as<const dir_path&> ()); if (p != out_root) fail << "new out_root " << out_root << " does not match " @@ -112,7 +112,7 @@ namespace build v = src_root; else { - const path& p (v.as<const path&> ()); + const dir_path& p (v.as<const dir_path&> ()); if (p != src_root) fail << "new src_root " << src_root << " does not match " @@ -166,9 +166,9 @@ namespace build if (!v) return; - const path& d (v.as<const path&> ()); - path out_root (root.path () / d); - path src_root (root.src_path () / d); + const dir_path& d (v.as<const dir_path&> ()); + dir_path out_root (root.path () / d); + dir_path src_root (root.src_path () / d); out_root.normalize (); src_root.normalize (); @@ -178,7 +178,7 @@ namespace build // Check if the bootstrap process changed src_root. // - const path& p (rs.variables["src_root"].as<const path&> ()); + const dir_path& p (rs.variables["src_root"].as<const dir_path&> ()); if (src_root != p) fail << "bootstrapped src_root " << p << " does not match " @@ -191,7 +191,7 @@ namespace build } scope& - create_bootstrap_inner (scope& root, const path& out_base) + create_bootstrap_inner (scope& root, const dir_path& out_base) { if (auto v = root.ro_variables ()["subprojects"]) { @@ -203,19 +203,19 @@ namespace build fail << "expected directory in subprojects variable " << "instead of " << n; - path out_root (root.path () / n.dir); + dir_path out_root (root.path () / n.dir); if (!out_base.sub (out_root)) continue; - path src_root (root.src_path () / n.dir); + dir_path src_root (root.src_path () / n.dir); scope& rs (create_root (out_root, src_root)); bootstrap_out (rs); // Check if the bootstrap process changed src_root. // - const path& p (rs.variables["src_root"].as<const path&> ()); + const dir_path& p (rs.variables["src_root"].as<const dir_path&> ()); if (src_root != p) fail << "bootstrapped src_root " << p << " does not match " @@ -270,13 +270,13 @@ namespace build info << "consider explicitly configuring its out_root via the " << var.name << " command line variable"; - const path& out_root (val.as<const path&> ()); + const dir_path& out_root (val.as<const dir_path&> ()); // Bootstrap the imported root scope. This is pretty similar to // what we do in main() except that here we don't try to guess // src_root. // - path src_root (is_src_root (out_root) ? out_root : path ()); + dir_path src_root (is_src_root (out_root) ? out_root : dir_path ()); scope& root (create_root (out_root, src_root)); bootstrap_out (root); @@ -285,7 +285,7 @@ namespace build // if (auto v = root.ro_variables ()["src_root"]) { - const path& p (v.as<const path&> ()); + const dir_path& p (v.as<const dir_path&> ()); if (!src_root.empty () && p != src_root) fail << "bootstrapped src_root " << p << " does not match " @@ -28,9 +28,9 @@ namespace build name (std::string v): value (std::move (v)) {} explicit - name (path d): dir (std::move (d)) {} + name (dir_path d): dir (std::move (d)) {} - name (std::string t, path d, std::string v) + name (std::string t, dir_path d, std::string v) : type (std::move (t)), dir (std::move (d)), value (std::move (v)) {} bool @@ -44,9 +44,9 @@ namespace build {return type.empty () && !dir.empty () && value.empty ();} std::string type; - path dir; + dir_path dir; std::string value; - bool pair {false}; + bool pair {false}; // Store pair symbol for printing? }; inline bool diff --git a/build/name.cxx b/build/name.cxx index ebc7372..4d30684 100644 --- a/build/name.cxx +++ b/build/name.cxx @@ -15,42 +15,28 @@ namespace build ostream& operator<< (ostream& os, const name& n) { - bool ht (!n.type.empty ()); - bool hv (!n.value.empty ()); - bool hd (false); - - if (ht) + // If the value is empty, then we want to print the directory + // inside {}, e.g., dir{bar/}, not bar/dir{}. We also want to + // print {} for an empty name. + // + bool d (!n.dir.empty ()); + bool v (!n.value.empty ()); + bool t (!n.type.empty () || (!d && !v)); + + if (v) + os << n.dir; + + if (t) os << n.type << '{'; - if (!n.dir.empty ()) - { - string s (diag_relative (n.dir)); - - // If both type and value are empty, there will be nothing printed. - // - if (s != "." || (!ht && !hv)) - { - os << s; - - // Add the directory separator unless it is already there - // or we have type but no value. The idea is to print foo/ - // or dir{foo}. - // - if (s.back () != path::traits::directory_separator && (hv || !ht)) - os << path::traits::directory_separator; + if (v) + os << n.value; + else + os << n.dir; - hd = true; - } - } - - os << n.value; - - if (ht) + if (t) os << '}'; - if (!ht && !hv && !hd) - os << "{}"; // Nothing got printed. - return os; } diff --git a/build/operation b/build/operation index 3d9c4a4..fc5651f 100644 --- a/build/operation +++ b/build/operation @@ -137,8 +137,8 @@ namespace build // void (*load) (const path& buildfile, scope& root, - const path& out_base, - const path& src_base, + const dir_path& out_base, + const dir_path& src_base, const location&); void (*match) (action, @@ -167,8 +167,8 @@ namespace build void load (const path& buildfile, scope& root, - const path& out_base, - const path& src_base, + const dir_path& out_base, + const dir_path& src_base, const location&); // Resolve and match the target. This is the default implementation diff --git a/build/operation.cxx b/build/operation.cxx index a8fdfb1..bceede5 100644 --- a/build/operation.cxx +++ b/build/operation.cxx @@ -35,8 +35,8 @@ namespace build void load (const path& bf, scope& root, - const path& out_base, - const path& src_base, + const dir_path& out_base, + const dir_path& src_base, const location&) { // Load project's root[-pre].build. @@ -51,7 +51,7 @@ namespace build base.variables["out_base"] = out_base; auto v (base.variables["src_base"] = src_base); - base.src_path_ = &v.as<const path&> (); + base.src_path_ = &v.as<const dir_path&> (); // Load the buildfile unless it has already been loaded. // diff --git a/build/parser b/build/parser index 53ce2d0..6168645 100644 --- a/build/parser +++ b/build/parser @@ -76,7 +76,7 @@ namespace build void names (token&, token_type&, names_type&, std::size_t pair, - const path* dir, const std::string* type); + const dir_path* dir, const std::string* type); // Buildspec. // @@ -116,12 +116,12 @@ namespace build const fail_mark<failed> fail; private: - const std::string* path_; // Path processed by diagnostic_string(). + const std::string* path_; // Path processed by diag_relative(). lexer* lexer_; scope* scope_; // Current base scope (out_base). scope* root_; // Current root scope (out_root). - const path* out_root_; - const path* src_root_; + const dir_path* out_root_; + const dir_path* src_root_; target* default_target_; token peek_ {token_type::eos, false, 0, 0}; diff --git a/build/parser.cxx b/build/parser.cxx index d3abd46..7c326a6 100644 --- a/build/parser.cxx +++ b/build/parser.cxx @@ -140,7 +140,7 @@ namespace build location nloc (get_location (t, &path_)); names_type ns (tt != type::colon ? names (t, tt) - : names_type ({name ("dir", path (), string ())})); + : names_type ({name ("dir", dir_path (), string ())})); if (tt == type::colon) { @@ -194,7 +194,7 @@ namespace build // scope& prev (*scope_); - path p (move (ns[0].dir)); // Steal. + dir_path p (move (ns[0].dir)); // Steal. if (p.relative ()) p = prev.path () / p; @@ -441,7 +441,7 @@ namespace build if (src_root_ == nullptr) { auto v (root_->ro_variables ()["src_root"]); - src_root_ = v ? &v.as<const path&> () : nullptr; + src_root_ = v ? &v.as<const dir_path&> () : nullptr; } } @@ -512,8 +512,8 @@ namespace build // Determine new bases. // - path out_base; - path src_base; + dir_path out_base; + dir_path src_base; if (in_out) { @@ -557,7 +557,7 @@ namespace build scope_->variables["out_base"] = move (out_base); auto v (scope_->variables["src_base"] = move (src_base)); - scope_->src_path_ = &v.as<const path&> (); + scope_->src_path_ = &v.as<const dir_path&> (); target* odt (default_target_); default_target_ = nullptr; @@ -768,7 +768,7 @@ namespace build type& tt, names_type& ns, size_t pair, - const path* dp, + const dir_path* dp, const string* tp) { // If pair is not 0, then it is an index + 1 of the first half of @@ -838,8 +838,8 @@ namespace build if (p != n && tp != nullptr) fail (t) << "nested type name " << name; - path d1; - const path* dp1 (dp); + dir_path d1; + const dir_path* dp1 (dp); string t1; const string* tp1 (tp); @@ -849,9 +849,9 @@ namespace build else if (p == n) // directory { if (dp == nullptr) - d1 = path (name); + d1 = dir_path (name); else - d1 = *dp / path (name); + d1 = *dp / dir_path (name); dp1 = &d1; } @@ -860,9 +860,9 @@ namespace build t1.assign (name, p + 1, n - p); if (dp == nullptr) - d1 = path (name, 0, p + 1); + d1 = dir_path (name, 0, p + 1); else - d1 = *dp / path (name, 0, p + 1); + d1 = *dp / dir_path (name, 0, p + 1); dp1 = &d1; tp1 = &t1; @@ -906,9 +906,9 @@ namespace build // Search for global_scope for details. // #ifdef _WIN32 - path dir (name != "/" ? path (name) : path ()); + dir_path dir (name != "/" ? dir_path (name) : dir_path ()); #else - path dir (name); + dir_path dir (name); #endif if (dp != nullptr) dir = *dp / dir; @@ -919,7 +919,7 @@ namespace build } else ns.emplace_back ((tp != nullptr ? *tp : string ()), - (dp != nullptr ? *dp : path ()), + (dp != nullptr ? *dp : dir_path ()), move (name)); count = 1; @@ -1015,10 +1015,10 @@ namespace build // for (const name& n: lv) { - const path* dp1 (dp); + const dir_path* dp1 (dp); const string* tp1 (tp); - path d1; + dir_path d1; if (!n.dir.empty ()) { if (dp != nullptr) @@ -1059,7 +1059,7 @@ namespace build } ns.emplace_back ((tp1 != nullptr ? *tp1 : string ()), - (dp1 != nullptr ? *dp1 : path ()), + (dp1 != nullptr ? *dp1 : dir_path ()), n.value); } @@ -1105,7 +1105,7 @@ namespace build // Empty LHS, (e.g., {=y}), create an empty name. // ns.emplace_back ((tp != nullptr ? *tp : string ()), - (dp != nullptr ? *dp : path ()), + (dp != nullptr ? *dp : dir_path ()), ""); count = 1; } @@ -1129,7 +1129,7 @@ namespace build ns.push_back (ns[pair - 1]); ns.emplace_back ((tp != nullptr ? *tp : string ()), - (dp != nullptr ? *dp : path ()), + (dp != nullptr ? *dp : dir_path ()), ""); break; } @@ -1142,7 +1142,7 @@ namespace build if (!ns.empty () && ns.back ().pair) { ns.emplace_back ((tp != nullptr ? *tp : string ()), - (dp != nullptr ? *dp : path ()), + (dp != nullptr ? *dp : dir_path ()), ""); } } @@ -1240,7 +1240,7 @@ namespace build { // Do we have the src_base? // - path src_base; + dir_path src_base; if (i->pair) { if (!i->type.empty ()) @@ -1249,7 +1249,7 @@ namespace build src_base = move (i->dir); if (!i->value.empty ()) - src_base /= path (move (i->value)); + src_base /= dir_path (move (i->value)); ++i; assert (i != e); @@ -1344,10 +1344,10 @@ namespace build // to their return values are not guaranteed to be stable (and, // in fact, path()'s is not). // - out_root_ = &root_->ro_variables ()["out_root"].as<const path&> (); + out_root_ = &root_->ro_variables ()["out_root"].as<const dir_path&> (); auto v (root_->ro_variables ()["src_root"]); - src_root_ = v ? &v.as<const path&> () : nullptr; + src_root_ = v ? &v.as<const dir_path&> () : nullptr; } return r; @@ -14,9 +14,6 @@ namespace build { template <typename C> - class basic_path; - - template <typename C> struct path_traits { typedef std::basic_string<C> string_type; @@ -125,6 +122,15 @@ namespace build return ln < rn ? -1 : (ln > rn ? 1 : 0); } + // Get/set current working directory. Throw std::system_error + // to report the underlying OS errors. + // + static string_type + current (); + + static void + current (string_type const&); + private: #ifdef _WIN32 static C @@ -135,10 +141,35 @@ namespace build template <typename C> class invalid_basic_path; - typedef basic_path<char> path; + template <typename C, typename K> + class basic_path; + + template <typename C> + class path_data; + + template <typename C> + struct dir_path_kind; + + template <typename C> + struct any_path_kind + { + typedef path_data<C> base_type; + typedef basic_path<C, dir_path_kind<C>> dir_type; + }; + + template <typename C> + struct dir_path_kind + { + typedef basic_path<C, any_path_kind<C>> base_type; + typedef basic_path<C, dir_path_kind<C>> dir_type; + }; + + typedef basic_path<char, any_path_kind<char>> path; + typedef basic_path<char, dir_path_kind<char>> dir_path; typedef invalid_basic_path<char> invalid_path; - typedef basic_path<wchar_t> wpath; + typedef basic_path<wchar_t, any_path_kind<wchar_t>> wpath; + typedef basic_path<wchar_t, dir_path_kind<wchar_t>> dir_wpath; typedef invalid_basic_path<wchar_t> invalid_wpath; // @@ -171,66 +202,68 @@ namespace build }; template <typename C> - class basic_path + class path_data + { + public: + typedef std::basic_string<C> string_type; + + path_data () = default; + + explicit + path_data (string_type s): path_ (std::move (s)) {} + + protected: + string_type path_; + }; + + template <typename C, typename K> + class basic_path: public K::base_type { public: typedef std::basic_string<C> string_type; typedef typename string_type::size_type size_type; + typedef typename K::base_type base_type; + typedef typename K::dir_type dir_type; + typedef path_traits<C> traits; // Construct special empty path. // - basic_path () - { - } + basic_path () = default; explicit - basic_path (C const* s) - : path_ (s) - { - init (); - } + basic_path (C const* s): base_type (s) {init ();} basic_path (C const* s, size_type n) - : path_ (s, n) - { - init (); - } + : base_type (string_type (s, n)) {init ();} explicit - basic_path (string_type s) - : path_ (std::move (s)) - { - init (); - } + basic_path (string_type s): base_type (std::move (s)) {init ();} basic_path (const string_type& s, size_type n) - : path_ (s, 0, n) - { - init (); - } + : base_type (string_type (s, 0, n)) {init ();} basic_path (const string_type& s, size_type p, size_type n) - : path_ (s, p, n) - { - init (); - } + : base_type (string_type (s, p, n)) {init ();} void swap (basic_path& p) { - path_.swap (p.path_); + this->path_.swap (p.path_); } void clear () { - path_.clear (); + this->path_.clear (); } - static basic_path - current (); + // Get/set current working directory. Throw std::system_error + // to report the underlying OS errors. + // + static dir_type + current () {return dir_type (traits::current ());} static void current (basic_path const&); @@ -239,7 +272,7 @@ namespace build bool empty () const { - return path_.empty (); + return this->path_.empty (); } bool @@ -286,20 +319,20 @@ namespace build // Return the directory part of the path or empty path if // there is no directory. // - basic_path + dir_type directory () const; // Return the directory part of the path without the specified // leaf part. Throws invalid_path if the leaf is not a suffix of // *this. Expects both paths to be normalized. // - basic_path + dir_type directory (basic_path const&) const; // Return the root directory of the path or empty path if // the directory is not absolute. // - basic_path + dir_type root_directory () const; // Return the path without the extension, if any. @@ -335,40 +368,32 @@ namespace build complete (); public: - basic_path - operator/ (basic_path const& x) const - { - basic_path r (*this); - r /= x; - return r; - } - basic_path& operator/= (basic_path const&); basic_path operator+ (string_type const& s) const { - return basic_path (path_ + s); + return basic_path (this->path_ + s); } basic_path operator+ (C c) const { - return basic_path (path_ + c); + return basic_path (this->path_ + c); } basic_path& operator+= (string_type const& s) { - path_ += s; + this->path_ += s; return *this; } basic_path& operator+= (C c) { - path_ += c; + this->path_ += c; return *this; } @@ -378,7 +403,7 @@ namespace build bool operator== (basic_path const& x) const { - return traits::compare (path_, x.path_) == 0; + return traits::compare (this->path_, x.path_) == 0; } bool @@ -390,14 +415,14 @@ namespace build bool operator< (basic_path const& x) const { - return traits::compare (path_, x.path_) < 0; + return traits::compare (this->path_, x.path_) < 0; } public: const string_type& string () const { - return path_; + return this->path_; } // If possible, return a POSIX representation of the path. For example, @@ -412,15 +437,36 @@ namespace build private: void init (); - - private: - string_type path_; }; - /* + template <typename C, typename K> + inline basic_path<C, K> + operator/ (basic_path<C, K> const& x, basic_path<C, K> const& y) + { + basic_path<C, K> r (x); + r /= y; + return r; + } + + // Additional operators for certain path kind combinations. + // template <typename C> + inline basic_path<C, any_path_kind<C>> + operator/ (basic_path<C, dir_path_kind<C>> const& x, + basic_path<C, any_path_kind<C>> const& y) + { + basic_path<C, any_path_kind<C>> r (x); + r /= y; + return r; + } + + // IO + // + + /* + template <typename C, typename K> inline std::basic_ostream<C>& - operator<< (std::basic_ostream<C>& os, basic_path<C> const& p) + operator<< (std::basic_ostream<C>& os, basic_path<C, K> const& p) { return os << p.string (); } @@ -429,11 +475,11 @@ namespace build namespace std { - template <typename C> - struct hash<build::basic_path<C>>: hash<basic_string<C>> + template <typename C, typename K> + struct hash<build::basic_path<C, K>>: hash<basic_string<C>> { size_t - operator() (const build::basic_path<C>& p) const noexcept + operator() (const build::basic_path<C, K>& p) const noexcept { return hash<basic_string<C>>::operator() (p.string ()); } diff --git a/build/path-io b/build/path-io index a9deea9..accdb94 100644 --- a/build/path-io +++ b/build/path-io @@ -8,14 +8,26 @@ #include <ostream> #include <build/path> -#include <build/diagnostics> namespace build { inline std::ostream& operator<< (std::ostream& os, const path& p) { - return os << (&os == diag_stream ? diag_relative (p) : p.string ()); + return os << p.string (); + } + + inline std::ostream& + operator<< (std::ostream& os, const dir_path& d) + { + const std::string& s (d.string ()); + + // Print the directory with trailing '/'. + // + if (!s.empty ()) + os << s << (dir_path::traits::is_separator (s.back ()) ? "" : "/"); + + return os; } } diff --git a/build/path-map b/build/path-map index ee2dd79..2b32b0d 100644 --- a/build/path-map +++ b/build/path-map @@ -24,10 +24,10 @@ namespace build // 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>> + template <typename C, typename K> + struct compare_prefix<basic_path<C, K>>: compare_prefix<std::basic_string<C>> { - typedef basic_path<C> K; + typedef basic_path<C, K> key_type; typedef C delimiter_type; typedef std::basic_string<C> string_type; @@ -37,7 +37,7 @@ namespace build compare_prefix (delimiter_type d): base (d) {} bool - operator() (const K& x, const K& y) const + operator() (const key_type& x, const key_type& y) const { const auto& xs (x.string ()); const auto& ys (y.string ()); @@ -56,7 +56,7 @@ namespace build } bool - prefix (const K& p, const K& k) const + prefix (const key_type& p, const key_type& k) const { const auto& ps (p.string ()); const auto& ks (k.string ()); @@ -72,6 +72,10 @@ namespace build template <typename T> using path_map = prefix_map<path, T, path::traits::directory_separator>; + + template <typename T> + using dir_path_map = + prefix_map<dir_path, T, dir_path::traits::directory_separator>; } #endif // BUILD_PATH_MAP diff --git a/build/path.cxx b/build/path.cxx index efd0532..899dc8f 100644 --- a/build/path.cxx +++ b/build/path.cxx @@ -8,11 +8,16 @@ # include <stdlib.h> // _MAX_PATH # include <direct.h> // _[w]getcwd, _[w]chdir #else +# include <errno.h> // EINVAL # include <stdlib.h> // mbstowcs, wcstombs # include <limits.h> // PATH_MAX # include <unistd.h> // getcwd, chdir #endif +#include <system_error> + +using namespace std; + namespace build { char const* invalid_path_base:: @@ -26,7 +31,7 @@ namespace build // template <> - basic_path<char> basic_path<char>:: + path_traits<char>::string_type path_traits<char>:: current () { // @@ throw system_error (and in the other current() versions). @@ -34,31 +39,26 @@ namespace build #ifdef _WIN32 char cwd[_MAX_PATH]; if(_getcwd(cwd, _MAX_PATH) == 0) - throw invalid_basic_path<char> ("."); + throw system_error (errno, system_category ()); #else char cwd[PATH_MAX]; if (getcwd (cwd, PATH_MAX) == 0) - throw invalid_basic_path<char> ("."); + throw system_error (errno, system_category ()); #endif - return basic_path<char> (cwd); + return string_type (cwd); } template <> - void basic_path<char>:: - current (basic_path const& p) + void path_traits<char>:: + current (string_type const& s) { - string_type const& s (p.string ()); - - if (p.empty ()) - throw invalid_basic_path<char> (s); - #ifdef _WIN32 if(_chdir(s.c_str ()) != 0) - throw invalid_basic_path<char> (s); + throw system_error (errno, system_category ()); #else if (chdir (s.c_str ()) != 0) - throw invalid_basic_path<char> (s); + throw system_error (errno, system_category ()); #endif } @@ -67,48 +67,43 @@ namespace build // template <> - basic_path<wchar_t> basic_path<wchar_t>:: + path_traits<wchar_t>::string_type path_traits<wchar_t>:: current () { #ifdef _WIN32 wchar_t wcwd[_MAX_PATH]; if(_wgetcwd(wcwd, _MAX_PATH) == 0) - throw invalid_basic_path<wchar_t> (L"."); + throw system_error (errno, system_category ()); #else char cwd[PATH_MAX]; if (getcwd (cwd, PATH_MAX) == 0) - throw invalid_basic_path<wchar_t> (L"."); + throw system_error (errno, system_category ()); wchar_t wcwd[PATH_MAX]; if (mbstowcs (wcwd, cwd, PATH_MAX) == size_type (-1)) - throw invalid_basic_path<wchar_t> (L"."); + throw system_error (EINVAL, system_category ()); #endif - return basic_path<wchar_t> (wcwd); + return string_type (wcwd); } template <> - void basic_path<wchar_t>:: - current (basic_path const& p) + void path_traits<wchar_t>:: + current (string_type const& s) { - string_type const& s (p.string ()); - - if (p.empty ()) - throw invalid_basic_path<wchar_t> (s); - #ifdef _WIN32 if(_wchdir(s.c_str ()) != 0) - throw invalid_basic_path<wchar_t> (s); + throw system_error (errno, system_category ()); #else char ns[PATH_MAX + 1]; if (wcstombs (ns, s.c_str (), PATH_MAX) == size_type (-1)) - throw invalid_basic_path<wchar_t> (s); + throw system_error (EINVAL, system_category ()); ns[PATH_MAX] = '\0'; if (chdir (ns) != 0) - throw invalid_basic_path<wchar_t> (s); + throw system_error (errno, system_category ()); #endif } } diff --git a/build/path.ixx b/build/path.ixx index 95608e9..ff1ec32 100644 --- a/build/path.ixx +++ b/build/path.ixx @@ -25,30 +25,30 @@ namespace build } #endif - template <typename C> - inline bool basic_path<C>:: + template <typename C, typename K> + inline bool basic_path<C, K>:: absolute () const { #ifdef _WIN32 - return path_.size () > 1 && path_[1] == ':'; + return this->path_.size () > 1 && this->path_[1] == ':'; #else - return !path_.empty () && traits::is_separator (path_[0]); + return !this->path_.empty () && traits::is_separator (this->path_[0]); #endif } - template <typename C> - inline bool basic_path<C>:: + template <typename C, typename K> + inline bool basic_path<C, K>:: root () const { #ifdef _WIN32 - return path_.size () == 2 && path_[1] == ':'; + return this->path_.size () == 2 && this->path_[1] == ':'; #else - return path_.size () == 1 && traits::is_separator (path_[0]); + return this->path_.size () == 1 && traits::is_separator (this->path_[0]); #endif } - template <typename C> - inline bool basic_path<C>:: + template <typename C, typename K> + inline bool basic_path<C, K>:: sub (const basic_path& p) const { size_type n (p.path_.size ()); @@ -56,18 +56,18 @@ namespace build if (n == 0) return true; - size_type m (path_.size ()); + size_type m (this->path_.size ()); // The second condition guards against the /foo-bar vs /foo case. // - return m >= n && path_.compare (0, n, p.path_) == 0 && + return m >= n && this->path_.compare (0, n, p.path_) == 0 && (traits::is_separator (p.path_.back ()) || // p ends with a separator m == n || // *this == p - traits::is_separator (path_[n])); // next char is a separator + traits::is_separator (this->path_[n])); // next char is a separator } - template <typename C> - inline bool basic_path<C>:: + template <typename C, typename K> + inline bool basic_path<C, K>:: sup (const basic_path& p) const { size_type n (p.path_.size ()); @@ -75,17 +75,17 @@ namespace build if (n == 0) return true; - size_type m (path_.size ()); + size_type m (this->path_.size ()); // The second condition guards against the /foo-bar vs bar case. // - return m >= n && path_.compare (m - n, n, p.path_) == 0 && - (m == n || // *this == p - traits::is_separator (path_[m - n - 1])); // prev char is a separator + return m >= n && this->path_.compare (m - n, n, p.path_) == 0 && + (m == n || // *this == p + traits::is_separator (this->path_[m - n - 1])); // prev char separator } - template <typename C> - inline basic_path<C>& basic_path<C>:: + template <typename C, typename K> + inline basic_path<C, K>& basic_path<C, K>:: complete () { if (relative ()) @@ -94,38 +94,40 @@ namespace build return *this; } - template <typename C> - inline basic_path<C> basic_path<C>:: + template <typename C, typename K> + inline typename basic_path<C, K>::dir_type basic_path<C, K>:: root_directory () const { return absolute () #ifdef _WIN32 - ? path (path_, 2) + ? dir_type (this->path_, 2) #else - ? path ("/") + ? dir_type ("/") #endif - : path (); + : dir_type (); } - template <typename C> - inline basic_path<C> basic_path<C>:: + template <typename C, typename K> + inline basic_path<C, K> basic_path<C, K>:: base () const { - size_type p (traits::find_extension (path_)); - return p != string_type::npos ? basic_path (path_.c_str (), p) : *this; + size_type p (traits::find_extension (this->path_)); + return p != string_type::npos + ? basic_path (this->path_.c_str (), p) + : *this; } - template <typename C> - inline const C* basic_path<C>:: + template <typename C, typename K> + inline const C* basic_path<C, K>:: extension () const { - size_type p (traits::find_extension (path_)); - return p != string_type::npos ? path_.c_str () + p + 1 : nullptr; + size_type p (traits::find_extension (this->path_)); + return p != string_type::npos ? this->path_.c_str () + p + 1 : nullptr; } #ifndef _WIN32 - template <typename C> - inline typename basic_path<C>::string_type basic_path<C>:: + template <typename C, typename K> + inline typename basic_path<C, K>::string_type basic_path<C, K>:: posix_string () const { return string (); diff --git a/build/path.txx b/build/path.txx index a8bf859..67a271d 100644 --- a/build/path.txx +++ b/build/path.txx @@ -6,43 +6,43 @@ namespace build { - template <typename C> - basic_path<C> basic_path<C>:: + template <typename C, typename K> + basic_path<C, K> basic_path<C, K>:: leaf () const { - size_type p (traits::rfind_separator (path_)); + size_type p (traits::rfind_separator (this->path_)); return p != string_type::npos - ? basic_path (path_.c_str () + p + 1, path_.size () - p - 1) + ? basic_path (this->path_.c_str () + p + 1, this->path_.size () - p - 1) : *this; } - template <typename C> - basic_path<C> basic_path<C>:: + template <typename C, typename K> + typename basic_path<C, K>::dir_type basic_path<C, K>:: directory () const { if (root ()) - return basic_path (); + return dir_type (); - size_type p (traits::rfind_separator (path_)); + size_type p (traits::rfind_separator (this->path_)); // Include the trailing slash so that we get correct behavior // if directory is root. // return p != string_type::npos - ? basic_path (path_.c_str (), p + 1) - : basic_path (); + ? dir_type (this->path_.c_str (), p + 1) + : dir_type (); } #ifdef _WIN32 - template <typename C> - typename basic_path<C>::string_type basic_path<C>:: + template <typename C, typename K> + typename basic_path<C, K>::string_type basic_path<C, K>:: posix_string () const { if (absolute ()) - throw invalid_basic_path<C> (path_); + throw invalid_basic_path<C> (this->path_); - string_type r (path_); + string_type r (this->path_); // Translate Windows-style separators to the POSIX ones. // @@ -54,30 +54,29 @@ namespace build } #endif - template <typename C> - basic_path<C>& basic_path<C>:: - operator/= (basic_path<C> const& r) + template <typename C, typename K> + basic_path<C, K>& basic_path<C, K>:: + operator/= (basic_path<C, K> const& r) { - if (r.absolute () && !path_.empty ()) // Allow ('' / '/foo'). + if (r.absolute () && !this->path_.empty ()) // Allow ('' / '/foo'). throw invalid_basic_path<C> (r.path_); - if (path_.empty () || r.path_.empty ()) + if (this->path_.empty () || r.path_.empty ()) { - path_ += r.path_; + this->path_ += r.path_; return *this; } - if (!traits::is_separator (path_[path_.size () - 1])) - path_ += traits::directory_separator; - - path_ += r.path_; + if (!traits::is_separator (this->path_[this->path_.size () - 1])) + this->path_ += traits::directory_separator; + this->path_ += r.path_; return *this; } - template <typename C> - basic_path<C> basic_path<C>:: - leaf (basic_path<C> const& d) const + template <typename C, typename K> + basic_path<C, K> basic_path<C, K>:: + leaf (basic_path<C, K> const& d) const { size_type n (d.path_.size ()); @@ -85,9 +84,9 @@ namespace build return *this; if (!sub (d)) - throw invalid_basic_path<C> (path_); + throw invalid_basic_path<C> (this->path_); - size_type m (path_.size ()); + size_type m (this->path_.size ()); if (n != m #ifndef _WIN32 @@ -96,32 +95,32 @@ namespace build ) n++; // Skip the directory separator (unless it is POSIX root). - return basic_path (path_.c_str () + n, m - n); + return basic_path (this->path_.c_str () + n, m - n); } - template <typename C> - basic_path<C> basic_path<C>:: - directory (basic_path<C> const& l) const + template <typename C, typename K> + typename basic_path<C, K>::dir_type basic_path<C, K>:: + directory (basic_path<C, K> const& l) const { size_type n (l.path_.size ()); if (n == 0) - return *this; + return dir_type (this->path_); if (!sup (l)) - throw invalid_basic_path<C> (path_); + throw invalid_basic_path<C> (this->path_); - size_type m (path_.size ()); + size_type m (this->path_.size ()); if (n != m) n++; // Skip the directory separator. - return basic_path (path_.c_str (), m - n); + return dir_type (this->path_.c_str (), m - n); } - template <typename C> - basic_path<C> basic_path<C>:: - relative (basic_path<C> d) const + template <typename C, typename K> + basic_path<C, K> basic_path<C, K>:: + relative (basic_path<C, K> d) const { basic_path r; @@ -130,19 +129,19 @@ namespace build if (sub (d)) break; - r /= path (".."); + r /= basic_path (".."); // Roots of the paths do not match. // if (d.root ()) - throw invalid_basic_path<C> (path_); + throw invalid_basic_path<C> (this->path_); } return r / leaf (d); } - template <typename C> - basic_path<C>& basic_path<C>:: + template <typename C, typename K> + basic_path<C, K>& basic_path<C, K>:: normalize () { if (empty ()) @@ -153,11 +152,11 @@ namespace build typedef std::vector<string_type> paths; paths ps; - for (size_type b (0), e (traits::find_separator (path_)), - n (path_.size ());; - e = traits::find_separator (path_, b)) + for (size_type b (0), e (traits::find_separator (this->path_)), + n (this->path_.size ());; + e = traits::find_separator (this->path_, b)) { - string_type s (path_, b, e == string_type::npos ? e : e - b); + string_type s (this->path_, b, e == string_type::npos ? e : e - b); ps.push_back (s); if (e == string_type::npos) @@ -165,7 +164,7 @@ namespace build ++e; - while (e < n && traits::is_separator (path_[e])) + while (e < n && traits::is_separator (this->path_[e])) ++e; if (e == n) @@ -200,7 +199,7 @@ namespace build // Cannot go past the root directory. // if (abs && r.size () == 1) - throw invalid_basic_path<C> (path_); + throw invalid_basic_path<C> (this->path_); r.pop_back (); continue; @@ -227,19 +226,31 @@ namespace build if (p.empty () && !r.empty ()) p += traits::directory_separator; // Root directory. - path_.swap (p); + this->path_.swap (p); return *this; } - template <typename C> - void basic_path<C>:: + template <typename C, typename K> + void basic_path<C, K>:: + current (basic_path const& p) + { + const string_type& s (p.string ()); + + if (s.empty ()) + throw invalid_basic_path<char> (s); + + traits::current (s); + } + + template <typename C, typename K> + void basic_path<C, K>:: init () { // Strip trailing slashes except for the case where the single // slash represents the root directory. // - size_type n (path_.size ()); - for (; n > 1 && traits::is_separator (path_[n - 1]); --n) ; - path_.resize (n); + size_type n (this->path_.size ()); + for (; n > 1 && traits::is_separator (this->path_[n - 1]); --n) ; + this->path_.resize (n); } } diff --git a/build/prerequisite b/build/prerequisite index d57f811..77e04c2 100644 --- a/build/prerequisite +++ b/build/prerequisite @@ -29,7 +29,7 @@ namespace build typedef build::scope scope_type; prerequisite (const target_type_type& t, - path d, + dir_path d, std::string n, const std::string* e, scope_type& s) @@ -38,7 +38,7 @@ namespace build public: const target_type_type& type; - const path dir; // Normalized absolute or relative (to scope). + const dir_path dir; // Normalized absolute or relative (to scope). const std::string name; const std::string* ext; // NULL if unspecified. scope_type& scope; @@ -55,7 +55,7 @@ namespace build { std::pair<prerequisite&, bool> insert (const target_type&, - path dir, + dir_path dir, std::string name, const std::string* ext, scope&, diff --git a/build/prerequisite.cxx b/build/prerequisite.cxx index aa6c53c..5d3235c 100644 --- a/build/prerequisite.cxx +++ b/build/prerequisite.cxx @@ -18,52 +18,38 @@ namespace build ostream& operator<< (ostream& os, const prerequisite& p) { - if (p.target != nullptr) - os << *p.target; - else + // Print scope unless the prerequisite's directory is absolute. + // + if (!p.dir.absolute ()) { - os << p.type.name << '{'; - - // Print scope unless the directory is absolute. - // - if (!p.dir.absolute ()) - { - string s (diag_relative (p.scope.path ())); + string s (diag_relative (p.scope.path (), false)); - if (s != ".") - { - os << s; - - if (s.back () != path::traits::directory_separator) - os << path::traits::directory_separator; - - os << ": "; - } - } + if (!s.empty ()) + os << s << ':'; + } - // Print directory. - // - if (!p.dir.empty ()) - { - string s (diag_relative (p.dir)); + // If the name is empty, then we want to print the directory + // inside {}, e.g., dir{bar/}, not bar/dir{}. + // + bool n (!p.name.empty ()); + string d (diag_relative (p.dir, false)); - if (s != ".") - { - os << s; + if (n) + os << d; - if (!p.name.empty () && - s.back () != path::traits::directory_separator) - os << path::traits::directory_separator; - } - } + os << p.type.name << '{'; + if (n) + { os << p.name; if (p.ext != nullptr && !p.ext->empty ()) os << '.' << *p.ext; - - os << '}'; } + else + os << d; + + os << '}'; return os; } @@ -89,7 +75,7 @@ namespace build // auto prerequisite_set:: insert (const target_type& tt, - path dir, + dir_path dir, std::string name, const std::string* ext, scope& s, diff --git a/build/scope b/build/scope index 2eb8ac7..f9492e6 100644 --- a/build/scope +++ b/build/scope @@ -20,12 +20,10 @@ namespace build class scope { public: - typedef build::path path_type; - - const path_type& + const dir_path& path () const {return i_->first;} // Absolute and normalized. - const path_type& + const dir_path& src_path () const {return *src_path_;} // Corresponding src path. scope* @@ -53,7 +51,7 @@ namespace build value_proxy operator[] (const variable&); - const path_type* src_path_ {nullptr}; // Cached src_{root,base} var value. + const dir_path* src_path_ {nullptr}; // Cached src_{root,base} var value. public: variable_map variables; @@ -69,6 +67,8 @@ namespace build meta_operation_table meta_operations; operation_table operations; + typedef build::path path_type; + // Set of buildfiles already loaded for this scope. The included // buildfiles are checked against the project's root scope while // imported -- against the global scope (global_scope). @@ -90,7 +90,7 @@ namespace build friend class scope_map; friend class temp_scope; - typedef path_map<scope>::const_iterator iterator; + typedef dir_path_map<scope>::const_iterator iterator; scope (): variables (*this) {} @@ -113,25 +113,36 @@ namespace build temp_scope (scope& p) {i_ = p.i_; parent_ = &p; root_ = p.root_;} }; - class scope_map: public path_map<scope> + class scope_map: public dir_path_map<scope> { public: // Note that we assume the first insertion into the map is that // of the global scope. // std::pair<scope&, bool> - insert (const path&, bool root); + insert (const dir_path&, bool root); scope& - operator[] (const path& p) {return insert (p, false).first;} + operator[] (const dir_path& p) {return insert (p, false).first;} // Find the most qualified scope that encompasses this path. // scope& - find (const path&); + find (const dir_path&); + + scope& + find (const path& p) + { + // Natural thing to do here would be to call find (p.directory ()). + // However, there could be a situation where the passed path is a + // directory (i.e., the calling code does not know what it is dealing + // with), so let's use the whole path. + // + return find (dir_path (p.string ())); + } private: - typedef path_map<scope> base; + typedef dir_path_map<scope> base; }; extern scope_map scopes; diff --git a/build/scope.cxx b/build/scope.cxx index 68eba3d..aced21b 100644 --- a/build/scope.cxx +++ b/build/scope.cxx @@ -36,7 +36,7 @@ namespace build scope* global_scope; pair<scope&, bool> scope_map:: - insert (const path& k, bool root) + insert (const dir_path& k, bool root) { auto er (emplace (k, scope ())); scope& s (er.first->second); @@ -104,7 +104,7 @@ namespace build // Find the most qualified scope that encompasses this path. // scope& scope_map:: - find (const path& k) + find (const dir_path& k) { // Normally we would have a scope for the full path so try // that before making any copies. @@ -114,7 +114,7 @@ namespace build if (i != end ()) return i->second; - for (path d (k.directory ());; d = d.directory ()) + for (dir_path d (k.directory ());; d = d.directory ()) { auto i (base::find (d)); diff --git a/build/search b/build/search index e7d2acd..dfbe32e 100644 --- a/build/search +++ b/build/search @@ -20,7 +20,7 @@ namespace build // Search for an existing file in the specified list of search paths. // target* - search_existing_file (prerequisite&, const paths&); + search_existing_file (prerequisite&, const dir_paths&); // Create a new target in this prerequisite's directory scope. // diff --git a/build/search.cxx b/build/search.cxx index bd81822..6434bf7 100644 --- a/build/search.cxx +++ b/build/search.cxx @@ -27,7 +27,7 @@ namespace build // Look for an existing target in this prerequisite's directory scope. // - path d; + dir_path d; if (p.dir.absolute ()) d = p.dir; // Already normalized. else @@ -56,7 +56,7 @@ namespace build } target* - search_existing_file (prerequisite& p, const paths& sp) + search_existing_file (prerequisite& p, const dir_paths& sp) { tracer trace ("search_existing_file"); @@ -64,7 +64,7 @@ namespace build // Go over paths and extension looking for a file. // - for (const path& d: sp) + for (const dir_path& d: sp) { path f (d / p.dir / path (p.name)); f.normalize (); @@ -116,7 +116,7 @@ namespace build // We default to the target in this prerequisite's directory scope. // - path d; + dir_path d; if (p.dir.absolute ()) d = p.dir; // Already normalized. else @@ -21,10 +21,10 @@ namespace build explicit targetspec (name_type n): name (std::move (n)) {} - targetspec (path sb, name_type n) + targetspec (dir_path sb, name_type n) : src_base (std::move (sb)), name (std::move (n)) {} - path src_base; + dir_path src_base; name_type name; }; diff --git a/build/spec.cxx b/build/spec.cxx index a1f6283..f796ad9 100644 --- a/build/spec.cxx +++ b/build/spec.cxx @@ -17,19 +17,10 @@ namespace build { if (!s.src_base.empty ()) { - string d (diag_relative (s.src_base)); + string d (diag_relative (s.src_base, false)); - if (d != ".") - { - os << d; - - // Add the directory separator unless it is already there. - // - if (d.back () != path::traits::directory_separator) - os << path::traits::directory_separator; - - os << '='; - } + if (!d.empty ()) + os << d << '@'; } os << s.name; diff --git a/build/target b/build/target index 48accc8..dd62ec8 100644 --- a/build/target +++ b/build/target @@ -76,7 +76,7 @@ namespace build std::type_index id; const char* name; const target_type* base; - target* (*const factory) (path, std::string, const std::string*); + target* (*const factory) (dir_path, std::string, const std::string*); target* (*const search) (prerequisite&); }; @@ -92,10 +92,10 @@ namespace build virtual ~target () = default; - target (path d, std::string n, const std::string* e) + target (dir_path d, std::string n, const std::string* e) : dir (std::move (d)), name (std::move (n)), ext (e) {} - const path dir; // Absolute and normalized. + const dir_path dir; // Absolute and normalized. const std::string name; const std::string* ext; // Extension, NULL means unspecified. @@ -183,7 +183,7 @@ namespace build struct target_key { mutable const target_type* type; - mutable const path* dir; + mutable const dir_path* dir; mutable const std::string* name; mutable const std::string* const* ext; @@ -221,7 +221,7 @@ namespace build iterator find (const target_type& type, - const path& dir, + const dir_path& dir, const std::string& name, const std::string* ext, tracer& trace) const @@ -235,7 +235,7 @@ namespace build std::pair<target&, bool> insert (const target_type&, - path dir, + dir_path dir, std::string name, const std::string* ext, tracer&); @@ -278,7 +278,7 @@ namespace build template <typename T> target* - target_factory (path d, std::string n, const std::string* e) + target_factory (dir_path d, std::string n, const std::string* e) { return new T (std::move (d), std::move (n), e); } diff --git a/build/target.cxx b/build/target.cxx index 4f49206..db02979 100644 --- a/build/target.cxx +++ b/build/target.cxx @@ -105,7 +105,7 @@ namespace build pair<target&, bool> target_set:: insert (const target_type& tt, - path dir, + dir_path dir, std::string name, const std::string* ext, tracer& trace) @@ -127,26 +127,26 @@ namespace build ostream& operator<< (ostream& os, const target_key& k) { + // If the name is empty, then we want to print the directory + // inside {}, e.g., dir{bar/}, not bar/dir{}. + // + bool n (!k.name->empty ()); + string d (diag_relative (*k.dir, false)); + + if (n) + os << d; + os << k.type->name << '{'; - if (!k.dir->empty ()) + if (n) { - string s (diag_relative (*k.dir)); - - if (s != ".") - { - os << s; + os << *k.name; - if (!k.name->empty () && - s.back () != path::traits::directory_separator) - os << path::traits::directory_separator; - } + if (*k.ext != nullptr && !(*k.ext)->empty ()) + os << '.' << **k.ext; } - - os << *k.name; - - if (*k.ext != nullptr && !(*k.ext)->empty ()) - os << '.' << **k.ext; + else + os << d; os << '}'; @@ -197,7 +197,7 @@ namespace build // if (!v.empty ()) { - n.dir /= path (v); // Move name value to dir. + n.dir /= dir_path (v); // Move name value to dir. v.clear (); } } @@ -212,7 +212,7 @@ namespace build if (i != string::npos) { - n.dir /= path (v, i != 0 ? i : 1); // Special case: "/". + n.dir /= dir_path (v, i != 0 ? i : 1); // Special case: "/". v = string (v, i + 1, string::npos); } @@ -255,7 +255,7 @@ namespace build // if (p.dir.relative ()) { - paths sp; + dir_paths sp; sp.push_back (src_out (p.scope.path (), p.scope)); // src_base return search_existing_file (p, sp); diff --git a/build/types b/build/types index c191eec..6850056 100644 --- a/build/types +++ b/build/types @@ -15,6 +15,7 @@ namespace build // typedef std::vector<path> paths; + typedef std::vector<dir_path> dir_paths; } #endif // BUILD_TYPES diff --git a/build/utility b/build/utility index 3196c81..6584c0a 100644 --- a/build/utility +++ b/build/utility @@ -20,6 +20,7 @@ namespace build // extern const std::string empty_string; extern const path empty_path; + extern const dir_path empty_dir_path; // Comparators. // diff --git a/build/utility.cxx b/build/utility.cxx index c66fba2..d84db52 100644 --- a/build/utility.cxx +++ b/build/utility.cxx @@ -10,6 +10,7 @@ namespace build { const string empty_string; const path empty_path; + const dir_path empty_dir_path; bool exception_unwinding_dtor = false; diff --git a/build/variable b/build/variable index 1365d54..f994b58 100644 --- a/build/variable +++ b/build/variable @@ -69,10 +69,7 @@ namespace build public: list_value (names d): names (std::move (d)) {} list_value (std::string d) {emplace_back (std::move (d));} - - // Note: stored in name as a directory. - // - list_value (path d) {emplace_back (std::move (d));} + list_value (dir_path d) {emplace_back (std::move (d));} virtual value_ptr clone () const {return value_ptr (new list_value (*this));} @@ -122,10 +119,8 @@ namespace build const value_proxy& operator= (std::string) const; - // Note: stored in name as a directory. - // const value_proxy& - operator= (path) const; + operator= (dir_path) const; // Implementation details. // @@ -155,11 +150,9 @@ namespace build const std::string& value_proxy:: as<const std::string&> () const; - // Note: get the name's dir. - // template <> - const path& value_proxy:: - as<const path&> () const; + const dir_path& value_proxy:: + as<const dir_path&> () const; } namespace std diff --git a/build/variable.cxx b/build/variable.cxx index 7067d9b..8f99ad9 100644 --- a/build/variable.cxx +++ b/build/variable.cxx @@ -39,17 +39,15 @@ namespace build return n.value; } - // Note: get the name's directory. - // template <> - const path& value_proxy:: - as<const path&> () const + const dir_path& value_proxy:: + as<const dir_path&> () const { const list_value& lv (as<list_value&> ()); assert (lv.size () < 2); if (lv.empty ()) - return empty_path; + return empty_dir_path; const name& n (lv.front ()); diff --git a/build/variable.ixx b/build/variable.ixx index ca5a24a..2d52d9f 100644 --- a/build/variable.ixx +++ b/build/variable.ixx @@ -37,7 +37,7 @@ namespace build } inline const value_proxy& value_proxy:: - operator= (path v) const + operator= (dir_path v) const { p->reset (new list_value (std::move (v))); return *this; |