diff options
-rw-r--r-- | libbuild2/config/functions.cxx | 52 | ||||
-rw-r--r-- | libbuild2/config/init.cxx | 31 | ||||
-rw-r--r-- | libbuild2/config/module.hxx | 10 | ||||
-rw-r--r-- | libbuild2/config/operation.cxx | 78 | ||||
-rw-r--r-- | libbuild2/config/operation.hxx | 16 | ||||
-rw-r--r-- | libbuild2/config/utility.cxx | 48 | ||||
-rw-r--r-- | libbuild2/config/utility.txx | 3 | ||||
-rw-r--r-- | libbuild2/dist/init.cxx | 3 | ||||
-rw-r--r-- | libbuild2/install/init.cxx | 7 | ||||
-rw-r--r-- | libbuild2/scope.hxx | 8 | ||||
-rw-r--r-- | libbuild2/test/init.cxx | 3 |
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)); |