aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2020-09-22 11:28:53 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2020-09-22 11:28:53 +0200
commitd06e8d1d3b0594c74fa444da76c3c7925ed58f70 (patch)
treea2c6d46e285b8109adc53a7ee2562cd26126a399
parent9f72ad00a0654bc965ff527615e02fd35596073c (diff)
Add ability to skip external modules during bootstrap (--no-external-modules)
-rw-r--r--build2/b-options.cxx15
-rw-r--r--build2/b-options.hxx4
-rw-r--r--build2/b-options.ixx6
-rw-r--r--build2/b.cli7
-rw-r--r--build2/b.cxx1
-rw-r--r--libbuild2/context.cxx2
-rw-r--r--libbuild2/context.hxx5
-rw-r--r--libbuild2/file.cxx8
-rw-r--r--libbuild2/module.cxx94
9 files changed, 108 insertions, 34 deletions
diff --git a/build2/b-options.cxx b/build2/b-options.cxx
index 95772bb..316d7ad 100644
--- a/build2/b-options.cxx
+++ b/build2/b-options.cxx
@@ -698,6 +698,7 @@ namespace build2
serial_stop_ (),
dry_run_ (),
match_only_ (),
+ no_external_modules_ (),
structured_result_ (),
mtime_check_ (),
no_mtime_check_ (),
@@ -898,6 +899,12 @@ namespace build2
this->match_only_, a.match_only_);
}
+ if (a.no_external_modules_)
+ {
+ ::build2::cl::parser< bool>::merge (
+ this->no_external_modules_, a.no_external_modules_);
+ }
+
if (a.structured_result_)
{
::build2::cl::parser< bool>::merge (
@@ -1110,6 +1117,12 @@ namespace build2
<< " mode is primarily useful for profiling." << ::std::endl;
os << std::endl
+ << "\033[1m--no-external-modules\033[0m Don't load external modules during project bootstrap." << ::std::endl
+ << " Note that this option can only be used with" << ::std::endl
+ << " meta-operations that do not load the project's" << ::std::endl
+ << " \033[1mbuildfiles\033[0m, such as \033[1minfo\033[0m." << ::std::endl;
+
+ os << std::endl
<< "\033[1m--structured-result\033[0m Write the result of execution in a structured form. In" << ::std::endl
<< " this mode, instead of printing to \033[1mSTDERR\033[0m diagnostics" << ::std::endl
<< " messages about the outcome of executing actions on" << ::std::endl
@@ -1267,6 +1280,8 @@ namespace build2
&::build2::cl::thunk< options, bool, &options::dry_run_ >;
_cli_options_map_["--match-only"] =
&::build2::cl::thunk< options, bool, &options::match_only_ >;
+ _cli_options_map_["--no-external-modules"] =
+ &::build2::cl::thunk< options, bool, &options::no_external_modules_ >;
_cli_options_map_["--structured-result"] =
&::build2::cl::thunk< options, bool, &options::structured_result_ >;
_cli_options_map_["--mtime-check"] =
diff --git a/build2/b-options.hxx b/build2/b-options.hxx
index c6f1f59..d55dd36 100644
--- a/build2/b-options.hxx
+++ b/build2/b-options.hxx
@@ -526,6 +526,9 @@ namespace build2
match_only () const;
const bool&
+ no_external_modules () const;
+
+ const bool&
structured_result () const;
const bool&
@@ -628,6 +631,7 @@ namespace build2
bool serial_stop_;
bool dry_run_;
bool match_only_;
+ bool no_external_modules_;
bool structured_result_;
bool mtime_check_;
bool no_mtime_check_;
diff --git a/build2/b-options.ixx b/build2/b-options.ixx
index 6444aa9..1d41af2 100644
--- a/build2/b-options.ixx
+++ b/build2/b-options.ixx
@@ -405,6 +405,12 @@ namespace build2
}
inline const bool& options::
+ no_external_modules () const
+ {
+ return this->no_external_modules_;
+ }
+
+ inline const bool& options::
structured_result () const
{
return this->structured_result_;
diff --git a/build2/b.cli b/build2/b.cli
index 57640b6..a03e9cc 100644
--- a/build2/b.cli
+++ b/build2/b.cli
@@ -535,6 +535,13 @@ namespace build2
useful for profiling."
}
+ bool --no-external-modules
+ {
+ "Don't load external modules during project bootstrap. Note that this
+ option can only be used with meta-operations that do not load the
+ project's \cb{buildfiles}, such as \cb{info}."
+ }
+
bool --structured-result
{
"Write the result of execution in a structured form. In this mode,
diff --git a/build2/b.cxx b/build2/b.cxx
index b7e6708..18326cc 100644
--- a/build2/b.cxx
+++ b/build2/b.cxx
@@ -785,6 +785,7 @@ main (int argc, char* argv[])
ctx.reset (new context (sched,
mutexes,
ops.match_only (),
+ ops.no_external_modules (),
ops.dry_run (),
!ops.serial_stop () /* keep_going */,
cmd_vars));
diff --git a/libbuild2/context.cxx b/libbuild2/context.cxx
index d62965c..b78cd27 100644
--- a/libbuild2/context.cxx
+++ b/libbuild2/context.cxx
@@ -59,6 +59,7 @@ namespace build2
context (scheduler& s,
global_mutexes& ms,
bool mo,
+ bool nem,
bool dr,
bool kg,
const strings& cmd_vars,
@@ -68,6 +69,7 @@ namespace build2
sched (s),
mutexes (ms),
match_only (mo),
+ no_external_modules (nem),
dry_run_option (dr),
keep_going (kg),
phase_mutex (*this),
diff --git a/libbuild2/context.hxx b/libbuild2/context.hxx
index c4e1259..0790355 100644
--- a/libbuild2/context.hxx
+++ b/libbuild2/context.hxx
@@ -146,6 +146,10 @@ namespace build2
//
bool match_only;
+ // Skip booting external modules flag (see --no-external-modules).
+ //
+ bool no_external_modules;
+
// Dry run flag (see --dry-run|-n).
//
// This flag is set (based on dry_run_option) only for the final execute
@@ -479,6 +483,7 @@ namespace build2
context (scheduler&,
global_mutexes&,
bool match_only = false,
+ bool no_external_modules = false,
bool dry_run = false,
bool keep_going = true,
const strings& cmd_vars = {},
diff --git a/libbuild2/file.cxx b/libbuild2/file.cxx
index 2660b9e..67aeb77 100644
--- a/libbuild2/file.cxx
+++ b/libbuild2/file.cxx
@@ -1431,6 +1431,8 @@ namespace build2
{
tracer trace ("load_root");
+ context& ctx (root.ctx);
+
const dir_path& out_root (root.out_path ());
const dir_path& src_root (root.src_path ());
@@ -1442,6 +1444,10 @@ namespace build2
if (root.buildfiles.find (f) != root.buildfiles.end ())
return;
+ if (ctx.no_external_modules)
+ fail << "attempt to load project " << root << " after skipped loading "
+ << "external modules";
+
// First load outer roots, if any.
//
if (scope* rs = root.parent_scope ()->root_scope ())
@@ -1483,7 +1489,7 @@ namespace build2
// Reuse the parser to accumulate the configuration variable information.
//
- parser p (root.ctx, load_stage::root);
+ parser p (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/module.cxx b/libbuild2/module.cxx
index 11b32cb..14cf183 100644
--- a/libbuild2/module.cxx
+++ b/libbuild2/module.cxx
@@ -81,6 +81,7 @@ namespace build2
new context (ctx.sched,
ctx.mutexes,
false, /* match_only */
+ false, /* no_external_modules */
false, /* dry_run */
ctx.keep_going,
ctx.global_var_overrides, /* cmd_vars */
@@ -238,7 +239,11 @@ namespace build2
#endif
const string& mod,
const location& loc,
- bool /* boot */,
+#if defined(BUILD2_BOOTSTRAP) || defined(LIBBUILD2_STATIC_BUILD)
+ bool,
+#else
+ bool boot,
+#endif
bool opt)
{
tracer trace ("import_module");
@@ -251,6 +256,26 @@ namespace build2
else if (mod == "install") return &install::build2_install_load;
else if (mod == "test") return &test::build2_test_load;
+ module_load_function* r (nullptr);
+
+ // No dynamic loading of build system modules during bootstrap or if
+ // statically-linked..
+ //
+#if defined(BUILD2_BOOTSTRAP) || defined(LIBBUILD2_STATIC_BUILD)
+ if (!opt)
+ {
+ fail (loc) << "unknown build system module " << mod <<
+#ifdef BUILD2_BOOTSTRAP
+ info << "running bootstrap build system";
+#else
+ info << "running statically-linked build system";
+#endif
+ }
+#else
+ context& ctx (bs.ctx);
+
+ bool bundled (bundled_module (mod));
+
// Note that importing external modules during bootstrap is problematic
// since we haven't loaded config.build nor entered non-global variable
// overrides. We used to just not support external modules that require
@@ -287,28 +312,20 @@ namespace build2
// And another case is the bdep-sync hook which also doesn't have the
// global overrides propagated to it.
//
- // It does feel right to propagate global overrides to all the nested
- // build system invocations. Maybe we should set an environment variable?
-
- module_load_function* r (nullptr);
-
- // No dynamic loading of build system modules during bootstrap or if
- // statically-linked..
- //
-#if defined(BUILD2_BOOTSTRAP) || defined(LIBBUILD2_STATIC_BUILD)
- if (!opt)
- {
- fail (loc) << "unknown build system module " << mod <<
-#ifdef BUILD2_BOOTSTRAP
- info << "running bootstrap build system";
-#else
- info << "running statically-linked build system";
-#endif
- }
-#else
- context& ctx (bs.ctx);
-
- bool bundled (bundled_module (mod));
+ // And it turns out the story does not end here: without an external
+ // module we cannot do info or dist. So to support this we now allow
+ // skipping of loading of external modules (for dist this is only part of
+ // the solution with the other part being the bootstrap mode). While no
+ // doubt a hack, it feels like this is the time to cut of this complexity
+ // escalation. Essentially, we are saying external module that require
+ // bootstrap must be prepared to be skipped if the project is only being
+ // bootstrapped. Note also that the fact that a module boot was skipped
+ // can be detected by checking the module's *.booted variable. In case of
+ // a skip it will be false, as opposed to true if the module was booted
+ // and undefined if the module was not mentioned.
+ //
+ if (boot && !bundled && ctx.no_external_modules)
+ return nullptr;
// See if we can import a target for this module.
//
@@ -570,7 +587,14 @@ namespace build2
<< mmod;
}
else
+ {
+ // Reduce skipped external module to optional.
+ //
+ if (boot)
+ opt = true;
+
i = loaded_modules.emplace (move (mmod), nullptr).first;
+ }
}
}
@@ -616,23 +640,27 @@ namespace build2
// Otherwise search for this module.
//
- const module_functions& mf (
- *find_module (rs, mod, loc, true /* boot */, false /* optional */));
+ // Note that find_module() may return NULL in case of a skipped external
+ // module.
+ //
+ const module_functions* mf (
+ find_module (rs, mod, loc, true /* boot */, false /* optional */));
- if (mf.boot == nullptr)
- fail (loc) << "build system module " << mod << " should not be loaded "
- << "during bootstrap";
+ if (mf != nullptr)
+ {
+ if (mf->boot == nullptr)
+ fail (loc) << "build system module " << mod << " should not be loaded "
+ << "during bootstrap";
- lm.push_back (module_state {loc, mod, mf.init, nullptr, nullopt});
- i = lm.end () - 1;
+ lm.push_back (module_state {loc, mod, mf->init, nullptr, nullopt});
+ i = lm.end () - 1;
- {
module_boot_extra e {nullptr, module_boot_init::before};
// Note: boot() can load additional modules invalidating the iterator.
//
size_t j (i - lm.begin ());
- mf.boot (rs, loc, e);
+ mf->boot (rs, loc, e);
i = lm.begin () + j;
if (e.module != nullptr)
@@ -641,7 +669,7 @@ namespace build2
i->boot_init = e.init;
}
- rs.assign (rs.var_pool ().insert (mod + ".booted")) = true;
+ rs.assign (rs.var_pool ().insert (mod + ".booted")) = (mf != nullptr);
}
module_state*