diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2019-06-24 12:01:19 +0200 |
---|---|---|
committer | Karen Arutyunov <karen@codesynthesis.com> | 2019-07-01 18:13:55 +0300 |
commit | 977d07a3ae47ef204665d1eda2d642e5064724f3 (patch) | |
tree | 525a3d6421f61ce789b690191d3c30fc09be3517 /build2/scope.hxx | |
parent | 7161b24963dd9da4d218f92c736b77c35c328a2d (diff) |
Split build system into library and driver
Diffstat (limited to 'build2/scope.hxx')
-rw-r--r-- | build2/scope.hxx | 466 |
1 files changed, 0 insertions, 466 deletions
diff --git a/build2/scope.hxx b/build2/scope.hxx deleted file mode 100644 index afd294e..0000000 --- a/build2/scope.hxx +++ /dev/null @@ -1,466 +0,0 @@ -// file : build2/scope.hxx -*- C++ -*- -// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd -// license : MIT; see accompanying LICENSE file - -#ifndef BUILD2_SCOPE_HXX -#define BUILD2_SCOPE_HXX - -#include <map> -#include <unordered_set> - -#include <build2/types.hxx> -#include <build2/utility.hxx> - -#include <build2/module.hxx> -#include <build2/variable.hxx> -#include <build2/target-key.hxx> -#include <build2/target-type.hxx> -#include <build2/target-state.hxx> -#include <build2/rule-map.hxx> -#include <build2/operation.hxx> - -namespace build2 -{ - class dir; - - class scope - { - public: - // Absolute and normalized. - // - const dir_path& out_path () const {return *out_path_;} - const dir_path& src_path () const {return *src_path_;} - - // The first is a pointer to the key in scope_map. The second is a pointer - // to the src_root/base variable value, if any (i.e., it can be NULL). - // - const dir_path* out_path_ = nullptr; - const dir_path* src_path_ = nullptr; - - bool - root () const {return root_ == this;} - - scope* parent_scope () {return parent_;} - const scope* 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 () {return root_;} - const scope* root_scope () const {return root_;} - - // Root scope of a strong amalgamation of this scope or NULL if - // this scope is not (yet) in any (known) project. If there is - // no strong amalgamation, then this function returns the root - // scope of the project (in other words, in this case a project - // is treated as its own strong amalgamation). - // - scope* strong_scope (); - const scope* strong_scope () const; - - // Root scope of the outermost amalgamation or NULL if this scope is not - // (yet) in any (known) project. If there is no amalgamation, then this - // function returns the root scope of the project (in other words, in this - // case a project is treated as its own amalgamation). - // - scope* weak_scope (); - const scope* weak_scope () const; - - // Return true if the specified root scope is a sub-scope of this root - // scope. Note that both scopes must be root. - // - bool - sub_root (const scope&) const; - - // Variables. - // - public: - variable_map vars; - - // Lookup, including in outer scopes. If you only want to lookup in this - // scope, do it on the the variables map directly (and note that there - // will be no overrides). - // - lookup - operator[] (const variable& var) const - { - return find (var).first; - } - - lookup - operator[] (const variable* var) const // For cached variables. - { - assert (var != nullptr); - return operator[] (*var); - } - - lookup - operator[] (const string& name) const - { - const variable* var (var_pool.find (name)); - return var != nullptr ? operator[] (*var) : lookup (); - } - - // As above, but include target type/pattern-specific variables. - // - lookup - find (const variable& var, const target_key& tk) const - { - return find (var, tk.type, tk.name).first; - } - - lookup - find (const variable& var, const target_type& tt, const string& tn) const - { - return find (var, &tt, &tn).first; - } - - pair<lookup, size_t> - find (const variable& var, - const target_type* tt = nullptr, - const string* tn = nullptr) const - { - auto p (find_original (var, tt, tn)); - return var.overrides == nullptr ? p : find_override (var, move (p)); - } - - // Implementation details (used by scope target lookup). The start_depth - // can be used to skip a number of initial lookups. - // - pair<lookup, size_t> - find_original ( - const variable&, - const target_type* tt = nullptr, const string* tn = nullptr, - const target_type* gt = nullptr, const string* gn = nullptr, - size_t start_depth = 1) const; - - pair<lookup, size_t> - find_override (const variable&, - pair<lookup, size_t> original, - bool target = false, - bool rule = false) const; - - // Return a value suitable for assignment (or append if you only want to - // append to the value from this scope). If the value does not exist in - // this scope's map, then a new one with the NULL value is added and - // returned. Otherwise the existing value is returned. - // - value& - assign (const variable& var) {return vars.assign (var);} - - value& - assign (const variable* var) {return vars.assign (var);} // For cached. - - value& - assign (string name) - { - return assign (variable_pool::instance.insert (move (name))); - } - - // Assign a typed non-overridable variable with normal visibility. - // - template <typename T> - value& - assign (string name) - { - return vars.assign (variable_pool::instance.insert<T> (move (name))); - } - - // Return a value suitable for appending. If the variable does not - // exist in this scope's map, then outer scopes are searched for - // the same variable. If found then a new variable with the found - // value is added to this scope and returned. Otherwise this - // function proceeds as assign(). - // - value& - append (const variable&); - - // Target type/pattern-specific variables. - // - variable_type_map target_vars; - - // Variable override caches. Only on project roots (in root_extra) plus a - // global one for the global scope. - // - // The key is the variable plus the innermost (scope-wise) variable map to - // which this override applies. See find_override() for details. - // - // Note: since it can be modified on any lookup (including during the - // execute phase), the cache is protected by its own mutex shard. - // - using variable_override_cache = variable_cache<pair<const variable*, - const variable_map*>>; - - static variable_override_cache global_override_cache; - - // 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. - // - public: - target_type_map target_types; - - const target_type* - find_target_type (const string&, const scope** = nullptr) const; - - // Given a target name, figure out its type, taking into account - // extensions, special names (e.g., '.' and '..'), or anything else that - // might be relevant. Process the name (in place) by extracting (and - // returning) extension, adjusting dir/leaf, etc., (note that the dir is - // not necessarily normalized). Return NULL if not found. - // - pair<const target_type*, optional<string>> - find_target_type (name&, const location&) 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. - // - pair<reference_wrapper<const target_type>, bool> - derive_target_type (const string& name, const target_type& base); - - template <typename T> - pair<reference_wrapper<const target_type>, bool> - derive_target_type (const string& name) - { - return derive_target_type (name, T::static_type); - } - - // Rules. - // - public: - rule_map rules; - - // Operation callbacks. - // - // An entity (module, core) can register a function that will be called - // when an action is executed on the dir{} target that corresponds to this - // scope. The pre callback is called just before the recipe and the post - // -- immediately after. The callbacks are only called if the recipe - // (including noop recipe) is executed for the corresponding target. The - // callbacks should only be registered during the load phase. - // - // It only makes sense for callbacks to return target_state changed or - // unchanged and to throw failed in case of an error. These pre/post - // states will be merged with the recipe state and become the target - // state. See execute_recipe() for details. - // - public: - struct operation_callback - { - using callback = target_state (action, const scope&, const dir&); - - function<callback> pre; - function<callback> post; - }; - - using operation_callback_map = std::multimap<action_id, - operation_callback>; - - operation_callback_map operation_callbacks; - - // Extra root scope-only data. - // - public: - struct root_data - { - bool altn; // True if using alternative build file/directory naming. - - // Build file/directory naming scheme used by this project. - // - const string& build_ext; // build or build2 (no dot) - const dir_path& build_dir; // build/ or build2/ - const path& buildfile_file; // buildfile or build2file - const path& buildignore_file; // buildignore or build2ignore - - const dir_path& root_dir; // build[2]/root/ - const dir_path& bootstrap_dir; // build[2]/bootstrap/ - - const path& bootstrap_file; // build[2]/bootstrap.build[2] - const path& root_file; // build[2]/root.build[2] - const path& export_file; // build[2]/export.build[2] - const path& src_root_file; // build[2]/bootstrap/src-root.build[2] - const path& out_root_file; // build[2]/bootstrap/src-root.build[2] - - // Meta/operations supported by this project. - // - build2::meta_operations meta_operations; - build2::operations operations; - - // Modules. - // - loaded_module_map modules; - - // Variable override cache (see above). - // - mutable variable_override_cache override_cache; - }; - - unique_ptr<root_data> root_extra; - - void - insert_operation (operation_id id, const operation_info& in) - { - root_extra->operations.insert (id, in); - } - - void - insert_meta_operation (meta_operation_id id, const meta_operation_info& in) - { - root_extra->meta_operations.insert (id, in); - } - - template <typename T> - T* - lookup_module (const string& name) const - { - return root_extra->modules.lookup<T> (name); - } - - public: - // RW access. - // - scope& - rw () const - { - assert (phase == run_phase::load); - return const_cast<scope&> (*this); - } - - // RW access to global scope (RO via global global_scope below). - // - scope& - global () {return *global_;} - - public: - static scope* global_; // Normally not accessed directly. - - private: - friend class parser; - friend class scope_map; - friend class temp_scope; - - // These two from <build2/file.hxx> set strong_. - // - friend void create_bootstrap_outer (scope&); - friend scope& create_bootstrap_inner (scope&, const dir_path&); - - explicit - scope (bool global): vars (global), target_vars (global) {} - - scope* parent_; - scope* root_; - scope* strong_ = nullptr; // Only set on root scopes. - // NULL means no strong amalgamtion. - }; - - inline ostream& - operator<< (ostream& os, const scope& s) - { - return os << s.out_path ().string (); // Always absolute. - } - - // 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). - // - class temp_scope: public scope - { - public: - temp_scope (scope& p) - : scope (false) // Not global. - { - 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. - } - }; - - // Scope map. - // - // Protected by the phase mutex. Note that the scope map is only for paths - // from the out tree. - // - using scope_map_base = dir_path_map<scope>; - - class scope_map: public scope_map_base - { - public: - // Note that we assume the first insertion into the map is always the - // global scope with empty key. - // - iterator - insert (const dir_path&, bool root = false); - - // Find the most qualified scope that encompasses this path. - // - const scope& - find (const dir_path& d) const - { - return const_cast<scope_map*> (this)->find (d); - } - - const scope& - find (const path& p) const - { - // 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. - // - // In fact, ideally, we should have used path_map instead of - // dir_path_map to be able to search for both paths without any casting - // (and copies). But currently we have too much stuff pointing to the - // key. - // - return find (path_cast<dir_path> (p)); - } - - // RW access. - // - public: - scope_map& - rw () const - { - assert (phase == run_phase::load); - return const_cast<scope_map&> (*this); - } - - scope_map& - rw (scope&) const {return const_cast<scope_map&> (*this);} - - private: - static scope_map instance; - - // Entities that can access bypassing the lock proof. - // - friend int main (int, char*[]); - friend variable_overrides reset (const strings&); - - scope& - find (const dir_path&); - - public: - static const scope_map& cinstance; // For var_pool initialization. - }; - - extern const scope_map& scopes; - extern const scope* global_scope; -} - -#include <build2/scope.ixx> - -#endif // BUILD2_SCOPE_HXX |