aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbuild2/config/init.cxx5
-rw-r--r--libbuild2/file.cxx22
-rw-r--r--libbuild2/file.hxx22
-rw-r--r--libbuild2/parser.cxx18
-rw-r--r--libbuild2/parser.hxx10
5 files changed, 47 insertions, 30 deletions
diff --git a/libbuild2/config/init.cxx b/libbuild2/config/init.cxx
index f0f4841..aa2c763 100644
--- a/libbuild2/config/init.cxx
+++ b/libbuild2/config/init.cxx
@@ -215,7 +215,10 @@ namespace build2
info << "consider reconfiguring " << project (rs) << '@'
<< rs.out_path ();
- source (rs, rs, lex);
+ // Treat it as continuation of bootstrap to avoid project switching
+ // (see switch_scope() for details).
+ //
+ source (rs, rs, lex, load_stage::boot);
};
auto load_config_file = [&load_config] (const path& f, const location& l)
diff --git a/libbuild2/file.cxx b/libbuild2/file.cxx
index cbad9ec..0bf3fd4 100644
--- a/libbuild2/file.cxx
+++ b/libbuild2/file.cxx
@@ -239,9 +239,9 @@ namespace build2
}
void
- source (scope& root, scope& base, lexer& l)
+ source (scope& root, scope& base, lexer& l, load_stage s)
{
- parser p (root.ctx);
+ parser p (root.ctx, s);
source (p, root, base, l);
}
@@ -412,16 +412,17 @@ namespace build2
}
pair<scope&, scope*>
- switch_scope (scope& root, const dir_path& p)
+ switch_scope (scope& root, const dir_path& p, bool proj)
{
// First, enter the scope into the map and see if it is in any project. If
// it is not, then there is nothing else to do.
//
auto i (root.ctx.scopes.rw (root).insert (p));
scope& base (i->second);
- scope* rs (base.root_scope ());
- if (rs != nullptr)
+ scope* rs (nullptr);
+
+ if (proj && (rs = base.root_scope ()) != nullptr)
{
// Path p can be src_base or out_base. Figure out which one it is.
//
@@ -536,7 +537,8 @@ namespace build2
// prevent multiple sourcing. We handle it here but we still need
// something like source_once (once [scope] source) in buildfiles.
//
- source_once (root, root, f);
+ parser p (root.ctx, load_stage::boot);
+ source_once (p, root, root, f, root);
}
pair<value, bool>
@@ -814,7 +816,7 @@ namespace build2
//
if (rs.buildfiles.insert (f).second)
{
- parser p (rs.ctx, parser::stage::boot);
+ parser p (rs.ctx, load_stage::boot);
source (p, rs, rs, f);
}
else
@@ -1047,7 +1049,7 @@ namespace build2
if (root.root_extra == nullptr)
setup_root_extra (root, altn);
- parser p (root.ctx, parser::stage::boot);
+ parser p (root.ctx, load_stage::boot);
source_hooks (p, root, d, true /* pre */);
}
}
@@ -1061,7 +1063,7 @@ namespace build2
if (exists (d))
{
- parser p (root.ctx, parser::stage::boot);
+ parser p (root.ctx, load_stage::boot);
source_hooks (p, root, d, false /* pre */);
}
}
@@ -1294,7 +1296,7 @@ namespace build2
// Reuse the parser to accumulate the configuration variable information.
//
- parser p (root.ctx, parser::stage::root);
+ parser p (root.ctx, load_stage::root);
if (he) {source_hooks (p, root, hd, true /* pre */); p.reset ();}
if (fe) {source_once (p, root, root, f, root);}
diff --git a/libbuild2/file.hxx b/libbuild2/file.hxx
index 2ca72b1..b44efb6 100644
--- a/libbuild2/file.hxx
+++ b/libbuild2/file.hxx
@@ -67,6 +67,15 @@ namespace build2
LIBBUILD2_SYMEXPORT pair<dir_path, bool>
find_out_root (const dir_path&, optional<bool>& altn);
+ // Project's loading stage during which the parsing is performed.
+ //
+ enum class load_stage
+ {
+ boot, // Loading bootstrap.build (or bootstrap pre/post hooks).
+ root, // Loading root.build (or root pre/post hooks).
+ rest // Loading the rest (ordinary buildfiles, command line, etc).
+ };
+
// If buildfile is '-', then read from STDIN.
//
LIBBUILD2_SYMEXPORT void
@@ -82,7 +91,7 @@ namespace build2
// stdin that requires parse_variable()).
//
LIBBUILD2_SYMEXPORT void
- source (scope& root, scope& base, lexer&);
+ source (scope& root, scope& base, lexer&, load_stage = load_stage::rest);
// As above but first check if this buildfile has already been sourced for
// the base scope. Return false if the file has already been sourced.
@@ -115,13 +124,14 @@ namespace build2
const dir_path& out_base,
const dir_path& src_base);
- // Return a scope for the specified directory (first). Note that switching
- // to this scope might also involve switch to a new root scope (second) if
- // the new scope is in another project. If the new scope is not in any
- // project, then NULL is returned in second.
+ // Return a scope for the specified directory (first). If project is true
+ // then switching to this scope might also involve switch to a new root
+ // scope (second) if the new scope is in another project. If project is
+ // false or the new scope is not in any project, then NULL is returned in
+ // second.
//
LIBBUILD2_SYMEXPORT pair<scope&, scope*>
- switch_scope (scope& root, const dir_path&);
+ switch_scope (scope& root, const dir_path&, bool project = true);
// Bootstrap and optionally load an ad hoc (sub)project (i.e., the kind that
// is not discovered and loaded automatically by bootstrap/load functions
diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx
index e3f9605..cd6fe5e 100644
--- a/libbuild2/parser.cxx
+++ b/libbuild2/parser.cxx
@@ -10,7 +10,6 @@
#include <libbutl/path-pattern.mxx>
#include <libbuild2/dump.hxx>
-#include <libbuild2/file.hxx>
#include <libbuild2/scope.hxx>
#include <libbuild2/module.hxx>
#include <libbuild2/target.hxx>
@@ -1435,7 +1434,7 @@ namespace build2
{
tracer trace ("parser::parse_include", &path_);
- if (root_->src_path_ == nullptr)
+ if (stage_ == stage::boot)
fail (t) << "inclusion during bootstrap";
// The rest should be a list of buildfiles. Parse them as names in the
@@ -1933,7 +1932,7 @@ namespace build2
{
tracer trace ("parser::parse_import", &path_);
- if (root_->src_path_ == nullptr)
+ if (stage_ == stage::boot)
fail (t) << "import during bootstrap";
// General import format:
@@ -6090,11 +6089,20 @@ namespace build2
{
tracer trace ("parser::switch_scope", &path_);
- auto p (build2::switch_scope (*root_, d));
+ // Switching the project during bootstrap can result in bizarre nesting
+ // with unexpected loading order (e.g., config.build are loaded from inner
+ // to outter rather than the expected reverse). On the other hand, it can
+ // be handy to assign a variable for a nested scope in config.build. So
+ // for this stage we are going to switch the scope without switching the
+ // project expecting the user to know what they are doing.
+ //
+ bool proj (stage_ != stage::boot);
+
+ auto p (build2::switch_scope (*root_, d, proj));
scope_ = &p.first;
pbase_ = scope_->src_path_ != nullptr ? scope_->src_path_ : &d;
- if (p.second != root_)
+ if (proj && p.second != root_)
{
root_ = p.second;
l5 ([&]
diff --git a/libbuild2/parser.hxx b/libbuild2/parser.hxx
index b21336d..6552114 100644
--- a/libbuild2/parser.hxx
+++ b/libbuild2/parser.hxx
@@ -9,6 +9,7 @@
#include <libbuild2/utility.hxx>
#include <libbuild2/spec.hxx>
+#include <libbuild2/file.hxx>
#include <libbuild2/lexer.hxx>
#include <libbuild2/token.hxx>
#include <libbuild2/variable.hxx>
@@ -21,14 +22,7 @@ namespace build2
class LIBBUILD2_SYMEXPORT parser
{
public:
- // The project's loading stage during which the parsing is performed.
- //
- enum class stage
- {
- boot, // Parsing bootstrap.build (or bootstrap pre/post hooks).
- root, // Parsing root.build (or root pre/post hooks).
- rest // Parsing the rest (ordinary buildfiles, command line, etc).
- };
+ using stage = load_stage;
explicit
parser (context& c, stage s = stage::rest)