diff options
Diffstat (limited to 'libbuild2/scope.hxx')
-rw-r--r-- | libbuild2/scope.hxx | 204 |
1 files changed, 147 insertions, 57 deletions
diff --git a/libbuild2/scope.hxx b/libbuild2/scope.hxx index f82db72..09d61e9 100644 --- a/libbuild2/scope.hxx +++ b/libbuild2/scope.hxx @@ -4,8 +4,6 @@ #ifndef LIBBUILD2_SCOPE_HXX #define LIBBUILD2_SCOPE_HXX -#include <unordered_set> - #include <libbuild2/types.hxx> #include <libbuild2/forward.hxx> #include <libbuild2/utility.hxx> @@ -28,8 +26,12 @@ namespace build2 using subprojects = map<project_name, dir_path>; + // Print as name@dir sequence. + // + // Note: trailing slash is not printed for the directory path. + // LIBBUILD2_SYMEXPORT ostream& - operator<< (ostream&, const subprojects&); // Print as name@dir sequence. + operator<< (ostream&, const subprojects&); class LIBBUILD2_SYMEXPORT scope { @@ -99,8 +101,8 @@ namespace build2 scope& global_scope () {return const_cast<scope&> (ctx.global_scope);} const scope& global_scope () const {return ctx.global_scope;} - // Return true if the specified root scope is a sub-scope of this root - // scope. Note that both scopes must be root. + // Return true if the specified root scope is a sub-scope of (but not the + // same as) this root scope. Note that both scopes must be root. // bool sub_root (const scope&) const; @@ -132,7 +134,7 @@ namespace build2 lookup_type operator[] (const string& name) const { - const variable* var (ctx.var_pool.find (name)); + const variable* var (var_pool ().find (name)); return var != nullptr ? operator[] (*var) : lookup_type (); } @@ -298,13 +300,6 @@ namespace build2 // variable_type_map target_vars; - // 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). - // - public: - std::unordered_set<path> buildfiles; - // Target types. // // Note that target types are project-wide (even if the module that @@ -325,7 +320,7 @@ namespace build2 const target_type& insert_target_type (const target_type& tt) { - return root_extra->target_types.insert (tt); + return root_extra->target_types.insert (tt).first; } template <typename T> @@ -363,40 +358,56 @@ namespace build2 // the out directory. // pair<const target_type&, optional<string>> - find_target_type (name&, name&, const location&) const; + find_target_type (name&, name&, + const location&, + const target_type* = nullptr) const; // As above, but return the result as a target key (with its members // shallow-pointing to processed parts in the two names). // target_key - find_target_key (name&, name&, const location&) const; + find_target_key (name&, name&, + const location&, + const target_type* = nullptr) const; // As above, but the names are passed as a vector. Issue appropriate // diagnostics if the wrong number of names is passed. // target_key - find_target_key (names&, const location&) const; + find_target_key (names&, + const location&, + const target_type* = nullptr) const; // Similar to the find_target_type() but does not complete relative // directories. // pair<const target_type&, optional<string>> - find_prerequisite_type (name&, name&, const location&) const; + find_prerequisite_type (name&, name&, + const location&, + const target_type* = nullptr) const; // As above, but return a prerequisite key. // prerequisite_key - find_prerequisite_key (name&, name&, const location&) const; + find_prerequisite_key (name&, name&, + const location&, + const target_type* = nullptr) const; prerequisite_key - find_prerequisite_key (names&, const location&) const; + find_prerequisite_key (names&, + const location&, + const target_type* = nullptr) const; // Dynamically derive a new target type from an existing one. Return the // reference to the target type and an indicator of whether it was // actually created. // + // Note: the flags are OR'ed to the base's flags. + // pair<reference_wrapper<const target_type>, bool> - derive_target_type (const string& name, const target_type& base); + derive_target_type (const string& name, + const target_type& base, + target_type::flag flags = target_type::flag::none); template <typename T> pair<reference_wrapper<const target_type>, bool> @@ -418,19 +429,20 @@ namespace build2 template <typename T> void - insert_rule (action_id a, string hint, const rule& r) + insert_rule (action_id a, string name, const rule& r) { - rules.insert<T> (a, move (hint), r); + rules.insert<T> (a, move (name), r); } + // 0 meta-operation id is treated as an (emulated) wildcard. + // + // Emulated means that we just iterate over all the meta-operations known + // to this project (and they should all be known at this point) and + // register the rule for each of them. + // template <typename T> void - insert_rule (meta_operation_id mid, operation_id oid, - string hint, - const rule& r) - { - rules.insert<T> (mid, oid, move (hint), r); - } + insert_rule (meta_operation_id, operation_id, string name, const rule&); // Operation callbacks. // @@ -481,9 +493,10 @@ namespace build2 // is not yet determined (happens at the end of bootstrap_src()). NULL // means there are no subprojects. // - optional<const build2::subprojects*> subprojects; + optional<build2::subprojects*> subprojects; - bool altn; // True if using alternative build file/directory naming. + bool altn; // True if using alternative build file/directory naming. + bool loaded; // True if already loaded (load_root()). // Build file/directory naming scheme used by this project. // @@ -502,14 +515,40 @@ namespace build2 const path& src_root_file; // build[2]/bootstrap/src-root.build[2] const path& out_root_file; // build[2]/bootstrap/src-root.build[2] + // Project-private variable pool. + // + // Note: see scope::var_pool_ and use scope::var_pool(). + // + variable_pool var_pool; + // Meta/operations supported by this project. // build2::meta_operations meta_operations; build2::operations operations; - // Modules loaded by this project. + // Modules imported/loaded by this project. + // + module_import_map imported_modules; + module_state_map loaded_modules; + + // Buildfiles already loaded for this project. // - module_map modules; + // We don't expect too many of them per project so let's use vector + // with linear search. + // + paths buildfiles; + + bool + insert_buildfile (const path& f) + { + bool r (find (buildfiles.begin (), + buildfiles.end (), + f) == buildfiles.end ()); + if (r) + buildfiles.push_back (f); + + return r; + } // Variable override cache. // @@ -537,33 +576,53 @@ namespace build2 // when, for example, caching environment-sensitive information. // string environment_checksum; + + root_extra_type (scope&, bool altn); // file.cxx }; unique_ptr<root_extra_type> root_extra; + // The last argument is the operation variable (see var_include) or NULL + // if not used. + // void - insert_operation (operation_id id, const operation_info& in) + insert_operation (operation_id id, + const operation_info& in, + const variable* ovar) { - root_extra->operations.insert (id, in); + // The operation variable should have prerequisite or target visibility. + // + assert (ovar == nullptr || + (ovar->visibility == variable_visibility::prereq || + ovar->visibility == variable_visibility::target)); + + root_extra->operations.insert (id, project_operation_info {&in, ovar}); } void insert_meta_operation (meta_operation_id id, const meta_operation_info& in) { - root_extra->meta_operations.insert (id, in); + root_extra->meta_operations.insert (id, &in); } bool find_module (const string& name) const { - return root_extra->modules.find_module<module> (name) != nullptr; + return root_extra->loaded_modules.find_module<module> (name) != nullptr; } template <typename T> T* + find_module (const string& name) + { + return root_extra->loaded_modules.find_module<T> (name); + } + + template <typename T> + const T* find_module (const string& name) const { - return root_extra->modules.find_module<T> (name); + return root_extra->loaded_modules.find_module<T> (name); } public: @@ -576,10 +635,29 @@ namespace build2 return const_cast<scope&> (*this); } + // Return the project-private variable pool (which is chained to the + // public pool) unless pub is true, in which case return the public pool. + // + // You would normally go for the public pool directly as an optimization + // (for example, in the module's init()) if you know all your variables + // are qualified and thus public. + // variable_pool& - var_pool () + var_pool (bool pub = false) { - return ctx.var_pool.rw (*this); + return (pub ? ctx.var_pool : + var_pool_ != nullptr ? *var_pool_ : + root_ != nullptr ? *root_->var_pool_ : + ctx.var_pool).rw (*this); + } + + const variable_pool& + var_pool (bool pub = false) const + { + return (pub ? ctx.var_pool : + var_pool_ != nullptr ? *var_pool_ : + root_ != nullptr ? *root_->var_pool_ : + ctx.var_pool); } private: @@ -587,13 +665,13 @@ namespace build2 friend class scope_map; friend class temp_scope; - // These two from <libbuild2/file.hxx> set strong_. + // These from <libbuild2/file.hxx> set strong_. // - friend LIBBUILD2_SYMEXPORT void create_bootstrap_outer (scope&); + friend LIBBUILD2_SYMEXPORT void create_bootstrap_outer (scope&, bool); friend LIBBUILD2_SYMEXPORT scope& create_bootstrap_inner (scope&, const dir_path&); - scope (context&, bool global); + scope (context&, bool shared); ~scope (); // Return true if this root scope can be amalgamated. @@ -608,6 +686,8 @@ namespace build2 scope* root_; scope* strong_ = nullptr; // Only set on root scopes. // NULL means no strong amalgamtion. + + variable_pool* var_pool_ = nullptr; // For temp_scope override. }; inline bool @@ -675,24 +755,28 @@ namespace build2 // Temporary scope. The idea is to be able to create a temporary scope in // order not to change the variables in the current scope. Such a scope is - // not entered in to the scope map. As a result it can only be used as a - // temporary set of variables. In particular, defining targets directly in - // such a scope will surely end up badly. Defining any nested scopes will be - // as if defining such a scope in the parent (since path() returns parent's - // path). + // not entered in to the scope map and its parent is the global scope. As a + // result it can only be used as a temporary set of variables. In + // particular, defining targets directly in such a scope will surely end up + // badly. // class temp_scope: public scope { public: - temp_scope (scope& p) - : scope (p.ctx, false /* global */) + temp_scope (scope& gs) + : scope (gs.ctx, false /* shared */), + var_pool_ (nullptr /* shared */, &gs.ctx.var_pool.rw (gs), nullptr) { - out_path_ = p.out_path_; - src_path_ = p.src_path_; - parent_ = &p; - root_ = p.root_; - // No need to copy strong_ since we are never root scope. + // Note that making this scope its own root is a bad idea. + // + root_ = nullptr; + parent_ = &gs; + out_path_ = gs.out_path_; + scope::var_pool_ = &var_pool_; } + + private: + variable_pool var_pool_; }; // Scope map. Protected by the phase mutex. @@ -709,6 +793,8 @@ namespace build2 // The first element, if not NULL, is for the "owning" out path. The rest // of the elements are for the src path shallow references. // + // Note that the global scope is in the first element. + // struct scopes: small_vector<scope*, 3> { scopes () = default; @@ -748,6 +834,10 @@ namespace build2 // Find all the scopes that encompass this path (out or src). // + // If skip_null_out is false, then the first element always corresponds to + // the out scope and is NULL if there is none (see struct scopes above for + // details). + // // Note that the returned range will never be empty (there is always the // global scope). // @@ -756,7 +846,7 @@ namespace build2 // single invocation. How can we pick the scope that is "ours", for some // definition of "ours"? // - // The current think is that a project can be "associated" with other + // The current thinking is that a project can be "associated" with other // projects: its sub-projects and imported projects (it doesn't feel like // its super-projects should be in this set, but maybe). And "ours" could // mean belonging to one of the associated projects. This feels correct @@ -780,7 +870,7 @@ namespace build2 // "island append" restriction we have on loading additional buildfile. // LIBBUILD2_SYMEXPORT pair<scopes::const_iterator, scopes::const_iterator> - find (const dir_path&) const; + find (const dir_path&, bool skip_null_out = true) const; const_iterator begin () const {return map_.begin ();} const_iterator end () const {return map_.end ();} |