From 088a60c512aff26eeb026c516d0afe724880cb2b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 7 Apr 2015 10:47:28 +0200 Subject: Provide more convenient access to root scope --- build/algorithm.cxx | 6 ++--- build/b.cxx | 4 +++- build/config/operation.cxx | 16 +++++++------ build/context | 3 +++ build/context.cxx | 12 +++++----- build/cxx/rule.cxx | 56 +++++++++++++++++++++++++--------------------- build/diagnostics.cxx | 36 ++++++++--------------------- build/dump.cxx | 4 ++-- build/scope | 36 ++++++++++++++++------------- build/scope.cxx | 35 +++++++++++++++++++++-------- build/search.cxx | 2 +- build/target | 13 +++++++++++ build/target.cxx | 31 ++++++++++++++++++------- 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& 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 (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& src_root (s["src_root"].as ()); + 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 (), - s["src_root"].as ()); + 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 (), - s["src_root"].as ()); + 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 ()); + scope& ts (o.base_scope ()); + scope& rs (*ts.root_scope ()); // Shouldn't have matched if nullptr. + const string& cxx (rs["config.cxx"].as ()); vector 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 ()); + scope& ts (o.base_scope ()); + scope& rs (*ts.root_scope ()); // Shouldn't have matched if nullptr. + const string& cxx (rs["config.cxx"].as ()); vector 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 (); - src_root = &s["src_root"].as (); + 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 ro; + path rele (relative (e.path ())); + vector relo; - scope& ts (scopes.find (e.path ())); - const string& cxx (ts["config.cxx"].as ()); + scope& ts (e.base_scope ()); + scope& rs (*ts.root_scope ()); // Shouldn't have matched if nullptr. + const string& cxx (rs["config.cxx"].as ()); vector 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 (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 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 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 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::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 triggers; private: + friend class scope_map; + typedef path_map::const_iterator iterator; + + scope (): variables (*this) {} + iterator i_; scope* parent_; + scope* root_; }; class scope_map: public path_map @@ -96,10 +100,10 @@ namespace build // of the global scope. // std::pair - 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_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 (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> 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 (**i, false); - - unique_ptr 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 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 (**i, true); + return pair (**i, r); } ostream& -- cgit v1.1