aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2020-03-16 08:06:15 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2020-03-17 07:47:17 +0200
commit9f71deeeb0f8e6fe2c29f209fc96f466fc2831b6 (patch)
tree81e07870c7a16f12c7aca69bf70a71d69251d1fc
parent1adbf7b710d52958f6c0168ccb492252c1f19d4a (diff)
Rework config::{omitted,required,optional}() into unified config_lookup()
-rw-r--r--build2/cli/init.cxx39
-rw-r--r--libbuild2/bin/init.cxx148
-rw-r--r--libbuild2/cc/compile-rule.cxx2
-rw-r--r--libbuild2/cc/init.cxx15
-rw-r--r--libbuild2/cc/module.cxx53
-rw-r--r--libbuild2/cc/module.hxx5
-rw-r--r--libbuild2/config/operation.cxx10
-rw-r--r--libbuild2/config/utility.cxx17
-rw-r--r--libbuild2/config/utility.hxx227
-rw-r--r--libbuild2/config/utility.ixx62
-rw-r--r--libbuild2/config/utility.txx39
-rw-r--r--libbuild2/dist/init.cxx19
-rw-r--r--libbuild2/file.hxx21
-rw-r--r--libbuild2/install/init.cxx14
-rw-r--r--libbuild2/test/init.cxx7
15 files changed, 422 insertions, 256 deletions
diff --git a/build2/cli/init.cxx b/build2/cli/init.cxx
index b196351..b0ff4f9 100644
--- a/build2/cli/init.cxx
+++ b/build2/cli/init.cxx
@@ -57,11 +57,15 @@ namespace build2
vp.insert<strings> ("cli.options");
}
- // Configure.
+ // Configuration.
//
// The plan is as follows: try to configure the module. If this fails,
// we are using default values, and the module is optional, leave it
// unconfigured.
+ //
+ using config::lookup_config;
+ using config::specified_config;
+
// First take care of the explicit request by the user to leave the
// module unconfigured.
@@ -81,7 +85,7 @@ namespace build2
// Otherwise we will only honor optional if the user didn't specify
// any cli configuration explicitly.
//
- optional = optional && !config::specified (rs, "cli");
+ optional = optional && !specified_config (rs, "cli");
// If the configuration says we are unconfigured, then we should't
// re-run tests, etc. But we may still need to print the config
@@ -197,9 +201,9 @@ namespace build2
//
config::save_module (rs, "cli", 150);
- string ver; // Empty means unconfigured.
- path cli ("cli"); // Default.
- bool nv (false); // New value.
+ string ver; // Empty means unconfigured.
+ path cli ("cli"); // Default value.
+ bool new_cfg (false); // New configuration.
if (optional)
{
@@ -212,27 +216,24 @@ namespace build2
ver = test (cli);
if (ver.empty ())
+ {
conf = false;
+ new_cfg = true;
+ }
else
{
- auto p (config::required (rs, "config.cli", cli));
- assert (p.second && cast<path> (p.first) == cli);
+ auto l (lookup_config (new_cfg, rs, "config.cli", cli));
+ assert (new_cfg && cast<path> (l) == cli);
}
-
- nv = true;
}
}
else
{
- auto p (config::required (rs, "config.cli", cli));
-
- cli = cast<path> (p.first);
+ cli = cast<path> (lookup_config (new_cfg, rs, "config.cli", cli));
ver = test (cli);
if (ver.empty ())
throw failed (); // Diagnostics already issued.
-
- nv = p.second;
}
string checksum;
@@ -250,13 +251,13 @@ namespace build2
// Note that we are unconfigured so that we don't keep re-testing
// this on each run.
//
- nv = config::unconfigured (rs, "cli", true) || nv;
+ new_cfg = config::unconfigured (rs, "cli", true) || new_cfg;
}
- // If this is a new value (e.g., we are configuring), then print the
- // report at verbosity level 2 and up (-v).
+ // If this is a configuration with new values, then print the report
+ // at verbosity level 2 and up (-v).
//
- if (verb >= (nv ? 2 : 3))
+ if (verb >= (new_cfg ? 2 : 3))
{
diag_record dr (text);
dr << "cli " << project (rs) << '@' << rs << '\n';
@@ -286,7 +287,7 @@ namespace build2
// semantics and some of its tricky aspects.
//
bs.assign ("cli.options") += cast_null<strings> (
- config::optional (rs, "config.cli.options"));
+ lookup_config (rs, "config.cli.options", nullptr));
}
return conf;
diff --git a/libbuild2/bin/init.cxx b/libbuild2/bin/init.cxx
index bb935de..25d5c39 100644
--- a/libbuild2/bin/init.cxx
+++ b/libbuild2/bin/init.cxx
@@ -160,11 +160,9 @@ namespace build2
//
load_module (rs, rs, "bin.vars", loc);
- // Configure.
+ // Configuration.
//
- using config::required;
- using config::optional;
- using config::omitted;
+ using config::lookup_config;
// Adjust module priority (binutils).
//
@@ -185,7 +183,7 @@ namespace build2
{
value& v (rs.assign ("bin.lib"));
if (!v)
- v = *required (rs, "config.bin.lib", "both").first;
+ v = *lookup_config (rs, "config.bin.lib", "both");
}
// config.bin.exe.lib
@@ -193,7 +191,7 @@ namespace build2
{
value& v (rs.assign ("bin.exe.lib"));
if (!v)
- v = *required (rs, "config.bin.exe.lib", exe_lib).first;
+ v = *lookup_config (rs, "config.bin.exe.lib", exe_lib);
}
// config.bin.liba.lib
@@ -201,7 +199,7 @@ namespace build2
{
value& v (rs.assign ("bin.liba.lib"));
if (!v)
- v = *required (rs, "config.bin.liba.lib", liba_lib).first;
+ v = *lookup_config (rs, "config.bin.liba.lib", liba_lib);
}
// config.bin.libs.lib
@@ -209,7 +207,7 @@ namespace build2
{
value& v (rs.assign ("bin.libs.lib"));
if (!v)
- v = *required (rs, "config.bin.libs.lib", libs_lib).first;
+ v = *lookup_config (rs, "config.bin.libs.lib", libs_lib);
}
// config.bin.rpath[_link]
@@ -218,10 +216,10 @@ namespace build2
// any.
//
rs.assign ("bin.rpath") += cast_null<dir_paths> (
- optional (rs, "config.bin.rpath"));
+ lookup_config (rs, "config.bin.rpath", nullptr));
rs.assign ("bin.rpath_link") += cast_null<dir_paths> (
- optional (rs, "config.bin.rpath_link"));
+ lookup_config (rs, "config.bin.rpath_link", nullptr));
// config.bin.rpath[_link].auto
//
@@ -229,12 +227,12 @@ namespace build2
lookup l;
rs.assign ("bin.rpath.auto") =
- (l = omitted (rs, "config.bin.rpath.auto").first)
+ (l = lookup_config (rs, "config.bin.rpath.auto"))
? cast<bool> (l)
: true;
rs.assign ("bin.rpath_link.auto") =
- (l = omitted (rs, "config.bin.rpath_link.auto").first)
+ (l = lookup_config (rs, "config.bin.rpath_link.auto"))
? cast<bool> (l)
: true;
}
@@ -246,12 +244,12 @@ namespace build2
// that might have been specified before loading the module.
//
{
- lookup p (omitted (rs, "config.bin.prefix").first);
- lookup s (omitted (rs, "config.bin.suffix").first);
+ lookup p (lookup_config (rs, "config.bin.prefix"));
+ lookup s (lookup_config (rs, "config.bin.suffix"));
auto set = [&rs] (const char* bv, const char* cv, lookup l)
{
- if (lookup o = omitted (rs, cv).first)
+ if (lookup o = lookup_config (rs, cv))
l = o;
if (l)
@@ -267,7 +265,7 @@ namespace build2
if (first)
{
- bool new_val (false); // Set any new values?
+ bool new_cfg (false); // Any new configuration values?
// config.bin.target
//
@@ -277,14 +275,15 @@ namespace build2
// We first see if the value was specified via the configuration
// mechanism.
//
- auto p (omitted (rs, var));
- lookup l (p.first);
+ lookup l (lookup_config (new_cfg, rs, var));
// Then see if there is a config hint (e.g., from the cc module).
//
bool hint (false);
if (!l)
{
+ // Note: new_cfg is false for a hinted value.
+ //
if (auto hl = extra.hints[var])
{
l = hl;
@@ -342,8 +341,6 @@ namespace build2
fail << "unable to parse binutils target '" << s << "': " << e <<
info << "consider using the --config-sub option";
}
-
- new_val = new_val || p.second; // False for a hinted value.
}
// config.bin.pattern
@@ -354,13 +351,14 @@ namespace build2
// We first see if the value was specified via the configuration
// mechanism.
//
- auto p (omitted (rs, var));
- lookup l (p.first);
+ lookup l (lookup_config (new_cfg, rs, var));
// Then see if there is a config hint (e.g., from the C++ module).
//
if (!l)
{
+ // Note: new_cfg is false for a hinted value.
+ //
if (auto hl = extra.hints[var])
l = hl;
}
@@ -382,14 +380,13 @@ namespace build2
}
rs.assign<string> ("bin.pattern") = s;
- new_val = new_val || p.second; // False for a hinted value.
}
}
- // If we set any new values (e.g., we are configuring), then print the
- // report at verbosity level 2 and up (-v).
+ // If this is a configuration with new values, then print the report
+ // at verbosity level 2 and up (-v).
//
- if (verb >= (new_val ? 2 : 3))
+ if (verb >= (new_cfg ? 2 : 3))
{
diag_record dr (text);
@@ -587,10 +584,14 @@ namespace build2
vp.insert<path> ("config.bin.ranlib", true);
}
- // Configure.
+ // Configuration.
//
if (first)
{
+ using config::lookup_config;
+
+ bool new_cfg (false); // Any new configuration values?
+
// config.bin.ar
// config.bin.ranlib
//
@@ -619,31 +620,28 @@ namespace build2
// changes, say, the C++ compiler (which hinted the pattern), then
// ar will automatically change as well.
//
- auto ap (
- config::required (
- rs,
- "config.bin.ar",
- path (apply_pattern (ar_d, pat.pattern)),
- false,
- config::save_default_commented));
-
- auto rp (
- config::required (
- rs,
- "config.bin.ranlib",
- nullptr,
- false,
- config::save_default_commented));
-
- const path& ar (cast<path> (ap.first));
- const path* ranlib (cast_null<path> (rp.first));
+ const path& ar (
+ cast<path> (
+ lookup_config (new_cfg,
+ rs,
+ "config.bin.ar",
+ path (apply_pattern (ar_d, pat.pattern)),
+ config::save_default_commented)));
+
+ const path* ranlib (
+ cast_null<path> (
+ lookup_config (new_cfg,
+ rs,
+ "config.bin.ranlib",
+ nullptr,
+ config::save_default_commented)));
ar_info ari (guess_ar (ar, ranlib, pat.paths));
- // If this is a new value (e.g., we are configuring), then print the
- // report at verbosity level 2 and up (-v).
+ // If this is a configuration with new values, then print the report
+ // at verbosity level 2 and up (-v).
//
- if (verb >= (ap.second || rp.second ? 2 : 3))
+ if (verb >= (new_cfg ? 2 : 3))
{
diag_record dr (text);
@@ -750,10 +748,14 @@ namespace build2
vp.insert<path> ("config.bin.ld", true);
}
- // Configure.
+ // Configuration.
//
if (first)
{
+ using config::lookup_config;
+
+ bool new_cfg (false); // Any new configuration values?
+
// config.bin.ld
//
// Use the target to decide on the default ld name.
@@ -765,21 +767,20 @@ namespace build2
//
pattern_paths pat (lookup_pattern (rs));
- auto p (
- config::required (
- rs,
- "config.bin.ld",
- path (apply_pattern (ld_d, pat.pattern)),
- false,
- config::save_default_commented));
+ const path& ld (
+ cast<path> (
+ lookup_config (new_cfg,
+ rs,
+ "config.bin.ld",
+ path (apply_pattern (ld_d, pat.pattern)),
+ config::save_default_commented)));
- const path& ld (cast<path> (p.first));
ld_info ldi (guess_ld (ld, pat.paths));
- // If this is a new value (e.g., we are configuring), then print the
- // report at verbosity level 2 and up (-v).
+ // If this is a configuration with new values, then print the report
+ // at verbosity level 2 and up (-v).
//
- if (verb >= (p.second ? 2 : 3))
+ if (verb >= (new_cfg ? 2 : 3))
{
diag_record dr (text);
@@ -883,10 +884,14 @@ namespace build2
vp.insert<path> ("config.bin.rc", true);
}
- // Configure.
+ // Configuration.
//
if (first)
{
+ using config::lookup_config;
+
+ bool new_cfg (false); // Any new configuration values?
+
// config.bin.rc
//
// Use the target to decide on the default rc name.
@@ -898,21 +903,20 @@ namespace build2
//
pattern_paths pat (lookup_pattern (rs));
- auto p (
- config::required (
- rs,
- "config.bin.rc",
- path (apply_pattern (rc_d, pat.pattern)),
- false,
- config::save_default_commented));
+ const path& rc (
+ cast<path> (
+ lookup_config (new_cfg,
+ rs,
+ "config.bin.rc",
+ path (apply_pattern (rc_d, pat.pattern)),
+ config::save_default_commented)));
- const path& rc (cast<path> (p.first));
rc_info rci (guess_rc (rc, pat.paths));
- // If this is a new value (e.g., we are configuring), then print the
- // report at verbosity level 2 and up (-v).
+ // If this is a configuration with new values, then print the report
+ // at verbosity level 2 and up (-v).
//
- if (verb >= (p.second ? 2 : 3))
+ if (verb >= (new_cfg ? 2 : 3))
{
text << "bin.rc " << project (rs) << '@' << rs << '\n'
<< " rc " << rci.path << '\n'
diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx
index 1cefcc5..a8916cf 100644
--- a/libbuild2/cc/compile-rule.cxx
+++ b/libbuild2/cc/compile-rule.cxx
@@ -5321,7 +5321,7 @@ namespace build2
extra, /* root_pre */
{string (x) + '.'}, /* root_modules */
"", /* root_post */
- nullopt, /* config */
+ nullopt, /* config_module */
false, /* buildfile */
"the cc module",
2); /* verbosity */
diff --git a/libbuild2/cc/init.cxx b/libbuild2/cc/init.cxx
index 202c612..723b678 100644
--- a/libbuild2/cc/init.cxx
+++ b/libbuild2/cc/init.cxx
@@ -244,8 +244,9 @@ namespace build2
//
load_module (rs, rs, "cc.core.guess", loc);
- // Configure.
+ // Configuration.
//
+ using config::lookup_config;
// Adjust module priority (compiler).
//
@@ -261,21 +262,21 @@ namespace build2
//
//
rs.assign ("cc.poptions") += cast_null<strings> (
- config::optional (rs, "config.cc.poptions"));
+ lookup_config (rs, "config.cc.poptions", nullptr));
rs.assign ("cc.coptions") += cast_null<strings> (
- config::optional (rs, "config.cc.coptions"));
+ lookup_config (rs, "config.cc.coptions", nullptr));
rs.assign ("cc.loptions") += cast_null<strings> (
- config::optional (rs, "config.cc.loptions"));
+ lookup_config (rs, "config.cc.loptions", nullptr));
rs.assign ("cc.aoptions") += cast_null<strings> (
- config::optional (rs, "config.cc.aoptions"));
+ lookup_config (rs, "config.cc.aoptions", nullptr));
rs.assign ("cc.libs") += cast_null<strings> (
- config::optional (rs, "config.cc.libs"));
+ lookup_config (rs, "config.cc.libs", nullptr));
- if (lookup l = config::omitted (rs, "config.cc.reprocess").first)
+ if (lookup l = lookup_config (rs, "config.cc.reprocess"))
rs.assign ("cc.reprocess") = *l;
// Load the bin.config module.
diff --git a/libbuild2/cc/module.cxx b/libbuild2/cc/module.cxx
index 138a11b..70cbc47 100644
--- a/libbuild2/cc/module.cxx
+++ b/libbuild2/cc/module.cxx
@@ -48,6 +48,10 @@ namespace build2
const variable& config_c_coptions (vp["config.cc.coptions"]);
const variable& config_c_loptions (vp["config.cc.loptions"]);
+ // Configuration.
+ //
+ using config::lookup_config;
+
// config.x
//
strings mode;
@@ -56,9 +60,9 @@ namespace build2
// default value every time will be a waste. So try without a default
// first.
//
- auto p (config::omitted (rs, config_x));
+ lookup l (lookup_config (new_config, rs, config_x));
- if (!p.first)
+ if (!l)
{
// If there is a config.x value for one of the modules that can hint
// us the toolchain, load it's .guess module. This makes sure that
@@ -113,17 +117,16 @@ namespace build2
// user changes the source of the pattern/mode, this one will get
// updated as well.
//
- p = config::required (
- rs,
- config_x,
- move (d),
- false,
- cc_loaded ? config::save_default_commented : 0);
+ l = lookup_config (new_config,
+ rs,
+ config_x,
+ move (d),
+ cc_loaded ? config::save_default_commented : 0);
}
// Split the value into the compiler path and mode.
//
- const strings& v (cast<strings> (*p.first));
+ const strings& v (cast<strings> (l));
path xc;
{
@@ -145,9 +148,9 @@ namespace build2
//
x_info = &build2::cc::guess (
x, x_lang, move (xc),
- cast_null<string> (config::omitted (rs, config_x_id).first),
- cast_null<string> (config::omitted (rs, config_x_version).first),
- cast_null<string> (config::omitted (rs, config_x_target).first),
+ cast_null<string> (lookup_config (rs, config_x_id)),
+ cast_null<string> (lookup_config (rs, config_x_version)),
+ cast_null<string> (lookup_config (rs, config_x_target)),
mode,
cast_null<strings> (rs[config_c_poptions]),
cast_null<strings> (rs[config_x_poptions]),
@@ -155,8 +158,6 @@ namespace build2
cast_null<strings> (rs[config_x_coptions]),
cast_null<strings> (rs[config_c_loptions]),
cast_null<strings> (rs[config_x_loptions]));
-
- new_ = p.second;
}
const compiler_info& xi (*x_info);
@@ -338,6 +339,10 @@ namespace build2
const compiler_info& xi (*x_info);
const target_triplet& tt (cast<target_triplet> (rs[x_target]));
+ // Configuration.
+ //
+ using config::lookup_config;
+
// config.x.{p,c,l}options
// config.x.libs
//
@@ -365,24 +370,24 @@ namespace build2
// x.coptions += <overriding options> # Note: '+='.
//
rs.assign (x_poptions) += cast_null<strings> (
- config::optional (rs, config_x_poptions));
+ lookup_config (rs, config_x_poptions, nullptr));
rs.assign (x_coptions) += cast_null<strings> (
- config::optional (rs, config_x_coptions));
+ lookup_config (rs, config_x_coptions, nullptr));
rs.assign (x_loptions) += cast_null<strings> (
- config::optional (rs, config_x_loptions));
+ lookup_config (rs, config_x_loptions, nullptr));
rs.assign (x_aoptions) += cast_null<strings> (
- config::optional (rs, config_x_aoptions));
+ lookup_config (rs, config_x_aoptions, nullptr));
rs.assign (x_libs) += cast_null<strings> (
- config::optional (rs, config_x_libs));
+ lookup_config (rs, config_x_libs, nullptr));
// config.x.std overrides x.std
//
{
- lookup l (config::omitted (rs, config_x_std).first);
+ lookup l (lookup_config (rs, config_x_std));
const string* v;
if (l.defined ())
@@ -407,7 +412,7 @@ namespace build2
//
if (x_translatable_headers != nullptr)
{
- lookup l (config::omitted (rs, *config_x_translatable_headers).first);
+ lookup l (lookup_config (rs, *config_x_translatable_headers));
// @@ MODHDR: if(modules) ?
//
@@ -533,10 +538,10 @@ namespace build2
}
#endif
- // If this is a new value (e.g., we are configuring), then print the
- // report at verbosity level 2 and up (-v).
+ // If this is a configuration with new values, then print the report
+ // at verbosity level 2 and up (-v).
//
- if (verb >= (new_ ? 2 : 3))
+ if (verb >= (new_config ? 2 : 3))
{
const strings& mode (cast<strings> (rs[x_mode]));
diff --git a/libbuild2/cc/module.hxx b/libbuild2/cc/module.hxx
index 4eca976..28e8d51 100644
--- a/libbuild2/cc/module.hxx
+++ b/libbuild2/cc/module.hxx
@@ -66,6 +66,8 @@ namespace build2
size_t sys_lib_dirs_extra;
size_t sys_inc_dirs_extra;
+ bool new_config = false; // See guess() and init() for details.
+
private:
// Defined in gcc.cxx.
//
@@ -82,9 +84,6 @@ namespace build2
pair<dir_paths, size_t>
msvc_library_search_dirs (const process_path&, scope&) const;
-
- private:
- bool new_; // See guess() and init() for details.
};
class LIBBUILD2_CC_SYMEXPORT module: public build2::module,
diff --git a/libbuild2/config/operation.cxx b/libbuild2/config/operation.cxx
index 07110e0..58f6aae 100644
--- a/libbuild2/config/operation.cxx
+++ b/libbuild2/config/operation.cxx
@@ -1219,13 +1219,13 @@ namespace build2
// configurations).
//
create_project (d,
- dir_path (), /* amalgamation */
+ dir_path (), /* amalgamation */
bmod,
- "", /* root_pre */
+ "", /* root_pre */
rmod,
- "", /* root_post */
- "config", /* config */
- true, /* buildfile */
+ "", /* root_post */
+ string ("config"), /* config_module */
+ true, /* buildfile */
"the create meta-operation");
save_config (ctx, d);
diff --git a/libbuild2/config/utility.cxx b/libbuild2/config/utility.cxx
index b9fc513..8ad150e 100644
--- a/libbuild2/config/utility.cxx
+++ b/libbuild2/config/utility.cxx
@@ -17,9 +17,9 @@ namespace build2
namespace config
{
pair<lookup, bool>
- omitted (scope& rs, const variable& var)
+ lookup_config_impl (scope& rs, const variable& var)
{
- // This is a stripped-down version of the required()'s twisted logic.
+ // This is a stripped-down version of the default value case.
pair<lookup, size_t> org (rs.find_original (var));
@@ -50,19 +50,8 @@ namespace build2
return pair<lookup, bool> (l, n);
}
- lookup
- optional (scope& rs, const variable& var)
- {
- save_variable (rs, var);
-
- auto l (rs[var]);
- return l.defined ()
- ? l
- : lookup (rs.assign (var), var, rs); // NULL.
- }
-
bool
- specified (scope& rs, const string& n)
+ specified_config (scope& rs, const string& n)
{
// Search all outer scopes for any value in this namespace.
//
diff --git a/libbuild2/config/utility.hxx b/libbuild2/config/utility.hxx
index 493d296..bf4728f 100644
--- a/libbuild2/config/utility.hxx
+++ b/libbuild2/config/utility.hxx
@@ -77,116 +77,184 @@ namespace build2
config_save_module (rs, module, prio);
}
- // Set, if necessary, a required config.* variable.
+ // Lookup a config.* variable value and, if the value is defined, mark it
+ // as saved.
+ //
+ // The second version in addition sets the new_value argument to true if
+ // the value is "new" (but not to false; so it can be used to accumulate
+ // the result from multiple calls). A value is considered new if it was
+ // set to the default value (inherited or not, including overrides). We
+ // also treat command line overrides (inherited or not) as new. In this
+ // case new means either the default value was inherited or it was
+ // overridden. This flag is usually used to test that the new value is
+ // valid, print the configuration report, etc.
+ //
+ // Unlike the rest of the lookup_config() versions, this one leaves the
+ // unspecified value as undefined rather than setting it to a default
+ // value. This can be useful when we don't have a default value or if we
+ // want the mentioning of the variable to be omitted from persistent
+ // storage (e.g., a config file) if the default value is used.
+ //
+ // @@ Should we pass flags and interpret save_null_omitted to treat null
+ // as undefined? Sounds logical.
+ //
+ lookup
+ lookup_config (scope& rs, const variable&);
+
+ lookup
+ lookup_config (bool& new_value, scope& rs, const variable&);
+
+ // Note that the variable is expected to have already been entered.
+ //
+ inline lookup
+ lookup_config (scope& rs, const string& var)
+ {
+ return lookup_config (rs, rs.ctx.var_pool[var]);
+ }
+
+ inline lookup
+ lookup_config (bool& new_value, scope& rs, const string& var)
+ {
+ return lookup_config (new_value, rs, rs.ctx.var_pool[var]);
+ }
+
+ // Lookup a config.* variable value and, if the value is undefined, set it
+ // to the default. Always mark it as saved.
+ //
+ // If the default value is nullptr, then the unspecified value is set to
+ // NULL which can be used to distinguish between the "not yet configured",
+ // "configured as unspecified", and "configures as empty" cases which can
+ // have different semantics if the value is merged into a non-config.*
+ // variable. This default value is traditionally used for "optional"
+ // values such as command line options.
+ //
+ // The value is returned as lookup (even though it is always defined
+ // though potentially as NULL) in order to pass along its location (could
+ // be used to detect inheritance, etc).
+ //
+ // The second version in addition sets the new_value argument as described
+ // above. Note, however, that if the save_default_commented flag is
+ // specified, then the default value is never considered "new" since for
+ // such variables absence of a value means it is the default value.
//
// 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 amalgamation),
// then its value is "overridden" to the default value on this root scope.
- // See save_variable() for more information on save_flags.
- //
- // Return the reference to the value as well as the indication of whether
- // the value is "new", that is, it was set to the default value (inherited
- // or not, including overrides). We also treat command line overrides
- // (inherited or not) as new. This flag is usually used to test that the
- // new value is valid, print report, etc. We return the value as lookup
- // (always defined) to pass along its location (could be used to detect
- // inheritance, etc).
- //
- // Note also that if save_flags has save_default_commented, then a default
- // value is never considered "new" since for such variables absence of a
- // value means the default value.
//
// @@ Should save_null_omitted be interpreted to treat null as undefined?
// Sounds logical.
//
template <typename T>
- pair<lookup, bool>
- required (scope& rs,
- const variable&,
- T&& default_value,
- bool override = false,
- uint64_t save_flags = 0);
+ lookup
+ lookup_config (scope& rs,
+ const variable&,
+ T&& default_value,
+ uint64_t save_flags = 0,
+ bool override = false);
- // Note that the variable is expected to have already been entered.
- //
template <typename T>
- inline pair<lookup, bool>
- required (scope& rs,
- const string& var,
- T&& default_value,
- bool override = false,
- uint64_t save_flags = 0)
+ lookup
+ lookup_config (bool& new_value,
+ scope& rs,
+ const variable&,
+ T&& default_value,
+ uint64_t save_flags = 0,
+ bool override = false);
+
+ inline lookup
+ lookup_config (scope& rs,
+ const variable& var,
+ const char* default_value,
+ uint64_t save_flags = 0,
+ bool override = false)
{
- return required (rs,
- rs.ctx.var_pool[var],
- std::forward<T> (default_value), // VC14
- override,
- save_flags);
+ return lookup_config (
+ rs, var, string (default_value), save_flags, override);
}
- inline pair<lookup, bool>
- required (scope& rs,
- const string& var,
- const char* default_value,
- bool override = false,
- uint64_t save_flags = 0)
+ inline lookup
+ lookup_config (bool& new_value,
+ scope& rs,
+ const variable& var,
+ const char* default_value,
+ uint64_t save_flags = 0,
+ bool override = false)
{
- return required (rs, var, string (default_value), override, save_flags);
+ return lookup_config (
+ new_value, rs, var, string (default_value), save_flags, override);
}
- // As above, but leave the unspecified value as undefined rather than
- // setting it to the default value.
- //
- // This can be useful when we don't have a default value but may figure
- // out some fallback. See config.bin.target for an example.
- //
- LIBBUILD2_SYMEXPORT pair<lookup, bool>
- omitted (scope& rs, const variable&);
-
// Note that the variable is expected to have already been entered.
//
- inline pair<lookup, bool>
- omitted (scope& rs, const string& var)
+ template <typename T>
+ inline lookup
+ lookup_config (scope& rs,
+ const string& var,
+ T&& default_value,
+ uint64_t save_flags = 0,
+ bool override = false)
{
- return omitted (rs, rs.ctx.var_pool[var]);
+ return lookup_config (rs,
+ rs.ctx.var_pool[var],
+ std::forward<T> (default_value), // VC14
+ save_flags,
+ override);
}
- // Set, if necessary, an optional config.* variable. In particular, an
- // unspecified variable is set to NULL which is used to distinguish
- // between the "configured as unspecified" and "not yet configured" cases.
- //
- // Return the value (as always defined lookup), which can be NULL.
- //
- // @@ Rename since clashes with the optional class template.
- //
- // @@ Does it make sense to return the new indicator here as well,
- // for consistency/generality.
- //
- LIBBUILD2_SYMEXPORT lookup
- optional (scope& rs, const variable&);
+ template <typename T>
+ inline lookup
+ lookup_config (bool& new_value,
+ scope& rs,
+ const string& var,
+ T&& default_value,
+ uint64_t save_flags = 0,
+ bool override = false)
+ {
+ return lookup_config (new_value,
+ rs,
+ rs.ctx.var_pool[var],
+ std::forward<T> (default_value), // VC14
+ save_flags,
+ override);
+ }
+
+ inline lookup
+ lookup_config (scope& rs,
+ const string& var,
+ const char* default_value,
+ uint64_t save_flags = 0,
+ bool override = false)
+ {
+ return lookup_config (
+ rs, var, string (default_value), save_flags, override);
+ }
- // Note that the variable is expected to have already been registered.
- //
inline lookup
- optional (scope& rs, const string& var)
+ lookup_config (bool& new_value,
+ scope& rs,
+ const string& var,
+ const char* default_value,
+ uint64_t save_flags = 0,
+ bool override = false)
{
- return optional (rs, rs.ctx.var_pool[var]);
+ return lookup_config (
+ new_value, rs, var, string (default_value), save_flags, override);
}
- // Check whether there are any variables specified from the config
+ // Check whether there are any variables specified from the config.<name>
// namespace. The idea is that we can check if there are any, say,
- // config.install.* values. If there are none, then we can assume
- // this functionality is not (yet) used and omit writing a whole
- // bunch of NULL config.install.* values to the config.build file.
- // We call it omitted/delayed configuration.
+ // config.install.* values. If there are none, then we can assume this
+ // functionality is not (yet) used and omit writing a whole bunch of NULL
+ // config.install.* values to the config.build file. We call this
+ // omitted/delayed configuration.
//
- // 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 (e.g., in order to avoid re-
- // running the tests, etc).
+ // Note that this function detects and ignores special config.* variables
+ // (such as config.*.configured) which may be used by a module to remember
+ // that it is unconfigured (e.g., in order to avoid re-running the tests,
+ // etc; see below).
//
LIBBUILD2_SYMEXPORT bool
- specified (scope& rs, const string& var);
+ specified_config (scope& rs, const string& var);
// Check if there is a false config.*.configured value. This mechanism can
// be used to "remember" that the module is left unconfigured in order to
@@ -204,6 +272,7 @@ namespace build2
}
}
+#include <libbuild2/config/utility.ixx>
#include <libbuild2/config/utility.txx>
#endif // LIBBUILD2_CONFIG_UTILITY_HXX
diff --git a/libbuild2/config/utility.ixx b/libbuild2/config/utility.ixx
new file mode 100644
index 0000000..79d5470
--- /dev/null
+++ b/libbuild2/config/utility.ixx
@@ -0,0 +1,62 @@
+// file : libbuild2/config/utility.ixx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+namespace build2
+{
+ namespace config
+ {
+ LIBBUILD2_SYMEXPORT pair<lookup, bool>
+ lookup_config_impl (scope&, const variable&);
+
+ template <typename T>
+ pair<lookup, bool>
+ lookup_config_impl (scope&, const variable&, T&&, uint64_t, bool);
+
+ inline lookup
+ lookup_config (scope& rs, const variable& var)
+ {
+ return lookup_config_impl (rs, var).first;
+ }
+
+ inline lookup
+ lookup_config (bool& new_value, scope& rs, const variable& var)
+ {
+ auto r (lookup_config_impl (rs, var));
+ new_value = new_value || r.second;
+ return r.first;
+ }
+
+ template <typename T>
+ inline lookup
+ lookup_config (scope& rs,
+ const variable& var,
+ T&& def_val,
+ uint64_t sflags,
+ bool def_ovr)
+ {
+ return lookup_config_impl (rs,
+ var,
+ std::forward<T> (def_val), // VC14
+ sflags,
+ def_ovr).first;
+ }
+
+ template <typename T>
+ inline lookup
+ lookup_config (bool& new_value,
+ scope& rs,
+ const variable& var,
+ T&& def_val,
+ uint64_t sflags,
+ bool def_ovr)
+ {
+ auto r (lookup_config_impl (rs,
+ var,
+ std::forward<T> (def_val), // VC14
+ sflags,
+ def_ovr));
+ new_value = new_value || r.second;
+ return r.first;
+ }
+ }
+}
diff --git a/libbuild2/config/utility.txx b/libbuild2/config/utility.txx
index f52df8d..ae40ba7 100644
--- a/libbuild2/config/utility.txx
+++ b/libbuild2/config/utility.txx
@@ -7,13 +7,14 @@ namespace build2
{
template <typename T>
pair<lookup, bool>
- required (scope& rs,
- const variable& var,
- T&& def_val,
- bool def_ovr,
- uint64_t sflags)
+ lookup_config_impl (scope& rs,
+ const variable& var,
+ T&& def_val,
+ uint64_t sflags,
+ bool def_ovr)
{
- // Note: see also omitted() if changing anything here.
+ // Note: see also the other lookup_config() implementation if changing
+ // anything here.
save_variable (rs, var, sflags);
@@ -28,6 +29,32 @@ namespace build2
// are going to do is first ignore overrides and perform the normal
// logic on the original. Then we apply the overrides on the result.
//
+ // Note that this is not exactly the "lookup and set to default if
+ // undefined" semantics in case there is no original but there is an
+ // override. In this case we will set original to default and then apply
+ // the override, which could be append or non-recursive (as mentioned
+ // above). It does, however, feel like taking into account the default
+ // in such cases is the correct semantics since append is meant as an
+ // addition to something existing and non-recursive override is only
+ // meant to override at the level it was specified. Though it won't be
+ // surprising at all if we end up with some counter-intuitive behavior
+ // here.
+ //
+ // Actually, the above analysis is not the full picture: if we have one
+ // of those overrides (append, non-recursive) in the outer project, then
+ // the lookup_config() call at that level will set the corresponding
+ // variable on that scope and we will see it as "original-defined" from
+ // our scope. Of course if there is no call to lookup_config() for this
+ // variable in the outer scope, then we won't see anything but then our
+ // behavior in this case seems correct: since that value is not part of
+ // the configuration (and won't be saved), then we should stick to our
+ // default. In other words, we should only inherit the value if it is
+ // actually recognized as a configuration value by the outer project.
+ //
+ // So, to summarize the current understanding, while our semantics is
+ // not exactly "lookup and set to default if undefined" in some obscure
+ // corner cases, it seem to be the correct/preferred one.
+ //
if (!l.defined () || (def_ovr && !l.belongs (rs)))
{
value& v (rs.assign (var) = std::forward<T> (def_val)); // VC14
diff --git a/libbuild2/dist/init.cxx b/libbuild2/dist/init.cxx
index ff2d757..8eaafa2 100644
--- a/libbuild2/dist/init.cxx
+++ b/libbuild2/dist/init.cxx
@@ -111,7 +111,10 @@ namespace build2
// must be explicitly specified or we will complain if and when
// we try to dist.
//
- bool s (config::specified (rs, "dist"));
+ using config::lookup_config;
+ using config::specified_config;
+
+ bool s (specified_config (rs, "dist"));
// Adjust module priority so that the config.dist.* values are saved at
// the end of config.build.
@@ -126,7 +129,7 @@ namespace build2
if (s)
{
- if (lookup l = config::optional (rs, "config.dist.root"))
+ if (lookup l = lookup_config (rs, "config.dist.root", nullptr))
v = cast<dir_path> (l); // Strip abs_dir_path.
}
}
@@ -138,9 +141,9 @@ namespace build2
if (s)
{
- if (lookup l = config::required (rs,
- "config.dist.cmd",
- path ("install")).first)
+ if (lookup l = lookup_config (rs,
+ "config.dist.cmd",
+ path ("install")))
v = run_search (cast<path> (l), true);
}
}
@@ -154,10 +157,10 @@ namespace build2
if (s)
{
- if (lookup l = config::optional (rs, "config.dist.archives"))
+ if (lookup l = lookup_config (rs, "config.dist.archives", nullptr))
a = *l;
- if (lookup l = config::optional (rs, "config.dist.checksums"))
+ if (lookup l = lookup_config (rs, "config.dist.checksums", nullptr))
{
c = *l;
@@ -173,7 +176,7 @@ namespace build2
//
// Omit it from the configuration unless specified.
//
- config::omitted (rs, "config.dist.uncommitted");
+ lookup_config (rs, "config.dist.uncommitted");
return true;
}
diff --git a/libbuild2/file.hxx b/libbuild2/file.hxx
index d3c6787..2ca72b1 100644
--- a/libbuild2/file.hxx
+++ b/libbuild2/file.hxx
@@ -265,16 +265,17 @@ namespace build2
// Create a build system project in the specified directory.
//
LIBBUILD2_SYMEXPORT void
- create_project (const dir_path&,
- const optional<dir_path>& amalgamation,
- const strings& boot_modules, // Bootstrap modules.
- const string& root_pre, // Extra root.build text.
- const strings& root_modules, // Root modules.
- const string& root_post, // Extra root.build text.
- const optional<string>& config, // Config module to load.
- bool buildfile, // Create root buildfile.
- const char* who, // Who is creating it.
- uint16_t verbosity = 1); // Diagnostic verbosity.
+ create_project (
+ const dir_path&,
+ const optional<dir_path>& amalgamation,
+ const strings& boot_modules, // Bootstrap modules.
+ const string& root_pre, // Extra root.build text.
+ const strings& root_modules, // Root modules.
+ const string& root_post, // Extra root.build text.
+ const optional<string>& config_module, // Config module to load.
+ bool buildfile, // Create root buildfile.
+ const char* who, // Who is creating it.
+ uint16_t verbosity = 1); // Diagnostic verbosity.
}
#include <libbuild2/file.ixx>
diff --git a/libbuild2/install/init.cxx b/libbuild2/install/init.cxx
index 34a5625..06e5d3a 100644
--- a/libbuild2/install/init.cxx
+++ b/libbuild2/install/init.cxx
@@ -63,11 +63,13 @@ namespace build2
vn += var;
const variable& vr (rs.var_pool ().insert<CT> (move (vn), true));
+ using config::lookup_config;
+
l = dv != nullptr
- ? config::required (rs, vr, *dv, override).first
+ ? lookup_config (rs, vr, *dv, 0 /* save_flags */, override)
: (global
- ? config::optional (rs, vr)
- : config::omitted (rs, vr).first);
+ ? lookup_config (rs, vr, nullptr)
+ : lookup_config (rs, vr));
}
if (global)
@@ -237,8 +239,10 @@ namespace build2
//
{
using build2::path;
+ using config::lookup_config;
+ using config::specified_config;
- bool s (config::specified (rs, "install"));
+ bool s (specified_config (rs, "install"));
// Adjust module priority so that the (numerous) config.install.*
// values are saved at the end of config.build.
@@ -280,7 +284,7 @@ namespace build2
if (s)
{
- if (lookup l = config::optional (rs, cvar))
+ if (lookup l = lookup_config (rs, cvar, nullptr))
v = cast<dir_path> (l); // Strip abs_dir_path.
}
}
diff --git a/libbuild2/test/init.cxx b/libbuild2/test/init.cxx
index c0d0331..a21e8f2 100644
--- a/libbuild2/test/init.cxx
+++ b/libbuild2/test/init.cxx
@@ -140,8 +140,9 @@ namespace build2
auto& m (extra.module_as<module> ());
- // Configure.
+ // Configuration.
//
+ using config::lookup_config;
// Adjust module priority so that the config.test.* values are saved at
// the end of config.build.
@@ -150,7 +151,7 @@ namespace build2
// config.test
//
- if (lookup l = config::omitted (rs, m.config_test).first)
+ if (lookup l = lookup_config (rs, m.config_test))
{
// Figure out which root scope it came from.
//
@@ -166,7 +167,7 @@ namespace build2
// config.test.output
//
- if (lookup l = config::omitted (rs, m.config_test_output).first)
+ if (lookup l = lookup_config (rs, m.config_test_output))
{
const name_pair& p (cast<name_pair> (l));