aboutsummaryrefslogtreecommitdiff
path: root/build2/config
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-07-21 15:39:52 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-07-21 15:39:52 +0200
commitc1d08dbc56d0c8d3346deaba5d6b1946b6d711f4 (patch)
treede85880067c80e56d83de8e3902d95f2c2f9d7c5 /build2/config
parent01fe759b58fbde7f8c7391122421dd08c754dc51 (diff)
Save config vars in order specified rather than alphabetically
This way we can group them semantically which results in easier to understand config.build output.
Diffstat (limited to 'build2/config')
-rw-r--r--build2/config/module38
-rw-r--r--build2/config/operation.cxx270
-rw-r--r--build2/config/utility.cxx59
3 files changed, 199 insertions, 168 deletions
diff --git a/build2/config/module b/build2/config/module
index aed85a5..5becfd4 100644
--- a/build2/config/module
+++ b/build2/config/module
@@ -17,15 +17,39 @@ namespace build2
{
namespace config
{
- struct module: module_base
+ // 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.
+ //
+ struct saved_variable
+ {
+ reference_wrapper<const variable> var;
+ uint64_t flags;
+ };
+
+ using saved_variables = vector<saved_variable>;
+
+ struct saved_modules: butl::prefix_map<string, saved_variables, '.'>
{
- // A sorted 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())
- //
- butl::prefix_map<variable_cref, uint64_t, '.'> vars;
+ vector<const_iterator> sequence;
+
+ iterator
+ insert (string name)
+ {
+ auto p (emplace (move (name), saved_variables ()));
+ if (p.second)
+ sequence.push_back (p.first);
+
+ return p.first;
+ }
+ };
+
+ struct module: module_base
+ {
+ config::saved_modules saved_modules;
static const string name;
};
diff --git a/build2/config/operation.cxx b/build2/config/operation.cxx
index 767ca1a..1b40832 100644
--- a/build2/config/operation.cxx
+++ b/build2/config/operation.cxx
@@ -87,192 +87,166 @@ namespace build2
ofs << "# Created automatically by the config module, but feel " <<
"free to edit." << endl
- << "#" << endl
- << endl;
+ << "#" << endl;
if (auto l = root.vars["amalgamation"])
{
const dir_path& d (cast<dir_path> (l));
- ofs << "# Base configuration inherited from " << d << endl
- << "#" << endl
- << endl;
+ ofs << endl
+ << "# Base configuration inherited from " << d << endl
+ << "#" << endl;
}
- // Separate variables for modules with blank lines.
- //
- const string* mod_s (nullptr);
- size_t mod_n (0);
-
- auto next_module = [&mod_s, &mod_n] (const variable& var) -> bool
- {
- const string& s (var.name);
-
- size_t p (s.find ('.', 7)); // 7 for "config."
- size_t n (p != string::npos ? p - 7 : s.size () - 7);
-
- if (mod_s == nullptr)
- {
- mod_s = &s;
- mod_n = n;
- return false; // First
- }
-
- if (s.compare (7, n, *mod_s, 7, mod_n) != 0)
- {
- mod_s = &s;
- mod_n = n;
- return true; // Next.
- }
-
- return false;
- };
-
// Save config variables.
//
names storage;
- for (auto b (mod.vars.begin ()), i (b), e (mod.vars.end ());
- i != e;
- ++i)
+ for (const saved_modules::const_iterator& i:
+ mod.saved_modules.sequence)
{
- const auto& p (*i);
- const variable& var (p.first);
- uint64_t sflags (p.second);
-
- pair<lookup, size_t> org (root.find_original (var));
- pair<lookup, size_t> ovr (var.override == nullptr
- ? org
- : root.find_override (var, org));
- const lookup& l (ovr.first);
-
- // We definitely write values that are set on our root scope or are
- // global overrides. Anything in-between is presumably inherited.
- // We might also not have any value at all (see unconfigured()).
+ const string& sname (i->first);
+ const saved_variables& svars (i->second);
+
+ // Separate modules with a blank line.
//
- if (!l.defined ())
- continue;
+ ofs << endl;
- if (!(l.belongs (root) || l.belongs (*global_scope)))
+ for (const saved_variable& sv: svars)
{
- // This is presumably an inherited value. But it could also be
- // some left-over garbage. For example, our amalgamation could
- // have used a module but then dropped it while its configuration
- // values are still lingering in config.build. They are probably
- // 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. Let's
- // also warn the user just in case.
+ const variable& var (sv.var);
+
+ pair<lookup, size_t> org (root.find_original (var));
+ pair<lookup, size_t> ovr (var.override == nullptr
+ ? org
+ : root.find_override (var, org));
+ const lookup& l (ovr.first);
+
+ // We definitely write values that are set on our root scope or
+ // are global overrides. Anything in-between is presumably
+ // inherited. We might also not have any value at all (see
+ // unconfigured()).
//
- bool found (false);
- scope* r (&root);
- while ((r = r->parent_scope ()->root_scope ()) != nullptr)
+ if (!l.defined ())
+ continue;
+
+ if (!(l.belongs (root) || l.belongs (*global_scope)))
{
- if (l.belongs (*r))
+ // This is presumably an inherited value. But it could also be
+ // some left-over garbage. For example, an amalgamation could
+ // have used a module but then dropped it while its config
+ // values are still lingering in config.build. They are probably
+ // 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. Let's
+ // also warn the user just in case.
+ //
+ bool found (false);
+ scope* r (&root);
+ while ((r = r->parent_scope ()->root_scope ()) != nullptr)
{
- if (auto* m = r->modules.lookup<const module> (module::name))
- found = m->vars.find (var) != m->vars.end ();
-
- break;
+ if (l.belongs (*r))
+ {
+ // Find config module.
+ //
+ if (auto* m = r->modules.lookup<const module> (module::name))
+ {
+ // Find the corresponding saved module.
+ //
+ auto i (m->saved_modules.find (sname));
+
+ if (i != m->saved_modules.end ())
+ {
+ // Find the variable. For now we do linear search.
+ //
+ const saved_variables& sv (i->second);
+ found = find_if (
+ sv.begin (),
+ sv.end (),
+ [&var] (const saved_variable& v) {
+ return var == v.var;}) != sv.end ();
+ }
+ }
+
+ break;
+ }
}
- }
-
- if (found) // Inherited.
- continue;
-
- 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.name << " value "
- << "is not from a root scope";
+ if (found) // Inherited.
+ continue;
- // 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.
- //
- if (org.first == ovr.first)
- {
- diag_record dr;
- dr << warn (loc) << "saving previously inherited variable "
- << var.name;
+ location loc (&f);
- dr << info (loc) << "because project " << r->out_path ()
- << " no longer uses it in its configuration";
+ // If this value is not defined in a project's root scope, then
+ // something is broken.
+ //
+ if (r == nullptr)
+ fail (loc) << "inherited variable " << var.name << " value "
+ << "is not from a root scope";
- if (verb >= 2)
+ // 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.
+ //
+ if (org.first == ovr.first)
{
- dr << info (loc) << "variable value: ";
+ diag_record dr;
+ dr << warn (loc) << "saving previously inherited variable "
+ << var.name;
- if (*l)
+ dr << info (loc) << "because project " << r->out_path ()
+ << " no longer uses it in its configuration";
+
+ if (verb >= 2)
{
- names storage;
- dr << "'" << reverse (*l, storage) << "'";
+ dr << info (loc) << "variable value: ";
+
+ if (*l)
+ {
+ storage.clear ();
+ dr << "'" << reverse (*l, storage) << "'";
+ }
+ else
+ dr << "[null]";
}
- else
- dr << "[null]";
}
}
- }
- const string& n (var.name);
- const value& v (*l);
+ const string& n (var.name);
+ const value& v (*l);
- // We will only write config.*.configured if it is false (true is
- // implied by its absence). We will also ignore false values if
- // there is any other value for this module (see unconfigured()).
- //
- if (n.size () > 11 &&
- n.compare (n.size () - 11, 11, ".configured") == 0)
- {
- if (cast<bool> (v))
- continue;
-
- size_t m (n.size () - 11); // Prefix size.
- auto same = [&n, m] (const variable& v)
- {
- return v.name.size () >= m &&
- v.name.compare (0, m, n, 0, m) == 0;
- };
-
- // Check if this is the first value for this module.
+ // We will only write config.*.configured if it is false (true is
+ // implied by its absence). We will also ignore false values if
+ // there is any other value for this module (see unconfigured()).
//
- auto j (i);
- if (j != b && same ((--j)->first))
- continue;
+ if (n.size () > 11 &&
+ n.compare (n.size () - 11, 11, ".configured") == 0)
+ {
+ if (cast<bool> (v) || svars.size () != 1)
+ continue;
+ }
- // Check if this is the last value for this module.
+ // Handle the save_commented flag.
//
- j = i;
- if (++j != e && same (j->first))
+ if ((org.first.defined () && org.first->extra) && // Default value.
+ org.first == ovr.first && // Not overriden.
+ (sv.flags & save_commented) == save_commented)
+ {
+ ofs << '#' << n << " =" << endl;
continue;
- }
-
- if (next_module (var))
- ofs << endl;
-
- // Handle the save_commented flag.
- //
- if ((org.first.defined () && org.first->extra) && // Default value.
- org.first == ovr.first && // Not overriden.
- (sflags & save_commented) == save_commented)
- {
- ofs << '#' << n << " =" << endl;
- continue;
- }
+ }
- if (v)
- {
- storage.clear ();
+ if (v)
+ {
+ storage.clear ();
- ofs << n << " = ";
- to_stream (ofs, reverse (v, storage), true, '@'); // Quote.
- ofs << endl;
+ ofs << n << " = ";
+ to_stream (ofs, reverse (v, storage), true, '@'); // Quote.
+ ofs << endl;
+ }
+ else
+ ofs << n << " = [null]" << endl;
}
- else
- ofs << n << " = [null]" << endl;
}
}
catch (const ofstream::failure&)
diff --git a/build2/config/utility.cxx b/build2/config/utility.cxx
index 768a70d..a24f7b3 100644
--- a/build2/config/utility.cxx
+++ b/build2/config/utility.cxx
@@ -14,19 +14,6 @@ namespace build2
{
namespace config
{
- void
- save_variable (scope& r, const variable& var, uint64_t flags)
- {
- if (current_mif->id == configure_id)
- {
- // The project might not be using the config module. But then how
- // could we be configuring it? Good question.
- //
- if (module* mod = r.modules.lookup<module> (module::name))
- mod->vars.emplace (var, flags);
- }
- }
-
pair<const value*, bool>
required (scope& r, const variable& var)
{
@@ -130,5 +117,51 @@ namespace build2
root.assign (var) = !v;
}
+
+ void
+ save_variable (scope& r, const variable& var, uint64_t flags)
+ {
+ if (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.modules.lookup<module> (module::name))
+ {
+ const string& n (var.name);
+
+ // First try to find the module with the name that is the longest
+ // prefix of this variable name.
+ //
+ saved_modules& sm (m->saved_modules);
+ auto i (sm.end ());
+
+ if (!sm.empty ())
+ {
+ i = sm.upper_bound (n);
+
+ // Get the greatest less than, if any. We might still not be a
+ // suffix. And we still have to check the last element if
+ // upper_bound() returned end().
+ //
+ if (i == sm.begin () || !sm.key_comp ().prefix ((--i)->first, n))
+ i = sm.end ();
+ }
+
+ // If no module matched, then create one based on the variable name.
+ //
+ if (i == sm.end ())
+ {
+ // @@ For now with 'config.' prefix.
+ //
+ i = sm.insert (string (n, 0, n.find ('.', 7)));
+ }
+
+ // We assume each variable is saved/configured once.
+ //
+ i->second.push_back (saved_variable {var, flags});
+ }
+ }
}
}