aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/scope.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/scope.hxx')
-rw-r--r--libbuild2/scope.hxx171
1 files changed, 124 insertions, 47 deletions
diff --git a/libbuild2/scope.hxx b/libbuild2/scope.hxx
index 948fc7d..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>
@@ -103,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;
@@ -136,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 ();
}
@@ -302,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
@@ -329,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>
@@ -367,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>
@@ -486,7 +493,7 @@ 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 loaded; // True if already loaded (load_root()).
@@ -508,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.
//
@@ -543,40 +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->modules.find_module<T> (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:
@@ -589,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:
@@ -600,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.
@@ -621,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
@@ -688,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.
@@ -722,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;
@@ -761,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).
//
@@ -793,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 ();}