diff options
Diffstat (limited to 'libbuild2/config/operation.cxx')
-rw-r--r-- | libbuild2/config/operation.cxx | 243 |
1 files changed, 147 insertions, 96 deletions
diff --git a/libbuild2/config/operation.cxx b/libbuild2/config/operation.cxx index d30de4d..c5e8004 100644 --- a/libbuild2/config/operation.cxx +++ b/libbuild2/config/operation.cxx @@ -286,7 +286,18 @@ namespace build2 const string& sname (p.second->first); const saved_variables& svars (p.second->second); - bool first (true); // Separate modules with a blank line. + // Separate modules with a blank line. + // + auto first = [v = true] () mutable + { + if (v) + { + v = false; + return "\n"; + } + return ""; + }; + for (const saved_variable& sv: svars) { if (!sv.flags) // unsaved @@ -306,7 +317,9 @@ namespace build2 // inherited. We might also not have any value at all (see // unconfigured()). // - if (!l.defined () || (l->null && flags & save_null_omitted)) + if (!l.defined () || + (l->null ? flags & save_null_omitted : + l->empty () ? flags & save_empty_omitted : false)) continue; // Handle inherited from outer scope values. @@ -315,90 +328,97 @@ namespace build2 // we save the inherited values regardless of whether they are // used or not. // - if (inherit && !(l.belongs (rs) || l.belongs (ctx.global_scope))) + const value* base (nullptr); + if (inherit) { - // 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 on the - // next reconfigure. Let's also warn the user just in case, - // unless there is no module and thus we couldn't really check - // (the latter could happen when calling $config.save() during - // other meta-operations, though it passes false for inherit). - // - // There is also another case that falls under this now that - // overrides are by default amalgamation-wide rather than just - // "project and subprojects": we may be (re-)configuring a - // subproject but the override is now set on the outer project's - // root. + // Return true if the specified value can be inherited from. // - bool found (false), checked (true); - const scope* r (&rs); - while ((r = r->parent_scope ()->root_scope ()) != nullptr) + auto find_inherited = [&on, &projects, + &info_value, + &sname, &rs, &var] (const lookup& org, + const lookup& ovr) { - if (l.belongs (*r)) + const lookup& l (ovr); + + // 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 on the next reconfigure. Let's + // also warn the user just in case, unless there is no module + // and thus we couldn't really check (the latter could happen + // when calling $config.save() during other meta-operations, + // though it passes false for inherit). + // + // There is also another case that falls under this now that + // overrides are by default amalgamation-wide rather than just + // "project and subprojects": we may be (re-)configuring a + // subproject but the override is now set on the outer + // project's root. + // + bool found (false), checked (true); + const scope* r (&rs); + while ((r = r->parent_scope ()->root_scope ()) != nullptr) { - // Find the config module (might not be there). - // - if (auto* m = r->find_module<const module> (module::name)) + if (l.belongs (*r)) { - // Find the corresponding saved module. + // Find the config module (might not be there). // - auto i (m->saved_modules.find (sname)); - - if (i != m->saved_modules.end ()) + if (auto* m = r->find_module<const module> (module::name)) { - // Find the variable. + // Find the corresponding saved module. // - const saved_variables& sv (i->second); - found = sv.find (var) != sv.end (); + auto i (m->saved_modules.find (sname)); - // If not marked as saved, check whether overriden via - // config.config.persist. - // - if (!found && m->persist != nullptr) + if (i != m->saved_modules.end ()) { - found = save_config_variable ( - var, - m->persist, - false /* inherited */, - true /* unused */).first; + // Find the variable. + // + const saved_variables& sv (i->second); + found = sv.find (var) != sv.end (); + + // If not marked as saved, check whether overriden via + // config.config.persist. + // + if (!found && m->persist != nullptr) + { + found = save_config_variable ( + var, + m->persist, + false /* inherited */, + true /* unused */).first; + } + + // Handle that other case: if this is an override but + // the outer project itself is not being configured, + // then we need to save this override. + // + // One problem with using the already configured + // project set is that the outer project may be + // configured only after us in which case both + // projects will save the value. But perhaps this is a + // feature, not a bug since this is how project-local + // (%) override behaves. + // + if (found && + org != ovr && + projects.find (r) == projects.end ()) + found = false; } - - // Handle that other case: if this is an override but - // the outer project itself is not being configured, - // then we need to save this override. - // - // One problem with using the already configured project - // set is that the outer project may be configured only - // after us in which case both projects will save the - // value. But perhaps this is a feature, not a bug since - // this is how project-local (%) override behaves. - // - if (found && - org.first != ovr.first && - projects.find (r) == projects.end ()) - found = false; } - } - else - checked = false; + else + checked = false; - break; + break; + } } - } - if (found) - { - // Inherited. - // - continue; - } - else - { + if (found) + return true; + // If this value is not defined in a project's root scope, // then something is broken. // @@ -411,7 +431,7 @@ namespace build2 // our own. One special case where we don't want to warn the // user is if the variable is overriden. // - if (checked && org.first == ovr.first) + if (checked && org == ovr) { diag_record dr; dr << warn (on) << "saving previously inherited variable " @@ -423,6 +443,39 @@ namespace build2 if (verb >= 2) info_value (dr, *l); } + + return false; + }; + + // Inherit as-is. + // + if (!l.belongs (rs) && + !l.belongs (ctx.global_scope) && + find_inherited (org.first, ovr.first)) + continue; + else if (flags & save_base) + { + // See if we can base our value on inherited. + // + if (const scope* ors = rs.parent_scope ()->root_scope ()) + { + pair<lookup, size_t> org (ors->lookup_original (var)); + pair<lookup, size_t> ovr (var.overrides == nullptr + ? org + : ors->lookup_override (var, org)); + const lookup& l (ovr.first); + + // We cannot base anything on an empty value. + // + if (l && !l->empty ()) + { + // @@ It's not clear we want the checks/diagnostics in + // this case. + // + if (find_inherited (org.first, ovr.first)) + base = l.value; + } + } } } @@ -440,44 +493,42 @@ namespace build2 continue; } - // If we got here then we are saving this variable. Handle the - // blank line. - // - if (first) - { - os << endl; - first = false; - } - // Handle the save_default_commented flag. // if ((org.first.defined () && org.first->extra) && // Default value. org.first == ovr.first && // Not overriden. (flags & save_default_commented) != 0) { - os << '#' << n << " =" << endl; + os << first () << '#' << n << " =" << endl; continue; } - if (v) + if (v.null) { - storage.clear (); - names_view ns (reverse (v, storage)); + os << first () << n << " = [null]" << endl; + continue; + } - os << n; + storage.clear (); + pair<names_view, const char*> p ( + sv.save != nullptr + ? sv.save (v, base, storage) + : make_pair (reverse (v, storage), "=")); - if (ns.empty ()) - os << " ="; - else - { - os << " = "; - to_stream (os, ns, true /* quote */, '@'); - } + // Might becomes empty after a custom save function had at it. + // + if (p.first.empty () && (flags & save_empty_omitted)) + continue; - os << endl; + os << first () << n << ' ' << p.second; + + if (!p.first.empty ()) + { + os << ' '; + to_stream (os, p.first, true /* quote */, '@'); } - else - os << n << " = [null]" << endl; + + os << endl; } } } |