aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-04-11 07:57:19 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-04-11 07:57:19 +0200
commit0342dc2fcdd78ef28a4e59d84193a3807068d726 (patch)
treee750c3062d6ff54f0d409fe1a25984b7e78592c8
parent5f7c3f923de106f9d204a8f3500274731ae84fd9 (diff)
New configuration logic, iteration 1
-rw-r--r--build2/bin/module2
-rw-r--r--build2/bin/module.cxx25
-rw-r--r--build2/cli/module2
-rw-r--r--build2/cli/module.cxx29
-rw-r--r--build2/config/module18
-rw-r--r--build2/config/module.cxx12
-rw-r--r--build2/config/operation.cxx88
-rw-r--r--build2/config/utility42
-rw-r--r--build2/config/utility.cxx87
-rw-r--r--build2/config/utility.txx40
-rw-r--r--build2/cxx/module2
-rw-r--r--build2/cxx/module.cxx35
-rw-r--r--build2/dist/module4
-rw-r--r--build2/dist/module.cxx30
-rw-r--r--build2/dist/operation.cxx9
-rw-r--r--build2/file.cxx35
-rw-r--r--build2/install/module4
-rw-r--r--build2/install/module.cxx41
-rw-r--r--build2/install/operation.cxx1
-rw-r--r--build2/install/rule.cxx8
-rw-r--r--build2/module23
-rw-r--r--build2/operation2
-rw-r--r--build2/operation.cxx4
-rw-r--r--build2/parser.cxx5
-rw-r--r--build2/scope.cxx16
-rw-r--r--build2/test/module4
-rw-r--r--build2/test/module.cxx16
-rw-r--r--build2/test/operation.cxx1
-rw-r--r--build2/test/rule.cxx5
-rw-r--r--build2/variable3
-rw-r--r--build2/variable.cxx2
31 files changed, 338 insertions, 257 deletions
diff --git a/build2/bin/module b/build2/bin/module
index 765eb2c..44dfbc7 100644
--- a/build2/bin/module
+++ b/build2/bin/module
@@ -16,7 +16,7 @@ namespace build2
{
extern "C" bool
bin_init (
- scope&, scope&, const location&, unique_ptr<module>&, bool, bool);
+ scope&, scope&, const location&, unique_ptr<module_base>&, bool, bool);
}
}
diff --git a/build2/bin/module.cxx b/build2/bin/module.cxx
index 5b1d8ca..866bab2 100644
--- a/build2/bin/module.cxx
+++ b/build2/bin/module.cxx
@@ -34,7 +34,7 @@ namespace build2
bin_init (scope& r,
scope& b,
const location&,
- unique_ptr<module>&,
+ unique_ptr<module_base>&,
bool first,
bool)
{
@@ -47,17 +47,16 @@ namespace build2
{
auto& v (var_pool);
- // @@ OVR
+ // Note: some overridable, some not.
//
+ v.insert<path> ("config.bin.ar", true);
+ v.insert<path> ("config.bin.ranlib", true);
- v.insert<path> ("config.bin.ar");
- v.insert<path> ("config.bin.ranlib");
-
- v.insert<string> ("config.bin.lib");
- v.insert<strings> ("config.bin.exe.lib");
- v.insert<strings> ("config.bin.liba.lib");
- v.insert<strings> ("config.bin.libso.lib");
- v.insert<dir_paths> ("config.bin.rpath");
+ v.insert<string> ("config.bin.lib", true);
+ v.insert<strings> ("config.bin.exe.lib", true);
+ v.insert<strings> ("config.bin.liba.lib", true);
+ v.insert<strings> ("config.bin.libso.lib", true);
+ v.insert<dir_paths> ("config.bin.rpath", true);
v.insert<string> ("bin.lib");
v.insert<strings> ("bin.exe.lib");
@@ -65,7 +64,7 @@ namespace build2
v.insert<strings> ("bin.libso.lib");
v.insert<dir_paths> ("bin.rpath");
- v.insert<string> ("bin.libprefix");
+ v.insert<string> ("bin.libprefix", true);
}
// Register target types.
@@ -158,8 +157,8 @@ namespace build2
// This one is optional and we merge it into bin.rpath, if any.
// See the cxx module for details on merging.
//
- if (const value& v = config::optional (r, "config.bin.rpath"))
- b.assign ("bin.rpath") += cast<dir_paths> (v);
+ b.assign ("bin.rpath") += cast_null<dir_paths> (
+ config::optional (r, "config.bin.rpath"));
// config.bin.ar
// config.bin.ranlib
diff --git a/build2/cli/module b/build2/cli/module
index ab629f1..0469b2c 100644
--- a/build2/cli/module
+++ b/build2/cli/module
@@ -16,7 +16,7 @@ namespace build2
{
extern "C" bool
cli_init (
- scope&, scope&, const location&, unique_ptr<module>&, bool, bool);
+ scope&, scope&, const location&, unique_ptr<module_base>&, bool, bool);
}
}
diff --git a/build2/cli/module.cxx b/build2/cli/module.cxx
index bf975e7..7b98e93 100644
--- a/build2/cli/module.cxx
+++ b/build2/cli/module.cxx
@@ -29,7 +29,7 @@ namespace build2
cli_init (scope& root,
scope& base,
const location& loc,
- unique_ptr<module>&,
+ unique_ptr<module_base>&,
bool first,
bool optional)
{
@@ -55,13 +55,11 @@ namespace build2
{
auto& v (var_pool);
- // @@ OVR
-
- v.insert<bool> ("config.cli.configured");
-
- v.insert<path> ("config.cli");
+ // Note: some overridable, some not.
+ //
+ v.insert<path> ("config.cli", true);
+ v.insert<strings> ("config.cli.options", true);
- v.insert<strings> ("config.cli.options");
v.insert<strings> ("cli.options");
}
@@ -88,13 +86,8 @@ namespace build2
// Don't re-run tests if the configuration says we are unconfigured.
//
- if (optional)
- {
- auto l (root["config.cli.configured"]);
-
- if (l && !cast<bool> (l))
+ if (optional && config::unconfigured (root, "config.cli"))
return false;
- }
// config.cli
//
@@ -167,7 +160,7 @@ namespace build2
// Note that we are unconfigured so that we don't keep re-testing
// this on each run.
//
- root.assign ("config.cli.configured") = false;
+ config::unconfigured (root, "config.cli", true);
if (verb >= 2)
text << cli << " not found, leaving cli module unconfigured";
@@ -198,7 +191,9 @@ namespace build2
// Clear the unconfigured flag, if any.
//
- root.assign ("config.cli.configured") = true;
+ // @@ Get rid of needing to do this.
+ //
+ config::unconfigured (root, "config.cli", false);
if (!ver.empty () && verb >= 2)
text << cli << " " << ver;
@@ -210,8 +205,8 @@ namespace build2
// cli.* variables. See the cxx module for more information on
// this merging semantics and some of its tricky aspects.
//
- if (const value& v = config::optional (root, "config.cli.options"))
- base.assign ("cli.options") += cast<strings> (v);
+ base.assign ("cli.options") += cast_null<strings> (
+ config::optional (root, "config.cli.options"));
// Register our rules.
//
diff --git a/build2/config/module b/build2/config/module
index 5f3c826..6012442 100644
--- a/build2/config/module
+++ b/build2/config/module
@@ -5,21 +5,35 @@
#ifndef BUILD2_CONFIG_MODULE
#define BUILD2_CONFIG_MODULE
+#include <butl/prefix-map>
+
#include <build2/types>
#include <build2/utility>
#include <build2/module>
+#include <build2/variable>
namespace build2
{
namespace config
{
+ struct module: module_base
+ {
+ // A sorted list of config.* variables and flags (currently unused) that
+ // are used (as opposed to just specified) in this configuration.
+ // Populated by the config utility functions (required(), optional())
+ //
+ butl::prefix_map<variable_cref, uint64_t, '.'> vars;
+
+ static const string name;
+ };
+
extern "C" void
- config_boot (scope&, const location&, unique_ptr<module>&);
+ config_boot (scope&, const location&, unique_ptr<module_base>&);
extern "C" bool
config_init (
- scope&, scope&, const location&, unique_ptr<module>&, bool, bool);
+ scope&, scope&, const location&, unique_ptr<module_base>&, bool, bool);
}
}
diff --git a/build2/config/module.cxx b/build2/config/module.cxx
index 6d2bd70..16eabe9 100644
--- a/build2/config/module.cxx
+++ b/build2/config/module.cxx
@@ -9,6 +9,7 @@
#include <build2/file>
#include <build2/rule>
#include <build2/scope>
+#include <build2/context>
#include <build2/diagnostics>
#include <build2/config/operation>
@@ -20,12 +21,14 @@ namespace build2
{
namespace config
{
+ const string module::name ("config");
+
//@@ Same as in operation.cxx
//
static const path config_file ("build/config.build");
extern "C" void
- config_boot (scope& root, const location&, unique_ptr<module>&)
+ config_boot (scope& root, const location&, unique_ptr<module_base>&)
{
tracer trace ("config::boot");
@@ -54,7 +57,7 @@ namespace build2
config_init (scope& root,
scope&,
const location& l,
- unique_ptr<module>&,
+ unique_ptr<module_base>& mod,
bool first,
bool)
{
@@ -68,6 +71,11 @@ namespace build2
l5 ([&]{trace << "for " << root.out_path ();});
+ // Only create the module if we are configuring.
+ //
+ if (current_mif->id == configure_id)
+ mod.reset (new module);
+
// Register alias and fallback rule for the configure meta-operation.
//
{
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 <build2/algorithm>
#include <build2/diagnostics>
+#include <build2/config/module>
+
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<const module> (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<scope*>& 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<scope*> projects;
+
for (void* v: ts)
{
target& t (*static_cast<target*> (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<scope*>& 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<scope*> projects;
+
for (void* v: ts)
{
scope& root (*static_cast<scope*> (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",
diff --git a/build2/config/utility b/build2/config/utility
index 9218106..451df30 100644
--- a/build2/config/utility
+++ b/build2/config/utility
@@ -19,12 +19,14 @@ namespace build2
{
// Set, if necessary, a required config.* variable.
//
- // If override is true and the variable doesn't come from this root
- // scope or from the command line, then its value is "overridden"
- // for this root scope.
+ // If override is true and the variable doesn't come from this root scope
+ // or from the command line (i.e., it is inherited from the amalgamtion),
+ // then its value is "overridden" for this root scope.
//
- // Return the reference to the value as well as the indication of
- // whether the variable has actually been set.
+ // Return the reference to the value as well as the indication of whether
+ // the value is "new", that is, it was either set (including override) or
+ // it came from the command line and was not inherited. This is usually
+ // used to test the new value.
//
template <typename T>
pair<reference_wrapper<const value>, bool>
@@ -68,19 +70,6 @@ namespace build2
return optional (root, var_pool.find (var));
}
- // As above but assumes the value is dir_path and makes it
- // absolute if the value specified on the command line is
- // relative.
- //
- const value&
- optional_absolute (scope& root, const variable&);
-
- inline const value&
- optional_absolute (scope& root, const string& var)
- {
- return optional_absolute (root, var_pool.find (var));
- }
-
// Check whether there are any variables specified from the config
// namespace. The idea is that we can check if there are any, say,
// config.install.* values. If there are none, then we can assume
@@ -90,10 +79,25 @@ namespace build2
//
// Note that this function detects and ignores the special
// config.*.configured variable which may be used by a module to
- // "remember" that it is unconfigured.
+ // "remember" that it is unconfigured (e.g., in order to avoid re-
+ // running the tests, etc).
//
bool
specified (scope& root, const string& ns);
+
+ //
+ //
+ bool
+ unconfigured (scope& root, const string& ns);
+
+ void
+ unconfigured (scope& root, const string& ns, bool);
+
+ // Enter the variable so that it is saved during configuration. See
+ // config::module.
+ //
+ void
+ save_variable (scope& root, const variable&, uint64_t flags = 0);
}
}
diff --git a/build2/config/utility.cxx b/build2/config/utility.cxx
index e96a896..1dbf3d3 100644
--- a/build2/config/utility.cxx
+++ b/build2/config/utility.cxx
@@ -6,53 +6,37 @@
#include <build2/context>
+#include <build2/config/module>
+
using namespace std;
namespace build2
{
namespace config
{
- const value&
- optional (scope& root, const variable& var)
+ void
+ save_variable (scope& root, const variable& var, uint64_t flags)
{
- auto l (root[var]);
-
- return l.defined ()
- ? l.belongs (*global_scope) ? (root.assign (var) = *l) : *l
- : root.assign (var); // NULL
+ 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 = root.modules.lookup<module> (module::name))
+ mod->vars.emplace (var, flags);
+ }
}
const value&
- optional_absolute (scope& root, const variable& var)
+ optional (scope& root, const variable& var)
{
- auto l (root[var]);
+ if (current_mif->id == configure_id)
+ save_variable (root, var);
- if (!l.defined ())
- return root.assign (var); // NULL
-
- if (!l.belongs (*global_scope)) // Value from (some) root scope.
- return *l;
-
- // Make the command-line value absolute. This is necessary to avoid
- // a warning issued by the config module about global/root scope
- // value mismatch.
- //
- // @@ CMDVAR
- //
- value& v (const_cast<value&> (*l));
-
- if (v && !v.empty ())
- {
- dir_path& d (cast<dir_path> (v));
-
- if (d.relative ())
- {
- d = work / d;
- d.normalize ();
- }
- }
-
- return root.assign (var) = v;
+ auto l (root[var]);
+ return l.defined ()
+ ? *l
+ : root.assign (var); // NULL.
}
bool
@@ -60,6 +44,12 @@ namespace build2
{
// 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.
+ //
for (scope* s (&r); s != nullptr; s = s->parent_scope ())
{
for (auto p (s->vars.find_namespace (ns));
@@ -78,5 +68,32 @@ namespace build2
return false;
}
+
+ bool
+ unconfigured (scope& root, const string& ns)
+ {
+ // Note: not overridable.
+ //
+ const variable& var (var_pool.insert<bool> (ns + ".configured"));
+
+ if (current_mif->id == configure_id)
+ save_variable (root, var);
+
+ auto l (root[var]); // Include inherited values.
+ return l && !cast<bool> (l);
+ }
+
+ void
+ unconfigured (scope& root, const string& ns, bool v)
+ {
+ // Note: not overridable.
+ //
+ const variable& var (var_pool.insert<bool> (ns + ".configured"));
+
+ if (current_mif->id == configure_id)
+ save_variable (root, var);
+
+ root.assign (var) = !v;
+ }
}
}
diff --git a/build2/config/utility.txx b/build2/config/utility.txx
index d3c57a5..f49be75 100644
--- a/build2/config/utility.txx
+++ b/build2/config/utility.txx
@@ -3,6 +3,7 @@
// license : MIT; see accompanying LICENSE file
#include <build2/scope>
+#include <build2/context>
namespace build2
{
@@ -10,20 +11,43 @@ namespace build2
{
template <typename T>
pair<reference_wrapper<const value>, bool>
- required (scope& root, const variable& var, const T& def_value, bool ovr)
+ required (scope& root, const variable& var, const T& def_val, bool def_ovr)
{
- using result = pair<reference_wrapper<const value>, bool>;
+ if (current_mif->id == configure_id)
+ save_variable (root, var);
- if (auto l = root[var])
+ pair<lookup, size_t> org (root.find_original (var));
+ lookup l (org.first);
+ bool n (false);
+
+ // The interaction with command line overrides can get tricky. For
+ // example, the override to defaul value could make (non-recursive)
+ // command line override in the outer scope no longer apply. So what we
+ // are going to do is first ignore overrides and perform the normal
+ // logic on the original. Then we apply the overrides on the result.
+ //
+ if (!l.defined () || (def_ovr && !l.belongs (root)))
{
- if (l.belongs (*global_scope))
- return result (root.assign (var) = *l, true);
+ l = lookup ((root.assign (var) = def_val), root);
+ org = make_pair (l, 1); // Lookup depth is 1 since in root.vars.
+ n = true;
+ }
+
+ if (var.override != nullptr)
+ {
+ pair<lookup, size_t> ovr (root.find_override (var, move (org)));
+
+ if (l != ovr.first) // Overriden?
+ {
+ l = move (ovr.first);
- if (!ovr || l.belongs (root))
- return result (*l, false);
+ // Overriden and not inherited (same logic as in save_config()).
+ //
+ n = l.belongs (root) || l.belongs (*global_scope);
+ }
}
- return result (root.assign (var) = def_value, true);
+ return pair<reference_wrapper<const value>, bool> (*l, n);
}
}
}
diff --git a/build2/cxx/module b/build2/cxx/module
index b9c50f4..39d1218 100644
--- a/build2/cxx/module
+++ b/build2/cxx/module
@@ -16,7 +16,7 @@ namespace build2
{
extern "C" bool
cxx_init (
- scope&, scope&, const location&, unique_ptr<module>&, bool, bool);
+ scope&, scope&, const location&, unique_ptr<module_base>&, bool, bool);
}
}
diff --git a/build2/cxx/module.cxx b/build2/cxx/module.cxx
index aac2af0..fba52b8 100644
--- a/build2/cxx/module.cxx
+++ b/build2/cxx/module.cxx
@@ -33,7 +33,7 @@ namespace build2
cxx_init (scope& r,
scope& b,
const location& loc,
- unique_ptr<module>&,
+ unique_ptr<module_base>&,
bool first,
bool)
{
@@ -62,14 +62,13 @@ namespace build2
{
auto& v (var_pool);
- // @@ OVR
-
- v.insert<path> ("config.cxx", true);
-
- v.insert<strings> ("config.cxx.poptions");
- v.insert<strings> ("config.cxx.coptions");
- v.insert<strings> ("config.cxx.loptions");
- v.insert<strings> ("config.cxx.libs");
+ // Note: some overridable, some not.
+ //
+ v.insert<path> ("config.cxx", true);
+ v.insert<strings> ("config.cxx.poptions", true);
+ v.insert<strings> ("config.cxx.coptions", true);
+ v.insert<strings> ("config.cxx.loptions", true);
+ v.insert<strings> ("config.cxx.libs", true);
v.insert<strings> ("cxx.poptions");
v.insert<strings> ("cxx.coptions");
@@ -81,7 +80,7 @@ namespace build2
v.insert<strings> ("cxx.export.loptions");
v.insert<strings> ("cxx.export.libs");
- v.insert<string> ("cxx.std");
+ v.insert<string> ("cxx.std", true);
}
// Register target types.
@@ -158,17 +157,17 @@ namespace build2
// using cxx
// cxx.coptions += <overriding options> # Note: '+='.
//
- if (const value& v = config::optional (r, "config.cxx.poptions"))
- b.assign ("cxx.poptions") += cast<strings> (v);
+ b.assign ("cxx.poptions") += cast_null<strings> (
+ config::optional (r, "config.cxx.poptions"));
- if (const value& v = config::optional (r, "config.cxx.coptions"))
- b.assign ("cxx.coptions") += cast<strings> (v);
+ b.assign ("cxx.coptions") += cast_null<strings> (
+ config::optional (r, "config.cxx.coptions"));
- if (const value& v = config::optional (r, "config.cxx.loptions"))
- b.assign ("cxx.loptions") += cast<strings> (v);
+ b.assign ("cxx.loptions") += cast_null<strings> (
+ config::optional (r, "config.cxx.loptions"));
- if (const value& v = config::optional (r, "config.cxx.libs"))
- b.assign ("cxx.libs") += cast<strings> (v);
+ b.assign ("cxx.libs") += cast_null<strings> (
+ config::optional (r, "config.cxx.libs"));
// config.cxx
//
diff --git a/build2/dist/module b/build2/dist/module
index 829f3f7..61e44c3 100644
--- a/build2/dist/module
+++ b/build2/dist/module
@@ -15,11 +15,11 @@ namespace build2
namespace dist
{
extern "C" void
- dist_boot (scope&, const location&, unique_ptr<module>&);
+ dist_boot (scope&, const location&, unique_ptr<module_base>&);
extern "C" bool
dist_init (
- scope&, scope&, const location&, unique_ptr<module>&, bool, bool);
+ scope&, scope&, const location&, unique_ptr<module_base>&, bool, bool);
}
}
diff --git a/build2/dist/module.cxx b/build2/dist/module.cxx
index 4b68bb8..2a7ba92 100644
--- a/build2/dist/module.cxx
+++ b/build2/dist/module.cxx
@@ -23,7 +23,7 @@ namespace build2
static rule rule_;
extern "C" void
- dist_boot (scope& r, const location&, unique_ptr<module>&)
+ dist_boot (scope& r, const location&, unique_ptr<module_base>&)
{
tracer trace ("dist::boot");
@@ -39,20 +39,18 @@ namespace build2
{
auto& v (var_pool);
- // @@ OVR
+ // Note: some overridable, some not.
+ //
+ v.insert<abs_dir_path> ("config.dist.root", true);
+ v.insert<strings> ("config.dist.archives", true);
+ v.insert<path> ("config.dist.cmd", true);
- v.insert<bool> ("dist");
+ v.insert<dir_path> ("dist.root");
+ v.insert<path> ("dist.cmd");
+ v.insert<strings> ("dist.archives");
- v.insert<string> ("dist.package");
-
- v.insert<dir_path> ("dist.root");
- v.insert<dir_path> ("config.dist.root");
-
- v.insert<path> ("dist.cmd");
- v.insert<path> ("config.dist.cmd");
-
- v.insert<strings> ("dist.archives");
- v.insert<strings> ("config.dist.archives");
+ v.insert<bool> ("dist"); // Flag.
+ v.insert<string> ("dist.package"); // Project's package name.
}
}
@@ -60,7 +58,7 @@ namespace build2
dist_init (scope& r,
scope&,
const location& l,
- unique_ptr<module>&,
+ unique_ptr<module_base>&,
bool first,
bool)
{
@@ -97,10 +95,10 @@ namespace build2
if (s)
{
- const value& cv (config::optional_absolute (r, "config.dist.root"));
+ const value& cv (config::optional (r, "config.dist.root"));
if (cv && !cv.empty ())
- v = cv;
+ v = cast<dir_path> (cv); // Strip abs_dir_path.
}
}
diff --git a/build2/dist/operation.cxx b/build2/dist/operation.cxx
index 8a890fa..9ae5773 100644
--- a/build2/dist/operation.cxx
+++ b/build2/dist/operation.cxx
@@ -72,7 +72,7 @@ namespace build2
// Make sure we have the necessary configuration before
// we get down to business.
//
- auto l (rs->vars["dist.root"]); //@@ OVR
+ auto l (rs->vars["dist.root"]);
if (!l || l->empty ())
fail << "unknown root distribution directory" <<
@@ -84,14 +84,14 @@ namespace build2
fail << "root distribution directory " << dist_root
<< " does not exist";
- l = rs->vars["dist.package"]; //@@ OVR
+ l = rs->vars["dist.package"];
if (!l || l->empty ())
fail << "unknown distribution package name" <<
info << "did you forget to set dist.package?";
const string& dist_package (cast<string> (l));
- const path& dist_cmd (cast<path> (rs->vars["dist.cmd"])); // @@ OVR
+ const path& dist_cmd (cast<path> (rs->vars["dist.cmd"]));
// Get the list of operations supported by this project. Skip
// default_id.
@@ -281,7 +281,7 @@ namespace build2
// Archive if requested.
//
- if (auto l = rs->vars["dist.archives"]) // @@ OVR
+ if (auto l = rs->vars["dist.archives"])
{
for (const string& e: cast<strings> (l))
archive (dist_root, dist_package, e);
@@ -425,6 +425,7 @@ namespace build2
}
meta_operation_info dist {
+ dist_id,
"dist",
"distribute",
"distributing",
diff --git a/build2/file.cxx b/build2/file.cxx
index e494f5a..c3d2273 100644
--- a/build2/file.cxx
+++ b/build2/file.cxx
@@ -18,6 +18,8 @@
#include <build2/lexer>
#include <build2/parser>
+#include <build2/config/utility>
+
using namespace std;
using namespace butl;
@@ -859,42 +861,19 @@ namespace build2
break;
}
- // Then try the config.import.* mechanism (overridable variable).
+ // Then try the config.import.* mechanism.
//
if (out_root.empty ())
{
- // @@ OVR
+ // Note: overridable variable with path auto-completion.
//
const variable& var (
- var_pool.insert<dir_path> ("config.import." + project, true));
+ var_pool.insert<abs_dir_path> ("config.import." + project, true));
if (auto l = iroot[var])
{
- out_root = cast<dir_path> (l);
-
- if (l.belongs (*global_scope)) // A value from command line.
- {
- // Process the path by making it absolute and normalized.
- //
- if (out_root.relative ())
- out_root = work / out_root;
-
- out_root.normalize ();
-
- // Set on our root scope (part of our configuration).
- //
- iroot.assign (var) = out_root;
-
- // Also update the command-line value. This is necessary to avoid
- // a warning issued by the config module about global/root scope
- // value mismatch. Not very clean.
- //
- // @@ CMDVAR
- //
- dir_path& d (cast<dir_path> (const_cast<value&> (*l)));
- if (d != out_root)
- d = out_root;
- }
+ out_root = cast<abs_dir_path> (l);
+ config::save_variable (iroot, var); // Mark as part of configuration.
}
else
{
diff --git a/build2/install/module b/build2/install/module
index a02d110..f81b6ac 100644
--- a/build2/install/module
+++ b/build2/install/module
@@ -15,11 +15,11 @@ namespace build2
namespace install
{
extern "C" void
- install_boot (scope&, const location&, unique_ptr<module>&);
+ install_boot (scope&, const location&, unique_ptr<module_base>&);
extern "C" bool
install_init (
- scope&, scope&, const location&, unique_ptr<module>&, bool, bool);
+ scope&, scope&, const location&, unique_ptr<module_base>&, bool, bool);
}
}
diff --git a/build2/install/module.cxx b/build2/install/module.cxx
index 7838a65..e7840ca 100644
--- a/build2/install/module.cxx
+++ b/build2/install/module.cxx
@@ -50,7 +50,7 @@ namespace build2
vn = "config.install.";
vn += name;
vn += var;
- const variable& vr (var_pool.insert<T> (move (vn))); // @@ OVR
+ const variable& vr (var_pool.insert<T> (move (vn), true));
cv = dv != nullptr
? &config::required (r, vr, *dv, override).first.get ()
@@ -60,7 +60,7 @@ namespace build2
vn = "install.";
vn += name;
vn += var;
- const variable& vr (var_pool.insert<T> (move (vn))); // @@ OVR
+ const variable& vr (var_pool.insert<T> (move (vn))); // Not overridable.
value& v (r.assign (vr));
@@ -76,11 +76,12 @@ namespace build2
}
}
+ template <typename T>
static void
set_dir (bool s, // specified
scope& r, // root scope
const char* n, // var name
- const string& ps, // path (as string)
+ const T& p, // path
const string& fm = string (), // file mode
const string& dm = string (), // dir mode
const build2::path& c = build2::path (), // command
@@ -88,7 +89,6 @@ namespace build2
{
using build2::path;
- dir_path p (ps);
set_var (s, r, n, "", p.empty () ? nullptr : &p, o);
set_var (s, r, n, ".mode", fm.empty () ? nullptr : &fm);
set_var (s, r, n, ".dir_mode", dm.empty () ? nullptr : &dm);
@@ -101,7 +101,7 @@ namespace build2
static file_rule file_;
extern "C" void
- install_boot (scope& r, const location&, unique_ptr<module>&)
+ install_boot (scope& r, const location&, unique_ptr<module_base>&)
{
tracer trace ("install::boot");
@@ -116,7 +116,7 @@ namespace build2
install_init (scope& r,
scope& b,
const location& l,
- unique_ptr<module>&,
+ unique_ptr<module_base>&,
bool first,
bool)
{
@@ -139,9 +139,9 @@ namespace build2
{
auto& v (var_pool);
- // @@ OVR
+ // Note: not overridable.
//
- v.insert<dir_path> ("install");
+ v.insert<dir_path> ("install"); // Flag.
}
// Register our alias and file installer rule.
@@ -162,22 +162,21 @@ namespace build2
bool s (config::specified (r, "config.install"));
const string& n (cast<string> (r["project"]));
- set_dir (s, r, "root", "", "", "755", path ("install"));
- set_dir (s, r, "data_root", "root", "644");
- set_dir (s, r, "exec_root", "root", "755");
-
- set_dir (s, r, "sbin", "exec_root/sbin");
- set_dir (s, r, "bin", "exec_root/bin");
- set_dir (s, r, "lib", "exec_root/lib");
- set_dir (s, r, "libexec", "exec_root/libexec/" + n, "", "", path (), true);
+ set_dir (s, r, "root", abs_dir_path (), "", "755", path ("install"));
+ set_dir (s, r, "data_root", dir_path ("root"), "644");
+ set_dir (s, r, "exec_root", dir_path ("root"), "755");
- set_dir (s, r, "data", "data_root/share/" + n, "", "", path (), true);
- set_dir (s, r, "include", "data_root/include");
+ set_dir (s, r, "sbin", dir_path ("exec_root/sbin"));
+ set_dir (s, r, "bin", dir_path ("exec_root/bin"));
+ set_dir (s, r, "lib", dir_path ("exec_root/lib"));
+ set_dir (s, r, "libexec", dir_path ("exec_root/libexec/" + n), "", "", path (), true);
- set_dir (s, r, "doc", "data_root/share/doc/" + n, "", "", path (), true);
- set_dir (s, r, "man", "data_root/share/man");
+ set_dir (s, r, "data", dir_path ("data_root/share/" + n), "", "", path (), true);
+ set_dir (s, r, "include", dir_path ("data_root/include"));
- set_dir (s, r, "man1", "man/man1");
+ set_dir (s, r, "doc", dir_path ("data_root/share/doc/" + n), "", "", path (), true);
+ set_dir (s, r, "man", dir_path ("data_root/share/man"));
+ set_dir (s, r, "man1", dir_path ("man/man1"));
}
// Configure "installability" for built-in target types.
diff --git a/build2/install/operation.cxx b/build2/install/operation.cxx
index 7778c70..77deb2c 100644
--- a/build2/install/operation.cxx
+++ b/build2/install/operation.cxx
@@ -20,6 +20,7 @@ namespace build2
}
operation_info install {
+ install_id,
"install",
"install",
"installing",
diff --git a/build2/install/rule.cxx b/build2/install/rule.cxx
index e756fc2..24c1df0 100644
--- a/build2/install/rule.cxx
+++ b/build2/install/rule.cxx
@@ -371,10 +371,10 @@ namespace build2
if (r.mode.empty ()) r.mode = "644";
if (r.dir_mode.empty ()) r.dir_mode = "755";
- // If the directory still doesn't exist, then this means it was specified
- // as absolute (it will normally be install.root with everything else
- // defined in term of it). We used to fail in this case but that proved
- // to be just too anal. So now we just create it.
+ // If the directory still doesn't exist, then this means it was
+ // specified as absolute (it will normally be install.root with
+ // everything else defined in term of it). We used to fail in this
+ // case but that proved to be just too anal. So now we just create it.
//
if (!dir_exists (r.dir)) // May throw (e.g., EACCES).
// fail << "installation directory " << d << " does not exist";
diff --git a/build2/module b/build2/module
index 7c8719e..25574d1 100644
--- a/build2/module
+++ b/build2/module
@@ -17,16 +17,16 @@ namespace build2
class scope;
class location;
- class module
+ class module_base
{
public:
virtual
- ~module () = default;
+ ~module_base () = default;
};
extern "C"
using module_boot_function =
- void (scope& root, const location&, unique_ptr<module>&);
+ void (scope& root, const location&, unique_ptr<module_base>&);
// Return false if the module configuration (normally based on the default
// values) was unsuccessful but this is not (yet) an error. One example
@@ -39,7 +39,7 @@ namespace build2
bool (scope& root,
scope& base,
const location&,
- unique_ptr<module>&,
+ unique_ptr<module_base>&,
bool first, // First time for this project.
bool optional); // Loaded with 'using?' (optional module).
@@ -48,11 +48,22 @@ namespace build2
{
bool boot; // True if the module boot'ed but not yet init'ed.
module_init_function* init;
- unique_ptr<build2::module> module;
+ unique_ptr<module_base> module;
const location loc; // Boot location.
};
- using loaded_module_map = std::map<string, module_state>;
+ struct loaded_module_map: std::map<string, module_state>
+ {
+ template<typename T>
+ T*
+ lookup (const string& name) const
+ {
+ auto i (find (name));
+ return i != end ()
+ ? static_cast<T*> (i->second.module.get ())
+ : nullptr;
+ }
+ };
// Load and boot the specified module.
//
diff --git a/build2/operation b/build2/operation
index 688663b..152353b 100644
--- a/build2/operation
+++ b/build2/operation
@@ -174,6 +174,7 @@ namespace build2
struct meta_operation_info
{
+ const meta_operation_id id;
const string name;
// Name derivatives for diagnostics. If empty, then the meta-
@@ -253,6 +254,7 @@ namespace build2
//
struct operation_info
{
+ const operation_id id;
const string name;
// Name derivatives for diagnostics. Note that unlike meta-operations,
diff --git a/build2/operation.cxx b/build2/operation.cxx
index ef620ba..c5ba2fb 100644
--- a/build2/operation.cxx
+++ b/build2/operation.cxx
@@ -172,6 +172,7 @@ namespace build2
}
meta_operation_info perform {
+ perform_id,
"perform",
"",
"",
@@ -189,6 +190,7 @@ namespace build2
// operations
//
operation_info default_ {
+ default_id,
"<default>",
"",
"",
@@ -199,6 +201,7 @@ namespace build2
};
operation_info update {
+ update_id,
"update",
"update",
"updating",
@@ -209,6 +212,7 @@ namespace build2
};
operation_info clean {
+ clean_id,
"clean",
"clean",
"cleaning",
diff --git a/build2/parser.cxx b/build2/parser.cxx
index 6926ce3..2c21de3 100644
--- a/build2/parser.cxx
+++ b/build2/parser.cxx
@@ -2660,16 +2660,15 @@ namespace build2
scope* nrs (&create_bootstrap_inner (*rs, out_base));
if (rs != nrs)
- {
- load_root_pre (*nrs); // Load outer roots recursively.
rs = nrs;
- }
}
// Switch to the new root scope.
//
if (rs != root_)
{
+ load_root_pre (*rs); // Load new root(s) recursively.
+
l5 ([&]{trace << "switching to root scope " << rs->out_path ();});
root_ = rs;
}
diff --git a/build2/scope.cxx b/build2/scope.cxx
index 75652a2..19f3b56 100644
--- a/build2/scope.cxx
+++ b/build2/scope.cxx
@@ -27,18 +27,26 @@ namespace build2
++d;
if (f)
- if (auto l = s->target_vars.find (*tt, *tn, var))
+ {
+ lookup l (s->target_vars.find (*tt, *tn, var));
+
+ if (l.defined ())
return make_pair (move (l), d);
+ }
++d;
if (f && gt != nullptr)
- if (auto l = s->target_vars.find (*gt, *gn, var))
+ {
+ lookup l (s->target_vars.find (*gt, *gn, var));
+
+ if (l.defined ())
return make_pair (move (l), d);
+ }
}
++d;
- if (auto r = s->vars.find (var))
- return make_pair (lookup (r, &s->vars), d);
+ if (const value* v = s->vars.find (var))
+ return make_pair (lookup (v, &s->vars), d);
switch (var.visibility)
{
diff --git a/build2/test/module b/build2/test/module
index 8736851..756b4f6 100644
--- a/build2/test/module
+++ b/build2/test/module
@@ -15,11 +15,11 @@ namespace build2
namespace test
{
extern "C" void
- test_boot (scope&, const location&, unique_ptr<module>&);
+ test_boot (scope&, const location&, unique_ptr<module_base>&);
extern "C" bool
test_init (
- scope&, scope&, const location&, unique_ptr<module>&, bool, bool);
+ scope&, scope&, const location&, unique_ptr<module_base>&, bool, bool);
}
}
diff --git a/build2/test/module.cxx b/build2/test/module.cxx
index d5f6430..3ae9996 100644
--- a/build2/test/module.cxx
+++ b/build2/test/module.cxx
@@ -22,7 +22,7 @@ namespace build2
static rule rule_;
extern "C" void
- test_boot (scope& root, const location&, unique_ptr<module>&)
+ test_boot (scope& root, const location&, unique_ptr<module_base>&)
{
tracer trace ("test::boot");
@@ -38,12 +38,12 @@ namespace build2
{
auto& v (var_pool);
- // @@ OVR
-
- v.insert<bool> ("test");
- v.insert<name> ("test.input");
- v.insert<name> ("test.output");
- v.insert<name> ("test.roundtrip");
+ // Note: none are overridable.
+ //
+ v.insert<bool> ("test");
+ v.insert<name> ("test.input");
+ v.insert<name> ("test.output");
+ v.insert<name> ("test.roundtrip");
v.insert<strings> ("test.options");
v.insert<strings> ("test.arguments");
}
@@ -53,7 +53,7 @@ namespace build2
test_init (scope& root,
scope&,
const location& l,
- unique_ptr<module>&,
+ unique_ptr<module_base>&,
bool first,
bool)
{
diff --git a/build2/test/operation.cxx b/build2/test/operation.cxx
index dc213cf..a63c409 100644
--- a/build2/test/operation.cxx
+++ b/build2/test/operation.cxx
@@ -20,6 +20,7 @@ namespace build2
}
operation_info test {
+ test_id,
"test",
"test",
"testing",
diff --git a/build2/test/rule.cxx b/build2/test/rule.cxx
index 75bae4a..ccf52e0 100644
--- a/build2/test/rule.cxx
+++ b/build2/test/rule.cxx
@@ -96,7 +96,6 @@ namespace build2
// We should have either arguments or input/roundtrip. Again, use
// lookup depth to figure out who takes precedence.
//
- //@@ OVR
auto ip (t.find ("test.input"));
auto op (t.find ("test.output"));
auto rp (t.find ("test.roundtrip"));
@@ -307,7 +306,7 @@ namespace build2
// Do we have options?
//
- if (auto l = t["test.options"]) //@@ OVR
+ if (auto l = t["test.options"])
append_options (args, cast<strings> (l));
// Do we have input?
@@ -323,7 +322,7 @@ namespace build2
//
else
{
- if (auto l = t["test.arguments"]) //@@ OVR
+ if (auto l = t["test.arguments"])
append_options (args, cast<strings> (l));
}
diff --git a/build2/variable b/build2/variable
index 77e9db2..14bf7af 100644
--- a/build2/variable
+++ b/build2/variable
@@ -161,6 +161,9 @@ namespace build2
template <typename T> value& operator= (T);
template <typename T> value& operator+= (T);
+ template <typename T> value& operator+= (T* v) {
+ return v != nullptr ? *this += *v : *this;}
+
value& operator= (const char* v) {return *this = string (v);}
value& operator+= (const char* v) {return *this += string (v);}
diff --git a/build2/variable.cxx b/build2/variable.cxx
index 4a2ffa9..db65e5b 100644
--- a/build2/variable.cxx
+++ b/build2/variable.cxx
@@ -536,6 +536,8 @@ namespace build2
if (d.relative ())
d.complete ();
+ d.normalize ();
+
return abs_dir_path (move (d));
}