aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/b-options.cxx3
-rw-r--r--build2/b.cli3
-rw-r--r--build2/b.cxx47
3 files changed, 47 insertions, 6 deletions
diff --git a/build2/b-options.cxx b/build2/b-options.cxx
index 60eeec6..2bc65b3 100644
--- a/build2/b-options.cxx
+++ b/build2/b-options.cxx
@@ -1529,7 +1529,8 @@ namespace build2
<< ::std::endl
<< "The default options files for the build system driver are called \033[1mb.options\033[0m and" << ::std::endl
<< "are searched for in the \033[1m.build2/\033[0m subdirectory of the home directory and in the" << ::std::endl
- << "system directory (for example, \033[1m/etc/build2/\033[0m) if configured." << ::std::endl
+ << "system directory (for example, \033[1m/etc/build2/\033[0m) if configured. Note that besides" << ::std::endl
+ << "options these files can also contain global variable overrides." << ::std::endl
<< ::std::endl
<< "Once the search is complete, the files are loaded in the reverse order, that" << ::std::endl
<< "is, beginning from the system directory (if any), followed by the home" << ::std::endl
diff --git a/build2/b.cli b/build2/b.cli
index 7566418..31247f9 100644
--- a/build2/b.cli
+++ b/build2/b.cli
@@ -659,7 +659,8 @@ namespace build2
The default options files for the build system driver are called
\cb{b.options} and are searched for in the \cb{.build2/} subdirectory of the
home directory and in the system directory (for example, \cb{/etc/build2/})
- if configured.
+ if configured. Note that besides options these files can also contain global
+ variable overrides.
Once the search is complete, the files are loaded in the reverse order, that
is, beginning from the system directory (if any), followed by the home
diff --git a/build2/b.cxx b/build2/b.cxx
index 4e9ebf7..66b217d 100644
--- a/build2/b.cxx
+++ b/build2/b.cxx
@@ -342,7 +342,7 @@ main (int argc, char* argv[])
}
// Merge all the individual buildspec arguments into a single string.
- // We wse newlines to separate arguments so that line numbers in
+ // We use newlines to separate arguments so that line numbers in
// diagnostics signify argument numbers. Clever, huh?
//
if (argn != 0)
@@ -381,7 +381,9 @@ main (int argc, char* argv[])
if (ops.default_options_specified ())
extra = ops.default_options ();
- ops = merge_default_options (
+ // Load default options files.
+ //
+ default_options<options> def_ops (
load_default_options<options,
cl::argv_file_scanner,
cl::unknown_mode> (
@@ -400,8 +402,45 @@ main (int argc, char* argv[])
else
trace << "loading " << (r ? "remote " : "local ") << f;
}
- }),
- ops);
+ },
+ true /* args */));
+
+ // Merge the default and command line options.
+ //
+ ops = merge_default_options (def_ops, ops);
+
+ // Merge the default and command line global overrides.
+ //
+ // Note that the "broken down" variable assignments occupying a single
+ // line are naturally supported.
+ //
+ cmd_vars =
+ merge_default_arguments (
+ def_ops,
+ cmd_vars,
+ [] (const default_options_entry<options>& e, const strings&)
+ {
+ path_name fn (e.file);
+
+ // Verify that all arguments are global overrides.
+ //
+ for (const string& a: e.arguments)
+ {
+ size_t p (a.find ('=', 1));
+ if (p == string::npos || a[0] != '!')
+ {
+ diag_record dr (fail (fn));
+ dr << "expected option or global variable override instead "
+ << "of '" << a << "'";
+
+ if (p != string::npos)
+ dr << info << "prefix variable assignment with '!'";
+ }
+
+ if (p == 1 || (p == 2 && a[1] == '+')) // '!=' or '!+=' ?
+ fail (fn) << "missing variable name in '" << a << "'";
+ }
+ });
}
catch (const pair<path, system_error>& e)
{