aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-04-07 10:47:28 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-04-07 10:47:28 +0200
commit088a60c512aff26eeb026c516d0afe724880cb2b (patch)
tree3fbd798bd6a385875c8db3b2677a94d3abeb23eb
parent137df0bea6cebabe5278e67e5dad6f3047c762fb (diff)
Provide more convenient access to root scope
-rw-r--r--build/algorithm.cxx6
-rw-r--r--build/b.cxx4
-rw-r--r--build/config/operation.cxx16
-rw-r--r--build/context3
-rw-r--r--build/context.cxx12
-rw-r--r--build/cxx/rule.cxx56
-rw-r--r--build/diagnostics.cxx36
-rw-r--r--build/dump.cxx4
-rw-r--r--build/scope36
-rw-r--r--build/scope.cxx35
-rw-r--r--build/search.cxx2
-rw-r--r--build/target13
-rw-r--r--build/target.cxx31
13 files changed, 148 insertions, 106 deletions
diff --git a/build/algorithm.cxx b/build/algorithm.cxx
index 87e2259..3fc2e92 100644
--- a/build/algorithm.cxx
+++ b/build/algorithm.cxx
@@ -173,11 +173,11 @@ namespace build
{
tracer trace ("inject_parent_fsdir");
- scope& s (scopes.find (t.dir));
+ scope& s (t.base_scope ());
- if (auto v = s["out_root"]) // Could be outside any project.
+ if (scope* rs = s.root_scope ()) // Could be outside any project.
{
- const path& out_root (v.as<const path&> ());
+ const 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/.
diff --git a/build/b.cxx b/build/b.cxx
index c71e6d3..d7a5638 100644
--- a/build/b.cxx
+++ b/build/b.cxx
@@ -502,7 +502,7 @@ main (int argc, char* argv[])
// files, if any. Note that we might already have done this
// as a result of one of the preceding target processing.
//
- scope& rs (scopes[out_root]);
+ scope& rs (scopes.insert (out_root, true).first);
// Enter built-in meta-operation and operation names. Note that
// the order of registration should match the id constants; see
@@ -740,6 +740,8 @@ main (int argc, char* argv[])
act = action (mid, oid);
+ current_mif = mif;
+ current_oif = oif;
current_mode = oif->mode;
current_rules = &rules[oid];
}
diff --git a/build/config/operation.cxx b/build/config/operation.cxx
index 6886752..6f5beba 100644
--- a/build/config/operation.cxx
+++ b/build/config/operation.cxx
@@ -65,8 +65,9 @@ namespace build
}
static void
- save_config (const path& out_root)
+ save_config (scope& r)
{
+ const path& out_root (r.path ());
path f (out_root / config_file);
if (verb >= 1)
@@ -85,8 +86,6 @@ namespace build
// Save all the variables in the config namespace that are set
// on the project's root scope.
//
- scope& r (scopes.find (out_root));
-
for (auto p (r.variables.find_namespace ("config"));
p.first != p.second;
++p.first)
@@ -135,10 +134,13 @@ namespace build
for (void* v: ts)
{
target& t (*static_cast<target*> (v));
- scope& s (scopes.find (t.dir));
+ scope* rs (t.root_scope ());
+
+ if (rs == nullptr)
+ fail << "out of project target " << t;
- const path& out_root (s["out_root"].as<const path&> ());
- const path& src_root (s["src_root"].as<const path&> ());
+ const path& out_root (rs->path ());
+ const path& src_root (rs->src_path ());
// Make sure the directories exist.
//
@@ -163,7 +165,7 @@ namespace build
// Save config.build.
//
- save_config (out_root);
+ save_config (*rs);
}
else
{
diff --git a/build/context b/build/context
index 8ebce26..39e00e7 100644
--- a/build/context
+++ b/build/context
@@ -23,6 +23,9 @@ namespace build
// Current action (meta/operation).
//
+ extern const meta_operation_info* current_mif;
+ extern const operation_info* current_oif;
+
extern execution_mode current_mode;
extern const target_rule_map* current_rules;
diff --git a/build/context.cxx b/build/context.cxx
index a0952ec..7303e7d 100644
--- a/build/context.cxx
+++ b/build/context.cxx
@@ -18,6 +18,8 @@ namespace build
path work;
path home;
+ const meta_operation_info* current_mif;
+ const operation_info* current_oif;
execution_mode current_mode;
const target_rule_map* current_rules;
@@ -79,17 +81,15 @@ namespace build
path
src_out (const path& out, scope& s)
{
- return src_out (out,
- s["out_root"].as<const path&> (),
- s["src_root"].as<const path&> ());
+ scope& rs (*s.root_scope ());
+ return src_out (out, rs.path (), rs.src_path ());
}
path
out_src (const path& src, scope& s)
{
- return out_src (src,
- s["out_root"].as<const path&> (),
- s["src_root"].as<const path&> ());
+ scope& rs (*s.root_scope ());
+ return out_src (src, rs.path (), rs.src_path ());
}
path
diff --git a/build/cxx/rule.cxx b/build/cxx/rule.cxx
index 8d7f3c3..daa76e0 100644
--- a/build/cxx/rule.cxx
+++ b/build/cxx/rule.cxx
@@ -182,18 +182,19 @@ namespace build
{
tracer trace ("cxx::compile::inject_prerequisites");
- scope& ts (scopes.find (o.path ()));
- const string& cxx (ts["config.cxx"].as<const string&> ());
+ scope& ts (o.base_scope ());
+ scope& rs (*ts.root_scope ()); // Shouldn't have matched if nullptr.
+ const string& cxx (rs["config.cxx"].as<const string&> ());
vector<const char*> args {cxx.c_str ()};
- append_options (args, ts, "config.cxx.poptions");
+ append_options (args, rs, "config.cxx.poptions");
append_options (args, ts, "cxx.poptions");
// @@ Some C++ options (e.g., -std, -m) affect the preprocessor.
// Or maybe they are not C++ options? Common options?
//
- append_options (args, ts, "config.cxx.coptions");
+ append_options (args, rs, "config.cxx.coptions");
string std; // Storage.
append_std (args, ts, std);
@@ -333,18 +334,19 @@ namespace build
// Translate paths to relative (to working directory) ones. This
// results in easier to read diagnostics.
//
- path ro (relative (o.path ()));
- path rs (relative (s->path ()));
+ path relo (relative (o.path ()));
+ path rels (relative (s->path ()));
- scope& ts (scopes.find (o.path ()));
- const string& cxx (ts["config.cxx"].as<const string&> ());
+ scope& ts (o.base_scope ());
+ scope& rs (*ts.root_scope ()); // Shouldn't have matched if nullptr.
+ const string& cxx (rs["config.cxx"].as<const string&> ());
vector<const char*> args {cxx.c_str ()};
- append_options (args, ts, "config.cxx.poptions");
+ append_options (args, rs, "config.cxx.poptions");
append_options (args, ts, "cxx.poptions");
- append_options (args, ts, "config.cxx.coptions");
+ append_options (args, rs, "config.cxx.coptions");
string std; // Storage.
append_std (args, ts, std);
@@ -352,10 +354,10 @@ namespace build
append_options (args, ts, "cxx.coptions");
args.push_back ("-o");
- args.push_back (ro.string ().c_str ());
+ args.push_back (relo.string ().c_str ());
args.push_back ("-c");
- args.push_back (rs.string ().c_str ());
+ args.push_back (rels.string ().c_str ());
args.push_back (nullptr);
@@ -495,13 +497,14 @@ namespace build
if (out_root == nullptr)
{
- // Which scope shall we use to resolve the roots? Unlikely,
+ // Which scope shall we use to resolve the root? Unlikely,
// but possible, the prerequisite is from a different project
// altogether. So we are going to use the target's project.
//
- scope& s (scopes.find (e.dir));
- out_root = &s["out_root"].as<const path&> ();
- src_root = &s["src_root"].as<const path&> ();
+ scope* rs (e.root_scope ());
+ assert (rs != nullptr); // Shouldn't have matched.
+ out_root = &rs->path ();
+ src_root = &rs->src_path ();
}
prerequisite& cp (p);
@@ -645,15 +648,16 @@ namespace build
// Translate paths to relative (to working directory) ones. This
// results in easier to read diagnostics.
//
- path re (relative (e.path ()));
- vector<path> ro;
+ path rele (relative (e.path ()));
+ vector<path> relo;
- scope& ts (scopes.find (e.path ()));
- const string& cxx (ts["config.cxx"].as<const string&> ());
+ scope& ts (e.base_scope ());
+ scope& rs (*ts.root_scope ()); // Shouldn't have matched if nullptr.
+ const string& cxx (rs["config.cxx"].as<const string&> ());
vector<const char*> args {cxx.c_str ()};
- append_options (args, ts, "config.cxx.coptions");
+ append_options (args, rs, "config.cxx.coptions");
string std; // Storage.
append_std (args, ts, std);
@@ -661,21 +665,21 @@ namespace build
append_options (args, ts, "cxx.coptions");
args.push_back ("-o");
- args.push_back (re.string ().c_str ());
+ args.push_back (rele.string ().c_str ());
- append_options (args, ts, "config.cxx.loptions");
+ append_options (args, rs, "config.cxx.loptions");
append_options (args, ts, "cxx.loptions");
for (const prerequisite& p: t.prerequisites)
{
if (const obj* o = dynamic_cast<const obj*> (p.target))
{
- ro.push_back (relative (o->path ()));
- args.push_back (ro.back ().string ().c_str ());
+ relo.push_back (relative (o->path ()));
+ args.push_back (relo.back ().string ().c_str ());
}
}
- append_options (args, ts, "config.cxx.libs");
+ append_options (args, rs, "config.cxx.libs");
append_options (args, ts, "cxx.libs");
args.push_back (nullptr);
diff --git a/build/diagnostics.cxx b/build/diagnostics.cxx
index aab7675..2fad0d3 100644
--- a/build/diagnostics.cxx
+++ b/build/diagnostics.cxx
@@ -60,16 +60,10 @@ namespace build
// diag_do(), etc.
//
string
- diag_do (const action& a, const target& t)
+ diag_do (const action&, const target& t)
{
- // @@ root scope
- //
- scope& root (
- scopes.find (
- scopes.find (t.dir)["out_root"].as<const path&> ()));
-
- const meta_operation_info& mi (root.meta_operations[a.meta_operation ()]);
- const operation_info& oi (root.operations[a.operation ()]);
+ const meta_operation_info& mi (*current_mif);
+ const operation_info& oi (*current_oif);
ostringstream os;
@@ -91,16 +85,10 @@ namespace build
}
string
- diag_doing (const action& a, const target& t)
+ diag_doing (const action&, const target& t)
{
- // @@ root scope
- //
- scope& root (
- scopes.find (
- scopes.find (t.dir)["out_root"].as<const path&> ()));
-
- const meta_operation_info& mi (root.meta_operations[a.meta_operation ()]);
- const operation_info& oi (root.operations[a.operation ()]);
+ const meta_operation_info& mi (*current_mif);
+ const operation_info& oi (*current_oif);
ostringstream os;
@@ -118,16 +106,10 @@ namespace build
}
string
- diag_already_done (const action& a, const target& t)
+ diag_already_done (const action&, const target& t)
{
- // @@ root scope
- //
- scope& root (
- scopes.find (
- scopes.find (t.dir)["out_root"].as<const path&> ()));
-
- const meta_operation_info& mi (root.meta_operations[a.meta_operation ()]);
- const operation_info& oi (root.operations[a.operation ()]);
+ const meta_operation_info& mi (*current_mif);
+ const operation_info& oi (*current_oif);
ostringstream os;
diff --git a/build/dump.cxx b/build/dump.cxx
index 0287d4a..5ba7269 100644
--- a/build/dump.cxx
+++ b/build/dump.cxx
@@ -75,7 +75,7 @@ namespace build
// Nested scopes of which we are a parent.
//
- for (auto e (scopes.end ()); i != e && i->second.parent () == &p; )
+ for (auto e (scopes.end ()); i != e && i->second.parent_scope () == &p; )
{
if (vb)
{
@@ -98,7 +98,7 @@ namespace build
for (const auto& pt: targets)
{
const target& t (*pt);
- const scope* ts (&scopes.find (t.dir));
+ const scope* ts (&t.base_scope ());
bool f (false);
diff --git a/build/scope b/build/scope
index 0fa3025..057fbc1 100644
--- a/build/scope
+++ b/build/scope
@@ -29,7 +29,18 @@ namespace build
src_path () const {return *src_path_;} // Corresponding src path.
scope*
- parent () const {return parent_;}
+ parent_scope () const {return parent_;}
+
+ // Root scope of this scope or NULL if this scope is not (yet)
+ // in any (known) project. Note that if the scope itself is
+ // root, then this function return this. To get to the outer
+ // root, query the root scope of the parent.
+ //
+ scope*
+ root_scope () const {return root_;}
+
+ bool
+ root () const {return root_ == this;}
// Variable lookup. Note that this find, not find or insert like
// in the variable_map, because we also search in outer scopes.
@@ -44,19 +55,6 @@ namespace build
const path_type* src_path_ {nullptr}; // Cached src_{root,base} var value.
- private:
- friend class scope_map;
-
- typedef path_map<scope>::const_iterator iterator;
-
- scope (): variables (*this) {}
-
- void
- init (const iterator& i, scope* p) {i_ = i; parent_ = p;}
-
- void
- parent (scope& p) {parent_ = &p;}
-
public:
variable_map variables;
prerequisite_set prerequisites;
@@ -85,8 +83,14 @@ namespace build
std::unordered_map<path_type, trigger_type> triggers;
private:
+ friend class scope_map;
+ typedef path_map<scope>::const_iterator iterator;
+
+ scope (): variables (*this) {}
+
iterator i_;
scope* parent_;
+ scope* root_;
};
class scope_map: public path_map<scope>
@@ -96,10 +100,10 @@ namespace build
// of the global scope.
//
std::pair<scope&, bool>
- insert (const path&);
+ insert (const path&, bool root);
scope&
- operator[] (const path& p) {return insert (p).first;}
+ operator[] (const path& p) {return insert (p, false).first;}
// Find the most qualified scope that encompasses this path.
//
diff --git a/build/scope.cxx b/build/scope.cxx
index f907163..cdca747 100644
--- a/build/scope.cxx
+++ b/build/scope.cxx
@@ -20,7 +20,7 @@ namespace build
value_proxy scope::
operator[] (const variable& var)
{
- for (scope* s (this); s != nullptr; s = s->parent ())
+ for (scope* s (this); s != nullptr; s = s->parent_scope ())
{
auto i (s->variables.find (var));
if (i != s->variables.end ())
@@ -36,7 +36,7 @@ namespace build
scope* global_scope;
pair<scope&, bool> scope_map::
- insert (const path& k)
+ insert (const path& k, bool root)
{
auto er (emplace (k, scope ()));
scope& s (er.first->second);
@@ -45,8 +45,8 @@ namespace build
{
scope* p (nullptr);
- // Update scopes of which we are a new parent (unless this is the
- // global scope).
+ // Update scopes of which we are a new parent/root (unless this
+ // is the global scope).
//
if (size () > 1)
{
@@ -62,11 +62,13 @@ namespace build
// between it and our parent.
//
if (p == nullptr)
- p = c.parent ();
- else if (p != c.parent ()) // A scope with an intermediate parent.
- continue;
+ p = c.parent_;
- c.parent (s);
+ if (root)
+ c.root_ = &s;
+
+ if (p == c.parent_) // A scope without an intermediate parent.
+ c.parent_ = &s;
}
// We couldn't get the parent from one of its old children
@@ -76,7 +78,22 @@ namespace build
p = &find (k.directory ());
}
- s.init (er.first, p);
+ s.i_ = er.first;
+ s.parent_ = p;
+ s.root_ = root ? &s : (p != nullptr ? p->root_ : nullptr);
+ }
+ else if (root && !s.root ())
+ {
+ // Upgrade to root scope.
+ //
+ auto r (find_prefix (k));
+ for (++r.first; r.first != r.second; ++r.first)
+ {
+ scope& c (r.first->second);
+ c.root_ = &s;
+ }
+
+ s.root_ = &s;
}
return pair<scope&, bool> (s, er.second);
diff --git a/build/search.cxx b/build/search.cxx
index 5f21c64..bd81822 100644
--- a/build/search.cxx
+++ b/build/search.cxx
@@ -110,7 +110,7 @@ namespace build
target&
create_new_target (prerequisite& p)
{
- tracer trace ("search_new_target");
+ tracer trace ("create_new_target");
assert (p.target == nullptr);
diff --git a/build/target b/build/target
index f8bb2c1..48accc8 100644
--- a/build/target
+++ b/build/target
@@ -100,6 +100,19 @@ namespace build
const std::string* ext; // Extension, NULL means unspecified.
public:
+ // Most qualified scope that contains this target.
+ //
+ scope&
+ base_scope () const;
+
+ // Root scope of a project that contains this target. Note that
+ // a target can be out of any (known) project root in which case
+ // NULL is returned.
+ //
+ scope*
+ root_scope () const;
+
+ public:
typedef
std::vector<std::reference_wrapper<prerequisite>>
prerequisites_type;
diff --git a/build/target.cxx b/build/target.cxx
index dc85402..4f49206 100644
--- a/build/target.cxx
+++ b/build/target.cxx
@@ -37,6 +37,20 @@ namespace build
// target
//
+ scope& target::
+ base_scope () const
+ {
+ return scopes.find (dir);
+ }
+
+ scope* target::
+ root_scope () const
+ {
+ // This is tricky to cache so we do the lookup for now.
+ //
+ return scopes.find (dir).root_scope ();
+ }
+
ostream&
operator<< (ostream& os, const target& t)
{
@@ -97,16 +111,17 @@ namespace build
tracer& trace)
{
iterator i (find (target_key {&tt, &dir, &name, &ext}, trace));
+ bool r (i == end ());
- if (i != end ())
- return pair<target&, bool> (**i, false);
-
- unique_ptr<target> t (tt.factory (move (dir), move (name), ext));
- i = map_.emplace (
- make_pair (target_key {&tt, &t->dir, &t->name, &t->ext},
- move (t))).first;
+ if (r)
+ {
+ unique_ptr<target> pt (tt.factory (move (dir), move (name), ext));
+ i = map_.emplace (
+ make_pair (target_key {&tt, &pt->dir, &pt->name, &pt->ext},
+ move (pt))).first;
+ }
- return pair<target&, bool> (**i, true);
+ return pair<target&, bool> (**i, r);
}
ostream&