From 0342dc2fcdd78ef28a4e59d84193a3807068d726 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 11 Apr 2016 07:57:19 +0200 Subject: New configuration logic, iteration 1 --- build2/config/operation.cxx | 88 ++++++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 37 deletions(-) (limited to 'build2/config/operation.cxx') diff --git a/build2/config/operation.cxx b/build2/config/operation.cxx index e75f8d0..d1a01ea 100644 --- a/build2/config/operation.cxx +++ b/build2/config/operation.cxx @@ -15,6 +15,8 @@ #include #include +#include + using namespace std; using namespace butl; @@ -51,8 +53,6 @@ namespace build2 ofs.exceptions (ofstream::failbit | ofstream::badbit); - //@@ TODO: quote path - // ofs << "# Created automatically by the config module." << endl << "#" << endl << "src_root = " << src_root << endl; @@ -72,6 +72,8 @@ namespace build2 if (verb) text << (verb >= 2 ? "config::save " : "save ") << f; + const module& mod (*root.modules.lookup (module::name)); + try { ofstream ofs (f.string ()); @@ -80,8 +82,8 @@ namespace build2 ofs.exceptions (ofstream::failbit | ofstream::badbit); - ofs << "# Created automatically by the config module, but" << endl - << "# feel free to edit." << endl + ofs << "# Created automatically by the config module, but feel " << + "free to edit." << endl << "#" << endl; if (auto l = root.vars["amalgamation"]) @@ -92,28 +94,33 @@ namespace build2 << "#" << endl; } - // Save all the variables in the config namespace that are set - // on the project's root scope. + // Save config variables. // names storage; - for (auto p (root.vars.find_namespace ("config")); - p.first != p.second; - ++p.first) + for (const auto& p: mod.vars) { - const variable& var (p.first->first); - const value& val (p.first->second); - const string& n (var.name); + const variable& var (p.first); - // Skip special variables. + lookup l (root[var]); + + // We only write values that are set on our root scope or are global + // overrides. Anything in-between is inherited. We might also not + // have any value at all (see unconfigured()). // - if (n == "config.loaded" || - n == "config.configured") + if (!l.defined () || + !(l.belongs (root) || l.belongs (*global_scope))) continue; - // We will only write config.*.configured if it is false - // (true is implied by its absence). + const value& val (*l); + + // We will only write config.*.configured if it is false (true is + // implied by its absence). + // + // @@ Do we still need this? // + const string& n (var.name); + if (n.size () > 11 && n.compare (n.size () - 11, 11, ".configured") == 0) { @@ -121,24 +128,13 @@ namespace build2 continue; } - // Warn the user if the value that we are saving differs - // from the one they specified on the command line. - // - auto l ((*global_scope)[var]); - if (l.defined () && *l != val) - { - warn << "variable " << var.name << " configured value " - << "differs from command line value" << - info << "reconfigure the project to use command line value"; - } - if (val) { storage.clear (); ofs << var.name << " = " << reverse (val, storage) << endl; } else - ofs << var.name << " = #[null]" << endl; // @@ TODO: [null] + ofs << var.name << " = [null]" << endl; } } catch (const ofstream::failure&) @@ -148,13 +144,19 @@ namespace build2 } static void - configure_project (action a, scope& root) + configure_project (action a, scope& root, set& projects) { tracer trace ("configure_project"); const dir_path& out_root (root.out_path ()); const dir_path& src_root (root.src_path ()); + if (!projects.insert (&root).second) + { + l5 ([&]{trace << "skipping already configured " << out_root;}); + return; + } + // Make sure the directories exist. // if (out_root != src_root) @@ -200,7 +202,7 @@ namespace build2 if (nroot.out_path () != out_nroot) // This subproject not loaded. continue; - configure_project (a, nroot); + configure_project (a, nroot, projects); } } } @@ -219,6 +221,8 @@ namespace build2 // callbacks here since the meta operation is configure and we // know what we are doing. // + set projects; + for (void* v: ts) { target& t (*static_cast (v)); @@ -243,11 +247,12 @@ namespace build2 match (action (configure_id, id), t); } - configure_project (a, *rs); + configure_project (a, *rs, projects); } } meta_operation_info configure { + configure_id, "configure", "configure", "configuring", @@ -299,15 +304,21 @@ namespace build2 disfigure_match (action, action_targets&) {} static bool - disfigure_project (action a, scope& root) + disfigure_project (action a, scope& root, set& projects) { tracer trace ("disfigure_project"); - bool m (false); // Keep track of whether we actually did anything. - const dir_path& out_root (root.out_path ()); const dir_path& src_root (root.src_path ()); + if (!projects.insert (&root).second) + { + l5 ([&]{trace << "skipping already disfigured " << out_root;}); + return true; + } + + bool m (false); // Keep track of whether we actually did anything. + // Disfigure subprojects. Since we don't load buildfiles during // disfigure, we do it for all known subprojects. // @@ -338,7 +349,7 @@ namespace build2 bootstrap_src (nroot); } - m = disfigure_project (a, nroot) || m; + m = disfigure_project (a, nroot, projects) || m; // We use mkdir_p() to create the out_root of a subproject // which means there could be empty parent directories left @@ -408,11 +419,13 @@ namespace build2 { tracer trace ("disfigure_execute"); + set projects; + for (void* v: ts) { scope& root (*static_cast (v)); - if (!disfigure_project (a, root)) + if (!disfigure_project (a, root, projects)) { // Create a dir{$out_root/} target to signify the project's // root in diagnostics. Not very clean but seems harmless. @@ -428,6 +441,7 @@ namespace build2 } meta_operation_info disfigure { + disfigure_id, "disfigure", "disfigure", "disfiguring", -- cgit v1.1