diff options
Diffstat (limited to 'libbuild2/config/utility.cxx')
-rw-r--r-- | libbuild2/config/utility.cxx | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/libbuild2/config/utility.cxx b/libbuild2/config/utility.cxx new file mode 100644 index 0000000..746639d --- /dev/null +++ b/libbuild2/config/utility.cxx @@ -0,0 +1,307 @@ +// file : libbuild2/config/utility.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include <libbuild2/config/utility.hxx> + +#include <libbuild2/file.hxx> +#include <libbuild2/context.hxx> +#include <libbuild2/filesystem.hxx> +#include <libbuild2/diagnostics.hxx> + +#include <libbuild2/config/module.hxx> + +using namespace std; + +namespace build2 +{ + namespace config + { + pair<lookup, bool> + omitted (scope& r, const variable& var) + { + // This is a stripped-down version of the required() twisted + // implementation. + + pair<lookup, size_t> org (r.find_original (var)); + + bool n (false); // New flag. + lookup l (org.first); + + // Treat an inherited value that was set to default as new. + // + if (l.defined () && l->extra) + n = true; + + if (var.overrides != nullptr) + { + pair<lookup, size_t> ovr (r.find_override (var, move (org))); + + if (l != ovr.first) // Overriden? + { + // Override is always treated as new. + // + n = true; + l = move (ovr.first); + } + } + + if (l.defined () && current_mif->id == configure_id) + save_variable (r, var); + + return pair<lookup, bool> (l, n); + } + + lookup + optional (scope& r, const variable& var) + { + if (current_mif->id == configure_id) + save_variable (r, var); + + auto l (r[var]); + return l.defined () + ? l + : lookup (r.assign (var), var, r); // NULL. + } + + bool + specified (scope& r, const string& n) + { + // Search all outer scopes for any value in this namespace. + // + // What about "pure" overrides, i.e., those without any original values? + // Well, they will also be found since their names have the original + // variable as a prefix. But do they apply? Yes, since we haven't found + // any original values, they will be "visible"; see find_override() for + // details. + // + const variable& vns (var_pool.rw (r).insert ("config." + n)); + for (scope* s (&r); s != nullptr; s = s->parent_scope ()) + { + for (auto p (s->vars.find_namespace (vns)); + p.first != p.second; + ++p.first) + { + const variable& var (p.first->first); + + // Ignore config.*.configured. + // + if (var.name.size () < 11 || + var.name.compare (var.name.size () - 11, 11, ".configured") != 0) + return true; + } + } + + return false; + } + + bool + unconfigured (scope& rs, const string& n) + { + // Pattern-typed in boot() as bool. + // + const variable& var ( + var_pool.rw (rs).insert ("config." + n + ".configured")); + + if (current_mif->id == configure_id) + save_variable (rs, var); + + auto l (rs[var]); // Include inherited values. + return l && !cast<bool> (l); + } + + bool + unconfigured (scope& rs, const string& n, bool v) + { + // Pattern-typed in boot() as bool. + // + const variable& var ( + var_pool.rw (rs).insert ("config." + n + ".configured")); + + if (current_mif->id == configure_id) + save_variable (rs, var); + + value& x (rs.assign (var)); + + if (x.null || cast<bool> (x) != !v) + { + x = !v; + return true; + } + else + return false; + } + + 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.lookup_module<module> (module::name)) + m->save_variable (var, flags); + } + + void + save_module (scope& r, const char* name, int prio) + { + if (current_mif->id != configure_id) + return; + + if (module* m = r.lookup_module<module> (module::name)) + m->save_module (name, prio); + } + + void + create_project (const dir_path& d, + const build2::optional<dir_path>& amal, + const strings& bmod, + const string& rpre, + const strings& rmod, + const string& rpos, + bool config, + bool buildfile, + const char* who, + uint16_t verbosity) + { + string hdr ("# Generated by " + string (who) + ". Edit if you know" + " what you are doing.\n" + "#"); + + // If the directory exists, verify it's empty. Otherwise, create it. + // + if (exists (d)) + { + if (!empty (d)) + fail << "directory " << d << " exists and is not empty"; + } + else + mkdir_p (d, verbosity); + + // Create the build/ subdirectory. + // + // Note that for now we use the standard build file/directory scheme. + // + mkdir (d / std_build_dir, verbosity); + + // Write build/bootstrap.build. + // + { + path f (d / std_bootstrap_file); + + if (verb >= verbosity) + text << (verb >= 2 ? "cat >" : "save ") << f; + + try + { + ofdstream ofs (f); + + ofs << hdr << endl + << "project =" << endl; + + if (amal) + { + ofs << "amalgamation ="; + + if (!amal->empty ()) + ofs << ' ' << amal->representation (); + + ofs << endl; + } + + ofs << endl; + + if (config) + ofs << "using config" << endl; + + for (const string& m: bmod) + { + if (!config || m != "config") + ofs << "using " << m << endl; + } + + ofs.close (); + } + catch (const io_error& e) + { + fail << "unable to write " << f << ": " << e; + } + } + + // Write build/root.build. + // + { + path f (d / std_root_file); + + if (verb >= verbosity) + text << (verb >= 2 ? "cat >" : "save ") << f; + + try + { + ofdstream ofs (f); + + ofs << hdr << endl; + + if (!rpre.empty ()) + ofs << rpre << endl + << endl; + + for (const string& cm: rmod) + { + // If the module name start with '?', then use optional load. + // + bool opt (cm.front () == '?'); + string m (cm, opt ? 1 : 0); + + // Append .config unless the module name ends with '.', in which + // case strip it. + // + if (m.back () == '.') + m.pop_back (); + else + m += ".config"; + + ofs << "using" << (opt ? "?" : "") << " " << m << endl; + } + + if (!rpos.empty ()) + ofs << endl + << rpre << endl; + + ofs.close (); + } + catch (const io_error& e) + { + fail << "unable to write " << f << ": " << e; + } + } + + // Write root buildfile. + // + if (buildfile) + { + path f (d / std_buildfile_file); + + if (verb >= verbosity) + text << (verb >= 2 ? "cat >" : "save ") << f; + + try + { + ofdstream ofs (f); + + ofs << hdr << endl + << "./: {*/ -build/}" << endl; + + ofs.close (); + } + catch (const io_error& e) + { + fail << "unable to write " << f << ": " << e; + } + } + } + } +} |