aboutsummaryrefslogtreecommitdiff
path: root/libbuild2
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2')
-rw-r--r--libbuild2/bash/init.cxx5
-rw-r--r--libbuild2/context.cxx13
-rw-r--r--libbuild2/context.hxx12
-rw-r--r--libbuild2/file.cxx7
-rw-r--r--libbuild2/in/init.cxx2
-rw-r--r--libbuild2/parser.cxx2
-rw-r--r--libbuild2/scope.cxx39
-rw-r--r--libbuild2/scope.hxx47
-rw-r--r--libbuild2/test/init.cxx6
9 files changed, 80 insertions, 53 deletions
diff --git a/libbuild2/bash/init.cxx b/libbuild2/bash/init.cxx
index bd0e34b..65d9d0f 100644
--- a/libbuild2/bash/init.cxx
+++ b/libbuild2/bash/init.cxx
@@ -28,7 +28,7 @@ namespace build2
scope& bs,
const location& l,
unique_ptr<module_base>&,
- bool,
+ bool first,
bool,
const variable_map&)
{
@@ -44,7 +44,8 @@ namespace build2
// Register target types and configure default installability.
//
- bs.target_types.insert<bash> ();
+ if (first)
+ rs.insert_target_type<bash> ();
if (install_loaded)
{
diff --git a/libbuild2/context.cxx b/libbuild2/context.cxx
index 687e9aa..db46319 100644
--- a/libbuild2/context.cxx
+++ b/libbuild2/context.cxx
@@ -45,9 +45,11 @@ namespace build2
target_set targets;
variable_pool var_pool;
variable_overrides var_overrides;
- variable_override_cache global_override_cache;
function_map functions;
+ target_type_map global_target_types;
+ variable_override_cache global_override_cache;
+
data (context& c): scopes (c), targets (c), var_pool (&c /* global */) {}
};
@@ -59,12 +61,13 @@ namespace build2
keep_going (kg),
phase_mutex (*this),
scopes (data_->scopes),
- global_scope (create_global_scope (data_->scopes)),
targets (data_->targets),
var_pool (data_->var_pool),
var_overrides (data_->var_overrides),
- global_override_cache (data_->global_override_cache),
- functions (data_->functions)
+ functions (data_->functions),
+ global_scope (create_global_scope (data_->scopes)),
+ global_target_types (data_->global_target_types),
+ global_override_cache (data_->global_override_cache)
{
tracer trace ("context");
@@ -217,7 +220,7 @@ namespace build2
// Register builtin target types.
//
{
- target_type_map& t (gs.target_types);
+ target_type_map& t (data_->global_target_types);
t.insert<file> ();
t.insert<alias> ();
diff --git a/libbuild2/context.hxx b/libbuild2/context.hxx
index 243ad2f..f9432ae 100644
--- a/libbuild2/context.hxx
+++ b/libbuild2/context.hxx
@@ -25,6 +25,7 @@ namespace build2
class scope;
class scope_map;
class target_set;
+ class target_type_map;
class value;
using values = small_vector<value, 1>;
@@ -274,16 +275,17 @@ namespace build2
// Build state (scopes, targets, variables, etc).
//
const scope_map& scopes;
- const scope& global_scope;
-
target_set& targets;
-
const variable_pool& var_pool;
const variable_overrides& var_overrides; // Project and relative scope.
- variable_override_cache& global_override_cache;
-
function_map& functions;
+ // Global scope.
+ //
+ const scope& global_scope;
+ const target_type_map& global_target_types;
+ variable_override_cache& global_override_cache;
+
// Cached variables.
//
diff --git a/libbuild2/file.cxx b/libbuild2/file.cxx
index 7520af2..4eaf854 100644
--- a/libbuild2/file.cxx
+++ b/libbuild2/file.cxx
@@ -443,8 +443,8 @@ namespace build2
assert (altn && root.root_extra == nullptr);
bool a (*altn);
- root.root_extra = unique_ptr<scope::root_data> (
- new scope::root_data {
+ root.root_extra.reset (
+ new scope::root_extra_type {
a,
a ? alt_build_ext : std_build_ext,
a ? alt_build_dir : std_build_dir,
@@ -460,7 +460,8 @@ namespace build2
{}, /* meta_operations */
{}, /* operations */
{}, /* modules */
- {} /* override_cache */});
+ {}, /* override_cache */
+ {}} /* target_types */);
// Enter built-in meta-operation and operation names. Loading of
// modules (via the src bootstrap; see below) can result in
diff --git a/libbuild2/in/init.cxx b/libbuild2/in/init.cxx
index 8b27336..ece1bcf 100644
--- a/libbuild2/in/init.cxx
+++ b/libbuild2/in/init.cxx
@@ -65,7 +65,7 @@ namespace build2
// Register target types.
//
- rs.target_types.insert<in> ();
+ rs.insert_target_type<in> ();
return true;
}
diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx
index c1787d6..2af5762 100644
--- a/libbuild2/parser.cxx
+++ b/libbuild2/parser.cxx
@@ -1982,7 +1982,7 @@ namespace build2
if (bt == nullptr)
fail (t) << "unknown target type " << bn;
- if (!scope_->derive_target_type (move (dn), *bt).second)
+ if (!root_->derive_target_type (move (dn), *bt).second)
fail (dnl) << "target type " << dn << " already define in this scope";
next (t, tt); // Get newline.
diff --git a/libbuild2/scope.cxx b/libbuild2/scope.cxx
index 6e00511..8d5e37a 100644
--- a/libbuild2/scope.cxx
+++ b/libbuild2/scope.cxx
@@ -589,48 +589,33 @@ namespace build2
}
const target_type* scope::
- find_target_type (const string& tt, const scope** rs) const
+ find_target_type (const string& tt) const
{
- // Search scopes outwards, stopping at the project root.
+ // Search the project's root scope then the global scope.
//
- for (const scope* s (this);
- s != nullptr;
- s = s->root () ? &s->global_scope () : s->parent_scope ())
+ if (const scope* rs = root_scope ())
{
- if (s->target_types.empty ())
- continue;
-
- if (const target_type* r = s->target_types.find (tt))
- {
- if (rs != nullptr)
- *rs = s;
-
+ if (const target_type* r = rs->root_extra->target_types.find (tt))
return r;
- }
}
- return nullptr;
+ return ctx.global_target_types.find (tt);
}
// Find target type from file name.
//
static const target_type*
- find_file_target_type (const scope* s, const string& n)
+ find_target_type_file (const scope& s, const string& n)
{
// Pretty much the same logic as in find_target_type() above.
//
- for (;
- s != nullptr;
- s = s->root () ? &s->global_scope () : s->parent_scope ())
+ if (const scope* rs = s.root_scope ())
{
- if (s->target_types.empty ())
- continue;
-
- if (const target_type* r = s->target_types.find_file (n))
+ if (const target_type* r = rs->root_extra->target_types.find_file (n))
return r;
}
- return nullptr;
+ return s.ctx.global_target_types.find_file (n);
}
pair<const target_type*, optional<string>> scope::
@@ -720,7 +705,7 @@ namespace build2
// We only consider files without extension for file name mapping.
//
if (!ext)
- tt = find_file_target_type (this, v);
+ tt = find_target_type_file (*this, v);
//@@ TODO: derive type from extension.
@@ -767,6 +752,8 @@ namespace build2
pair<reference_wrapper<const target_type>, bool> scope::
derive_target_type (const string& name, const target_type& base)
{
+ assert (root_scope () == this);
+
// Base target type uses extensions.
//
bool ext (base.fixed_extension != nullptr ||
@@ -818,7 +805,7 @@ namespace build2
? &target_print_0_ext_verb // Fixed extension, no use printing.
: nullptr; // Normal.
- return target_types.insert (name, move (dt));
+ return root_extra->target_types.insert (name, move (dt));
}
// scope_map
diff --git a/libbuild2/scope.hxx b/libbuild2/scope.hxx
index 35f07dd..08eb06b 100644
--- a/libbuild2/scope.hxx
+++ b/libbuild2/scope.hxx
@@ -202,11 +202,42 @@ namespace build2
// Target types.
//
+ // Note that target types are project-wide (even if the module that
+ // registers them is loaded in a base scope). The thinking here is that
+ // having target types only visible in certain scopes of a project just
+ // complicates and confuses things (e.g., you cannot refer to a target
+ // whose buildfile you just included). On the other hand, it feels highly
+ // unlikely that a target type will somehow need to be different for
+ // different parts of the project (unlike, say, a rule).
+ //
+ // The target types are also project-local. This means one has to use
+ // import to refer to targets across projects, even in own subprojects
+ // (because we stop searching at project boundaries).
+ //
+ // See also context::global_target_types.
+ //
public:
- target_type_map target_types;
+ const target_type&
+ insert_target_type (const target_type& tt)
+ {
+ return root_extra->target_types.insert (tt);
+ }
+
+ template <typename T>
+ const target_type&
+ insert_target_type ()
+ {
+ return root_extra->target_types.insert<T> ();
+ }
+
+ void
+ insert_target_type_file (const string& n, const target_type& tt)
+ {
+ root_extra->target_types.insert_file (n, tt);
+ }
const target_type*
- find_target_type (const string&, const scope** = nullptr) const;
+ find_target_type (const string&) const;
// Given a target name, figure out its type, taking into account
// extensions, special names (e.g., '.' and '..'), or anything else that
@@ -267,7 +298,7 @@ namespace build2
// Extra root scope-only data.
//
public:
- struct root_data
+ struct root_extra_type
{
bool altn; // True if using alternative build file/directory naming.
@@ -292,16 +323,20 @@ namespace build2
build2::meta_operations meta_operations;
build2::operations operations;
- // Modules.
+ // Modules loaded by this project.
//
module_map modules;
// Variable override cache.
//
mutable variable_override_cache override_cache;
+
+ // Target types.
+ //
+ target_type_map target_types;
};
- unique_ptr<root_data> root_extra;
+ unique_ptr<root_extra_type> root_extra;
void
insert_operation (operation_id id, const operation_info& in)
@@ -381,7 +416,7 @@ namespace build2
project (const scope& root);
// 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
+ // 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
diff --git a/libbuild2/test/init.cxx b/libbuild2/test/init.cxx
index 3fb4df6..923f047 100644
--- a/libbuild2/test/init.cxx
+++ b/libbuild2/test/init.cxx
@@ -202,10 +202,8 @@ namespace build2
// Register target types.
//
{
- auto& t (rs.target_types);
-
- auto& tt (t.insert<testscript> ());
- t.insert_file ("testscript", tt);
+ auto& tt (rs.insert_target_type<testscript> ());
+ rs.insert_target_type_file ("testscript", tt);
}
// Register our test running rule.