aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbuild2/config/functions.cxx52
-rw-r--r--libbuild2/config/init.cxx31
-rw-r--r--libbuild2/config/module.hxx10
-rw-r--r--libbuild2/config/operation.cxx78
-rw-r--r--libbuild2/config/operation.hxx16
-rw-r--r--libbuild2/config/utility.cxx48
-rw-r--r--libbuild2/config/utility.txx3
-rw-r--r--libbuild2/dist/init.cxx3
-rw-r--r--libbuild2/install/init.cxx7
-rw-r--r--libbuild2/scope.hxx8
-rw-r--r--libbuild2/test/init.cxx3
11 files changed, 174 insertions, 85 deletions
diff --git a/libbuild2/config/functions.cxx b/libbuild2/config/functions.cxx
new file mode 100644
index 0000000..79447a4
--- /dev/null
+++ b/libbuild2/config/functions.cxx
@@ -0,0 +1,52 @@
+// file : libbuild2/config/functions.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <sstream>
+
+#include <libbuild2/scope.hxx>
+#include <libbuild2/function.hxx>
+#include <libbuild2/variable.hxx>
+
+#include <libbuild2/config/operation.hxx>
+
+using namespace std;
+
+namespace build2
+{
+ namespace config
+ {
+ void
+ functions (function_map& m)
+ {
+ function_family f (m, "config");
+
+ // Return the configuration file contents as a string, similar to the
+ // config.export variable functionality.
+ //
+ // Note that this function can only be used during configure unless the
+ // config module creation was forced for other meta-operations with
+ // config.module=true in bootstrap.build.
+ //
+ f[".export"] = [] (const scope* s)
+ {
+ if (s == nullptr)
+ fail << "config.export() called out of scope" << endf;
+
+ s = s->root_scope ();
+
+ if (s == nullptr)
+ fail << "config.export() called out of project" << endf;
+
+ ostringstream os;
+
+ // Empty project set should is ok as long as inherit is false.
+ //
+ project_set ps;
+ save_config (*s, os, "config.export()", false /* inherit */, ps);
+
+ return os.str ();
+ };
+ }
+ }
+}
diff --git a/libbuild2/config/init.cxx b/libbuild2/config/init.cxx
index 4e1890a..cda34fa 100644
--- a/libbuild2/config/init.cxx
+++ b/libbuild2/config/init.cxx
@@ -9,6 +9,7 @@
#include <libbuild2/lexer.hxx>
#include <libbuild2/scope.hxx>
#include <libbuild2/context.hxx>
+#include <libbuild2/function.hxx>
#include <libbuild2/filesystem.hxx> // exists()
#include <libbuild2/diagnostics.hxx>
@@ -23,15 +24,19 @@ namespace build2
{
namespace config
{
+ void
+ functions (function_map&); // functions.cxx
+
bool
boot (scope& rs, const location&, unique_ptr<module_base>& mod)
{
tracer trace ("config::boot");
+ context& ctx (rs.ctx);
+
l5 ([&]{trace << "for " << rs;});
- const string& mname (rs.ctx.current_mname);
- const string& oname (rs.ctx.current_oname);
+ auto& vp (rs.ctx.var_pool.rw (rs));
// While config.import (see below) could theoretically be specified in a
// buildfile, config.export is expected to always be specified as a
@@ -46,8 +51,17 @@ namespace build2
// forced with config.module (useful if we need to call $config.export()
// during other meta-operations).
//
- if (( mname == "configure" || mname == "create") ||
- (mname.empty () && (oname == "configure" || oname == "create")))
+ // Detecting the former (configuring/creating) is a bit tricky since the
+ // build2 core may not yet know if this is the case. But we know.
+ //
+ auto& c_m (vp.insert<bool> ("config.module", false /*ovr*/));
+
+ const string& mname (ctx.current_mname);
+ const string& oname (ctx.current_oname);
+
+ if (( mname == "configure" || mname == "create") ||
+ (mname.empty () && (oname == "configure" || oname == "create")) ||
+ cast_false<bool> (rs.vars[c_m]))
{
unique_ptr<module> m (new module);
@@ -59,6 +73,12 @@ namespace build2
mod = move (m);
}
+ // Register the config function family if this is the first instance of
+ // the config module.
+ //
+ if (!function_family::defined (ctx.functions, "config"))
+ functions (ctx.functions);
+
// Register meta-operations. Note that we don't register create_id
// since it will be pre-processed into configure.
//
@@ -85,8 +105,7 @@ namespace build2
return true;
}
- const dir_path& out_root (rs.out_path ());
- l5 ([&]{trace << "for " << out_root;});
+ l5 ([&]{trace << "for " << rs;});
assert (config_hints.empty ()); // We don't known any hints.
diff --git a/libbuild2/config/module.hxx b/libbuild2/config/module.hxx
index 6222319..4b9d4f2 100644
--- a/libbuild2/config/module.hxx
+++ b/libbuild2/config/module.hxx
@@ -19,11 +19,11 @@ namespace build2
{
namespace config
{
- // An ordered list of modules each with an ordered list of list of
- // config.* variables and their "save flags" (see save_variable()) that
- // are used (as opposed to just being specified) in this configuration.
- // Populated by the config utility functions (required(), optional())
- // and saved in the order populated.
+ // An ordered list of build system modules each with an ordered list of
+ // list of config.* variables and their "save flags" (see save_variable())
+ // that are used (as opposed to just being specified) in this
+ // configuration. Populated by the config utility functions (required(),
+ // optional()) and saved in the order populated.
//
struct saved_variable
{
diff --git a/libbuild2/config/operation.cxx b/libbuild2/config/operation.cxx
index 9050645..c9b5ef6 100644
--- a/libbuild2/config/operation.cxx
+++ b/libbuild2/config/operation.cxx
@@ -4,8 +4,6 @@
#include <libbuild2/config/operation.hxx>
-#include <set>
-
#include <libbuild2/file.hxx>
#include <libbuild2/spec.hxx>
#include <libbuild2/scope.hxx>
@@ -90,26 +88,23 @@ namespace build2
// If inherit is false, then don't rely on inheritance from outer scopes
// (used for config.export).
//
- static void
+ void
save_config (const scope& rs,
- const path& f,
+ ostream& os,
+ const string& name,
bool inherit,
const project_set& projects)
{
context& ctx (rs.ctx);
- const module& mod (*rs.lookup_module<const module> (module::name));
+ const module* mod (rs.lookup_module<const module> (module::name));
- const string& df (f.string () != "-" ? f.string () : "<stdout>");
-
- if (verb)
- text << (verb >= 2 ? "cat >" : "save ") << df;
+ if (mod == nullptr)
+ fail << "no configuration information available during this meta-"
+ << "operation";
try
{
- ofdstream ofs;
- ostream& os (open_file_or_stdout (f, ofs));
-
os << "# Created automatically by the config module, but feel " <<
"free to edit." << endl
<< "#" << endl;
@@ -132,7 +127,7 @@ namespace build2
//
names storage;
- for (auto p: mod.saved_modules.order)
+ for (auto p: mod->saved_modules.order)
{
const string& sname (p.second->first);
const saved_variables& svars (p.second->second);
@@ -170,7 +165,8 @@ namespace build2
// still valid and we should probably continue using them but we
// definitely want to move them to our config.build since they
// will be dropped from the amalgamation's config.build on the
- // next reconfigure. Let's also warn the user just in case.
+ // next reconfigure. Let's also warn the user just in case,
+ // unless there is no module and thus we couldn't really check.
//
// There is also another case that falls under this now that
// overrides are by default amalgamation-wide rather than just
@@ -178,13 +174,13 @@ namespace build2
// subproject but the override is now set on the outer project's
// root.
//
- bool found (false);
+ bool found (false), checked (true);
const scope* r (&rs);
while ((r = r->parent_scope ()->root_scope ()) != nullptr)
{
if (l.belongs (*r))
{
- // Find the config module.
+ // Find the config module (might not be there).
//
if (auto* m = r->lookup_module<const module> (module::name))
{
@@ -215,6 +211,8 @@ namespace build2
found = false;
}
}
+ else
+ checked = false;
break;
}
@@ -229,32 +227,30 @@ namespace build2
}
else
{
- location loc (&f);
-
// If this value is not defined in a project's root scope,
// then something is broken.
//
if (r == nullptr)
- fail (loc) << "inherited variable " << var << " value "
- << "is not from a root scope";
+ fail << name << ": inherited variable " << var << " value "
+ << "is not from a root scope";
// If none of the outer project's configurations use this
- // value, then we warn and save as our own. One special case
- // where we don't want to warn the user is if the variable is
- // overriden.
+ // value, then we warn (unless we couldn't check) and save as
+ // our own. One special case where we don't want to warn the
+ // user is if the variable is overriden.
//
- if (org.first == ovr.first)
+ if (checked && org.first == ovr.first)
{
diag_record dr;
- dr << warn (loc) << "saving previously inherited variable "
- << var;
+ dr << warn << name << ": saving previously inherited "
+ << "variable " << var;
- dr << info (loc) << "because project " << *r
- << " no longer uses it in its configuration";
+ dr << info << "because project " << *r << " no longer uses "
+ << "it in its configuration";
if (verb >= 2)
{
- dr << info (loc) << "variable value: ";
+ dr << info << "variable value: ";
if (*l)
{
@@ -322,12 +318,34 @@ namespace build2
os << n << " = [null]" << endl;
}
}
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to write " << name << ": " << e;
+ }
+ }
+ static void
+ save_config (const scope& rs,
+ const path& f,
+ bool inherit,
+ const project_set& projects)
+ {
+ const string& fs (f.string () != "-" ? f.string () : "<stdout>");
+
+ if (verb)
+ text << (verb >= 2 ? "cat >" : "save ") << fs;
+
+ try
+ {
+ ofdstream ofs;
+ ostream& os ();
+ save_config (rs, open_file_or_stdout (f, ofs), fs, inherit, projects);
ofs.close ();
}
catch (const io_error& e)
{
- fail << "unable to write " << df << ": " << e;
+ fail << "unable to write " << fs << ": " << e;
}
}
diff --git a/libbuild2/config/operation.hxx b/libbuild2/config/operation.hxx
index 8b2a29d..9ec854a 100644
--- a/libbuild2/config/operation.hxx
+++ b/libbuild2/config/operation.hxx
@@ -5,6 +5,8 @@
#ifndef LIBBUILD2_CONFIG_OPERATION_HXX
#define LIBBUILD2_CONFIG_OPERATION_HXX
+#include <set>
+
#include <libbuild2/types.hxx>
#include <libbuild2/utility.hxx>
@@ -23,6 +25,20 @@ namespace build2
vector_view<opspec>&,
bool,
const location&);
+
+ // Configuration exporting.
+ //
+ using project_set = std::set<const scope*>; // Pointers for comparison.
+
+ // If inherit is false, then don't rely on inheritance from outer scopes
+ // (used for config.export). In this case the already configured project
+ // set can be empty.
+ //
+ void
+ save_config (const scope& rs,
+ ostream&, const string& name,
+ bool inherit,
+ const project_set&);
}
}
diff --git a/libbuild2/config/utility.cxx b/libbuild2/config/utility.cxx
index 355e896..8a99a8b 100644
--- a/libbuild2/config/utility.cxx
+++ b/libbuild2/config/utility.cxx
@@ -18,12 +18,12 @@ namespace build2
namespace config
{
pair<lookup, bool>
- omitted (scope& r, const variable& var)
+ omitted (scope& rs, const variable& var)
{
// This is a stripped-down version of the required() twisted
// implementation.
- pair<lookup, size_t> org (r.find_original (var));
+ pair<lookup, size_t> org (rs.find_original (var));
bool n (false); // New flag.
lookup l (org.first);
@@ -35,7 +35,7 @@ namespace build2
if (var.overrides != nullptr)
{
- pair<lookup, size_t> ovr (r.find_override (var, move (org)));
+ pair<lookup, size_t> ovr (rs.find_override (var, move (org)));
if (l != ovr.first) // Overriden?
{
@@ -46,26 +46,25 @@ namespace build2
}
}
- if (l.defined () && r.ctx.current_mif->id == configure_id)
- save_variable (r, var);
+ if (l.defined ())
+ save_variable (rs, var);
return pair<lookup, bool> (l, n);
}
lookup
- optional (scope& r, const variable& var)
+ optional (scope& rs, const variable& var)
{
- if (r.ctx.current_mif->id == configure_id)
- save_variable (r, var);
+ save_variable (rs, var);
- auto l (r[var]);
+ auto l (rs[var]);
return l.defined ()
? l
- : lookup (r.assign (var), var, r); // NULL.
+ : lookup (rs.assign (var), var, rs); // NULL.
}
bool
- specified (scope& r, const string& n)
+ specified (scope& rs, const string& n)
{
// Search all outer scopes for any value in this namespace.
//
@@ -75,8 +74,8 @@ namespace build2
// any original values, they will be "visible"; see find_override() for
// details.
//
- const variable& vns (r.ctx.var_pool.rw (r).insert ("config." + n));
- for (scope* s (&r); s != nullptr; s = s->parent_scope ())
+ const variable& vns (rs.ctx.var_pool.rw (rs).insert ("config." + n));
+ for (scope* s (&rs); s != nullptr; s = s->parent_scope ())
{
for (auto p (s->vars.find_namespace (vns));
p.first != p.second;
@@ -103,8 +102,7 @@ namespace build2
const variable& var (
rs.ctx.var_pool.rw (rs).insert ("config." + n + ".configured"));
- if (rs.ctx.current_mif->id == configure_id)
- save_variable (rs, var);
+ save_variable (rs, var);
auto l (rs[var]); // Include inherited values.
return l && !cast<bool> (l);
@@ -118,8 +116,7 @@ namespace build2
const variable& var (
rs.ctx.var_pool.rw (rs).insert ("config." + n + ".configured"));
- if (rs.ctx.current_mif->id == configure_id)
- save_variable (rs, var);
+ save_variable (rs, var);
value& x (rs.assign (var));
@@ -133,25 +130,16 @@ namespace build2
}
void
- save_variable (scope& r, const variable& var, uint64_t flags)
+ save_variable (scope& rs, const variable& var, uint64_t flags)
{
- if (r.ctx.current_mif->id != configure_id)
- return;
-
- // The project might not be using the config module. But then how
- // could we be configuring it? Good question.
- //
- if (module* m = r.lookup_module<module> (module::name))
+ if (module* m = rs.lookup_module<module> (module::name))
m->save_variable (var, flags);
}
void
- save_module (scope& r, const char* name, int prio)
+ save_module (scope& rs, const char* name, int prio)
{
- if (r.ctx.current_mif->id != configure_id)
- return;
-
- if (module* m = r.lookup_module<module> (module::name))
+ if (module* m = rs.lookup_module<module> (module::name))
m->save_module (name, prio);
}
diff --git a/libbuild2/config/utility.txx b/libbuild2/config/utility.txx
index 4c4e305..8c92f86 100644
--- a/libbuild2/config/utility.txx
+++ b/libbuild2/config/utility.txx
@@ -19,8 +19,7 @@ namespace build2
{
// Note: see also omitted() if changing anything here.
- if (root.ctx.current_mif->id == configure_id)
- save_variable (root, var, save_flags);
+ save_variable (root, var, save_flags);
pair<lookup, size_t> org (root.find_original (var));
diff --git a/libbuild2/dist/init.cxx b/libbuild2/dist/init.cxx
index c6ffb67..bea8917 100644
--- a/libbuild2/dist/init.cxx
+++ b/libbuild2/dist/init.cxx
@@ -99,8 +99,7 @@ namespace build2
return true;
}
- const dir_path& out_root (rs.out_path ());
- l5 ([&]{trace << "for " << out_root;});
+ l5 ([&]{trace << "for " << rs;});
assert (config_hints.empty ()); // We don't known any hints.
diff --git a/libbuild2/install/init.cxx b/libbuild2/install/init.cxx
index 445f2b1..1054e83 100644
--- a/libbuild2/install/init.cxx
+++ b/libbuild2/install/init.cxx
@@ -137,8 +137,8 @@ namespace build2
context& ctx (rs.ctx);
- // Register install function family if this is the first instance of the
- // install modules.
+ // Register the install function family if this is the first instance of
+ // the install modules.
//
if (!function_family::defined (ctx.functions, "install"))
functions (ctx.functions);
@@ -188,8 +188,7 @@ namespace build2
return true;
}
- const dir_path& out_root (rs.out_path ());
- l5 ([&]{trace << "for " << out_root;});
+ l5 ([&]{trace << "for " << rs;});
assert (config_hints.empty ()); // We don't known any hints.
diff --git a/libbuild2/scope.hxx b/libbuild2/scope.hxx
index 2737958..cd8fcb2 100644
--- a/libbuild2/scope.hxx
+++ b/libbuild2/scope.hxx
@@ -51,10 +51,10 @@ namespace build2
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.
+ // 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_;}
diff --git a/libbuild2/test/init.cxx b/libbuild2/test/init.cxx
index 5681b37..af112fb 100644
--- a/libbuild2/test/init.cxx
+++ b/libbuild2/test/init.cxx
@@ -137,8 +137,7 @@ namespace build2
return true;
}
- const dir_path& out_root (rs.out_path ());
- l5 ([&]{trace << "for " << out_root;});
+ l5 ([&]{trace << "for " << rs;});
assert (mod != nullptr);
module& m (static_cast<module&> (*mod));