aboutsummaryrefslogtreecommitdiff
path: root/build2
diff options
context:
space:
mode:
Diffstat (limited to 'build2')
-rw-r--r--build2/b-options.cxx1665
-rw-r--r--build2/b-options.hxx690
-rw-r--r--build2/b-options.ixx561
-rw-r--r--build2/b.cli749
-rw-r--r--build2/b.cxx1285
-rw-r--r--build2/buildfile42
-rw-r--r--build2/cli/init.cxx291
-rw-r--r--build2/cli/init.hxx29
-rw-r--r--build2/cli/module.hxx30
-rw-r--r--build2/cli/rule.cxx336
-rw-r--r--build2/cli/rule.hxx43
-rw-r--r--build2/cli/target.cxx75
-rw-r--r--build2/cli/target.hxx54
-rw-r--r--build2/types-parsers.cxx50
-rw-r--r--build2/types-parsers.hxx43
15 files changed, 590 insertions, 5353 deletions
diff --git a/build2/b-options.cxx b/build2/b-options.cxx
deleted file mode 100644
index 096aebc..0000000
--- a/build2/b-options.cxx
+++ /dev/null
@@ -1,1665 +0,0 @@
-// -*- C++ -*-
-//
-// This file was generated by CLI, a command line interface
-// compiler for C++.
-//
-
-// Begin prologue.
-//
-#include <build2/types-parsers.hxx>
-//
-// End prologue.
-
-#include <build2/b-options.hxx>
-
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-#include <ostream>
-#include <sstream>
-#include <cstring>
-#include <fstream>
-
-namespace build2
-{
- namespace cl
- {
- // unknown_option
- //
- unknown_option::
- ~unknown_option () throw ()
- {
- }
-
- void unknown_option::
- print (::std::ostream& os) const
- {
- os << "unknown option '" << option ().c_str () << "'";
- }
-
- const char* unknown_option::
- what () const throw ()
- {
- return "unknown option";
- }
-
- // unknown_argument
- //
- unknown_argument::
- ~unknown_argument () throw ()
- {
- }
-
- void unknown_argument::
- print (::std::ostream& os) const
- {
- os << "unknown argument '" << argument ().c_str () << "'";
- }
-
- const char* unknown_argument::
- what () const throw ()
- {
- return "unknown argument";
- }
-
- // missing_value
- //
- missing_value::
- ~missing_value () throw ()
- {
- }
-
- void missing_value::
- print (::std::ostream& os) const
- {
- os << "missing value for option '" << option ().c_str () << "'";
- }
-
- const char* missing_value::
- what () const throw ()
- {
- return "missing option value";
- }
-
- // invalid_value
- //
- invalid_value::
- ~invalid_value () throw ()
- {
- }
-
- void invalid_value::
- print (::std::ostream& os) const
- {
- os << "invalid value '" << value ().c_str () << "' for option '"
- << option ().c_str () << "'";
-
- if (!message ().empty ())
- os << ": " << message ().c_str ();
- }
-
- const char* invalid_value::
- what () const throw ()
- {
- return "invalid option value";
- }
-
- // eos_reached
- //
- void eos_reached::
- print (::std::ostream& os) const
- {
- os << what ();
- }
-
- const char* eos_reached::
- what () const throw ()
- {
- return "end of argument stream reached";
- }
-
- // file_io_failure
- //
- file_io_failure::
- ~file_io_failure () throw ()
- {
- }
-
- void file_io_failure::
- print (::std::ostream& os) const
- {
- os << "unable to open file '" << file ().c_str () << "' or read failure";
- }
-
- const char* file_io_failure::
- what () const throw ()
- {
- return "unable to open file or read failure";
- }
-
- // unmatched_quote
- //
- unmatched_quote::
- ~unmatched_quote () throw ()
- {
- }
-
- void unmatched_quote::
- print (::std::ostream& os) const
- {
- os << "unmatched quote in argument '" << argument ().c_str () << "'";
- }
-
- const char* unmatched_quote::
- what () const throw ()
- {
- return "unmatched quote";
- }
-
- // scanner
- //
- scanner::
- ~scanner ()
- {
- }
-
- // argv_scanner
- //
- bool argv_scanner::
- more ()
- {
- return i_ < argc_;
- }
-
- const char* argv_scanner::
- peek ()
- {
- if (i_ < argc_)
- return argv_[i_];
- else
- throw eos_reached ();
- }
-
- const char* argv_scanner::
- next ()
- {
- if (i_ < argc_)
- {
- const char* r (argv_[i_]);
-
- if (erase_)
- {
- for (int i (i_ + 1); i < argc_; ++i)
- argv_[i - 1] = argv_[i];
-
- --argc_;
- argv_[argc_] = 0;
- }
- else
- ++i_;
-
- return r;
- }
- else
- throw eos_reached ();
- }
-
- void argv_scanner::
- skip ()
- {
- if (i_ < argc_)
- ++i_;
- else
- throw eos_reached ();
- }
-
- // argv_file_scanner
- //
- int argv_file_scanner::zero_argc_ = 0;
- std::string argv_file_scanner::empty_string_;
-
- bool argv_file_scanner::
- more ()
- {
- if (!args_.empty ())
- return true;
-
- while (base::more ())
- {
- // See if the next argument is the file option.
- //
- const char* a (base::peek ());
- const option_info* oi = 0;
- const char* ov = 0;
-
- if (!skip_)
- {
- if ((oi = find (a)) != 0)
- {
- base::next ();
-
- if (!base::more ())
- throw missing_value (a);
-
- ov = base::next ();
- }
- else if (std::strncmp (a, "-", 1) == 0)
- {
- if ((ov = std::strchr (a, '=')) != 0)
- {
- std::string o (a, 0, ov - a);
- if ((oi = find (o.c_str ())) != 0)
- {
- base::next ();
- ++ov;
- }
- }
- }
- }
-
- if (oi != 0)
- {
- if (oi->search_func != 0)
- {
- std::string f (oi->search_func (ov, oi->arg));
-
- if (!f.empty ())
- load (f);
- }
- else
- load (ov);
-
- if (!args_.empty ())
- return true;
- }
- else
- {
- if (!skip_)
- skip_ = (std::strcmp (a, "--") == 0);
-
- return true;
- }
- }
-
- return false;
- }
-
- const char* argv_file_scanner::
- peek ()
- {
- if (!more ())
- throw eos_reached ();
-
- return args_.empty () ? base::peek () : args_.front ().value.c_str ();
- }
-
- const std::string& argv_file_scanner::
- peek_file ()
- {
- if (!more ())
- throw eos_reached ();
-
- return args_.empty () ? empty_string_ : *args_.front ().file;
- }
-
- std::size_t argv_file_scanner::
- peek_line ()
- {
- if (!more ())
- throw eos_reached ();
-
- return args_.empty () ? 0 : args_.front ().line;
- }
-
- const char* argv_file_scanner::
- next ()
- {
- if (!more ())
- throw eos_reached ();
-
- if (args_.empty ())
- return base::next ();
- else
- {
- hold_[i_ == 0 ? ++i_ : --i_].swap (args_.front ().value);
- args_.pop_front ();
- return hold_[i_].c_str ();
- }
- }
-
- void argv_file_scanner::
- skip ()
- {
- if (!more ())
- throw eos_reached ();
-
- if (args_.empty ())
- return base::skip ();
- else
- args_.pop_front ();
- }
-
- const argv_file_scanner::option_info* argv_file_scanner::
- find (const char* a) const
- {
- for (std::size_t i (0); i < options_count_; ++i)
- if (std::strcmp (a, options_[i].option) == 0)
- return &options_[i];
-
- return 0;
- }
-
- void argv_file_scanner::
- load (const std::string& file)
- {
- using namespace std;
-
- ifstream is (file.c_str ());
-
- if (!is.is_open ())
- throw file_io_failure (file);
-
- files_.push_back (file);
-
- arg a;
- a.file = &*files_.rbegin ();
-
- for (a.line = 1; !is.eof (); ++a.line)
- {
- string line;
- getline (is, line);
-
- if (is.fail () && !is.eof ())
- throw file_io_failure (file);
-
- string::size_type n (line.size ());
-
- // Trim the line from leading and trailing whitespaces.
- //
- if (n != 0)
- {
- const char* f (line.c_str ());
- const char* l (f + n);
-
- const char* of (f);
- while (f < l && (*f == ' ' || *f == '\t' || *f == '\r'))
- ++f;
-
- --l;
-
- const char* ol (l);
- while (l > f && (*l == ' ' || *l == '\t' || *l == '\r'))
- --l;
-
- if (f != of || l != ol)
- line = f <= l ? string (f, l - f + 1) : string ();
- }
-
- // Ignore empty lines, those that start with #.
- //
- if (line.empty () || line[0] == '#')
- continue;
-
- string::size_type p (string::npos);
- if (line.compare (0, 1, "-") == 0)
- {
- p = line.find (' ');
-
- string::size_type q (line.find ('='));
- if (q != string::npos && q < p)
- p = q;
- }
-
- string s1;
- if (p != string::npos)
- {
- s1.assign (line, 0, p);
-
- // Skip leading whitespaces in the argument.
- //
- if (line[p] == '=')
- ++p;
- else
- {
- n = line.size ();
- for (++p; p < n; ++p)
- {
- char c (line[p]);
- if (c != ' ' && c != '\t' && c != '\r')
- break;
- }
- }
- }
- else if (!skip_)
- skip_ = (line == "--");
-
- string s2 (line, p != string::npos ? p : 0);
-
- // If the string (which is an option value or argument) is
- // wrapped in quotes, remove them.
- //
- n = s2.size ();
- char cf (s2[0]), cl (s2[n - 1]);
-
- if (cf == '"' || cf == '\'' || cl == '"' || cl == '\'')
- {
- if (n == 1 || cf != cl)
- throw unmatched_quote (s2);
-
- s2 = string (s2, 1, n - 2);
- }
-
- if (!s1.empty ())
- {
- // See if this is another file option.
- //
- const option_info* oi;
- if (!skip_ && (oi = find (s1.c_str ())))
- {
- if (s2.empty ())
- throw missing_value (oi->option);
-
- if (oi->search_func != 0)
- {
- string f (oi->search_func (s2.c_str (), oi->arg));
- if (!f.empty ())
- load (f);
- }
- else
- {
- // If the path of the file being parsed is not simple and the
- // path of the file that needs to be loaded is relative, then
- // complete the latter using the former as a base.
- //
-#ifndef _WIN32
- string::size_type p (file.find_last_of ('/'));
- bool c (p != string::npos && s2[0] != '/');
-#else
- string::size_type p (file.find_last_of ("/\\"));
- bool c (p != string::npos && s2[1] != ':');
-#endif
- if (c)
- s2.insert (0, file, 0, p + 1);
-
- load (s2);
- }
-
- continue;
- }
-
- a.value = s1;
- args_.push_back (a);
- }
-
- a.value = s2;
- args_.push_back (a);
- }
- }
-
- template <typename X>
- struct parser
- {
- static void
- parse (X& x, bool& xs, scanner& s)
- {
- using namespace std;
-
- const char* o (s.next ());
- if (s.more ())
- {
- string v (s.next ());
- istringstream is (v);
- if (!(is >> x && is.peek () == istringstream::traits_type::eof ()))
- throw invalid_value (o, v);
- }
- else
- throw missing_value (o);
-
- xs = true;
- }
-
- static void
- merge (X& b, const X& a)
- {
- b = a;
- }
- };
-
- template <>
- struct parser<bool>
- {
- static void
- parse (bool& x, scanner& s)
- {
- s.next ();
- x = true;
- }
-
- static void
- merge (bool& b, const bool&)
- {
- b = true;
- }
- };
-
- template <>
- struct parser<std::string>
- {
- static void
- parse (std::string& x, bool& xs, scanner& s)
- {
- const char* o (s.next ());
-
- if (s.more ())
- x = s.next ();
- else
- throw missing_value (o);
-
- xs = true;
- }
-
- static void
- merge (std::string& b, const std::string& a)
- {
- b = a;
- }
- };
-
- template <typename X>
- struct parser<std::vector<X> >
- {
- static void
- parse (std::vector<X>& c, bool& xs, scanner& s)
- {
- X x;
- bool dummy;
- parser<X>::parse (x, dummy, s);
- c.push_back (x);
- xs = true;
- }
-
- static void
- merge (std::vector<X>& b, const std::vector<X>& a)
- {
- b.insert (b.end (), a.begin (), a.end ());
- }
- };
-
- template <typename X, typename C>
- struct parser<std::set<X, C> >
- {
- static void
- parse (std::set<X, C>& c, bool& xs, scanner& s)
- {
- X x;
- bool dummy;
- parser<X>::parse (x, dummy, s);
- c.insert (x);
- xs = true;
- }
-
- static void
- merge (std::set<X, C>& b, const std::set<X, C>& a)
- {
- b.insert (a.begin (), a.end ());
- }
- };
-
- template <typename K, typename V, typename C>
- struct parser<std::map<K, V, C> >
- {
- static void
- parse (std::map<K, V, C>& m, bool& xs, scanner& s)
- {
- const char* o (s.next ());
-
- if (s.more ())
- {
- std::string ov (s.next ());
- std::string::size_type p = ov.find ('=');
-
- K k = K ();
- V v = V ();
- std::string kstr (ov, 0, p);
- std::string vstr (ov, (p != std::string::npos ? p + 1 : ov.size ()));
-
- int ac (2);
- char* av[] =
- {
- const_cast<char*> (o),
- 0
- };
-
- bool dummy;
- if (!kstr.empty ())
- {
- av[1] = const_cast<char*> (kstr.c_str ());
- argv_scanner s (0, ac, av);
- parser<K>::parse (k, dummy, s);
- }
-
- if (!vstr.empty ())
- {
- av[1] = const_cast<char*> (vstr.c_str ());
- argv_scanner s (0, ac, av);
- parser<V>::parse (v, dummy, s);
- }
-
- m[k] = v;
- }
- else
- throw missing_value (o);
-
- xs = true;
- }
-
- static void
- merge (std::map<K, V, C>& b, const std::map<K, V, C>& a)
- {
- for (typename std::map<K, V, C>::const_iterator i (a.begin ());
- i != a.end ();
- ++i)
- b[i->first] = i->second;
- }
- };
-
- template <typename X, typename T, T X::*M>
- void
- thunk (X& x, scanner& s)
- {
- parser<T>::parse (x.*M, s);
- }
-
- template <typename X, typename T, T X::*M, bool X::*S>
- void
- thunk (X& x, scanner& s)
- {
- parser<T>::parse (x.*M, x.*S, s);
- }
- }
-}
-
-#include <map>
-#include <cstring>
-
-namespace build2
-{
- // options
- //
-
- options::
- options ()
- : build2_metadata_ (),
- build2_metadata_specified_ (false),
- v_ (),
- V_ (),
- quiet_ (),
- silent_ (),
- verbose_ (1),
- verbose_specified_ (false),
- stat_ (),
- dump_ (),
- dump_specified_ (false),
- progress_ (),
- no_progress_ (),
- jobs_ (),
- jobs_specified_ (false),
- max_jobs_ (),
- max_jobs_specified_ (false),
- queue_depth_ (4),
- queue_depth_specified_ (false),
- file_cache_ (),
- file_cache_specified_ (false),
- max_stack_ (),
- max_stack_specified_ (false),
- serial_stop_ (),
- dry_run_ (),
- match_only_ (),
- no_external_modules_ (),
- structured_result_ (),
- mtime_check_ (),
- no_mtime_check_ (),
- no_column_ (),
- no_line_ (),
- buildfile_ (),
- buildfile_specified_ (false),
- config_guess_ (),
- config_guess_specified_ (false),
- config_sub_ (),
- config_sub_specified_ (false),
- pager_ (),
- pager_specified_ (false),
- pager_option_ (),
- pager_option_specified_ (false),
- options_file_ (),
- options_file_specified_ (false),
- default_options_ (),
- default_options_specified_ (false),
- no_default_options_ (),
- help_ (),
- version_ ()
- {
- }
-
- bool options::
- parse (int& argc,
- char** argv,
- bool erase,
- ::build2::cl::unknown_mode opt,
- ::build2::cl::unknown_mode arg)
- {
- ::build2::cl::argv_scanner s (argc, argv, erase);
- bool r = _parse (s, opt, arg);
- return r;
- }
-
- bool options::
- parse (int start,
- int& argc,
- char** argv,
- bool erase,
- ::build2::cl::unknown_mode opt,
- ::build2::cl::unknown_mode arg)
- {
- ::build2::cl::argv_scanner s (start, argc, argv, erase);
- bool r = _parse (s, opt, arg);
- return r;
- }
-
- bool options::
- parse (int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::cl::unknown_mode opt,
- ::build2::cl::unknown_mode arg)
- {
- ::build2::cl::argv_scanner s (argc, argv, erase);
- bool r = _parse (s, opt, arg);
- end = s.end ();
- return r;
- }
-
- bool options::
- parse (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase,
- ::build2::cl::unknown_mode opt,
- ::build2::cl::unknown_mode arg)
- {
- ::build2::cl::argv_scanner s (start, argc, argv, erase);
- bool r = _parse (s, opt, arg);
- end = s.end ();
- return r;
- }
-
- bool options::
- parse (::build2::cl::scanner& s,
- ::build2::cl::unknown_mode opt,
- ::build2::cl::unknown_mode arg)
- {
- bool r = _parse (s, opt, arg);
- return r;
- }
-
- void options::
- merge (const options& a)
- {
- CLI_POTENTIALLY_UNUSED (a);
-
- if (a.build2_metadata_specified_)
- {
- ::build2::cl::parser< uint64_t>::merge (
- this->build2_metadata_, a.build2_metadata_);
- this->build2_metadata_specified_ = true;
- }
-
- if (a.v_)
- {
- ::build2::cl::parser< bool>::merge (
- this->v_, a.v_);
- }
-
- if (a.V_)
- {
- ::build2::cl::parser< bool>::merge (
- this->V_, a.V_);
- }
-
- if (a.quiet_)
- {
- ::build2::cl::parser< bool>::merge (
- this->quiet_, a.quiet_);
- }
-
- if (a.silent_)
- {
- ::build2::cl::parser< bool>::merge (
- this->silent_, a.silent_);
- }
-
- if (a.verbose_specified_)
- {
- ::build2::cl::parser< uint16_t>::merge (
- this->verbose_, a.verbose_);
- this->verbose_specified_ = true;
- }
-
- if (a.stat_)
- {
- ::build2::cl::parser< bool>::merge (
- this->stat_, a.stat_);
- }
-
- if (a.dump_specified_)
- {
- ::build2::cl::parser< std::set<string>>::merge (
- this->dump_, a.dump_);
- this->dump_specified_ = true;
- }
-
- if (a.progress_)
- {
- ::build2::cl::parser< bool>::merge (
- this->progress_, a.progress_);
- }
-
- if (a.no_progress_)
- {
- ::build2::cl::parser< bool>::merge (
- this->no_progress_, a.no_progress_);
- }
-
- if (a.jobs_specified_)
- {
- ::build2::cl::parser< size_t>::merge (
- this->jobs_, a.jobs_);
- this->jobs_specified_ = true;
- }
-
- if (a.max_jobs_specified_)
- {
- ::build2::cl::parser< size_t>::merge (
- this->max_jobs_, a.max_jobs_);
- this->max_jobs_specified_ = true;
- }
-
- if (a.queue_depth_specified_)
- {
- ::build2::cl::parser< size_t>::merge (
- this->queue_depth_, a.queue_depth_);
- this->queue_depth_specified_ = true;
- }
-
- if (a.file_cache_specified_)
- {
- ::build2::cl::parser< string>::merge (
- this->file_cache_, a.file_cache_);
- this->file_cache_specified_ = true;
- }
-
- if (a.max_stack_specified_)
- {
- ::build2::cl::parser< size_t>::merge (
- this->max_stack_, a.max_stack_);
- this->max_stack_specified_ = true;
- }
-
- if (a.serial_stop_)
- {
- ::build2::cl::parser< bool>::merge (
- this->serial_stop_, a.serial_stop_);
- }
-
- if (a.dry_run_)
- {
- ::build2::cl::parser< bool>::merge (
- this->dry_run_, a.dry_run_);
- }
-
- if (a.match_only_)
- {
- ::build2::cl::parser< bool>::merge (
- this->match_only_, a.match_only_);
- }
-
- if (a.no_external_modules_)
- {
- ::build2::cl::parser< bool>::merge (
- this->no_external_modules_, a.no_external_modules_);
- }
-
- if (a.structured_result_)
- {
- ::build2::cl::parser< bool>::merge (
- this->structured_result_, a.structured_result_);
- }
-
- if (a.mtime_check_)
- {
- ::build2::cl::parser< bool>::merge (
- this->mtime_check_, a.mtime_check_);
- }
-
- if (a.no_mtime_check_)
- {
- ::build2::cl::parser< bool>::merge (
- this->no_mtime_check_, a.no_mtime_check_);
- }
-
- if (a.no_column_)
- {
- ::build2::cl::parser< bool>::merge (
- this->no_column_, a.no_column_);
- }
-
- if (a.no_line_)
- {
- ::build2::cl::parser< bool>::merge (
- this->no_line_, a.no_line_);
- }
-
- if (a.buildfile_specified_)
- {
- ::build2::cl::parser< path>::merge (
- this->buildfile_, a.buildfile_);
- this->buildfile_specified_ = true;
- }
-
- if (a.config_guess_specified_)
- {
- ::build2::cl::parser< path>::merge (
- this->config_guess_, a.config_guess_);
- this->config_guess_specified_ = true;
- }
-
- if (a.config_sub_specified_)
- {
- ::build2::cl::parser< path>::merge (
- this->config_sub_, a.config_sub_);
- this->config_sub_specified_ = true;
- }
-
- if (a.pager_specified_)
- {
- ::build2::cl::parser< string>::merge (
- this->pager_, a.pager_);
- this->pager_specified_ = true;
- }
-
- if (a.pager_option_specified_)
- {
- ::build2::cl::parser< strings>::merge (
- this->pager_option_, a.pager_option_);
- this->pager_option_specified_ = true;
- }
-
- if (a.options_file_specified_)
- {
- ::build2::cl::parser< string>::merge (
- this->options_file_, a.options_file_);
- this->options_file_specified_ = true;
- }
-
- if (a.default_options_specified_)
- {
- ::build2::cl::parser< dir_path>::merge (
- this->default_options_, a.default_options_);
- this->default_options_specified_ = true;
- }
-
- if (a.no_default_options_)
- {
- ::build2::cl::parser< bool>::merge (
- this->no_default_options_, a.no_default_options_);
- }
-
- if (a.help_)
- {
- ::build2::cl::parser< bool>::merge (
- this->help_, a.help_);
- }
-
- if (a.version_)
- {
- ::build2::cl::parser< bool>::merge (
- this->version_, a.version_);
- }
- }
-
- ::build2::cl::usage_para options::
- print_usage (::std::ostream& os, ::build2::cl::usage_para p)
- {
- CLI_POTENTIALLY_UNUSED (os);
-
- if (p != ::build2::cl::usage_para::none)
- os << ::std::endl;
-
- os << "\033[1mOPTIONS\033[0m" << ::std::endl;
-
- os << std::endl
- << "\033[1m-v\033[0m Print actual commands being executed. This options is" << ::std::endl
- << " equivalent to \033[1m--verbose 2\033[0m." << ::std::endl;
-
- os << std::endl
- << "\033[1m-V\033[0m Print all underlying commands being executed. This" << ::std::endl
- << " options is equivalent to \033[1m--verbose 3\033[0m." << ::std::endl;
-
- os << std::endl
- << "\033[1m--quiet\033[0m|\033[1m-q\033[0m Run quietly, only printing error messages in most" << ::std::endl
- << " contexts. In certain contexts (for example, while" << ::std::endl
- << " updating build system modules) this verbosity level may" << ::std::endl
- << " be ignored. Use \033[1m--silent\033[0m to run quietly in all contexts." << ::std::endl
- << " This option is equivalent to \033[1m--verbose 0\033[0m." << ::std::endl;
-
- os << std::endl
- << "\033[1m--silent\033[0m Run quietly, only printing error messages in all" << ::std::endl
- << " contexts." << ::std::endl;
-
- os << std::endl
- << "\033[1m--verbose\033[0m \033[4mlevel\033[0m Set the diagnostics verbosity to \033[4mlevel\033[0m between 0 and 6." << ::std::endl
- << " Level 0 disables any non-error messages (but see the" << ::std::endl
- << " difference between \033[1m--quiet\033[0m and \033[1m--silent\033[0m) while level 6" << ::std::endl
- << " produces lots of information, with level 1 being the" << ::std::endl
- << " default. The following additional types of diagnostics" << ::std::endl
- << " are produced at each level:" << ::std::endl
- << ::std::endl
- << " 1. High-level information messages." << ::std::endl
- << " 2. Essential underlying commands being executed." << ::std::endl
- << " 3. All underlying commands being executed." << ::std::endl
- << " 4. Information that could be helpful to the user." << ::std::endl
- << " 5. Information that could be helpful to the developer." << ::std::endl
- << " 6. Even more detailed information." << ::std::endl;
-
- os << std::endl
- << "\033[1m--stat\033[0m Display build statistics." << ::std::endl;
-
- os << std::endl
- << "\033[1m--dump\033[0m \033[4mphase\033[0m Dump the build system state after the specified phase." << ::std::endl
- << " Valid \033[4mphase\033[0m values are \033[1mload\033[0m (after loading \033[1mbuildfiles\033[0m)" << ::std::endl
- << " and \033[1mmatch\033[0m (after matching rules to targets). Repeat this" << ::std::endl
- << " option to dump the state after multiple phases." << ::std::endl;
-
- os << std::endl
- << "\033[1m--progress\033[0m Display build progress. If printing to a terminal the" << ::std::endl
- << " progress is displayed by default for low verbosity" << ::std::endl
- << " levels. Use \033[1m--no-progress\033[0m to suppress." << ::std::endl;
-
- os << std::endl
- << "\033[1m--no-progress\033[0m Don't display build progress." << ::std::endl;
-
- os << std::endl
- << "\033[1m--jobs\033[0m|\033[1m-j\033[0m \033[4mnum\033[0m Number of active jobs to perform in parallel. This" << ::std::endl
- << " includes both the number of active threads inside the" << ::std::endl
- << " build system as well as the number of external commands" << ::std::endl
- << " (compilers, linkers, etc) started but not yet finished." << ::std::endl
- << " If this option is not specified or specified with the \033[1m0\033[0m" << ::std::endl
- << " value, then the number of available hardware threads is" << ::std::endl
- << " used." << ::std::endl;
-
- os << std::endl
- << "\033[1m--max-jobs\033[0m|\033[1m-J\033[0m \033[4mnum\033[0m Maximum number of jobs (threads) to create. The default" << ::std::endl
- << " is 8x the number of active jobs (\033[1m--jobs|j\033[0m) on 32-bit" << ::std::endl
- << " architectures and 32x on 64-bit. See the build system" << ::std::endl
- << " scheduler implementation for details." << ::std::endl;
-
- os << std::endl
- << "\033[1m--queue-depth\033[0m|\033[1m-Q\033[0m \033[4mnum\033[0m The queue depth as a multiplier over the number of active" << ::std::endl
- << " jobs. Normally we want a deeper queue if the jobs take" << ::std::endl
- << " long (for example, compilation) and shorter if they are" << ::std::endl
- << " quick (for example, simple tests). The default is 4. See" << ::std::endl
- << " the build system scheduler implementation for details." << ::std::endl;
-
- os << std::endl
- << "\033[1m--file-cache\033[0m \033[4mimpl\033[0m File cache implementation to use for intermediate build" << ::std::endl
- << " results. Valid values are \033[1mnoop\033[0m (no caching or" << ::std::endl
- << " compression) and \033[1msync-lz4\033[0m (no caching with synchronous" << ::std::endl
- << " LZ4 on-disk compression). If this option is not" << ::std::endl
- << " specified, then a suitable default implementation is used" << ::std::endl
- << " (currently \033[1msync-lz4\033[0m)." << ::std::endl;
-
- os << std::endl
- << "\033[1m--max-stack\033[0m \033[4mnum\033[0m The maximum stack size in KBytes to allow for newly" << ::std::endl
- << " created threads. For \033[4mpthreads\033[0m-based systems the driver" << ::std::endl
- << " queries the stack size of the main thread and uses the" << ::std::endl
- << " same size for creating additional threads. This allows" << ::std::endl
- << " adjusting the stack size using familiar mechanisms, such" << ::std::endl
- << " as \033[1mulimit\033[0m. Sometimes, however, the stack size of the main" << ::std::endl
- << " thread is excessively large. As a result, the driver" << ::std::endl
- << " checks if it is greater than a predefined limit (64MB on" << ::std::endl
- << " 64-bit systems and 32MB on 32-bit ones) and caps it to a" << ::std::endl
- << " more sensible value (8MB) if that's the case. This option" << ::std::endl
- << " allows you to override this check with the special zero" << ::std::endl
- << " value indicating that the main thread stack size should" << ::std::endl
- << " be used as is." << ::std::endl;
-
- os << std::endl
- << "\033[1m--serial-stop\033[0m|\033[1m-s\033[0m Run serially and stop at the first error. This mode is" << ::std::endl
- << " useful to investigate build failures that are caused by" << ::std::endl
- << " build system errors rather than compilation errors. Note" << ::std::endl
- << " that if you don't want to keep going but still want" << ::std::endl
- << " parallel execution, add \033[1m--jobs|-j\033[0m (for example \033[1m-j 0\033[0m for" << ::std::endl
- << " default concurrency)." << ::std::endl;
-
- os << std::endl
- << "\033[1m--dry-run\033[0m|\033[1m-n\033[0m Print commands without actually executing them. Note that" << ::std::endl
- << " commands that are required to create an accurate build" << ::std::endl
- << " state will still be executed and the extracted auxiliary" << ::std::endl
- << " dependency information saved. In other words, this is not" << ::std::endl
- << " the \033[4m\"don't touch the filesystem\"\033[0m mode but rather \033[4m\"do" << ::std::endl
- << " minimum amount of work to show what needs to be done\"\033[0m." << ::std::endl
- << " Note also that only the \033[1mperform\033[0m meta-operation supports" << ::std::endl
- << " this mode." << ::std::endl;
-
- os << std::endl
- << "\033[1m--match-only\033[0m Match the rules but do not execute the operation. This" << ::std::endl
- << " mode is primarily useful for profiling." << ::std::endl;
-
- os << std::endl
- << "\033[1m--no-external-modules\033[0m Don't load external modules during project bootstrap." << ::std::endl
- << " Note that this option can only be used with" << ::std::endl
- << " meta-operations that do not load the project's" << ::std::endl
- << " \033[1mbuildfiles\033[0m, such as \033[1minfo\033[0m." << ::std::endl;
-
- os << std::endl
- << "\033[1m--structured-result\033[0m Write the result of execution in a structured form. In" << ::std::endl
- << " this mode, instead of printing to \033[1mSTDERR\033[0m diagnostics" << ::std::endl
- << " messages about the outcome of executing actions on" << ::std::endl
- << " targets, the driver writes to \033[1mSTDOUT\033[0m a structured result" << ::std::endl
- << " description one line per the buildspec action/target" << ::std::endl
- << " pair. Each line has the following format:" << ::std::endl
- << ::std::endl
- << " \033[4mstate\033[0m \033[4mmeta-operation\033[0m \033[4moperation\033[0m \033[4mtarget\033[0m\033[0m" << ::std::endl
- << ::std::endl
- << " Where \033[4mstate\033[0m can be one of \033[1munchanged\033[0m, \033[1mchanged\033[0m, or \033[1mfailed\033[0m." << ::std::endl
- << " If the action is a pre or post operation, then the outer" << ::std::endl
- << " operation is specified in parenthesis. For example:" << ::std::endl
- << ::std::endl
- << " unchanged perform update(test) /tmp/dir{hello/}" << ::std::endl
- << " changed perform test /tmp/dir{hello/}" << ::std::endl
- << ::std::endl
- << " Note that only the \033[1mperform\033[0m meta-operation supports the" << ::std::endl
- << " structured result output." << ::std::endl;
-
- os << std::endl
- << "\033[1m--mtime-check\033[0m Perform file modification time sanity checks. These" << ::std::endl
- << " checks can be helpful in diagnosing spurious rebuilds and" << ::std::endl
- << " are enabled by default for the staged version of the" << ::std::endl
- << " build system. Use \033[1m--no-mtime-check\033[0m to disable." << ::std::endl;
-
- os << std::endl
- << "\033[1m--no-mtime-check\033[0m Don't perform file modification time sanity checks." << ::std::endl;
-
- os << std::endl
- << "\033[1m--no-column\033[0m Don't print column numbers in diagnostics." << ::std::endl;
-
- os << std::endl
- << "\033[1m--no-line\033[0m Don't print line and column numbers in diagnostics." << ::std::endl;
-
- os << std::endl
- << "\033[1m--buildfile\033[0m \033[4mpath\033[0m The alternative file to read build information from. The" << ::std::endl
- << " default is \033[1mbuildfile\033[0m or \033[1mbuild2file\033[0m, depending on the" << ::std::endl
- << " project's build file/directory naming scheme. If \033[4mpath\033[0m is" << ::std::endl
- << " '\033[1m-\033[0m', then read from \033[1mSTDIN\033[0m. Note that this option only" << ::std::endl
- << " affects the files read as part of the buildspec" << ::std::endl
- << " processing. Specifically, it has no effect on the \033[1msource\033[0m" << ::std::endl
- << " and \033[1minclude\033[0m directives. As a result, this option is" << ::std::endl
- << " primarily intended for testing rather than changing the" << ::std::endl
- << " build file names in real projects." << ::std::endl;
-
- os << std::endl
- << "\033[1m--config-guess\033[0m \033[4mpath\033[0m The path to the \033[1mconfig.guess(1)\033[0m script that should be" << ::std::endl
- << " used to guess the host machine triplet. If this option is" << ::std::endl
- << " not specified, then \033[1mb\033[0m will fall back on to using the" << ::std::endl
- << " target it was built for as host." << ::std::endl;
-
- os << std::endl
- << "\033[1m--config-sub\033[0m \033[4mpath\033[0m The path to the \033[1mconfig.sub(1)\033[0m script that should be used" << ::std::endl
- << " to canonicalize machine triplets. If this option is not" << ::std::endl
- << " specified, then \033[1mb\033[0m will use its built-in canonicalization" << ::std::endl
- << " support which should be sufficient for commonly-used" << ::std::endl
- << " platforms." << ::std::endl;
-
- os << std::endl
- << "\033[1m--pager\033[0m \033[4mpath\033[0m The pager program to be used to show long text. Commonly" << ::std::endl
- << " used pager programs are \033[1mless\033[0m and \033[1mmore\033[0m. You can also" << ::std::endl
- << " specify additional options that should be passed to the" << ::std::endl
- << " pager program with \033[1m--pager-option\033[0m. If an empty string is" << ::std::endl
- << " specified as the pager program, then no pager will be" << ::std::endl
- << " used. If the pager program is not explicitly specified," << ::std::endl
- << " then \033[1mb\033[0m will try to use \033[1mless\033[0m. If it is not available, then" << ::std::endl
- << " no pager will be used." << ::std::endl;
-
- os << std::endl
- << "\033[1m--pager-option\033[0m \033[4mopt\033[0m Additional option to be passed to the pager program. See" << ::std::endl
- << " \033[1m--pager\033[0m for more information on the pager program. Repeat" << ::std::endl
- << " this option to specify multiple pager options." << ::std::endl;
-
- os << std::endl
- << "\033[1m--options-file\033[0m \033[4mfile\033[0m Read additional options from \033[4mfile\033[0m. Each option should" << ::std::endl
- << " appear on a separate line optionally followed by space or" << ::std::endl
- << " equal sign (\033[1m=\033[0m) and an option value. Empty lines and lines" << ::std::endl
- << " starting with \033[1m#\033[0m are ignored. Option values can be" << ::std::endl
- << " enclosed in double (\033[1m\"\033[0m) or single (\033[1m'\033[0m) quotes to preserve" << ::std::endl
- << " leading and trailing whitespaces as well as to specify" << ::std::endl
- << " empty values. If the value itself contains trailing or" << ::std::endl
- << " leading quotes, enclose it with an extra pair of quotes," << ::std::endl
- << " for example \033[1m'\"x\"'\033[0m. Non-leading and non-trailing quotes" << ::std::endl
- << " are interpreted as being part of the option value." << ::std::endl
- << ::std::endl
- << " The semantics of providing options in a file is" << ::std::endl
- << " equivalent to providing the same set of options in the" << ::std::endl
- << " same order on the command line at the point where the" << ::std::endl
- << " \033[1m--options-file\033[0m option is specified except that the shell" << ::std::endl
- << " escaping and quoting is not required. Repeat this option" << ::std::endl
- << " to specify more than one options file." << ::std::endl;
-
- os << std::endl
- << "\033[1m--default-options\033[0m \033[4mdir\033[0m The directory to load additional default options files" << ::std::endl
- << " from." << ::std::endl;
-
- os << std::endl
- << "\033[1m--no-default-options\033[0m Don't load default options files." << ::std::endl;
-
- os << std::endl
- << "\033[1m--help\033[0m Print usage information and exit." << ::std::endl;
-
- os << std::endl
- << "\033[1m--version\033[0m Print version and exit." << ::std::endl;
-
- p = ::build2::cl::usage_para::option;
-
- return p;
- }
-
- typedef
- std::map<std::string, void (*) (options&, ::build2::cl::scanner&)>
- _cli_options_map;
-
- static _cli_options_map _cli_options_map_;
-
- struct _cli_options_map_init
- {
- _cli_options_map_init ()
- {
- _cli_options_map_["--build2-metadata"] =
- &::build2::cl::thunk< options, uint64_t, &options::build2_metadata_,
- &options::build2_metadata_specified_ >;
- _cli_options_map_["-v"] =
- &::build2::cl::thunk< options, bool, &options::v_ >;
- _cli_options_map_["-V"] =
- &::build2::cl::thunk< options, bool, &options::V_ >;
- _cli_options_map_["--quiet"] =
- &::build2::cl::thunk< options, bool, &options::quiet_ >;
- _cli_options_map_["-q"] =
- &::build2::cl::thunk< options, bool, &options::quiet_ >;
- _cli_options_map_["--silent"] =
- &::build2::cl::thunk< options, bool, &options::silent_ >;
- _cli_options_map_["--verbose"] =
- &::build2::cl::thunk< options, uint16_t, &options::verbose_,
- &options::verbose_specified_ >;
- _cli_options_map_["--stat"] =
- &::build2::cl::thunk< options, bool, &options::stat_ >;
- _cli_options_map_["--dump"] =
- &::build2::cl::thunk< options, std::set<string>, &options::dump_,
- &options::dump_specified_ >;
- _cli_options_map_["--progress"] =
- &::build2::cl::thunk< options, bool, &options::progress_ >;
- _cli_options_map_["--no-progress"] =
- &::build2::cl::thunk< options, bool, &options::no_progress_ >;
- _cli_options_map_["--jobs"] =
- &::build2::cl::thunk< options, size_t, &options::jobs_,
- &options::jobs_specified_ >;
- _cli_options_map_["-j"] =
- &::build2::cl::thunk< options, size_t, &options::jobs_,
- &options::jobs_specified_ >;
- _cli_options_map_["--max-jobs"] =
- &::build2::cl::thunk< options, size_t, &options::max_jobs_,
- &options::max_jobs_specified_ >;
- _cli_options_map_["-J"] =
- &::build2::cl::thunk< options, size_t, &options::max_jobs_,
- &options::max_jobs_specified_ >;
- _cli_options_map_["--queue-depth"] =
- &::build2::cl::thunk< options, size_t, &options::queue_depth_,
- &options::queue_depth_specified_ >;
- _cli_options_map_["-Q"] =
- &::build2::cl::thunk< options, size_t, &options::queue_depth_,
- &options::queue_depth_specified_ >;
- _cli_options_map_["--file-cache"] =
- &::build2::cl::thunk< options, string, &options::file_cache_,
- &options::file_cache_specified_ >;
- _cli_options_map_["--max-stack"] =
- &::build2::cl::thunk< options, size_t, &options::max_stack_,
- &options::max_stack_specified_ >;
- _cli_options_map_["--serial-stop"] =
- &::build2::cl::thunk< options, bool, &options::serial_stop_ >;
- _cli_options_map_["-s"] =
- &::build2::cl::thunk< options, bool, &options::serial_stop_ >;
- _cli_options_map_["--dry-run"] =
- &::build2::cl::thunk< options, bool, &options::dry_run_ >;
- _cli_options_map_["-n"] =
- &::build2::cl::thunk< options, bool, &options::dry_run_ >;
- _cli_options_map_["--match-only"] =
- &::build2::cl::thunk< options, bool, &options::match_only_ >;
- _cli_options_map_["--no-external-modules"] =
- &::build2::cl::thunk< options, bool, &options::no_external_modules_ >;
- _cli_options_map_["--structured-result"] =
- &::build2::cl::thunk< options, bool, &options::structured_result_ >;
- _cli_options_map_["--mtime-check"] =
- &::build2::cl::thunk< options, bool, &options::mtime_check_ >;
- _cli_options_map_["--no-mtime-check"] =
- &::build2::cl::thunk< options, bool, &options::no_mtime_check_ >;
- _cli_options_map_["--no-column"] =
- &::build2::cl::thunk< options, bool, &options::no_column_ >;
- _cli_options_map_["--no-line"] =
- &::build2::cl::thunk< options, bool, &options::no_line_ >;
- _cli_options_map_["--buildfile"] =
- &::build2::cl::thunk< options, path, &options::buildfile_,
- &options::buildfile_specified_ >;
- _cli_options_map_["--config-guess"] =
- &::build2::cl::thunk< options, path, &options::config_guess_,
- &options::config_guess_specified_ >;
- _cli_options_map_["--config-sub"] =
- &::build2::cl::thunk< options, path, &options::config_sub_,
- &options::config_sub_specified_ >;
- _cli_options_map_["--pager"] =
- &::build2::cl::thunk< options, string, &options::pager_,
- &options::pager_specified_ >;
- _cli_options_map_["--pager-option"] =
- &::build2::cl::thunk< options, strings, &options::pager_option_,
- &options::pager_option_specified_ >;
- _cli_options_map_["--options-file"] =
- &::build2::cl::thunk< options, string, &options::options_file_,
- &options::options_file_specified_ >;
- _cli_options_map_["--default-options"] =
- &::build2::cl::thunk< options, dir_path, &options::default_options_,
- &options::default_options_specified_ >;
- _cli_options_map_["--no-default-options"] =
- &::build2::cl::thunk< options, bool, &options::no_default_options_ >;
- _cli_options_map_["--help"] =
- &::build2::cl::thunk< options, bool, &options::help_ >;
- _cli_options_map_["--version"] =
- &::build2::cl::thunk< options, bool, &options::version_ >;
- }
- };
-
- static _cli_options_map_init _cli_options_map_init_;
-
- bool options::
- _parse (const char* o, ::build2::cl::scanner& s)
- {
- _cli_options_map::const_iterator i (_cli_options_map_.find (o));
-
- if (i != _cli_options_map_.end ())
- {
- (*(i->second)) (*this, s);
- return true;
- }
-
- return false;
- }
-
- bool options::
- _parse (::build2::cl::scanner& s,
- ::build2::cl::unknown_mode opt_mode,
- ::build2::cl::unknown_mode arg_mode)
- {
- // Can't skip combined flags (--no-combined-flags).
- //
- assert (opt_mode != ::build2::cl::unknown_mode::skip);
-
- bool r = false;
- bool opt = true;
-
- while (s.more ())
- {
- const char* o = s.peek ();
-
- if (std::strcmp (o, "--") == 0)
- {
- opt = false;
- }
-
- if (opt)
- {
- if (_parse (o, s))
- {
- r = true;
- continue;
- }
-
- if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0')
- {
- // Handle combined option values.
- //
- std::string co;
- if (const char* v = std::strchr (o, '='))
- {
- co.assign (o, 0, v - o);
- ++v;
-
- int ac (2);
- char* av[] =
- {
- const_cast<char*> (co.c_str ()),
- const_cast<char*> (v)
- };
-
- ::build2::cl::argv_scanner ns (0, ac, av);
-
- if (_parse (co.c_str (), ns))
- {
- // Parsed the option but not its value?
- //
- if (ns.end () != 2)
- throw ::build2::cl::invalid_value (co, v);
-
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = co.c_str ();
- }
- }
-
- // Handle combined flags.
- //
- char cf[3];
- {
- const char* p = o + 1;
- for (; *p != '\0'; ++p)
- {
- if (!((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9')))
- break;
- }
-
- if (*p == '\0')
- {
- for (p = o + 1; *p != '\0'; ++p)
- {
- std::strcpy (cf, "-");
- cf[1] = *p;
- cf[2] = '\0';
-
- int ac (1);
- char* av[] =
- {
- cf
- };
-
- ::build2::cl::argv_scanner ns (0, ac, av);
-
- if (!_parse (cf, ns))
- break;
- }
-
- if (*p == '\0')
- {
- // All handled.
- //
- s.next ();
- r = true;
- continue;
- }
- else
- {
- // Set the unknown option and fall through.
- //
- o = cf;
- }
- }
- }
-
- switch (opt_mode)
- {
- case ::build2::cl::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::cl::unknown_mode::stop:
- {
- break;
- }
- case ::build2::cl::unknown_mode::fail:
- {
- throw ::build2::cl::unknown_option (o);
- }
- }
-
- break;
- }
- }
-
- switch (arg_mode)
- {
- case ::build2::cl::unknown_mode::skip:
- {
- s.skip ();
- r = true;
- continue;
- }
- case ::build2::cl::unknown_mode::stop:
- {
- break;
- }
- case ::build2::cl::unknown_mode::fail:
- {
- throw ::build2::cl::unknown_argument (o);
- }
- }
-
- break;
- }
-
- return r;
- }
-}
-
-namespace build2
-{
- ::build2::cl::usage_para
- print_b_usage (::std::ostream& os, ::build2::cl::usage_para p)
- {
- CLI_POTENTIALLY_UNUSED (os);
-
- if (p != ::build2::cl::usage_para::none)
- os << ::std::endl;
-
- os << "\033[1mSYNOPSIS\033[0m" << ::std::endl
- << ::std::endl
- << "\033[1mb --help\033[0m" << ::std::endl
- << "\033[1mb --version\033[0m" << ::std::endl
- << "\033[1mb\033[0m [\033[4moptions\033[0m] [\033[4mvariables\033[0m] [\033[4mbuildspec\033[0m]\033[0m" << ::std::endl
- << ::std::endl
- << "\033[4mbuildspec\033[0m = \033[4mmeta-operation\033[0m\033[1m(\033[0m\033[4moperation\033[0m\033[1m(\033[0m\033[4mtarget\033[0m...[\033[1m,\033[0m\033[4mparameters\033[0m]\033[1m)\033[0m...\033[1m)\033[0m...\033[0m" << ::std::endl
- << ::std::endl
- << "\033[1mDESCRIPTION\033[0m" << ::std::endl
- << ::std::endl
- << "The \033[1mbuild2\033[0m build system driver executes a set of meta-operations on operations" << ::std::endl
- << "on targets according to the build specification, or \033[4mbuildspec\033[0m for short. This" << ::std::endl
- << "process can be controlled by specifying driver \033[4moptions\033[0m and build system" << ::std::endl
- << "\033[4mvariables\033[0m." << ::std::endl
- << ::std::endl
- << "Note that \033[4moptions\033[0m, \033[4mvariables\033[0m, and \033[4mbuildspec\033[0m fragments can be specified in any" << ::std::endl
- << "order. To avoid treating an argument that starts with \033[1m'-'\033[0m as an option, add the" << ::std::endl
- << "\033[1m'--'\033[0m separator. To avoid treating an argument that contains \033[1m'='\033[0m as a variable," << ::std::endl
- << "add the second \033[1m'--'\033[0m separator." << ::std::endl;
-
- p = ::build2::options::print_usage (os, ::build2::cl::usage_para::text);
-
- if (p != ::build2::cl::usage_para::none)
- os << ::std::endl;
-
- os << "\033[1mDEFAULT OPTIONS FILES\033[0m" << ::std::endl
- << ::std::endl
- << "Instead of having a separate config file format for tool configuration, the" << ::std::endl
- << "\033[1mbuild2\033[0m toolchain uses \033[4mdefault options files\033[0m which contain the same options as" << ::std::endl
- << "what can be specified on the command line. The default options files are like" << ::std::endl
- << "options files that one can specify with \033[1m--options-file\033[0m except that they are" << ::std::endl
- << "loaded by default." << ::std::endl
- << ::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. 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
- << "directory, and finishing off with the options specified on the command line. In" << ::std::endl
- << "other words, the files are loaded from the more generic to the more specific" << ::std::endl
- << "with the command line options having the ability to override any values" << ::std::endl
- << "specified in the default options files." << ::std::endl
- << ::std::endl
- << "If a default options file contains \033[1m--no-default-options\033[0m, then the search is" << ::std::endl
- << "stopped at the directory containing this file and no outer files are loaded. If" << ::std::endl
- << "this option is specified on the command line, then none of the default options" << ::std::endl
- << "files are searched for or loaded." << ::std::endl
- << ::std::endl
- << "An additional directory containing default options files can be specified with" << ::std::endl
- << "\033[1m--default-options\033[0m. Its configuration files are loaded after the home directory." << ::std::endl
- << ::std::endl
- << "The order in which default options files are loaded is traced at the verbosity" << ::std::endl
- << "level 3 (\033[1m-V\033[0m option) or higher." << ::std::endl
- << ::std::endl
- << "\033[1mEXIT STATUS\033[0m" << ::std::endl
- << ::std::endl
- << "Non-zero exit status is returned in case of an error." << ::std::endl;
-
- os << std::endl
- << "\033[1mENVIRONMENT\033[0m" << ::std::endl
- << ::std::endl
- << "The \033[1mHOME\033[0m environment variable is used to determine the user's home directory." << ::std::endl
- << "If it is not set, then \033[1mgetpwuid(3)\033[0m is used instead. This value is used to" << ::std::endl
- << "shorten paths printed in diagnostics by replacing the home directory with \033[1m~/\033[0m." << ::std::endl
- << "It is also made available to \033[1mbuildfile\033[0m's as the \033[1mbuild.home\033[0m variable." << ::std::endl
- << ::std::endl
- << "The \033[1mBUILD2_VAR_OVR\033[0m environment variable is used to propagate global variable" << ::std::endl
- << "overrides to nested build system driver invocations. Its value is a list of" << ::std::endl
- << "global variable assignments separated with newlines." << ::std::endl
- << ::std::endl
- << "The \033[1mBUILD2_DEF_OPT\033[0m environment variable is used to suppress loading of default" << ::std::endl
- << "options files in nested build system driver invocations. Its values are \033[1mfalse\033[0m" << ::std::endl
- << "or \033[1m0\033[0m to suppress and \033[1mtrue\033[0m or \033[1m1\033[0m to load." << ::std::endl;
-
- p = ::build2::cl::usage_para::text;
-
- return p;
- }
-}
-
-// Begin epilogue.
-//
-//
-// End epilogue.
-
diff --git a/build2/b-options.hxx b/build2/b-options.hxx
deleted file mode 100644
index 4e1b7bd..0000000
--- a/build2/b-options.hxx
+++ /dev/null
@@ -1,690 +0,0 @@
-// -*- C++ -*-
-//
-// This file was generated by CLI, a command line interface
-// compiler for C++.
-//
-
-#ifndef BUILD2_B_OPTIONS_HXX
-#define BUILD2_B_OPTIONS_HXX
-
-// Begin prologue.
-//
-//
-// End prologue.
-
-#include <list>
-#include <deque>
-#include <iosfwd>
-#include <string>
-#include <cstddef>
-#include <exception>
-
-#ifndef CLI_POTENTIALLY_UNUSED
-# if defined(_MSC_VER) || defined(__xlC__)
-# define CLI_POTENTIALLY_UNUSED(x) (void*)&x
-# else
-# define CLI_POTENTIALLY_UNUSED(x) (void)x
-# endif
-#endif
-
-namespace build2
-{
- namespace cl
- {
- class usage_para
- {
- public:
- enum value
- {
- none,
- text,
- option
- };
-
- usage_para (value);
-
- operator value () const
- {
- return v_;
- }
-
- private:
- value v_;
- };
-
- class unknown_mode
- {
- public:
- enum value
- {
- skip,
- stop,
- fail
- };
-
- unknown_mode (value);
-
- operator value () const
- {
- return v_;
- }
-
- private:
- value v_;
- };
-
- // Exceptions.
- //
-
- class exception: public std::exception
- {
- public:
- virtual void
- print (::std::ostream&) const = 0;
- };
-
- ::std::ostream&
- operator<< (::std::ostream&, const exception&);
-
- class unknown_option: public exception
- {
- public:
- virtual
- ~unknown_option () throw ();
-
- unknown_option (const std::string& option);
-
- const std::string&
- option () const;
-
- virtual void
- print (::std::ostream&) const;
-
- virtual const char*
- what () const throw ();
-
- private:
- std::string option_;
- };
-
- class unknown_argument: public exception
- {
- public:
- virtual
- ~unknown_argument () throw ();
-
- unknown_argument (const std::string& argument);
-
- const std::string&
- argument () const;
-
- virtual void
- print (::std::ostream&) const;
-
- virtual const char*
- what () const throw ();
-
- private:
- std::string argument_;
- };
-
- class missing_value: public exception
- {
- public:
- virtual
- ~missing_value () throw ();
-
- missing_value (const std::string& option);
-
- const std::string&
- option () const;
-
- virtual void
- print (::std::ostream&) const;
-
- virtual const char*
- what () const throw ();
-
- private:
- std::string option_;
- };
-
- class invalid_value: public exception
- {
- public:
- virtual
- ~invalid_value () throw ();
-
- invalid_value (const std::string& option,
- const std::string& value,
- const std::string& message = std::string ());
-
- const std::string&
- option () const;
-
- const std::string&
- value () const;
-
- const std::string&
- message () const;
-
- virtual void
- print (::std::ostream&) const;
-
- virtual const char*
- what () const throw ();
-
- private:
- std::string option_;
- std::string value_;
- std::string message_;
- };
-
- class eos_reached: public exception
- {
- public:
- virtual void
- print (::std::ostream&) const;
-
- virtual const char*
- what () const throw ();
- };
-
- class file_io_failure: public exception
- {
- public:
- virtual
- ~file_io_failure () throw ();
-
- file_io_failure (const std::string& file);
-
- const std::string&
- file () const;
-
- virtual void
- print (::std::ostream&) const;
-
- virtual const char*
- what () const throw ();
-
- private:
- std::string file_;
- };
-
- class unmatched_quote: public exception
- {
- public:
- virtual
- ~unmatched_quote () throw ();
-
- unmatched_quote (const std::string& argument);
-
- const std::string&
- argument () const;
-
- virtual void
- print (::std::ostream&) const;
-
- virtual const char*
- what () const throw ();
-
- private:
- std::string argument_;
- };
-
- // Command line argument scanner interface.
- //
- // The values returned by next() are guaranteed to be valid
- // for the two previous arguments up until a call to a third
- // peek() or next().
- //
- class scanner
- {
- public:
- virtual
- ~scanner ();
-
- virtual bool
- more () = 0;
-
- virtual const char*
- peek () = 0;
-
- virtual const char*
- next () = 0;
-
- virtual void
- skip () = 0;
- };
-
- class argv_scanner: public scanner
- {
- public:
- argv_scanner (int& argc, char** argv, bool erase = false);
- argv_scanner (int start, int& argc, char** argv, bool erase = false);
-
- int
- end () const;
-
- virtual bool
- more ();
-
- virtual const char*
- peek ();
-
- virtual const char*
- next ();
-
- virtual void
- skip ();
-
- private:
- int i_;
- int& argc_;
- char** argv_;
- bool erase_;
- };
-
- class argv_file_scanner: public argv_scanner
- {
- public:
- argv_file_scanner (int& argc,
- char** argv,
- const std::string& option,
- bool erase = false);
-
- argv_file_scanner (int start,
- int& argc,
- char** argv,
- const std::string& option,
- bool erase = false);
-
- argv_file_scanner (const std::string& file,
- const std::string& option);
-
- struct option_info
- {
- // If search_func is not NULL, it is called, with the arg
- // value as the second argument, to locate the options file.
- // If it returns an empty string, then the file is ignored.
- //
- const char* option;
- std::string (*search_func) (const char*, void* arg);
- void* arg;
- };
-
- argv_file_scanner (int& argc,
- char** argv,
- const option_info* options,
- std::size_t options_count,
- bool erase = false);
-
- argv_file_scanner (int start,
- int& argc,
- char** argv,
- const option_info* options,
- std::size_t options_count,
- bool erase = false);
-
- argv_file_scanner (const std::string& file,
- const option_info* options = 0,
- std::size_t options_count = 0);
-
- virtual bool
- more ();
-
- virtual const char*
- peek ();
-
- virtual const char*
- next ();
-
- virtual void
- skip ();
-
- // Return the file path if the peeked at argument came from a file and
- // the empty string otherwise. The reference is guaranteed to be valid
- // till the end of the scanner lifetime.
- //
- const std::string&
- peek_file ();
-
- // Return the 1-based line number if the peeked at argument came from
- // a file and zero otherwise.
- //
- std::size_t
- peek_line ();
-
- private:
- const option_info*
- find (const char*) const;
-
- void
- load (const std::string& file);
-
- typedef argv_scanner base;
-
- const std::string option_;
- option_info option_info_;
- const option_info* options_;
- std::size_t options_count_;
-
- struct arg
- {
- std::string value;
- const std::string* file;
- std::size_t line;
- };
-
- std::deque<arg> args_;
- std::list<std::string> files_;
-
- // Circular buffer of two arguments.
- //
- std::string hold_[2];
- std::size_t i_;
-
- bool skip_;
-
- static int zero_argc_;
- static std::string empty_string_;
- };
-
- template <typename X>
- struct parser;
- }
-}
-
-#include <set>
-
-#include <libbuild2/types.hxx>
-
-namespace build2
-{
- class options
- {
- public:
- options ();
-
- // Return true if anything has been parsed.
- //
- bool
- parse (int& argc,
- char** argv,
- bool erase = false,
- ::build2::cl::unknown_mode option = ::build2::cl::unknown_mode::fail,
- ::build2::cl::unknown_mode argument = ::build2::cl::unknown_mode::stop);
-
- bool
- parse (int start,
- int& argc,
- char** argv,
- bool erase = false,
- ::build2::cl::unknown_mode option = ::build2::cl::unknown_mode::fail,
- ::build2::cl::unknown_mode argument = ::build2::cl::unknown_mode::stop);
-
- bool
- parse (int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::cl::unknown_mode option = ::build2::cl::unknown_mode::fail,
- ::build2::cl::unknown_mode argument = ::build2::cl::unknown_mode::stop);
-
- bool
- parse (int start,
- int& argc,
- char** argv,
- int& end,
- bool erase = false,
- ::build2::cl::unknown_mode option = ::build2::cl::unknown_mode::fail,
- ::build2::cl::unknown_mode argument = ::build2::cl::unknown_mode::stop);
-
- bool
- parse (::build2::cl::scanner&,
- ::build2::cl::unknown_mode option = ::build2::cl::unknown_mode::fail,
- ::build2::cl::unknown_mode argument = ::build2::cl::unknown_mode::stop);
-
- // Merge options from the specified instance appending/overriding
- // them as if they appeared after options in this instance.
- //
- void
- merge (const options&);
-
- // Option accessors.
- //
- const uint64_t&
- build2_metadata () const;
-
- bool
- build2_metadata_specified () const;
-
- const bool&
- v () const;
-
- const bool&
- V () const;
-
- const bool&
- quiet () const;
-
- const bool&
- silent () const;
-
- const uint16_t&
- verbose () const;
-
- bool
- verbose_specified () const;
-
- const bool&
- stat () const;
-
- const std::set<string>&
- dump () const;
-
- bool
- dump_specified () const;
-
- const bool&
- progress () const;
-
- const bool&
- no_progress () const;
-
- const size_t&
- jobs () const;
-
- bool
- jobs_specified () const;
-
- const size_t&
- max_jobs () const;
-
- bool
- max_jobs_specified () const;
-
- const size_t&
- queue_depth () const;
-
- bool
- queue_depth_specified () const;
-
- const string&
- file_cache () const;
-
- bool
- file_cache_specified () const;
-
- const size_t&
- max_stack () const;
-
- bool
- max_stack_specified () const;
-
- const bool&
- serial_stop () const;
-
- const bool&
- dry_run () const;
-
- const bool&
- match_only () const;
-
- const bool&
- no_external_modules () const;
-
- const bool&
- structured_result () const;
-
- const bool&
- mtime_check () const;
-
- const bool&
- no_mtime_check () const;
-
- const bool&
- no_column () const;
-
- const bool&
- no_line () const;
-
- const path&
- buildfile () const;
-
- bool
- buildfile_specified () const;
-
- const path&
- config_guess () const;
-
- bool
- config_guess_specified () const;
-
- const path&
- config_sub () const;
-
- bool
- config_sub_specified () const;
-
- const string&
- pager () const;
-
- bool
- pager_specified () const;
-
- const strings&
- pager_option () const;
-
- bool
- pager_option_specified () const;
-
- const string&
- options_file () const;
-
- bool
- options_file_specified () const;
-
- const dir_path&
- default_options () const;
-
- bool
- default_options_specified () const;
-
- const bool&
- no_default_options () const;
-
- const bool&
- help () const;
-
- const bool&
- version () const;
-
- // Print usage information.
- //
- static ::build2::cl::usage_para
- print_usage (::std::ostream&,
- ::build2::cl::usage_para = ::build2::cl::usage_para::none);
-
- // Implementation details.
- //
- protected:
- bool
- _parse (const char*, ::build2::cl::scanner&);
-
- private:
- bool
- _parse (::build2::cl::scanner&,
- ::build2::cl::unknown_mode option,
- ::build2::cl::unknown_mode argument);
-
- public:
- uint64_t build2_metadata_;
- bool build2_metadata_specified_;
- bool v_;
- bool V_;
- bool quiet_;
- bool silent_;
- uint16_t verbose_;
- bool verbose_specified_;
- bool stat_;
- std::set<string> dump_;
- bool dump_specified_;
- bool progress_;
- bool no_progress_;
- size_t jobs_;
- bool jobs_specified_;
- size_t max_jobs_;
- bool max_jobs_specified_;
- size_t queue_depth_;
- bool queue_depth_specified_;
- string file_cache_;
- bool file_cache_specified_;
- size_t max_stack_;
- bool max_stack_specified_;
- bool serial_stop_;
- bool dry_run_;
- bool match_only_;
- bool no_external_modules_;
- bool structured_result_;
- bool mtime_check_;
- bool no_mtime_check_;
- bool no_column_;
- bool no_line_;
- path buildfile_;
- bool buildfile_specified_;
- path config_guess_;
- bool config_guess_specified_;
- path config_sub_;
- bool config_sub_specified_;
- string pager_;
- bool pager_specified_;
- strings pager_option_;
- bool pager_option_specified_;
- string options_file_;
- bool options_file_specified_;
- dir_path default_options_;
- bool default_options_specified_;
- bool no_default_options_;
- bool help_;
- bool version_;
- };
-}
-
-// Print page usage information.
-//
-namespace build2
-{
- ::build2::cl::usage_para
- print_b_usage (::std::ostream&,
- ::build2::cl::usage_para = ::build2::cl::usage_para::none);
-}
-
-#include <build2/b-options.ixx>
-
-// Begin epilogue.
-//
-//
-// End epilogue.
-
-#endif // BUILD2_B_OPTIONS_HXX
diff --git a/build2/b-options.ixx b/build2/b-options.ixx
deleted file mode 100644
index 0e90ba1..0000000
--- a/build2/b-options.ixx
+++ /dev/null
@@ -1,561 +0,0 @@
-// -*- C++ -*-
-//
-// This file was generated by CLI, a command line interface
-// compiler for C++.
-//
-
-// Begin prologue.
-//
-//
-// End prologue.
-
-#include <cassert>
-
-namespace build2
-{
- namespace cl
- {
- // usage_para
- //
- inline usage_para::
- usage_para (value v)
- : v_ (v)
- {
- }
-
- // unknown_mode
- //
- inline unknown_mode::
- unknown_mode (value v)
- : v_ (v)
- {
- }
-
- // exception
- //
- inline ::std::ostream&
- operator<< (::std::ostream& os, const exception& e)
- {
- e.print (os);
- return os;
- }
-
- // unknown_option
- //
- inline unknown_option::
- unknown_option (const std::string& option)
- : option_ (option)
- {
- }
-
- inline const std::string& unknown_option::
- option () const
- {
- return option_;
- }
-
- // unknown_argument
- //
- inline unknown_argument::
- unknown_argument (const std::string& argument)
- : argument_ (argument)
- {
- }
-
- inline const std::string& unknown_argument::
- argument () const
- {
- return argument_;
- }
-
- // missing_value
- //
- inline missing_value::
- missing_value (const std::string& option)
- : option_ (option)
- {
- }
-
- inline const std::string& missing_value::
- option () const
- {
- return option_;
- }
-
- // invalid_value
- //
- inline invalid_value::
- invalid_value (const std::string& option,
- const std::string& value,
- const std::string& message)
- : option_ (option),
- value_ (value),
- message_ (message)
- {
- }
-
- inline const std::string& invalid_value::
- option () const
- {
- return option_;
- }
-
- inline const std::string& invalid_value::
- value () const
- {
- return value_;
- }
-
- inline const std::string& invalid_value::
- message () const
- {
- return message_;
- }
-
- // file_io_failure
- //
- inline file_io_failure::
- file_io_failure (const std::string& file)
- : file_ (file)
- {
- }
-
- inline const std::string& file_io_failure::
- file () const
- {
- return file_;
- }
-
- // unmatched_quote
- //
- inline unmatched_quote::
- unmatched_quote (const std::string& argument)
- : argument_ (argument)
- {
- }
-
- inline const std::string& unmatched_quote::
- argument () const
- {
- return argument_;
- }
-
- // argv_scanner
- //
- inline argv_scanner::
- argv_scanner (int& argc, char** argv, bool erase)
- : i_ (1), argc_ (argc), argv_ (argv), erase_ (erase)
- {
- }
-
- inline argv_scanner::
- argv_scanner (int start, int& argc, char** argv, bool erase)
- : i_ (start), argc_ (argc), argv_ (argv), erase_ (erase)
- {
- }
-
- inline int argv_scanner::
- end () const
- {
- return i_;
- }
-
- // argv_file_scanner
- //
- inline argv_file_scanner::
- argv_file_scanner (int& argc,
- char** argv,
- const std::string& option,
- bool erase)
- : argv_scanner (argc, argv, erase),
- option_ (option),
- options_ (&option_info_),
- options_count_ (1),
- i_ (1),
- skip_ (false)
- {
- option_info_.option = option_.c_str ();
- option_info_.search_func = 0;
- }
-
- inline argv_file_scanner::
- argv_file_scanner (int start,
- int& argc,
- char** argv,
- const std::string& option,
- bool erase)
- : argv_scanner (start, argc, argv, erase),
- option_ (option),
- options_ (&option_info_),
- options_count_ (1),
- i_ (1),
- skip_ (false)
- {
- option_info_.option = option_.c_str ();
- option_info_.search_func = 0;
- }
-
- inline argv_file_scanner::
- argv_file_scanner (const std::string& file,
- const std::string& option)
- : argv_scanner (0, zero_argc_, 0),
- option_ (option),
- options_ (&option_info_),
- options_count_ (1),
- i_ (1),
- skip_ (false)
- {
- option_info_.option = option_.c_str ();
- option_info_.search_func = 0;
-
- load (file);
- }
-
- inline argv_file_scanner::
- argv_file_scanner (int& argc,
- char** argv,
- const option_info* options,
- std::size_t options_count,
- bool erase)
- : argv_scanner (argc, argv, erase),
- options_ (options),
- options_count_ (options_count),
- i_ (1),
- skip_ (false)
- {
- }
-
- inline argv_file_scanner::
- argv_file_scanner (int start,
- int& argc,
- char** argv,
- const option_info* options,
- std::size_t options_count,
- bool erase)
- : argv_scanner (start, argc, argv, erase),
- options_ (options),
- options_count_ (options_count),
- i_ (1),
- skip_ (false)
- {
- }
-
- inline argv_file_scanner::
- argv_file_scanner (const std::string& file,
- const option_info* options,
- std::size_t options_count)
- : argv_scanner (0, zero_argc_, 0),
- options_ (options),
- options_count_ (options_count),
- i_ (1),
- skip_ (false)
- {
- load (file);
- }
- }
-}
-
-namespace build2
-{
- // options
- //
-
- inline const uint64_t& options::
- build2_metadata () const
- {
- return this->build2_metadata_;
- }
-
- inline bool options::
- build2_metadata_specified () const
- {
- return this->build2_metadata_specified_;
- }
-
- inline const bool& options::
- v () const
- {
- return this->v_;
- }
-
- inline const bool& options::
- V () const
- {
- return this->V_;
- }
-
- inline const bool& options::
- quiet () const
- {
- return this->quiet_;
- }
-
- inline const bool& options::
- silent () const
- {
- return this->silent_;
- }
-
- inline const uint16_t& options::
- verbose () const
- {
- return this->verbose_;
- }
-
- inline bool options::
- verbose_specified () const
- {
- return this->verbose_specified_;
- }
-
- inline const bool& options::
- stat () const
- {
- return this->stat_;
- }
-
- inline const std::set<string>& options::
- dump () const
- {
- return this->dump_;
- }
-
- inline bool options::
- dump_specified () const
- {
- return this->dump_specified_;
- }
-
- inline const bool& options::
- progress () const
- {
- return this->progress_;
- }
-
- inline const bool& options::
- no_progress () const
- {
- return this->no_progress_;
- }
-
- inline const size_t& options::
- jobs () const
- {
- return this->jobs_;
- }
-
- inline bool options::
- jobs_specified () const
- {
- return this->jobs_specified_;
- }
-
- inline const size_t& options::
- max_jobs () const
- {
- return this->max_jobs_;
- }
-
- inline bool options::
- max_jobs_specified () const
- {
- return this->max_jobs_specified_;
- }
-
- inline const size_t& options::
- queue_depth () const
- {
- return this->queue_depth_;
- }
-
- inline bool options::
- queue_depth_specified () const
- {
- return this->queue_depth_specified_;
- }
-
- inline const string& options::
- file_cache () const
- {
- return this->file_cache_;
- }
-
- inline bool options::
- file_cache_specified () const
- {
- return this->file_cache_specified_;
- }
-
- inline const size_t& options::
- max_stack () const
- {
- return this->max_stack_;
- }
-
- inline bool options::
- max_stack_specified () const
- {
- return this->max_stack_specified_;
- }
-
- inline const bool& options::
- serial_stop () const
- {
- return this->serial_stop_;
- }
-
- inline const bool& options::
- dry_run () const
- {
- return this->dry_run_;
- }
-
- inline const bool& options::
- match_only () const
- {
- return this->match_only_;
- }
-
- inline const bool& options::
- no_external_modules () const
- {
- return this->no_external_modules_;
- }
-
- inline const bool& options::
- structured_result () const
- {
- return this->structured_result_;
- }
-
- inline const bool& options::
- mtime_check () const
- {
- return this->mtime_check_;
- }
-
- inline const bool& options::
- no_mtime_check () const
- {
- return this->no_mtime_check_;
- }
-
- inline const bool& options::
- no_column () const
- {
- return this->no_column_;
- }
-
- inline const bool& options::
- no_line () const
- {
- return this->no_line_;
- }
-
- inline const path& options::
- buildfile () const
- {
- return this->buildfile_;
- }
-
- inline bool options::
- buildfile_specified () const
- {
- return this->buildfile_specified_;
- }
-
- inline const path& options::
- config_guess () const
- {
- return this->config_guess_;
- }
-
- inline bool options::
- config_guess_specified () const
- {
- return this->config_guess_specified_;
- }
-
- inline const path& options::
- config_sub () const
- {
- return this->config_sub_;
- }
-
- inline bool options::
- config_sub_specified () const
- {
- return this->config_sub_specified_;
- }
-
- inline const string& options::
- pager () const
- {
- return this->pager_;
- }
-
- inline bool options::
- pager_specified () const
- {
- return this->pager_specified_;
- }
-
- inline const strings& options::
- pager_option () const
- {
- return this->pager_option_;
- }
-
- inline bool options::
- pager_option_specified () const
- {
- return this->pager_option_specified_;
- }
-
- inline const string& options::
- options_file () const
- {
- return this->options_file_;
- }
-
- inline bool options::
- options_file_specified () const
- {
- return this->options_file_specified_;
- }
-
- inline const dir_path& options::
- default_options () const
- {
- return this->default_options_;
- }
-
- inline bool options::
- default_options_specified () const
- {
- return this->default_options_specified_;
- }
-
- inline const bool& options::
- no_default_options () const
- {
- return this->no_default_options_;
- }
-
- inline const bool& options::
- help () const
- {
- return this->help_;
- }
-
- inline const bool& options::
- version () const
- {
- return this->version_;
- }
-}
-
-// Begin epilogue.
-//
-//
-// End epilogue.
diff --git a/build2/b.cli b/build2/b.cli
deleted file mode 100644
index 0ce0f9e..0000000
--- a/build2/b.cli
+++ /dev/null
@@ -1,749 +0,0 @@
-// file : build2/b.cli
-// license : MIT; see accompanying LICENSE file
-
-include <set>;
-include <libbuild2/types.hxx>;
-
-"\section=1"
-"\name=b"
-"\summary=build system driver"
-
-namespace build2
-{
- {
- "<options>
- <variables>
- <buildspec> <meta-operation> <operation> <target> <parameters>",
-
- "\h|SYNOPSIS|
-
- \c{\b{b --help}\n
- \b{b --version}\n
- \b{b} [<options>] [<variables>] [<buildspec>]}
-
- \c{<buildspec> = <meta-operation>\b{(}<operation>\b{(}<target>...[\b{,}<parameters>]\b{)}...\b{)}...}
-
- \h|DESCRIPTION|
-
- The \cb{build2} build system driver executes a set of meta-operations on
- operations on targets according to the build specification, or
- \i{buildspec} for short. This process can be controlled by specifying
- driver <options> and build system <variables>.
-
- Note that <options>, <variables>, and <buildspec> fragments can be
- specified in any order. To avoid treating an argument that starts with
- \cb{'-'} as an option, add the \cb{'--'} separator. To avoid treating an
- argument that contains \cb{'='} as a variable, add the second \cb{'--'}
- separator."
- }
-
- // For usage it's nice to see the list of options on the first page. So
- // let's not put this "extended" description into usage.
- //
- {
- "<meta-operation> <operation> <target> <parameters> <src-base>",
- "",
-
- "All components in the buildspec can be omitted. If <meta-operation> is
- omitted, then it defaults to \cb{perform}. If <operation> is omitted,
- then it defaults to the default operation for this meta-operation. For
- \cb{perform} it is \cb{update}. Finally, if <target> is omitted, then it
- defaults to the current working directory. A meta-operation on operation
- is called an \i{action}. Some operations and meta-operations may take
- additional <parameters>. For example:
-
- \
- $ b # perform(update(./))
- $ b foo/ # perform(update(foo/))
- $ b foo/ bar/ # perform(update(foo/ bar/))
- $ b update # perform(update(./))
- $ b 'clean(../)' # perform(clean(../))
- $ b perform # perform(update(./))
- $ b configure # configure(?(./))
- $ b 'configure(../)' # configure(?(../))
- $ b clean update # perform(clean(./) update(./))
- $ b configure update # configure(?(./)) perform(update(./))
- $ b 'create(conf/, cxx)' # create(?(conf/), cxx)
- \
-
- Notice the question mark used to show the (imaginary) default operation
- for the \cb{configure} meta-operation. For \cb{configure} the default
- operation is \"all operations\". That is, it will configure all the
- operations for the specified target.
-
- You can also \"generate\" multiple operations for the same set of targets.
- Compare:
-
- \
- $ b 'clean(foo/ bar/)' 'update(foo/ bar/)'
- $ b '{clean update}(foo/ bar/)'
- \
-
- Some more useful buildspec examples:
-
- \
- $ b '{clean update}(...)' # rebuild
- $ b '{clean update clean}(...)' # make sure builds
- $ b '{clean test clean}(...)' # make sure passes tests
- $ b '{clean disfigure}(...)' # similar to distclean
- \
-
- In POSIX shells parenthesis are special characters and must be quoted
- when used in a buildspec. Besides being an inconvenience in itself,
- quoting also inhibits path auto-completion. To help with this situation a
- shortcut syntax is available for executing a single operation or
- meta-operation, for example:
-
- \
- $ b clean: foo/ bar/ # clean(foo/ bar/)
- $ b configure: src/@out/ # configure(src/@out/)
- $ b create: conf/, cxx # create(conf/, cxx)
- $ b configure: config.cxx=g++ src/ # configure(src/) config.cxx=g++
- \
-
- To activate the shortcut syntax the first buildspec argument must start
- with an operation or meta-operation name and end with a colon (\cb{:}).
- To transform the shortcut syntax to the normal buildspec syntax the colon
- is replaced with the opening parenthesis ('\cb{(}'), the rest of the
- buildspec arguments are treated as is, and the final closing parenthesis
- ('\cb{)}') is added.
-
- For each <target> the driver expects to find \cb{buildfile} either in the
- target's directory or, if the directory is part of the \cb{out} tree
- (\cb{out_base}), in the corresponding \cb{src} directory (\cb{src_base}).
-
- For example, assuming \cb{foo/} is the source directory of a project:
-
- \
- $ b foo/ # out_base=src_base=foo/
- $ b foo-out/ # out_base=foo-out/ src_base=foo/
- $ b foo-out/exe{foo} # out_base=foo-out/ src_base=foo/
- \
-
- An exception to this requirement is a directory target in which case,
- provided the directory has subdirectories, an \i{implied} \cb{buildfile}
- with the following content is assumed:
-
- \
- # Implied directory buildfile: build all subdirectories.
- #
- ./: */
- \
-
- In the above example, we assumed that the build system driver was able to
- determine the association between \cb{out_base} and \cb{src_base}. In
- case \cb{src_base} and \cb{out_base} are not the same directory, this is
- achieved in one of two ways: the \cb{config} module (which implements the
- \cb{configure}, \cb{disfigure}, and \cb{create} meta-operations) saves
- this association as part of the configuration process. If, however, the
- association hasn't been saved, then we have to specify \cb{src_base}
- explicitly using the following extended <target> syntax:
-
- \c{<src-base>/@<target>}
-
- Continuing with the previous example:
-
- \
- $ b foo/@foo-out/exe{foo} # out_base=foo-out/ src_base=foo/
- \
-
- Normally, you would need to specify \cb{src_base} explicitly only once,
- during configuration. For example, a typical usage would be:
-
- \
- $ b configure: foo/@foo-out/ # src_base is saved
- $ b foo-out/ # no need to specify src_base
- $ b clean: foo-out/exe{foo} # no need to specify src_base
- \
-
- Besides in and out of source builds, \cb{build2} also supports
- configuring a project's source directory as \i{forwarded} to an out of
- source build. With such a forwarded configuration in place, if we run the
- build system driver from the source directory, it will automatically
- build in the output directory and \i{backlink} (using symlinks or another
- suitable mechanism) certain \"interesting\" targets (executables,
- documentation, etc) to the source directory for easy access. Continuing
- with the previous example:
-
- \
- $ b configure: foo/@foo-out/,forward # foo/ forwarded to foo-out/
- $ cd foo/
- $ b # build in foo-out/
- $ ./foo # symlink to foo-out/foo
- \
-
- The ability to specify \cb{build2} variables as part of the command line
- is normally used to pass configuration values, for example:
-
- \
- $ b config.cxx=clang++ config.cxx.coptions=-O3
- \
-
- Similar to buildspec, POSIX shells often inhibit path auto-completion on
- the right hand side of a variable assignment. To help with this situation
- the assignment can be broken down into three separate command line
- arguments, for example:
-
- \
- $ b config.import.libhello = ../libhello/
- \
-
- The build system has the following built-in and pre-defined
- meta-operations:
-
- \dl|
-
- \li|\cb{perform}
-
- Perform an operation.|
-
- \li|\cb{configure}
-
- Configure all operations supported by a project and save the result
- in the project's \cb{build/config.build} file. Implemented by the
- \cb{config} module. For example:
-
- \
- $ b configure \
- config.cxx=clang++ \
- config.cxx.coptions=-O3 \
- config.install.root=/usr/local \
- config.install.root.sudo=sudo
- \
-
- Use the \cb{forward} parameter to instead configure a source
- directory as forwarded to an out of source build. For example:
-
- \
- $ b configure: src/@out/,forward
- \
-
- |
-
- \li|\cb{disfigure}
-
- Disfigure all operations supported by a project and remove the
- project's \cb{build/config.build} file. Implemented by the
- \cb{config} module.
-
- Use the \cb{forward} parameter to instead disfigure forwarding of a
- source directory to an out of source build. For example:
-
- \
- $ b disfigure: src/,forward
- \
-
- |
-
- \li|\cb{create}
-
- Create and configure a \i{configuration} project. Implemented by the
- \cb{config} module.
-
- Normally a \cb{build2} project is created manually by writing the
- \cb{bootstrap.build} and \cb{config.build} files, adding source
- files, and so on. However, a special kind of project, which we call
- \i{configuration}, is often useful. Such a project doesn't have any
- source files of its own. Instead, it serves as an amalgamation for
- building other projects as part of it. Doing it this way has two
- major benefits: sub-projects automatically resolve their imports
- to other projects in the amalgamation and sub-projects inherits their
- configuration from the amalgamation (which means if we want to change
- something, we only need to do it in one place).
-
- As an example, let's assume we have two C++ projects: the
- \cb{libhello} library in \cb{libhello/} and the \cb{hello} executable
- that imports it in \cb{hello/}. And we want to build \cb{hello} with
- \cb{clang++}.
-
- One way to do it would be to configure and build each project in its
- own directory, for example:
-
- \
- $ b configure: libhello/@libhello-clang/ config.cxx=clang++
- $ b configure: hello/@hello-clang/ config.cxx=clang++ \
- config.import.libhello=libhello-clang/
- \
-
- The two drawbacks, as mentioned above, are the need to explicitly
- resolve the import and having to make changes in multiple places
- should, for example, we want to switch from \cb{clang++} to \cb{g++}.
-
- We can, however, achieve the same end result but without any of the
- drawbacks using the configuration project:
-
- \
- $ b create: clang/,cxx config.cxx=clang++ # Creates clang/.
- $ b configure: libhello/@clang/libhello/
- $ b configure: hello/@clang/hello/
- \
-
- The targets passed to the \cb{create} meta-operation must be
- directories which should either not exist or be empty. For each
- such directory \cb{create} first initializes a project as described
- below and then configures it by executing the \cb{configure}
- meta-operation.
-
- The first optional parameter to \cb{create} is the list of modules to
- load in \cb{root.build}. By default, \cb{create} appends \cb{.config}
- to the names of these modules so that only their configurations are
- loaded. You can override this behavior by specifying the period
- (\cb{.}) after the module name. You can also instruct \cb{create} to
- use the optional module load by prefixing the module name with the
- question mark (\cb{?}).
-
- The second optional parameter is the list of modules to load in
- \cb{bootstrap.build}. If not specified, then the \cb{test},
- \cb{dist}, and \cb{install} modules are loaded by default. The
- \cb{config} module is always loaded first.
-
- Besides creating project's \cb{bootstrap.build} and \cb{root.build},
- \cb{create} also writes the root \cb{buildfile} with the following
- contents:
-
- \
- ./: {*/ -build/}
- \
-
- If used, this \cb{buildfile} will build all the sub-projects
- currently present in the configuration.|
-
- \li|\cb{dist}
-
- Prepare a distribution containing all files necessary to perform all
- operations in a project. Implemented by the \cb{dist} module.|
-
- \li|\cb{info}
-
- Print basic information (name, version, source and output
- directories, etc) about one or more projects to \cb{STDOUT},
- separating multiple projects with a blank line. Each project is
- identified by its root directory target. For example:
-
- \
- $ b info: libfoo/ libbar/
- \
-
- ||
-
- The build system has the following built-in and pre-defined operations:
-
- \dl|
-
- \li|\cb{update}
-
- Update a target.|
-
- \li|\cb{clean}
-
- Clean a target.|
-
- \li|\cb{test}
-
- Test a target. Performs \cb{update} as a pre-operation. Implemented by
- the \cb{test} module.|
-
- \li|\cb{update-for-test}
-
- Update a target for testing. This operation is equivalent to the
- \cb{update} pre-operation as executed by the \cb{test} operation and
- can be used to only update what is necessary for testing. Implemented
- by the \cb{test} module.|
-
- \li|\cb{install}
-
- Install a target. Performs \cb{update} as a pre-operation. Implemented
- by the \cb{install} module.|
-
-
- \li|\cb{uninstall}
-
- Uninstall a target. Performs \cb{update} as a pre-operation.
- Implemented by the \cb{install} module.|
-
- \li|\cb{update-for-install}
-
- Update a target for installation. This operation is equivalent to the
- \cb{update} pre-operation as executed by the \cb{install} operation
- and can be used to only update what is necessary for
- installation. Implemented by the \cb{install} module.||
-
- Note that buildspec and command line variable values are treated as
- \cb{buildfile} fragments and so can use quoting and escaping as well as
- contain variable expansions and evaluation contexts. However, to be more
- usable on various platforms, escaping in these two situations is limited
- to the \i{effective sequences} of \cb{\\'}, \cb{\\\"}, \cb{\\\\},
- \cb{\\$}, and \cb{\\(} with all other sequences interpreted as is.
- Together with double-quoting this is sufficient to represent any value.
- For example:
-
- \
- $ b config.install.root=c:\projects\install
- $ b \"config.install.root='c:\Program Files (x86)\test\'\"
- $ b 'config.cxx.poptions=-DFOO_STR=\"foo\"'
- \
- "
- }
-
- class options
- {
- "\h#options|OPTIONS|"
-
- uint64_t --build2-metadata; // Leave undocumented/hidden.
-
- bool -v
- {
- "Print actual commands being executed. This options is equivalent to
- \cb{--verbose 2}."
- }
-
- bool -V
- {
- "Print all underlying commands being executed. This options is
- equivalent to \cb{--verbose 3}."
- }
-
- bool --quiet|-q
- {
- "Run quietly, only printing error messages in most contexts. In certain
- contexts (for example, while updating build system modules) this
- verbosity level may be ignored. Use \cb{--silent} to run quietly in all
- contexts. This option is equivalent to \cb{--verbose 0}."
- }
-
- bool --silent
- {
- "Run quietly, only printing error messages in all contexts."
- }
-
- uint16_t --verbose = 1
- {
- "<level>",
- "Set the diagnostics verbosity to <level> between 0 and 6. Level 0
- disables any non-error messages (but see the difference between
- \cb{--quiet} and \cb{--silent}) while level 6 produces lots of
- information, with level 1 being the default. The following additional
- types of diagnostics are produced at each level:
-
- \ol|
-
- \li|High-level information messages.|
-
- \li|Essential underlying commands being executed.|
-
- \li|All underlying commands being executed.|
-
- \li|Information that could be helpful to the user.|
-
- \li|Information that could be helpful to the developer.|
-
- \li|Even more detailed information.||"
- }
-
- bool --stat
- {
- "Display build statistics."
- }
-
- std::set<string> --dump
- {
- "<phase>",
- "Dump the build system state after the specified phase. Valid <phase>
- values are \cb{load} (after loading \cb{buildfiles}) and \cb{match}
- (after matching rules to targets). Repeat this option to dump the
- state after multiple phases."
- }
-
- bool --progress
- {
- "Display build progress. If printing to a terminal the progress is
- displayed by default for low verbosity levels. Use \cb{--no-progress}
- to suppress."
- }
-
- bool --no-progress
- {
- "Don't display build progress."
- }
-
- size_t --jobs|-j
- {
- "<num>",
- "Number of active jobs to perform in parallel. This includes both the
- number of active threads inside the build system as well as the number
- of external commands (compilers, linkers, etc) started but not yet
- finished. If this option is not specified or specified with the \cb{0}
- value, then the number of available hardware threads is used."
- }
-
- size_t --max-jobs|-J
- {
- "<num>",
- "Maximum number of jobs (threads) to create. The default is 8x the
- number of active jobs (\cb{--jobs|j}) on 32-bit architectures and 32x
- on 64-bit. See the build system scheduler implementation for details."
- }
-
- size_t --queue-depth|-Q = 4
- {
- "<num>",
- "The queue depth as a multiplier over the number of active jobs.
- Normally we want a deeper queue if the jobs take long (for example,
- compilation) and shorter if they are quick (for example, simple tests).
- The default is 4. See the build system scheduler implementation for
- details."
- }
-
- string --file-cache
- {
- "<impl>",
- "File cache implementation to use for intermediate build results. Valid
- values are \cb{noop} (no caching or compression) and \cb{sync-lz4} (no
- caching with synchronous LZ4 on-disk compression). If this option is
- not specified, then a suitable default implementation is used
- (currently \cb{sync-lz4})."
- }
-
- size_t --max-stack
- {
- "<num>",
- "The maximum stack size in KBytes to allow for newly created threads.
- For \i{pthreads}-based systems the driver queries the stack size of
- the main thread and uses the same size for creating additional threads.
- This allows adjusting the stack size using familiar mechanisms, such
- as \cb{ulimit}. Sometimes, however, the stack size of the main thread
- is excessively large. As a result, the driver checks if it is greater
- than a predefined limit (64MB on 64-bit systems and 32MB on 32-bit
- ones) and caps it to a more sensible value (8MB) if that's the case.
- This option allows you to override this check with the special zero
- value indicating that the main thread stack size should be used as is."
- }
-
- bool --serial-stop|-s
- {
- "Run serially and stop at the first error. This mode is useful to
- investigate build failures that are caused by build system errors
- rather than compilation errors. Note that if you don't want to keep
- going but still want parallel execution, add \cb{--jobs|-j} (for
- example \cb{-j\ 0} for default concurrency)."
- }
-
- bool --dry-run|-n
- {
- "Print commands without actually executing them. Note that commands
- that are required to create an accurate build state will still be
- executed and the extracted auxiliary dependency information saved. In
- other words, this is not the \i{\"don't touch the filesystem\"} mode
- but rather \i{\"do minimum amount of work to show what needs to be
- done\"}. Note also that only the \cb{perform} meta-operation supports
- this mode."
- }
-
- bool --match-only
- {
- "Match the rules but do not execute the operation. This mode is primarily
- useful for profiling."
- }
-
- bool --no-external-modules
- {
- "Don't load external modules during project bootstrap. Note that this
- option can only be used with meta-operations that do not load the
- project's \cb{buildfiles}, such as \cb{info}."
- }
-
- bool --structured-result
- {
- "Write the result of execution in a structured form. In this mode,
- instead of printing to \cb{STDERR} diagnostics messages about the
- outcome of executing actions on targets, the driver writes to
- \cb{STDOUT} a structured result description one line per the
- buildspec action/target pair. Each line has the following format:
-
- \c{\i{state} \i{meta-operation} \i{operation} \i{target}}
-
- Where \ci{state} can be one of \cb{unchanged}, \cb{changed}, or
- \cb{failed}. If the action is a pre or post operation, then the
- outer operation is specified in parenthesis. For example:
-
- \
- unchanged perform update(test) /tmp/dir{hello/}
- changed perform test /tmp/dir{hello/}
- \
-
- Note that only the \cb{perform} meta-operation supports the structured
- result output.
- "
- }
-
- bool --mtime-check
- {
- "Perform file modification time sanity checks. These checks can be
- helpful in diagnosing spurious rebuilds and are enabled by default
- for the staged version of the build system. Use \cb{--no-mtime-check}
- to disable."
- }
-
- bool --no-mtime-check
- {
- "Don't perform file modification time sanity checks."
- }
-
- bool --no-column
- {
- "Don't print column numbers in diagnostics."
- }
-
- bool --no-line
- {
- "Don't print line and column numbers in diagnostics."
- }
-
- path --buildfile
- {
- "<path>",
- "The alternative file to read build information from. The default is
- \cb{buildfile} or \cb{build2file}, depending on the project's build
- file/directory naming scheme. If <path> is '\cb{-}', then read from
- \cb{STDIN}. Note that this option only affects the files read as part
- of the buildspec processing. Specifically, it has no effect on the
- \cb{source} and \cb{include} directives. As a result, this option is
- primarily intended for testing rather than changing the build file
- names in real projects."
- }
-
- path --config-guess
- {
- "<path>",
- "The path to the \cb{config.guess(1)} script that should be used to
- guess the host machine triplet. If this option is not specified, then
- \cb{b} will fall back on to using the target it was built for as host."
- }
-
- path --config-sub
- {
- "<path>",
- "The path to the \cb{config.sub(1)} script that should be used to
- canonicalize machine triplets. If this option is not specified, then
- \cb{b} will use its built-in canonicalization support which should
- be sufficient for commonly-used platforms."
- }
-
- string --pager // String to allow empty value.
- {
- "<path>",
- "The pager program to be used to show long text. Commonly used pager
- programs are \cb{less} and \cb{more}. You can also specify additional
- options that should be passed to the pager program with
- \cb{--pager-option}. If an empty string is specified as the pager
- program, then no pager will be used. If the pager program is not
- explicitly specified, then \cb{b} will try to use \cb{less}. If it
- is not available, then no pager will be used."
- }
-
- strings --pager-option
- {
- "<opt>",
- "Additional option to be passed to the pager program. See \cb{--pager}
- for more information on the pager program. Repeat this option to
- specify multiple pager options."
- }
-
- // The following option is "fake" in that it is actually handled by
- // argv_file_scanner. We have it here for documentation.
- //
- string --options-file
- {
- "<file>",
- "Read additional options from <file>. Each option should appear on a
- separate line optionally followed by space or equal sign (\cb{=}) and
- an option value. Empty lines and lines starting with \cb{#} are
- ignored. Option values can be enclosed in double (\cb{\"}) or single
- (\cb{'}) quotes to preserve leading and trailing whitespaces as well as
- to specify empty values. If the value itself contains trailing or
- leading quotes, enclose it with an extra pair of quotes, for example
- \cb{'\"x\"'}. Non-leading and non-trailing quotes are interpreted as
- being part of the option value.
-
- The semantics of providing options in a file is equivalent to providing
- the same set of options in the same order on the command line at the
- point where the \cb{--options-file} option is specified except that
- the shell escaping and quoting is not required. Repeat this option
- to specify more than one options file."
- }
-
- dir_path --default-options
- {
- "<dir>",
- "The directory to load additional default options files from."
- }
-
- bool --no-default-options
- {
- "Don't load default options files."
- }
-
- bool --help {"Print usage information and exit."}
- bool --version {"Print version and exit."}
- };
-
- "
- \h|DEFAULT OPTIONS FILES|
-
- Instead of having a separate config file format for tool configuration, the
- \cb{build2} toolchain uses \i{default options files} which contain the same
- options as what can be specified on the command line. The default options
- files are like options files that one can specify with \cb{--options-file}
- except that they are loaded by default.
-
- 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. 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
- directory, and finishing off with the options specified on the command line.
- In other words, the files are loaded from the more generic to the more
- specific with the command line options having the ability to override any
- values specified in the default options files.
-
- If a default options file contains \cb{--no-default-options}, then the
- search is stopped at the directory containing this file and no outer files
- are loaded. If this option is specified on the command line, then none of
- the default options files are searched for or loaded.
-
- An additional directory containing default options files can be specified
- with \cb{--default-options}. Its configuration files are loaded after the
- home directory.
-
- The order in which default options files are loaded is traced at the
- verbosity level 3 (\cb{-V} option) or higher.
-
- \h|EXIT STATUS|
-
- Non-zero exit status is returned in case of an error.
- "
-
- // NOTE: remember to update --build2-metadata output if adding any relevant
- // new environment variables.
- //
- "
- \h|ENVIRONMENT|
-
- The \cb{HOME} environment variable is used to determine the user's home
- directory. If it is not set, then \cb{getpwuid(3)} is used instead. This
- value is used to shorten paths printed in diagnostics by replacing the home
- directory with \cb{~/}. It is also made available to \cb{buildfile}'s as the
- \cb{build.home} variable.
-
- The \cb{BUILD2_VAR_OVR} environment variable is used to propagate global
- variable overrides to nested build system driver invocations. Its value is a
- list of global variable assignments separated with newlines.
-
- The \cb{BUILD2_DEF_OPT} environment variable is used to suppress loading of
- default options files in nested build system driver invocations. Its values
- are \cb{false} or \cb{0} to suppress and \cb{true} or \cb{1} to load.
- "
-}
diff --git a/build2/b.cxx b/build2/b.cxx
index b07dd0e..8decadf 100644
--- a/build2/b.cxx
+++ b/build2/b.cxx
@@ -1,26 +1,18 @@
// file : build2/b.cxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#ifndef _WIN32
-# include <signal.h> // signal()
-#else
-# include <libbutl/win32-utility.hxx>
-#endif
-
-#ifdef __GLIBCXX__
-# include <locale>
-#endif
-
#include <sstream>
-#include <cstring> // strcmp(), strchr()
#include <typeinfo>
#include <iostream> // cout
#include <exception> // terminate(), set_terminate(), terminate_handler
-#include <libbutl/pager.mxx>
-#include <libbutl/fdstream.mxx> // stderr_fd(), fdterm()
-#include <libbutl/backtrace.mxx> // backtrace()
-#include <libbutl/default-options.mxx>
+#include <libbutl/pager.hxx>
+#include <libbutl/fdstream.hxx> // stderr_fd(), fdterm()
+#include <libbutl/backtrace.hxx> // backtrace()
+
+#ifndef BUILD2_BOOTSTRAP
+# include <libbutl/json/serializer.hxx>
+#endif
#include <libbuild2/types.hxx>
#include <libbuild2/utility.hxx>
@@ -43,7 +35,8 @@
#include <libbuild2/parser.hxx>
-#include <build2/b-options.hxx>
+#include <libbuild2/b-options.hxx>
+#include <libbuild2/b-cmdline.hxx>
// Build system modules.
//
@@ -61,8 +54,7 @@
#ifndef BUILD2_BOOTSTRAP
# include <libbuild2/bash/init.hxx>
-
-# include <build2/cli/init.hxx>
+# include <libbuild2/cli/init.hxx>
#endif
using namespace butl;
@@ -70,75 +62,161 @@ using namespace std;
namespace build2
{
- static options ops;
-
int
main (int argc, char* argv[]);
+#ifndef BUILD2_BOOTSTRAP
// Structured result printer (--structured-result mode).
//
class result_printer
{
public:
- result_printer (const action_targets& tgs): tgs_ (tgs) {}
+ result_printer (const b_options& ops,
+ const action_targets& tgs,
+ json::stream_serializer& js)
+ : ops_ (ops), tgs_ (tgs), json_serializer_ (js) {}
+
~result_printer ();
private:
+ void
+ print_lines ();
+
+ void
+ print_json ();
+
+ private:
+ const b_options& ops_;
const action_targets& tgs_;
+ json::stream_serializer& json_serializer_;
};
+ void result_printer::
+ print_lines ()
+ {
+ for (const action_target& at: tgs_)
+ {
+ if (at.state == target_state::unknown)
+ continue; // Not a target/no result.
+
+ const target& t (at.as<target> ());
+ context& ctx (t.ctx);
+
+ cout << at.state
+ << ' ' << ctx.current_mif->name
+ << ' ' << ctx.current_inner_oif->name;
+
+ if (ctx.current_outer_oif != nullptr)
+ cout << '(' << ctx.current_outer_oif->name << ')';
+
+ // There are two ways one may wish to identify the target of the
+ // operation: as something specific but inherently non-portable (say, a
+ // filesystem path, for example c:\tmp\foo.exe) or as something regular
+ // that can be used to refer to a target in a portable way (for example,
+ // c:\tmp\exe{foo}; note that the directory part is still not portable).
+ // Which one should we use is a good question. Let's go with the
+ // portable one for now and see how it goes (we can always add a format
+ // variant, e.g., --structured-result=lines-path). Note also that the
+ // json format includes both.
+
+ // Set the stream extension verbosity to 0 to suppress extension
+ // printing by default (this can still be overriden by the target type's
+ // print function as is the case for file{}, for example). And set the
+ // path verbosity to 1 to always print absolute.
+ //
+ stream_verbosity sv (stream_verb (cout));
+ stream_verb (cout, stream_verbosity (1, 0));
+
+ cout << ' ' << t << endl;
+
+ stream_verb (cout, sv);
+ }
+ }
+
+ void result_printer::
+ print_json ()
+ {
+ json::stream_serializer& s (json_serializer_);
+
+ for (const action_target& at: tgs_)
+ {
+ if (at.state == target_state::unknown)
+ continue; // Not a target/no result.
+
+ const target& t (at.as<target> ());
+ context& ctx (t.ctx);
+
+ s.begin_object ();
+
+ // Quoted target.
+ //
+ s.member_name ("target");
+ dump_quoted_target_name (s, t);
+
+ // Display target.
+ //
+ s.member_name ("display_target");
+ dump_display_target_name (s, t);
+
+ s.member ("target_type", t.type ().name, false /* check */);
+
+ if (t.is_a<dir> ())
+ s.member ("target_path", t.dir.string ());
+ else if (const auto* pt = t.is_a<path_target> ())
+ s.member ("target_path", pt->path ().string ());
+
+ s.member ("meta_operation", ctx.current_mif->name, false /* check */);
+ s.member ("operation", ctx.current_inner_oif->name, false /* check */);
+
+ if (ctx.current_outer_oif != nullptr)
+ s.member ("outer_operation",
+ ctx.current_outer_oif->name,
+ false /* check */);
+
+ s.member ("state", to_string (at.state), false /* check */);
+
+ s.end_object ();
+ }
+ }
+
result_printer::
~result_printer ()
{
// Let's do some sanity checking even when we are not in the structred
// output mode.
//
+#ifndef NDEBUG
for (const action_target& at: tgs_)
{
switch (at.state)
{
- case target_state::unknown: continue; // Not a target/no result.
+ case target_state::unknown:
case target_state::unchanged:
case target_state::changed:
case target_state::failed: break; // Valid states.
default: assert (false);
}
+ }
+#endif
- if (ops.structured_result ())
+ if (ops_.structured_result_specified ())
+ {
+ switch (ops_.structured_result ())
{
- const target& t (at.as<target> ());
- context& ctx (t.ctx);
-
- cout << at.state
- << ' ' << ctx.current_mif->name
- << ' ' << ctx.current_inner_oif->name;
-
- if (ctx.current_outer_oif != nullptr)
- cout << '(' << ctx.current_outer_oif->name << ')';
-
- // There are two ways one may wish to identify the target of the
- // operation: as something specific but inherently non-portable (say,
- // a filesystem path, for example c:\tmp\foo.exe) or as something
- // regular that can be used to refer to a target in a portable way
- // (for example, c:\tmp\exe{foo}; note that the directory part is
- // still not portable). Which one should we use is a good question.
- // Let's go with the portable one for now and see how it goes (we
- // can always add a format version, e.g., --structured-result=2).
-
- // Set the stream extension verbosity to 0 to suppress extension
- // printing by default (this can still be overriden by the target
- // type's print function as is the case for file{}, for example).
- // And set the path verbosity to 1 to always print absolute.
- //
- stream_verbosity sv (stream_verb (cout));
- stream_verb (cout, stream_verbosity (1, 0));
-
- cout << ' ' << t << endl;
-
- stream_verb (cout, sv);
+ case structured_result_format::lines:
+ {
+ print_lines ();
+ break;
+ }
+ case structured_result_format::json:
+ {
+ print_json ();
+ break;
+ }
}
}
}
+#endif
}
// Print backtrace if terminating due to an unhandled exception. Note that
@@ -171,425 +249,21 @@ main (int argc, char* argv[])
tracer trace ("main");
- int r (0);
-
- // This is a little hack to make out baseutils for Windows work when called
- // with absolute path. In a nutshell, MSYS2's exec*p() doesn't search in the
- // parent's executable directory, only in PATH. And since we are running
- // without a shell (that would read /etc/profile which sets PATH to some
- // sensible values), we are only getting Win32 PATH values. And MSYS2 /bin
- // is not one of them. So what we are going to do is add /bin at the end of
- // PATH (which will be passed as is by the MSYS2 machinery). This will make
- // MSYS2 search in /bin (where our baseutils live). And for everyone else
- // this should be harmless since it is not a valid Win32 path.
- //
-#ifdef _WIN32
- {
- string mp;
- if (optional<string> p = getenv ("PATH"))
- {
- mp = move (*p);
- mp += ';';
- }
- mp += "/bin";
-
- setenv ("PATH", mp);
- }
-#endif
-
- // A data race happens in the libstdc++ (as of GCC 7.2) implementation of
- // the ctype<char>::narrow() function (bug #77704). The issue is easily
- // triggered by the testscript runner that indirectly (via regex) uses
- // ctype<char> facet of the global locale (and can potentially be triggered
- // by other locale- aware code). We work around this by pre-initializing the
- // global locale facet internal cache.
- //
-#ifdef __GLIBCXX__
- {
- const ctype<char>& ct (use_facet<ctype<char>> (locale ()));
-
- for (size_t i (0); i != 256; ++i)
- ct.narrow (static_cast<char> (i), '\0');
- }
-#endif
-
- // On POSIX ignore SIGPIPE which is signaled to a pipe-writing process if
- // the pipe reading end is closed. Note that by default this signal
- // terminates a process. Also note that there is no way to disable this
- // behavior on a file descriptor basis or for the write() function call.
- //
-#ifndef _WIN32
- if (signal (SIGPIPE, SIG_IGN) == SIG_ERR)
- fail << "unable to ignore broken pipe (SIGPIPE) signal: "
- << system_error (errno, generic_category ()); // Sanitize.
-#endif
+ init_process ();
+ int r (0);
+ b_options ops;
scheduler sched;
- // Parse the command line.
+ // Statistics.
//
+ size_t phase_switch_contention (0);
+
try
{
- // Note that the diagnostics verbosity level can only be calculated after
- // default options are loaded and merged (see below). Thus, until then we
- // refer to the verbosity level specified on the command line.
- //
- auto verbosity = [] ()
- {
- uint16_t v (
- ops.verbose_specified ()
- ? ops.verbose ()
- : ops.V () ? 3 : ops.v () ? 2 : ops.quiet () || ops.silent () ? 0 : 1);
-
- if (ops.silent () && v != 0)
- fail << "specified with -v, -V, or --verbose verbosity level " << v
- << " is incompatible with --silent";
-
- return v;
- };
-
- // We want to be able to specify options, vars, and buildspecs in any
- // order (it is really handy to just add -v at the end of the command
- // line).
+ // Parse the command line.
//
- strings cmd_vars;
- string args;
- try
- {
- cl::argv_file_scanner scan (argc, argv, "--options-file");
-
- size_t argn (0); // Argument count.
- bool shortcut (false); // True if the shortcut syntax is used.
-
- for (bool opt (true), var (true); scan.more (); )
- {
- if (opt)
- {
- // If we see first "--", then we are done parsing options.
- //
- if (strcmp (scan.peek (), "--") == 0)
- {
- scan.next ();
- opt = false;
- continue;
- }
-
- // Parse the next chunk of options until we reach an argument (or
- // eos).
- //
- if (ops.parse (scan))
- continue;
-
- // Fall through.
- }
-
- const char* s (scan.next ());
-
- // See if this is a command line variable. What if someone needs to
- // pass a buildspec that contains '='? One way to support this would
- // be to quote such a buildspec (e.g., "'/tmp/foo=bar/'"). Or invent
- // another separator. Or use a second "--". Actually, let's just do
- // the second "--".
- //
- if (var)
- {
- // If we see second "--", then we are also done parsing variables.
- //
- if (strcmp (s, "--") == 0)
- {
- var = false;
- continue;
- }
-
- if (const char* p = strchr (s, '=')) // Covers =, +=, and =+.
- {
- // Diagnose the empty variable name situation. Note that we don't
- // allow "partially broken down" assignments (as in foo =bar)
- // since foo= bar would be ambigous.
- //
- if (p == s || (p == s + 1 && *s == '+'))
- fail << "missing variable name in '" << s << "'";
-
- cmd_vars.push_back (s);
- continue;
- }
-
- // Handle the "broken down" variable assignments (i.e., foo = bar
- // instead of foo=bar).
- //
- if (scan.more ())
- {
- const char* a (scan.peek ());
-
- if (strcmp (a, "=" ) == 0 ||
- strcmp (a, "+=") == 0 ||
- strcmp (a, "=+") == 0)
- {
- string v (s);
- v += a;
-
- scan.next ();
-
- if (scan.more ())
- v += scan.next ();
-
- cmd_vars.push_back (move (v));
- continue;
- }
- }
-
- // Fall through.
- }
-
- // Merge all the individual buildspec arguments into a single string.
- // We use newlines to separate arguments so that line numbers in
- // diagnostics signify argument numbers. Clever, huh?
- //
- if (argn != 0)
- args += '\n';
-
- args += s;
-
- // See if we are using the shortcut syntax.
- //
- if (argn == 0 && args.back () == ':')
- {
- args.back () = '(';
- shortcut = true;
- }
-
- argn++;
- }
-
- // Add the closing parenthesis unless there wasn't anything in between
- // in which case pop the opening one.
- //
- if (shortcut)
- {
- if (argn == 1)
- args.pop_back ();
- else
- args += ')';
- }
-
- // Get/set an environment variable tracing the operation.
- //
- auto get_env = [&verbosity, &trace] (const char* nm)
- {
- optional<string> r (getenv (nm));
-
- if (verbosity () >= 5)
- {
- if (r)
- trace << nm << ": '" << *r << "'";
- else
- trace << nm << ": <NULL>";
- }
-
- return r;
- };
-
- auto set_env = [&verbosity, &trace] (const char* nm, const string& vl)
- {
- try
- {
- if (verbosity () >= 5)
- trace << "setting " << nm << "='" << vl << "'";
-
- setenv (nm, vl);
- }
- catch (const system_error& e)
- {
- // The variable value can potentially be long/multi-line, so let's
- // print it last.
- //
- fail << "unable to set environment variable " << nm << ": " << e <<
- info << "value: '" << vl << "'";
- }
- };
-
- // If the BUILD2_VAR_OVR environment variable is present, then parse its
- // value as a newline-separated global variable overrides and prepend
- // them to the overrides specified on the command line.
- //
- // Note that this means global overrides may not contain a newline.
-
- // Verify that the string is a valid global override. Uses the file name
- // and the options flag for diagnostics only.
- //
- auto verify_glb_ovr = [] (const string& v, const path_name& fn, bool opt)
- {
- size_t p (v.find ('=', 1));
- if (p == string::npos || v[0] != '!')
- {
- diag_record dr (fail (fn));
- dr << "expected " << (opt ? "option or " : "") << "global "
- << "variable override instead of '" << v << "'";
-
- if (p != string::npos)
- dr << info << "prefix variable assignment with '!'";
- }
-
- if (p == 1 || (p == 2 && v[1] == '+')) // '!=' or '!+=' ?
- fail (fn) << "missing variable name in '" << v << "'";
- };
-
- optional<string> env_ovr (get_env ("BUILD2_VAR_OVR"));
- if (env_ovr)
- {
- path_name fn ("<BUILD2_VAR_OVR>");
-
- auto i (cmd_vars.begin ());
- for (size_t b (0), e (0); next_word (*env_ovr, b, e, '\n', '\r'); )
- {
- // Extract the override from the current line, stripping the leading
- // and trailing spaces.
- //
- string s (*env_ovr, b, e - b);
- trim (s);
-
- // Verify and save the override, unless the line is empty.
- //
- if (!s.empty ())
- {
- verify_glb_ovr (s, fn, false /* opt */);
- i = cmd_vars.insert (i, move (s)) + 1;
- }
- }
- }
-
- // Load the default options files, unless --no-default-options is
- // specified on the command line or the BUILD2_DEF_OPT environment
- // variable is set to a value other than 'true' or '1'.
- //
- // If loaded, prepend the default global overrides to the variables
- // specified on the command line, unless BUILD2_VAR_OVR is set in which
- // case just ignore them.
- //
- optional<string> env_def (get_env ("BUILD2_DEF_OPT"));
-
- // False if --no-default-options is specified on the command line. Note
- // that we cache the flag since it can be overridden by a default
- // options file.
- //
- bool cmd_def (!ops.no_default_options ());
-
- if (cmd_def && (!env_def || *env_def == "true" || *env_def == "1"))
- try
- {
- optional<dir_path> extra;
- if (ops.default_options_specified ())
- extra = ops.default_options ();
-
- // Load default options files.
- //
- default_options<options> def_ops (
- load_default_options<options,
- cl::argv_file_scanner,
- cl::unknown_mode> (
- nullopt /* sys_dir */,
- path::home_directory (), // The home variable is not assigned yet.
- extra,
- default_options_files {{path ("b.options")},
- nullopt /* start */},
- [&trace, &verbosity] (const path& f, bool r, bool o)
- {
- if (verbosity () >= 3)
- {
- if (o)
- trace << "treating " << f << " as "
- << (r ? "remote" : "local");
- else
- trace << "loading " << (r ? "remote " : "local ") << f;
- }
- },
- "--options-file",
- true /* args */));
-
- // Merge the default and command line options.
- //
- ops = merge_default_options (def_ops, ops);
-
- // Merge the default and command line global overrides, unless
- // BUILD2_VAR_OVR is already set (in which case we assume this has
- // already been done).
- //
- // Note that the "broken down" variable assignments occupying a single
- // line are naturally supported.
- //
- if (!env_ovr)
- cmd_vars =
- merge_default_arguments (
- def_ops,
- cmd_vars,
- [&verify_glb_ovr] (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)
- verify_glb_ovr (a, fn, true /* opt */);
- });
- }
- catch (const pair<path, system_error>& e)
- {
- fail << "unable to load default options files: " << e.first << ": "
- << e.second;
- }
- catch (const system_error& e)
- {
- fail << "unable to obtain home directory: " << e;
- }
-
- // Verify and save the global overrides present in cmd_vars (default,
- // from the command line, etc), if any, into the BUILD2_VAR_OVR
- // environment variable.
- //
- if (!cmd_vars.empty ())
- {
- string ovr;
- for (const string& v: cmd_vars)
- {
- if (v[0] == '!')
- {
- if (v.find_first_of ("\n\r") != string::npos)
- fail << "newline in global variable override '" << v << "'";
-
- if (!ovr.empty ())
- ovr += '\n';
-
- ovr += v;
- }
- }
-
- // Optimize for the common case.
- //
- // Note: cmd_vars may contain non-global overrides.
- //
- if (!ovr.empty () && (!env_ovr || *env_ovr != ovr))
- set_env ("BUILD2_VAR_OVR", ovr);
- }
-
- // Propagate disabling of the default options files to the potential
- // nested invocations.
- //
- if (!cmd_def && (!env_def || *env_def != "0"))
- set_env ("BUILD2_DEF_OPT", "0");
-
- // Validate options.
- //
- if (ops.progress () && ops.no_progress ())
- fail << "both --progress and --no-progress specified";
-
- if (ops.mtime_check () && ops.no_mtime_check ())
- fail << "both --mtime-check and --no-mtime-check specified";
- }
- catch (const cl::exception& e)
- {
- fail << e;
- }
+ b_cmdline cmdl (parse_b_cmdline (trace, argc, argv, ops));
// Handle --build2-metadata (see also buildfile).
//
@@ -639,10 +313,10 @@ main (int argc, char* argv[])
// Initialize the diagnostics state.
//
- init_diag (verbosity (),
+ init_diag (cmdl.verbosity,
ops.silent (),
- (ops.progress () ? optional<bool> (true) :
- ops.no_progress () ? optional<bool> (false) : nullopt),
+ cmdl.progress,
+ cmdl.diag_color,
ops.no_line (),
ops.no_column (),
fdterm (stderr_fd ()));
@@ -673,36 +347,14 @@ main (int argc, char* argv[])
}
}
- // Initialize time conversion data that is used by localtime_r().
- //
-#ifndef _WIN32
- tzset ();
-#else
- _tzset ();
-#endif
-
// Initialize the global state.
//
init (&::terminate,
argv[0],
- (ops.mtime_check () ? optional<bool> (true) :
- ops.no_mtime_check () ? optional<bool> (false) : nullopt),
- (ops.config_sub_specified ()
- ? optional<path> (ops.config_sub ())
- : nullopt),
- (ops.config_guess_specified ()
- ? optional<path> (ops.config_guess ())
- : nullopt));
-
-#ifdef _WIN32
- // On Windows disable displaying error reporting dialog box for the
- // current and child processes unless we are in the stop mode. Failed that
- // we may have multiple dialog boxes popping up.
- //
- if (!ops.serial_stop ())
- SetErrorMode (SetErrorMode (0) | // Returns the current mode.
- SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
-#endif
+ ops.serial_stop (),
+ cmdl.mtime_check,
+ cmdl.config_sub,
+ cmdl.config_guess);
// Load builtin modules.
//
@@ -719,64 +371,20 @@ main (int argc, char* argv[])
load_builtin_module (&in::build2_in_load);
#ifndef BUILD2_BOOTSTRAP
- load_builtin_module (&cli::build2_cli_load);
load_builtin_module (&bash::build2_bash_load);
+ load_builtin_module (&cli::build2_cli_load);
#endif
// Start up the scheduler and allocate lock shards.
//
- size_t jobs (0);
-
- if (ops.jobs_specified ())
- jobs = ops.jobs ();
- else if (ops.serial_stop ())
- jobs = 1;
-
- if (jobs == 0)
- jobs = scheduler::hardware_concurrency ();
-
- if (jobs == 0)
- {
- warn << "unable to determine the number of hardware threads" <<
- info << "falling back to serial execution" <<
- info << "use --jobs|-j to override";
-
- jobs = 1;
- }
-
- size_t max_jobs (0);
-
- if (ops.max_jobs_specified ())
- {
- max_jobs = ops.max_jobs ();
-
- if (max_jobs != 0 && max_jobs < jobs)
- fail << "invalid --max-jobs|-J value";
- }
-
- sched.startup (jobs,
- 1,
- max_jobs,
- jobs * ops.queue_depth (),
- (ops.max_stack_specified ()
- ? optional<size_t> (ops.max_stack () * 1024)
- : nullopt));
+ sched.startup (cmdl.jobs,
+ 1 /* init_active */,
+ cmdl.max_jobs,
+ cmdl.jobs * ops.queue_depth (),
+ cmdl.max_stack);
global_mutexes mutexes (sched.shard_size ());
-
- bool fcache_comp (true);
- if (ops.file_cache_specified ())
- {
- const string& v (ops.file_cache ());
- if (v == "noop" || v == "none")
- fcache_comp = false;
- else if (v == "sync-lz4")
- fcache_comp = true;
- else
- fail << "invalid --file-cache value '" << v << "'";
- }
-
- file_cache fcache (fcache_comp);
+ file_cache fcache (cmdl.fcache_compress);
// Trace some overall environment information.
//
@@ -788,25 +396,45 @@ main (int argc, char* argv[])
trace << "home: " << home;
trace << "path: " << (p ? *p : "<NULL>");
trace << "type: " << (build_installed ? "installed" : "development");
- trace << "jobs: " << jobs;
+ trace << "jobs: " << cmdl.jobs;
}
// Set the build context before parsing the buildspec since it relies on
// the global scope being setup. We reset it for every meta-operation (see
// below).
//
- unique_ptr<context> ctx;
- auto new_context = [&ctx, &sched, &mutexes, &fcache, &cmd_vars]
+ unique_ptr<context> pctx;
+ auto new_context = [&ops, &cmdl,
+ &sched, &mutexes, &fcache,
+ &phase_switch_contention,
+ &pctx]
{
- ctx = nullptr; // Free first.
- ctx.reset (new context (sched,
- mutexes,
- fcache,
- ops.match_only (),
- ops.no_external_modules (),
- ops.dry_run (),
- !ops.serial_stop () /* keep_going */,
- cmd_vars));
+ if (pctx != nullptr)
+ {
+ phase_switch_contention += (pctx->phase_mutex.contention +
+ pctx->phase_mutex.contention_load);
+ pctx = nullptr; // Free first to reuse memory.
+ }
+
+ optional<match_only_level> mo;
+ if (ops.load_only ()) mo = match_only_level::alias;
+ else if (ops.match_only ()) mo = match_only_level::all;
+
+ pctx.reset (new context (sched,
+ mutexes,
+ fcache,
+ mo,
+ ops.no_external_modules (),
+ ops.dry_run (),
+ ops.no_diag_buffer (),
+ !ops.serial_stop () /* keep_going */,
+ cmdl.cmd_vars));
+
+ if (ops.trace_match_specified ())
+ pctx->trace_match = &ops.trace_match ();
+
+ if (ops.trace_execute_specified ())
+ pctx->trace_execute = &ops.trace_execute ();
};
new_context ();
@@ -814,17 +442,18 @@ main (int argc, char* argv[])
// Parse the buildspec.
//
buildspec bspec;
+ path_name bspec_name ("<buildspec>");
try
{
- istringstream is (args);
+ istringstream is (cmdl.buildspec);
is.exceptions (istringstream::failbit | istringstream::badbit);
- parser p (*ctx);
- bspec = p.parse_buildspec (is, path_name ("<buildspec>"));
+ parser p (*pctx);
+ bspec = p.parse_buildspec (is, bspec_name);
}
catch (const io_error&)
{
- fail << "unable to parse buildspec '" << args << "'";
+ fail << "unable to parse buildspec '" << cmdl.buildspec << "'";
}
l5 ([&]{trace << "buildspec: " << bspec;});
@@ -832,18 +461,194 @@ main (int argc, char* argv[])
if (bspec.empty ())
bspec.push_back (metaopspec ()); // Default meta-operation.
+ // The reserve values were picked experimentally. They allow building a
+ // sample application that depends on Qt and Boost without causing a
+ // rehash.
+ //
+ // Note: omit reserving anything for the info meta-operation since it
+ // won't be loading the buildfiles and needs to be as fast as possible.
+ //
+ bool mo_info (bspec.size () == 1 &&
+ bspec.front ().size () == 1 &&
+ (bspec.front ().name == "info" ||
+ (bspec.front ().name.empty () &&
+ bspec.front ().front ().name == "info")));
+
+ if (!mo_info)
+ {
+ // Note: also adjust in bpkg if adjusting here.
+ //
+ pctx->reserve (context::reserves {
+ 30000 /* targets */,
+ 1100 /* variables */});
+ }
+
+ bool load_only (ops.load_only ());
+
const path& buildfile (ops.buildfile_specified ()
? ops.buildfile ()
: empty_path);
bool dump_load (false);
bool dump_match (false);
- if (ops.dump_specified ())
+ bool dump_match_pre (false);
+ bool dump_match_post (false);
+ for (const string& p: ops.dump ())
{
- dump_load = ops.dump ().find ("load") != ops.dump ().end ();
- dump_match = ops.dump ().find ("match") != ops.dump ().end ();
+ if (p == "load") dump_load = true;
+ else if (p == "match") dump_match = true;
+ else if (p == "match-pre") dump_match_pre = true;
+ else if (p == "match-post") dump_match_post = true;
+ else fail << "unknown phase '" << p << "' specified with --dump";
}
+ dump_format dump_fmt (dump_format::buildfile);
+ if (ops.dump_format_specified ())
+ {
+ const string& f (ops.dump_format ());
+
+ if (f == "json-v0.1")
+ {
+#ifdef BUILD2_BOOTSTRAP
+ fail << "json dump not supported in bootstrap build system";
+#endif
+ dump_fmt = dump_format::json;
+ }
+ else if (f != "buildfile")
+ {
+ diag_record dr (fail);
+
+ dr << "unsupported format '" << f << "' specified with --dump-format";
+
+ if (f.compare (0, 4, "json") == 0)
+ dr << info << "supported json format version is json-v0.1";
+ }
+ }
+
+ auto dump = [&trace, &ops, dump_fmt] (context& ctx, optional<action> a)
+ {
+ const dir_paths& scopes (ops.dump_scope ());
+ const vector<pair<name, optional<name>>>& targets (ops.dump_target ());
+
+ if (scopes.empty () && targets.empty ())
+ build2::dump (ctx, a, dump_fmt);
+ else
+ {
+ auto comp_norm = [] (dir_path& d, const char* what)
+ {
+ try
+ {
+ if (d.relative ())
+ d.complete ();
+
+ d.normalize ();
+ }
+ catch (const invalid_path& e)
+ {
+ fail << "invalid path '" << e.path << "' specified with " << what;
+ }
+ };
+
+ // If exact is false then return any outer scope that contains this
+ // directory except for the global scope.
+ //
+ auto find_scope = [&ctx, &comp_norm] (dir_path& d,
+ bool exact,
+ const char* what) -> const scope*
+ {
+ comp_norm (d, what);
+
+ // This is always the output directory (specifically, see the target
+ // case below).
+ //
+ const scope& s (ctx.scopes.find_out (d));
+
+ return ((exact ? s.out_path () == d : s != ctx.global_scope)
+ ? &s
+ : nullptr);
+ };
+
+ // Dump scopes.
+ //
+ for (dir_path d: scopes)
+ {
+ const scope* s (find_scope (d, true, "--dump-scope"));
+
+ if (s == nullptr)
+ l5 ([&]{trace << "unknown target scope " << d
+ << " specified with --dump-scope";});
+
+ build2::dump (s, a, dump_fmt);
+ }
+
+ // Dump targets.
+ //
+ for (const pair<name, optional<name>>& p: targets)
+ {
+ const target* t (nullptr);
+
+ // Find the innermost known scope that contains this target. This
+ // is where we are going to resolve its type.
+ //
+ dir_path d (p.second ? p.second->dir : p.first.dir);
+
+ if (const scope* s = find_scope (d, false, "--dump-target"))
+ {
+ // Complete relative directories in names.
+ //
+ name n (p.first), o;
+
+ if (p.second)
+ {
+ comp_norm (n.dir, "--dump-target");
+ o.dir = move (d);
+ }
+ else
+ n.dir = move (d);
+
+ // Similar logic to parser::enter_target::find_target() as used by
+ // the dump directive. Except here we treat unknown target type as
+ // unknown target.
+ //
+ auto r (s->find_target_type (n, location ()));
+
+ if (r.first != nullptr)
+ {
+ t = ctx.targets.find (*r.first, // target type
+ n.dir,
+ o.dir,
+ n.value,
+ r.second, // extension
+ trace);
+
+ if (t == nullptr)
+ l5 ([&]
+ {
+ // @@ TODO: default_extension?
+ //
+ target::combine_name (n.value, r.second, false);
+ names ns {move (n)};
+ if (p.second)
+ ns.push_back (move (o));
+
+ trace << "unknown target " << ns
+ << " specified with --dump-target";
+ });
+ }
+ else
+ l5 ([&]{trace << "unknown target type '" << n.type << "' in "
+ << *s << " specified with --dump-target";});
+
+ }
+ else
+ l5 ([&]{trace << "unknown target scope " << d
+ << " specified with --dump-target";});
+
+ build2::dump (t, a, dump_fmt);
+ }
+ }
+ };
+
// If not NULL, then lifted points to the operation that has been "lifted"
// to the meta-operaion (see the logic below for details). Skip is the
// position of the next operation.
@@ -856,6 +661,20 @@ main (int argc, char* argv[])
//
bool dirty (false); // Already (re)set for the first run.
+#ifndef BUILD2_BOOTSTRAP
+ // Note that this constructor is cheap and so we rather call it always
+ // instead of resorting to dynamic allocations.
+ //
+ // Note also that we disable pretty-printing if there is also the JSON
+ // dump and thus we need to combine the two in the JSON Lines format.
+ //
+ json::stream_serializer js (cout, dump_fmt == dump_format::json ? 0 : 2);
+
+ if (ops.structured_result_specified () &&
+ ops.structured_result () == structured_result_format::json)
+ js.begin_array ();
+#endif
+
for (auto mit (bspec.begin ()); mit != bspec.end (); )
{
vector_view<opspec> opspecs;
@@ -897,8 +716,9 @@ main (int argc, char* argv[])
dirty = false;
}
- const path p ("<buildspec>");
- const location l (p, 0, 0); //@@ TODO
+ context& ctx (*pctx);
+
+ const location l (bspec_name, 0, 0); //@@ TODO (also bpkg::pkg_configure())
meta_operation_id mid (0); // Not yet translated.
const meta_operation_info* mif (nullptr);
@@ -911,25 +731,25 @@ main (int argc, char* argv[])
values& mparams (lifted == nullptr ? mit->params : lifted->params);
string mname (lifted == nullptr ? mit->name : lifted->name);
- ctx->current_mname = mname; // Set early.
+ ctx.current_mname = mname; // Set early.
if (!mname.empty ())
{
- if (meta_operation_id m = ctx->meta_operation_table.find (mname))
+ if (meta_operation_id m = ctx.meta_operation_table.find (mname))
{
// Can modify params, opspec, change meta-operation name.
//
- if (auto f = ctx->meta_operation_table[m].process)
- mname = ctx->current_mname = f (
- *ctx, mparams, opspecs, lifted != nullptr, l);
+ if (auto f = ctx.meta_operation_table[m].process)
+ mname = ctx.current_mname = f (
+ ctx, mparams, opspecs, lifted != nullptr, l);
}
}
// Expose early so can be used during bootstrap (with the same
// limitations as for pre-processing).
//
- scope& gs (ctx->global_scope.rw ());
- gs.assign (ctx->var_build_meta_operation) = mname;
+ scope& gs (ctx.global_scope.rw ());
+ gs.assign (ctx.var_build_meta_operation) = mname;
for (auto oit (opspecs.begin ()); oit != opspecs.end (); ++oit)
{
@@ -940,7 +760,7 @@ main (int argc, char* argv[])
const values& oparams (lifted == nullptr ? os.params : values ());
const string& oname (lifted == nullptr ? os.name : empty_string);
- ctx->current_oname = oname; // Set early.
+ ctx.current_oname = oname; // Set early.
if (lifted != nullptr)
lifted = nullptr; // Clear for the next iteration.
@@ -964,7 +784,7 @@ main (int argc, char* argv[])
&oname, &mname,
&os, &mit, &lifted, &skip, &l, &trace] ()
{
- meta_operation_id m (ctx->meta_operation_table.find (oname));
+ meta_operation_id m (ctx.meta_operation_table.find (oname));
if (m != 0)
{
@@ -1036,12 +856,19 @@ main (int argc, char* argv[])
}
}
- if (out_base.relative ())
- out_base = work / out_base;
+ try
+ {
+ if (out_base.relative ())
+ out_base = work / out_base;
- // This directory came from the command line so actualize it.
- //
- out_base.normalize (true);
+ // This directory came from the command line so actualize it.
+ //
+ out_base.normalize (true);
+ }
+ catch (const invalid_path& e)
+ {
+ fail << "invalid out_base directory '" << e.path << "'";
+ }
// The order in which we determine the roots depends on whether
// src_base was specified explicitly.
@@ -1067,12 +894,19 @@ main (int argc, char* argv[])
if (!exists (src_base))
fail << "src_base directory " << src_base << " does not exist";
- if (src_base.relative ())
- src_base = work / src_base;
+ try
+ {
+ if (src_base.relative ())
+ src_base = work / src_base;
- // Also came from the command line, so actualize.
- //
- src_base.normalize (true);
+ // Also came from the command line, so actualize.
+ //
+ src_base.normalize (true);
+ }
+ catch (const invalid_path& e)
+ {
+ fail << "invalid src_base directory '" << e.path << "'";
+ }
// Make sure out_base is not a subdirectory of src_base. Who would
// want to do that, you may ask. Well, you would be surprised...
@@ -1123,7 +957,7 @@ main (int argc, char* argv[])
// Handle a forwarded configuration. Note that if we've changed
// out_root then we also have to remap out_base.
//
- out_root = bootstrap_fwd (*ctx, src_root, altn);
+ out_root = bootstrap_fwd (ctx, src_root, altn);
if (src_root != out_root)
{
out_base = out_root / out_base.leaf (src_root);
@@ -1168,7 +1002,7 @@ main (int argc, char* argv[])
// use to the bootstrap files (other than src-root.build, which,
// BTW, doesn't need to exist if src_root == out_root).
//
- scope& rs (*create_root (*ctx, out_root, src_root)->second.front ());
+ scope& rs (*create_root (ctx, out_root, src_root)->second.front ());
bool bstrapped (bootstrapped (rs));
@@ -1204,8 +1038,8 @@ main (int argc, char* argv[])
<< (forwarded ? "forwarded " : "specified ")
<< src_root;
- ctx->new_src_root = src_root;
- ctx->old_src_root = move (p);
+ ctx.new_src_root = src_root;
+ ctx.old_src_root = move (p);
p = src_root;
}
}
@@ -1227,8 +1061,13 @@ main (int argc, char* argv[])
// Now that we have src_root, load the src_root bootstrap file,
// if there is one.
//
+ // As an optimization, omit discovering subprojects for the info
+ // meta-operation if not needed.
+ //
bootstrap_pre (rs, altn);
- bootstrap_src (rs, altn);
+ bootstrap_src (rs, altn,
+ nullopt /* amalgamation */,
+ !mo_info || info_subprojects (mparams) /*subprojects*/);
// If this is a simple project, then implicitly load the test and
// install modules.
@@ -1248,7 +1087,7 @@ main (int argc, char* argv[])
// command line and import).
//
if (forwarded)
- rs.assign (ctx->var_forwarded) = true;
+ rs.assign (ctx.var_forwarded) = true;
// Sync local variable that are used below with actual values.
//
@@ -1300,8 +1139,8 @@ main (int argc, char* argv[])
// all be known. We store the combined action id in uint8_t;
// see <operation> for details.
//
- assert (ctx->operation_table.size () <= 128);
- assert (ctx->meta_operation_table.size () <= 128);
+ assert (ctx.operation_table.size () <= 128);
+ assert (ctx.meta_operation_table.size () <= 128);
// Since we now know all the names of meta-operations and
// operations, "lift" names that we assumed (from buildspec syntax)
@@ -1318,7 +1157,7 @@ main (int argc, char* argv[])
if (!mname.empty ())
{
- m = ctx->meta_operation_table.find (mname);
+ m = ctx.meta_operation_table.find (mname);
if (m == 0)
fail (l) << "unknown meta-operation " << mname;
@@ -1326,7 +1165,7 @@ main (int argc, char* argv[])
if (!oname.empty ())
{
- o = ctx->operation_table.find (oname);
+ o = ctx.operation_table.find (oname);
if (o == 0)
fail (l) << "unknown operation " << oname;
@@ -1349,7 +1188,7 @@ main (int argc, char* argv[])
if (mif == nullptr)
fail (l) << "target " << tn << " does not support meta-"
- << "operation " << ctx->meta_operation_table[m].name;
+ << "operation " << ctx.meta_operation_table[m].name;
}
//
// Otherwise, check that all the targets in a meta-operation
@@ -1362,7 +1201,7 @@ main (int argc, char* argv[])
if (mi == nullptr)
fail (l) << "target " << tn << " does not support meta-"
- << "operation " << ctx->meta_operation_table[mid].name;
+ << "operation " << ctx.meta_operation_table[mid].name;
if (mi != mif)
fail (l) << "different implementations of meta-operation "
@@ -1385,12 +1224,12 @@ main (int argc, char* argv[])
<< ", id " << static_cast<uint16_t> (mid);});
if (mif->meta_operation_pre != nullptr)
- mif->meta_operation_pre (mparams, l);
+ mif->meta_operation_pre (ctx, mparams, l);
else if (!mparams.empty ())
fail (l) << "unexpected parameters for meta-operation "
<< mif->name;
- ctx->current_meta_operation (*mif);
+ ctx.current_meta_operation (*mif);
dirty = true;
}
@@ -1406,7 +1245,7 @@ main (int argc, char* argv[])
if (r == nullptr)
fail (l) << "target " << tn << " does not support "
- << "operation " << ctx->operation_table[o];
+ << "operation " << ctx.operation_table[o];
return r;
};
@@ -1424,7 +1263,7 @@ main (int argc, char* argv[])
// Allow the meta-operation to translate the operation.
//
if (mif->operation_pre != nullptr)
- oid = mif->operation_pre (mparams, oif->id);
+ oid = mif->operation_pre (ctx, mparams, oif->id);
else // Otherwise translate default to update.
oid = (oif->id == default_id ? update_id : oif->id);
@@ -1445,24 +1284,38 @@ main (int argc, char* argv[])
if (oif->outer_id != 0)
outer_oif = lookup (oif->outer_id);
+ if (!oparams.empty ())
+ {
+ // Operation parameters belong to outer operation, if any.
+ //
+ auto* i (outer_oif != nullptr ? outer_oif : oif);
+
+ if (i->operation_pre == nullptr)
+ fail (l) << "unexpected parameters for operation " << i->name;
+ }
+
// Handle pre/post operations.
//
- if (oif->pre != nullptr)
+ if (auto po = oif->pre_operation)
{
- if ((orig_pre_oid = oif->pre (oparams, mid, l)) != 0)
+ if ((orig_pre_oid = po (
+ ctx,
+ outer_oif == nullptr ? oparams : values {},
+ mid,
+ l)) != 0)
{
assert (orig_pre_oid != default_id);
pre_oif = lookup (orig_pre_oid);
pre_oid = pre_oif->id; // De-alias.
}
}
- else if (!oparams.empty ())
- fail (l) << "unexpected parameters for operation "
- << oif->name;
- if (oif->post != nullptr)
+ if (auto po = oif->post_operation)
{
- if ((orig_post_oid = oif->post (oparams, mid)) != 0)
+ if ((orig_post_oid = po (
+ ctx,
+ outer_oif == nullptr ? oparams : values {},
+ mid)) != 0)
{
assert (orig_post_oid != default_id);
post_oif = lookup (orig_post_oid);
@@ -1483,7 +1336,7 @@ main (int argc, char* argv[])
if (r == nullptr)
fail (l) << "target " << tn << " does not support "
- << "operation " << ctx->operation_table[o];
+ << "operation " << ctx.operation_table[o];
if (r != i)
fail (l) << "different implementations of operation "
@@ -1508,6 +1361,9 @@ main (int argc, char* argv[])
// defined there (common with non-intrusive project conversions
// where everything is built from a single root buildfile).
//
+ // Note: we use find_plausible_buildfile() and not find_buildfile()
+ // to look in outer directories.
+ //
optional<path> bf (
find_buildfile (src_base, src_base, altn, buildfile));
@@ -1545,6 +1401,7 @@ main (int argc, char* argv[])
if (const dir_path* a = *rs.root_extra->amalgamation)
{
trace << " amalgamation: " << *a;
+ trace << " bundle scope: " << *rs.bundle_scope ();
trace << " strong scope: " << *rs.strong_scope ();
trace << " weak scope: " << *rs.weak_scope ();
}
@@ -1557,62 +1414,7 @@ main (int argc, char* argv[])
// boundaries (specifically, amalgamation) are only known after
// bootstrap.
//
- // The mildly tricky part here is to distinguish the situation where
- // we are bootstrapping the same project multiple times. The first
- // override that we set cannot already exist (because the override
- // variable names are unique) so if it is already set, then it can
- // only mean this project is already bootstrapped.
- //
- // This is further complicated by the project vs amalgamation logic
- // (we may have already done the amalgamation but not the project).
- // So we split it into two passes.
- //
- {
- auto& sm (ctx->scopes.rw ());
-
- for (const variable_override& o: ctx->var_overrides)
- {
- if (o.ovr.visibility != variable_visibility::global)
- continue;
-
- // If we have a directory, enter the scope, similar to how we do
- // it in the context ctor.
- //
- scope& s (
- o.dir
- ? *sm.insert_out ((out_base / *o.dir).normalize ())->second.front ()
- : *rs.weak_scope ());
-
- auto p (s.vars.insert (o.ovr));
-
- if (!p.second)
- break;
-
- value& v (p.first);
- v = o.val;
- }
-
- for (const variable_override& o: ctx->var_overrides)
- {
- // Ours is either project (%foo) or scope (/foo).
- //
- if (o.ovr.visibility == variable_visibility::global)
- continue;
-
- scope& s (
- o.dir
- ? *sm.insert_out ((out_base / *o.dir).normalize ())->second.front ()
- : rs);
-
- auto p (s.vars.insert (o.ovr));
-
- if (!p.second)
- break;
-
- value& v (p.first);
- v = o.val;
- }
- }
+ ctx.enter_project_overrides (rs, out_base, ctx.var_overrides);
ts.root_scope = &rs;
ts.out_base = move (out_base);
@@ -1627,6 +1429,9 @@ main (int argc, char* argv[])
break;
}
+ if (load_only && (mid != perform_id || oid != update_id))
+ fail << "--load-only requires perform(update) action";
+
// Now load the buildfiles and search the targets.
//
action_targets tgs;
@@ -1647,7 +1452,7 @@ main (int argc, char* argv[])
// building before we know how to for all the targets in this
// operation batch.
//
- const scope& bs (ctx->scopes.find_out (ts.out_base));
+ const scope& bs (ctx.scopes.find_out (ts.out_base));
// Find the target type and extract the extension.
//
@@ -1658,6 +1463,9 @@ main (int argc, char* argv[])
if (tt == nullptr)
fail (l) << "unknown target type " << tn.type;
+ if (load_only && !tt->is_a<alias> ())
+ fail << "--load-only requires alias target";
+
if (mif->search != nullptr)
{
// If the directory is relative, assume it is relative to work
@@ -1665,10 +1473,17 @@ main (int argc, char* argv[])
//
dir_path& d (tn.dir);
- if (d.relative ())
- d = work / d;
+ try
+ {
+ if (d.relative ())
+ d = work / d;
- d.normalize (true); // Actualize since came from command line.
+ d.normalize (true); // Actualize since came from command line.
+ }
+ catch (const invalid_path& e)
+ {
+ fail << "invalid target directory '" << e.path << "'";
+ }
if (ts.forwarded)
d = rs.out_path () / d.leaf (rs.src_path ()); // Remap.
@@ -1688,8 +1503,10 @@ main (int argc, char* argv[])
}
} // target
- if (dump_load)
- dump (*ctx);
+ // Delay until after match in the --load-only mode (see below).
+ //
+ if (dump_load && !load_only)
+ dump (ctx, nullopt /* action */);
// Finally, match the rules and perform the operation.
//
@@ -1699,28 +1516,42 @@ main (int argc, char* argv[])
<< ", id " << static_cast<uint16_t> (pre_oid);});
if (mif->operation_pre != nullptr)
- mif->operation_pre (mparams, pre_oid); // Cannot be translated.
+ mif->operation_pre (ctx, mparams, pre_oid); // Can't be translated.
+
+ ctx.current_operation (*pre_oif, oif);
+
+ if (oif->operation_pre != nullptr)
+ oif->operation_pre (ctx, oparams, false /* inner */, l);
- ctx->current_operation (*pre_oif, oif);
+ if (pre_oif->operation_pre != nullptr)
+ pre_oif->operation_pre (ctx, {}, true /* inner */, l);
action a (mid, pre_oid, oid);
{
- result_printer p (tgs);
- uint16_t diag (ops.structured_result () ? 0 : 1);
+#ifndef BUILD2_BOOTSTRAP
+ result_printer p (ops, tgs, js);
+#endif
+ uint16_t diag (ops.structured_result_specified () ? 0 : 1);
if (mif->match != nullptr)
mif->match (mparams, a, tgs, diag, true /* progress */);
- if (dump_match)
- dump (*ctx, a);
+ if (dump_match_pre)
+ dump (ctx, a);
- if (mif->execute != nullptr && !ctx->match_only)
+ if (mif->execute != nullptr && !ctx.match_only)
mif->execute (mparams, a, tgs, diag, true /* progress */);
}
+ if (pre_oif->operation_post != nullptr)
+ pre_oif->operation_post (ctx, {}, true /* inner */);
+
+ if (oif->operation_post != nullptr)
+ oif->operation_post (ctx, oparams, false /* inner */);
+
if (mif->operation_post != nullptr)
- mif->operation_post (mparams, pre_oid);
+ mif->operation_post (ctx, mparams, pre_oid);
l5 ([&]{trace << "end pre-operation batch " << pre_oif->name
<< ", id " << static_cast<uint16_t> (pre_oid);});
@@ -1728,24 +1559,43 @@ main (int argc, char* argv[])
tgs.reset ();
}
- ctx->current_operation (*oif, outer_oif);
+ ctx.current_operation (*oif, outer_oif);
+
+ if (outer_oif != nullptr && outer_oif->operation_pre != nullptr)
+ outer_oif->operation_pre (ctx, oparams, false /* inner */, l);
+
+ if (oif->operation_pre != nullptr)
+ oif->operation_pre (ctx,
+ outer_oif == nullptr ? oparams : values {},
+ true /* inner */,
+ l);
action a (mid, oid, oif->outer_id);
{
- result_printer p (tgs);
- uint16_t diag (ops.structured_result () ? 0 : 2);
+#ifndef BUILD2_BOOTSTRAP
+ result_printer p (ops, tgs, js);
+#endif
+ uint16_t diag (ops.structured_result_specified () ? 0 : 2);
if (mif->match != nullptr)
mif->match (mparams, a, tgs, diag, true /* progress */);
if (dump_match)
- dump (*ctx, a);
+ dump (ctx, a);
- if (mif->execute != nullptr && !ctx->match_only)
+ if (mif->execute != nullptr && !ctx.match_only)
mif->execute (mparams, a, tgs, diag, true /* progress */);
}
+ if (oif->operation_post != nullptr)
+ oif->operation_post (ctx,
+ outer_oif == nullptr ? oparams : values {},
+ true /* inner */);
+
+ if (outer_oif != nullptr && outer_oif->operation_post != nullptr)
+ outer_oif->operation_post (ctx, oparams, false /* inner */);
+
if (post_oid != 0)
{
tgs.reset ();
@@ -1754,35 +1604,52 @@ main (int argc, char* argv[])
<< ", id " << static_cast<uint16_t> (post_oid);});
if (mif->operation_pre != nullptr)
- mif->operation_pre (mparams, post_oid); // Cannot be translated.
+ mif->operation_pre (ctx, mparams, post_oid); // Can't be translated.
+
+ ctx.current_operation (*post_oif, oif);
+
+ if (oif->operation_pre != nullptr)
+ oif->operation_pre (ctx, oparams, false /* inner */, l);
- ctx->current_operation (*post_oif, oif);
+ if (post_oif->operation_pre != nullptr)
+ post_oif->operation_pre (ctx, {}, true /* inner */, l);
action a (mid, post_oid, oid);
{
- result_printer p (tgs);
- uint16_t diag (ops.structured_result () ? 0 : 1);
+#ifndef BUILD2_BOOTSTRAP
+ result_printer p (ops, tgs, js);
+#endif
+ uint16_t diag (ops.structured_result_specified () ? 0 : 1);
if (mif->match != nullptr)
mif->match (mparams, a, tgs, diag, true /* progress */);
- if (dump_match)
- dump (*ctx, a);
+ if (dump_match_post)
+ dump (ctx, a);
- if (mif->execute != nullptr && !ctx->match_only)
+ if (mif->execute != nullptr && !ctx.match_only)
mif->execute (mparams, a, tgs, diag, true /* progress */);
}
+ if (post_oif->operation_post != nullptr)
+ post_oif->operation_post (ctx, {}, true /* inner */);
+
+ if (oif->operation_post != nullptr)
+ oif->operation_post (ctx, oparams, false /* inner */);
+
if (mif->operation_post != nullptr)
- mif->operation_post (mparams, post_oid);
+ mif->operation_post (ctx, mparams, post_oid);
l5 ([&]{trace << "end post-operation batch " << post_oif->name
<< ", id " << static_cast<uint16_t> (post_oid);});
}
+ if (dump_load && load_only)
+ dump (ctx, nullopt /* action */);
+
if (mif->operation_post != nullptr)
- mif->operation_post (mparams, oid);
+ mif->operation_post (ctx, mparams, oid);
l5 ([&]{trace << "end operation batch " << oif->name
<< ", id " << static_cast<uint16_t> (oid);});
@@ -1791,7 +1658,7 @@ main (int argc, char* argv[])
if (mid != 0)
{
if (mif->meta_operation_post != nullptr)
- mif->meta_operation_post (mparams);
+ mif->meta_operation_post (ctx, mparams);
l5 ([&]{trace << "end meta-operation batch " << mif->name
<< ", id " << static_cast<uint16_t> (mid);});
@@ -1800,6 +1667,18 @@ main (int argc, char* argv[])
if (lifted == nullptr && skip == 0)
++mit;
} // meta-operation
+
+#ifndef BUILD2_BOOTSTRAP
+ if (ops.structured_result_specified () &&
+ ops.structured_result () == structured_result_format::json)
+ {
+ js.end_array ();
+ cout << endl;
+ }
+#endif
+
+ phase_switch_contention += (pctx->phase_mutex.contention +
+ pctx->phase_mutex.contention_load);
}
catch (const failed&)
{
@@ -1821,16 +1700,18 @@ main (int argc, char* argv[])
{
text << '\n'
<< "build statistics:" << "\n\n"
- << " thread_max_active " << st.thread_max_active << '\n'
- << " thread_max_total " << st.thread_max_total << '\n'
- << " thread_helpers " << st.thread_helpers << '\n'
- << " thread_max_waiting " << st.thread_max_waiting << '\n'
+ << " thread_max_active " << st.thread_max_active << '\n'
+ << " thread_max_total " << st.thread_max_total << '\n'
+ << " thread_helpers " << st.thread_helpers << '\n'
+ << " thread_max_waiting " << st.thread_max_waiting << '\n'
+ << '\n'
+ << " task_queue_depth " << st.task_queue_depth << '\n'
+ << " task_queue_full " << st.task_queue_full << '\n'
<< '\n'
- << " task_queue_depth " << st.task_queue_depth << '\n'
- << " task_queue_full " << st.task_queue_full << '\n'
+ << " wait_queue_slots " << st.wait_queue_slots << '\n'
+ << " wait_queue_collisions " << st.wait_queue_collisions << '\n'
<< '\n'
- << " wait_queue_slots " << st.wait_queue_slots << '\n'
- << " wait_queue_collisions " << st.wait_queue_collisions << '\n';
+ << " phase_switch_contention " << phase_switch_contention << '\n';
}
return r;
diff --git a/build2/buildfile b/build2/buildfile
index 4d62fb5..0111ed2 100644
--- a/build2/buildfile
+++ b/build2/buildfile
@@ -5,16 +5,19 @@
#
libs = $libbutl
+# NOTE: don't forget to also update bpkg's buildfile if changing anything
+# here.
+#
include ../libbuild2/
libs += ../libbuild2/lib{build2}
-for m: bash bin c cc cxx in version
+for m: bash bin c cc cli cxx in version
{
include ../libbuild2/$m/
libs += ../libbuild2/$m/lib{build2-$m}
}
-exe{b}: {hxx ixx txx cxx}{** -b-options} {hxx ixx cxx}{b-options} $libs
+exe{b}: {hxx ixx txx cxx}{**} $libs
# Target metadata, see also --build2-metadata in b.cxx.
#
@@ -42,6 +45,8 @@ copyright = $process.run_regex( \
obj{b}: cxx.poptions += -DBUILD2_COPYRIGHT=\"$copyright\"
+# NOTE: remember to update bpkg buildfile if changing anything here.
+#
switch $cxx.target.class
{
case 'linux'
@@ -68,36 +73,3 @@ switch $cxx.target.class
: "-Wl,--stack,$stack_size")
}
}
-
-# Generated options parser.
-#
-if $cli.configured
-{
- cli.cxx{b-options}: cli{b}
-
- cli.options += --std c++11 -I $src_root --include-with-brackets \
---include-prefix build2 --guard-prefix BUILD2 \
---cxx-prologue "#include <build2/types-parsers.hxx>" \
---cli-namespace build2::cl --generate-file-scanner --keep-separator \
---generate-parse --generate-merge --generate-specifier
-
- # Usage options.
- #
- cli.options += --suppress-undocumented --long-usage --ansi-color \
---page-usage 'build2::print_$name$_' --option-length 21
-
- cli.cxx{*}:
- {
- # Include the generated cli files into the distribution and don't remove
- # them when cleaning in src (so that clean results in a state identical to
- # distributed).
- #
- dist = true
- clean = ($src_root != $out_root)
-
- # We keep the generated code in the repository so copy it back to src in
- # case of a forwarded configuration.
- #
- backlink = overwrite
- }
-}
diff --git a/build2/cli/init.cxx b/build2/cli/init.cxx
deleted file mode 100644
index eadf32c..0000000
--- a/build2/cli/init.cxx
+++ /dev/null
@@ -1,291 +0,0 @@
-// file : build2/cli/init.cxx -*- C++ -*-
-// license : MIT; see accompanying LICENSE file
-
-#include <build2/cli/init.hxx>
-
-#include <libbuild2/file.hxx>
-#include <libbuild2/scope.hxx>
-#include <libbuild2/target.hxx>
-#include <libbuild2/variable.hxx>
-#include <libbuild2/diagnostics.hxx>
-
-#include <libbuild2/config/utility.hxx>
-
-#include <libbuild2/cxx/target.hxx>
-
-#include <build2/cli/rule.hxx>
-#include <build2/cli/module.hxx>
-#include <build2/cli/target.hxx>
-
-namespace build2
-{
- namespace cli
- {
- // Remaining issues/semantics change:
- //
- // @@ Unconfigured caching.
- //
- // @@ Default-found cli used to result in config.cli=cli and now it's just
- // omitted (and default-not-found -- in config.cli.configured=false).
- //
- // - Writing any default will take precedence over config.import.cli.
- // In fact, this duality is a bigger problem: if we have a config
- // that uses config.cli there is no way to reconfigure it to use
- // config.import.cli.
- //
- // - We could have saved it commented.
- //
- // - We could do this at the module level only since we also have
- // config.cli.options?
- //
- // - Note that in the CLI compiler itself we now rely on default cli
- // being NULL/undefined. So if faving, should probably be commented
- // out. BUT: it will still be defined, so will need to be defined
- // NULL. Note also that long term the CLI compiler will not use the
- // module relying on an ad hoc recipe instead.
- //
- // ! Maybe reserving NULL (instead of making it the same as NULL) for
- // this "configured to default" state and saving commented is not a
- // bad idea. Feels right to have some marker in config.build that
- // things are in effect. And I believe if config.import.cli is
- // specified, it will just be dropped.
-
- bool
- guess_init (scope& rs,
- scope& bs,
- const location& loc,
- bool,
- bool opt,
- module_init_extra& extra)
- {
- tracer trace ("cli::guess_init");
- l5 ([&]{trace << "for " << rs;});
-
- // We only support root loading (which means there can only be one).
- //
- if (rs != bs)
- fail (loc) << "cli.guess module must be loaded in project root";
-
- // Adjust module config.build save priority (code generator).
- //
- config::save_module (rs, "cli", 150);
-
- // Enter metadata variables.
- //
- auto& vp (rs.var_pool ());
-
- auto& v_ver (vp.insert<string> ("cli.version"));
- auto& v_sum (vp.insert<string> ("cli.checksum"));
-
- // Import the CLI compiler target.
- //
- // Note that the special config.cli=false value (recognized by the
- // import machinery) is treated as an explicit request to leave the
- // module unconfigured.
- //
- bool new_cfg (false);
- pair<const exe*, import_kind> ir (
- import_direct<exe> (
- new_cfg,
- rs,
- name ("cli", dir_path (), "exe", "cli"), // cli%exe{cli}
- true /* phase2 */,
- opt,
- true /* metadata */,
- loc,
- "module load"));
-
- const exe* tgt (ir.first);
-
- // Extract metadata.
- //
- auto* ver (tgt != nullptr ? &cast<string> (tgt->vars[v_ver]) : nullptr);
- auto* sum (tgt != nullptr ? &cast<string> (tgt->vars[v_sum]) : nullptr);
-
- // Print the report.
- //
- // If this is a configuration with new values, then print the report
- // at verbosity level 2 and up (-v).
- //
- if (verb >= (new_cfg ? 2 : 3))
- {
- diag_record dr (text);
- dr << "cli " << project (rs) << '@' << rs << '\n';
-
- if (tgt != nullptr)
- dr << " cli " << ir << '\n'
- << " version " << *ver << '\n'
- << " checksum " << *sum;
- else
- dr << " cli " << "not found, leaving unconfigured";
- }
-
- if (tgt == nullptr)
- return false;
-
- // The cli variable (untyped) is an imported compiler target name.
- //
- rs.assign ("cli") = tgt->as_name ();
- rs.assign (v_sum) = *sum;
- rs.assign (v_ver) = *ver;
-
- {
- standard_version v (*ver);
-
- rs.assign<uint64_t> ("cli.version.number") = v.version;
- rs.assign<uint64_t> ("cli.version.major") = v.major ();
- rs.assign<uint64_t> ("cli.version.minor") = v.minor ();
- rs.assign<uint64_t> ("cli.version.patch") = v.patch ();
- }
-
- // Cache some values in the module for easier access in the rule.
- //
- extra.set_module (new module (data {*tgt, *sum}));
-
- return true;
- }
-
- bool
- config_init (scope& rs,
- scope& bs,
- const location& loc,
- bool,
- bool opt,
- module_init_extra& extra)
- {
- tracer trace ("cli::config_init");
- l5 ([&]{trace << "for " << rs;});
-
- // We only support root loading (which means there can only be one).
- //
- if (rs != bs)
- fail (loc) << "cli.config module must be loaded in project root";
-
- // Load cli.guess and share its module instance as ours.
- //
- if (optional<shared_ptr<build2::module>> r = load_module (
- rs, rs, "cli.guess", loc, opt, extra.hints))
- {
- extra.module = *r;
- }
- else
- {
- // This can happen if someone already optionally loaded cli.guess
- // and it has failed to configure.
- //
- if (!opt)
- fail (loc) << "cli could not be configured" <<
- info << "re-run with -V for more information";
-
- return false;
- }
-
- // Configuration.
- //
- using config::append_config;
-
- // config.cli.options
- //
- // Note that we merge it into the corresponding cli.* variable.
- //
- append_config<strings> (rs, rs, "cli.options", nullptr);
-
- return true;
- }
-
- bool
- init (scope& rs,
- scope& bs,
- const location& loc,
- bool,
- bool opt,
- module_init_extra& extra)
- {
- tracer trace ("cli::init");
- l5 ([&]{trace << "for " << rs;});
-
- // We only support root loading (which means there can only be one).
- //
- if (rs != bs)
- fail (loc) << "cli module must be loaded in project root";
-
- // Make sure the cxx module has been loaded since we need its targets
- // types (?xx{}). Note that we don't try to load it ourselves because of
- // the non-trivial variable merging semantics. So it is better to let
- // the user load cxx explicitly. @@ Not sure the reason still holds
- // though it might still make sense to expect the user to load cxx.
- //
- if (!cast_false<bool> (rs["cxx.loaded"]))
- fail (loc) << "cxx module must be loaded before cli";
-
- // Load cli.config and get its module instance.
- //
- if (optional<shared_ptr<build2::module>> r = load_module (
- rs, rs, "cli.config", loc, opt, extra.hints))
- {
- extra.module = *r;
- }
- else
- {
- // This can happen if someone already optionally loaded cli.config
- // and it has failed to configure.
- //
- if (!opt)
- fail (loc) << "cli could not be configured" <<
- info << "re-run with -V for more information";
-
- return false;
- }
-
- auto& m (extra.module_as<module> ());
-
- // Register target types.
- //
- rs.insert_target_type<cli> ();
- rs.insert_target_type<cli_cxx> ();
-
- // Register our rules.
- //
- {
- auto reg = [&rs, &m] (meta_operation_id mid, operation_id oid)
- {
- rs.insert_rule<cli_cxx> (mid, oid, "cli.compile", m);
- rs.insert_rule<cxx::hxx> (mid, oid, "cli.compile", m);
- rs.insert_rule<cxx::cxx> (mid, oid, "cli.compile", m);
- rs.insert_rule<cxx::ixx> (mid, oid, "cli.compile", m);
- };
-
- reg (perform_id, update_id);
- reg (perform_id, clean_id);
-
- // Other rules (e.g., cc::compile) may need to have the group members
- // resolved/linked up. Looks like a general pattern: groups should
- // resolve on *(update).
- //
- // @@ meta-op wildcard?
- //
- reg (configure_id, update_id);
- reg (dist_id, update_id);
- }
-
- return true;
- }
-
- static const module_functions mod_functions[] =
- {
- // NOTE: don't forget to also update the documentation in init.hxx if
- // changing anything here.
-
- {"cli.guess", nullptr, guess_init},
- {"cli.config", nullptr, config_init},
- {"cli", nullptr, init},
- {nullptr, nullptr, nullptr}
- };
-
- const module_functions*
- build2_cli_load ()
- {
- return mod_functions;
- }
- }
-}
diff --git a/build2/cli/init.hxx b/build2/cli/init.hxx
deleted file mode 100644
index 1c54316..0000000
--- a/build2/cli/init.hxx
+++ /dev/null
@@ -1,29 +0,0 @@
-// file : build2/cli/init.hxx -*- C++ -*-
-// license : MIT; see accompanying LICENSE file
-
-#ifndef BUILD2_CLI_INIT_HXX
-#define BUILD2_CLI_INIT_HXX
-
-#include <libbuild2/types.hxx>
-#include <libbuild2/utility.hxx>
-
-#include <libbuild2/module.hxx>
-
-namespace build2
-{
- namespace cli
- {
- // Module `cli` does not require bootstrapping.
- //
- // Submodules:
- //
- // `cli.guess` -- set variables describing the compiler.
- // `cli.config` -- load `cli.guess` and set the rest of the variables.
- // `cli` -- load `cli.config` and register targets and rules.
- //
- extern "C" const module_functions*
- build2_cli_load ();
- }
-}
-
-#endif // BUILD2_CLI_INIT_HXX
diff --git a/build2/cli/module.hxx b/build2/cli/module.hxx
deleted file mode 100644
index 70f6ba8..0000000
--- a/build2/cli/module.hxx
+++ /dev/null
@@ -1,30 +0,0 @@
-// file : build2/cli/module.hxx -*- C++ -*-
-// license : MIT; see accompanying LICENSE file
-
-#ifndef BUILD2_CLI_MODULE_HXX
-#define BUILD2_CLI_MODULE_HXX
-
-#include <libbuild2/types.hxx>
-#include <libbuild2/utility.hxx>
-
-#include <libbuild2/module.hxx>
-
-#include <build2/cli/rule.hxx>
-
-namespace build2
-{
- namespace cli
- {
- class module: public build2::module,
- public virtual data,
- public compile_rule
- {
- public:
- explicit
- module (data&& d)
- : data (move (d)), compile_rule (move (d)) {}
- };
- }
-}
-
-#endif // BUILD2_CLI_MODULE_HXX
diff --git a/build2/cli/rule.cxx b/build2/cli/rule.cxx
deleted file mode 100644
index 99b6bee..0000000
--- a/build2/cli/rule.cxx
+++ /dev/null
@@ -1,336 +0,0 @@
-// file : build2/cli/rule.cxx -*- C++ -*-
-// license : MIT; see accompanying LICENSE file
-
-#include <build2/cli/rule.hxx>
-
-#include <libbuild2/depdb.hxx>
-#include <libbuild2/scope.hxx>
-#include <libbuild2/target.hxx>
-#include <libbuild2/context.hxx>
-#include <libbuild2/algorithm.hxx>
-#include <libbuild2/filesystem.hxx>
-#include <libbuild2/diagnostics.hxx>
-
-#include <build2/cli/target.hxx>
-
-namespace build2
-{
- namespace cli
- {
- // Figure out if name contains stem and, optionally, calculate prefix and
- // suffix.
- //
- static bool
- match_stem (const string& name, const string& stem,
- string* prefix = nullptr, string* suffix = nullptr)
- {
- size_t p (name.find (stem));
-
- if (p != string::npos)
- {
- if (prefix != nullptr)
- prefix->assign (name, 0, p);
-
- if (suffix != nullptr)
- suffix->assign (name, p + stem.size (), string::npos);
-
- return true;
- }
-
- return false;
- }
-
- bool compile_rule::
- match (action a, target& t, const string&) const
- {
- tracer trace ("cli::compile_rule::match");
-
- // Find the .cli source file.
- //
- auto find = [&trace, a, &t] (auto&& r) -> optional<prerequisite_member>
- {
- for (prerequisite_member p: r)
- {
- // If excluded or ad hoc, then don't factor it into our tests.
- //
- if (include (a, t, p) != include_type::normal)
- continue;
-
- if (p.is_a<cli> ())
- {
- // Check that the stem match.
- //
- if (match_stem (t.name, p.name ()))
- return p;
-
- l4 ([&]{trace << ".cli file stem '" << p.name () << "' "
- << "doesn't match target " << t;});
- }
- }
-
- return nullopt;
- };
-
- if (cli_cxx* pt = t.is_a<cli_cxx> ())
- {
- // The cli.cxx{} group.
- //
- cli_cxx& t (*pt);
-
- // See if we have a .cli source file.
- //
- if (!find (group_prerequisite_members (a, t)))
- {
- l4 ([&]{trace << "no .cli source file for target " << t;});
- return false;
- }
-
- // Figure out the member list.
- //
- // At this stage, no further changes to cli.options are possible and
- // we can determine whether the --suppress-inline option is present.
- //
- // Passing the group as a "reference target" is a bit iffy,
- // conceptually.
- //
- t.h = &search<cxx::hxx> (t, t.dir, t.out, t.name);
- t.c = &search<cxx::cxx> (t, t.dir, t.out, t.name);
- t.i = find_option ("--suppress-inline", t, "cli.options")
- ? nullptr
- : &search<cxx::ixx> (t, t.dir, t.out, t.name);
-
- return true;
- }
- else
- {
- // One of the ?xx{} members.
- //
-
- // Check if there is a corresponding cli.cxx{} group.
- //
- const cli_cxx* g (t.ctx.targets.find<cli_cxx> (t.dir, t.out, t.name));
-
- // If not or if it has no prerequisites (happens when we use it to
- // set cli.options) and this target has a cli{} prerequisite, then
- // synthesize the dependency.
- //
- if (g == nullptr || !g->has_prerequisites ())
- {
- if (optional<prerequisite_member> p = find (
- prerequisite_members (a, t)))
- {
- if (g == nullptr)
- g = &t.ctx.targets.insert<cli_cxx> (t.dir, t.out, t.name, trace);
-
- g->prerequisites (prerequisites {p->as_prerequisite ()});
- }
- }
-
- if (g == nullptr)
- return false;
-
- // For ixx{}, verify it is part of the group (i.e., not disabled
- // via --suppress-inline).
- //
- if (t.is_a<cxx::ixx> () &&
- find_option ("--suppress-inline", *g, "cli.options"))
- return false;
-
- t.group = g;
- return true;
- }
- }
-
- recipe compile_rule::
- apply (action a, target& xt) const
- {
- if (cli_cxx* pt = xt.is_a<cli_cxx> ())
- {
- cli_cxx& t (*pt);
-
- // Derive file names for the members.
- //
- t.h->derive_path ();
- t.c->derive_path ();
- if (t.i != nullptr)
- t.i->derive_path ();
-
- // Inject dependency on the output directory.
- //
- inject_fsdir (a, t);
-
- // Match prerequisites.
- //
- match_prerequisite_members (a, t);
-
- // For update inject dependency on the CLI compiler target.
- //
- if (a == perform_update_id)
- inject (a, t, ctgt);
-
- switch (a)
- {
- case perform_update_id: return [this] (action a, const target& t)
- {
- return perform_update (a, t);
- };
- case perform_clean_id: return &perform_clean_group_depdb;
- default: return noop_recipe; // Configure/dist update.
- }
- }
- else
- {
- const cli_cxx& g (xt.group->as<cli_cxx> ());
- build2::match (a, g);
- return group_recipe; // Execute the group's recipe.
- }
- }
-
- static void
- append_extension (cstrings& args,
- const path_target& t,
- const char* option,
- const char* default_extension)
- {
- const string* e (t.ext ());
- assert (e != nullptr); // Should have been figured out in apply().
-
- if (*e != default_extension)
- {
- // CLI needs the extension with the leading dot (unless it is empty)
- // while we store the extension without. But if there is an extension,
- // then we can get it (with the dot) from the file name.
- //
- args.push_back (option);
- args.push_back (e->empty ()
- ? e->c_str ()
- : t.path ().extension_cstring () - 1);
- }
- }
-
- target_state compile_rule::
- perform_update (action a, const target& xt) const
- {
- tracer trace ("cli::compile_rule::perform_update");
-
- // The rule has been matched which means the members should be resolved
- // and paths assigned. We use the header file as our "target path" for
- // timestamp, depdb, etc.
- //
- const cli_cxx& t (xt.as<cli_cxx> ());
- const path& tp (t.h->path ());
-
- // Update prerequisites and determine if any relevant ones render us
- // out-of-date. Note that currently we treat all the prerequisites as
- // potentially affecting the result (think prologues/epilogues, CLI
- // compiler target itself, etc).
- //
- timestamp mt (t.load_mtime (tp));
- auto pr (execute_prerequisites<cli> (a, t, mt));
-
- bool update (!pr.first);
- target_state ts (update ? target_state::changed : *pr.first);
-
- const cli& s (pr.second);
-
- // We use depdb to track changes to the .cli file name, options,
- // compiler, etc.
- //
- depdb dd (tp + ".d");
- {
- // First should come the rule name/version.
- //
- if (dd.expect ("cli.compile 1") != nullptr)
- l4 ([&]{trace << "rule mismatch forcing update of " << t;});
-
- // Then the compiler checksum.
- //
- if (dd.expect (csum) != nullptr)
- l4 ([&]{trace << "compiler mismatch forcing update of " << t;});
-
- // Then the options checksum.
- //
- sha256 cs;
- append_options (cs, t, "cli.options");
-
- if (dd.expect (cs.string ()) != nullptr)
- l4 ([&]{trace << "options mismatch forcing update of " << t;});
-
- // Finally the .cli input file.
- //
- if (dd.expect (s.path ()) != nullptr)
- l4 ([&]{trace << "input file mismatch forcing update of " << t;});
- }
-
- // Update if depdb mismatch.
- //
- if (dd.writing () || dd.mtime > mt)
- update = true;
-
- dd.close ();
-
- // If nothing changed, then we are done.
- //
- if (!update)
- return ts;
-
- // Translate paths to relative (to working directory). This results in
- // easier to read diagnostics.
- //
- path relo (relative (t.dir));
- path rels (relative (s.path ()));
-
- const process_path& pp (ctgt.process_path ());
- cstrings args {pp.recall_string ()};
-
- // See if we need to pass --output-{prefix,suffix}
- //
- string prefix, suffix;
- match_stem (t.name, s.name, &prefix, &suffix);
-
- if (!prefix.empty ())
- {
- args.push_back ("--output-prefix");
- args.push_back (prefix.c_str ());
- }
-
- if (!suffix.empty ())
- {
- args.push_back ("--output-suffix");
- args.push_back (suffix.c_str ());
- }
-
- // See if we need to pass any --?xx-suffix options.
- //
- append_extension (args, *t.h, "--hxx-suffix", "hxx");
- append_extension (args, *t.c, "--cxx-suffix", "cxx");
- if (t.i != nullptr)
- append_extension (args, *t.i, "--ixx-suffix", "ixx");
-
- append_options (args, t, "cli.options");
-
- if (!relo.empty ())
- {
- args.push_back ("-o");
- args.push_back (relo.string ().c_str ());
- }
-
- args.push_back (rels.string ().c_str ());
- args.push_back (nullptr);
-
- if (verb >= 2)
- print_process (args);
- else if (verb)
- text << "cli " << s;
-
- if (!t.ctx.dry_run)
- {
- run (pp, args);
- dd.check_mtime (tp);
- }
-
- t.mtime (system_clock::now ());
- return target_state::changed;
- }
- }
-}
diff --git a/build2/cli/rule.hxx b/build2/cli/rule.hxx
deleted file mode 100644
index b3ecc2c..0000000
--- a/build2/cli/rule.hxx
+++ /dev/null
@@ -1,43 +0,0 @@
-// file : build2/cli/rule.hxx -*- C++ -*-
-// license : MIT; see accompanying LICENSE file
-
-#ifndef BUILD2_CLI_RULE_HXX
-#define BUILD2_CLI_RULE_HXX
-
-#include <libbuild2/types.hxx>
-#include <libbuild2/utility.hxx>
-
-#include <libbuild2/rule.hxx>
-
-namespace build2
-{
- namespace cli
- {
- // Cached data shared between rules and the module.
- //
- struct data
- {
- const exe& ctgt; // CLI compiler target.
- const string& csum; // CLI compiler checksum.
- };
-
- // @@ Redo as two separate rules?
- //
- class compile_rule: public simple_rule, virtual data
- {
- public:
- compile_rule (data&& d): data (move (d)) {}
-
- virtual bool
- match (action, target&, const string&) const override;
-
- virtual recipe
- apply (action, target&) const override;
-
- target_state
- perform_update (action, const target&) const;
- };
- }
-}
-
-#endif // BUILD2_CLI_RULE_HXX
diff --git a/build2/cli/target.cxx b/build2/cli/target.cxx
deleted file mode 100644
index ca16044..0000000
--- a/build2/cli/target.cxx
+++ /dev/null
@@ -1,75 +0,0 @@
-// file : build2/cli/target.cxx -*- C++ -*-
-// license : MIT; see accompanying LICENSE file
-
-#include <build2/cli/target.hxx>
-
-#include <libbuild2/context.hxx>
-
-namespace build2
-{
- namespace cli
- {
- // cli
- //
- extern const char cli_ext_def[] = "cli";
-
- const target_type cli::static_type
- {
- "cli",
- &file::static_type,
- &target_factory<cli>,
- nullptr, /* fixed_extension */
- &target_extension_var<cli_ext_def>,
- &target_pattern_var<cli_ext_def>,
- nullptr,
- &file_search,
- false
- };
-
- // cli.cxx
- //
- group_view cli_cxx::
- group_members (action) const
- {
- static_assert (sizeof (cli_cxx_members) == sizeof (const target*) * 3,
- "member layout incompatible with array");
-
- return h != nullptr
- ? group_view {reinterpret_cast<const target* const*> (&h),
- (i != nullptr ? 3U : 2U)}
- : group_view {nullptr, 0};
- }
-
- static target*
- cli_cxx_factory (context& ctx,
- const target_type&, dir_path d, dir_path o, string n)
- {
- tracer trace ("cli::cli_cxx_factory");
-
- // Pre-enter (potential) members as targets. The main purpose of doing
- // this is to avoid searching for existing files in src_base if the
- // buildfile mentions some of them explicitly as prerequisites.
- //
- // Also required for the src-out remapping logic.
- //
- ctx.targets.insert<cxx::hxx> (d, o, n, trace);
- ctx.targets.insert<cxx::cxx> (d, o, n, trace);
- ctx.targets.insert<cxx::ixx> (d, o, n, trace);
-
- return new cli_cxx (ctx, move (d), move (o), move (n));
- }
-
- const target_type cli_cxx::static_type
- {
- "cli.cxx",
- &mtime_target::static_type,
- &cli_cxx_factory,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- &target_search,
- true // "See through" default iteration mode.
- };
- }
-}
diff --git a/build2/cli/target.hxx b/build2/cli/target.hxx
deleted file mode 100644
index 722bb5f..0000000
--- a/build2/cli/target.hxx
+++ /dev/null
@@ -1,54 +0,0 @@
-// file : build2/cli/target.hxx -*- C++ -*-
-// license : MIT; see accompanying LICENSE file
-
-#ifndef BUILD2_CLI_TARGET_HXX
-#define BUILD2_CLI_TARGET_HXX
-
-#include <libbuild2/types.hxx>
-#include <libbuild2/utility.hxx>
-
-#include <libbuild2/target.hxx>
-
-#include <libbuild2/cxx/target.hxx>
-
-namespace build2
-{
- namespace cli
- {
- class cli: public file
- {
- public:
- using file::file;
-
- public:
- static const target_type static_type;
- virtual const target_type& dynamic_type () const {return static_type;}
- };
-
- // Standard layout type compatible with group_view's const target*[3].
- //
- struct cli_cxx_members
- {
- const cxx::hxx* h = nullptr;
- const cxx::cxx* c = nullptr;
- const cxx::ixx* i = nullptr;
- };
-
- class cli_cxx: public mtime_target, public cli_cxx_members
- {
- public:
- using mtime_target::mtime_target;
-
- virtual group_view
- group_members (action) const override;
-
- public:
- static const target_type static_type;
-
- virtual const target_type&
- dynamic_type () const override {return static_type;}
- };
- }
-}
-
-#endif // BUILD2_CLI_TARGET_HXX
diff --git a/build2/types-parsers.cxx b/build2/types-parsers.cxx
deleted file mode 100644
index 3593143..0000000
--- a/build2/types-parsers.cxx
+++ /dev/null
@@ -1,50 +0,0 @@
-// file : build2/types-parsers.cxx -*- C++ -*-
-// license : MIT; see accompanying LICENSE file
-
-#include <build2/types-parsers.hxx>
-
-#include <build2/b-options.hxx> // build2::cl namespace
-
-namespace build2
-{
- namespace cl
- {
- template <typename T>
- static void
- parse_path (T& x, scanner& s)
- {
- const char* o (s.next ());
-
- if (!s.more ())
- throw missing_value (o);
-
- const char* v (s.next ());
-
- try
- {
- x = T (v);
-
- if (x.empty ())
- throw invalid_value (o, v);
- }
- catch (const invalid_path&)
- {
- throw invalid_value (o, v);
- }
- }
-
- void parser<path>::
- parse (path& x, bool& xs, scanner& s)
- {
- xs = true;
- parse_path (x, s);
- }
-
- void parser<dir_path>::
- parse (dir_path& x, bool& xs, scanner& s)
- {
- xs = true;
- parse_path (x, s);
- }
- }
-}
diff --git a/build2/types-parsers.hxx b/build2/types-parsers.hxx
deleted file mode 100644
index d39a096..0000000
--- a/build2/types-parsers.hxx
+++ /dev/null
@@ -1,43 +0,0 @@
-// file : build2/types-parsers.hxx -*- C++ -*-
-// license : MIT; see accompanying LICENSE file
-
-// CLI parsers, included into the generated source files.
-//
-
-#ifndef BUILD2_TYPES_PARSERS_HXX
-#define BUILD2_TYPES_PARSERS_HXX
-
-#include <libbuild2/types.hxx>
-
-namespace build2
-{
- namespace cl
- {
- class scanner;
-
- template <typename T>
- struct parser;
-
- template <>
- struct parser<path>
- {
- static void
- parse (path&, bool&, scanner&);
-
- static void
- merge (path& b, const path& a) {b = a;}
- };
-
- template <>
- struct parser<dir_path>
- {
- static void
- parse (dir_path&, bool&, scanner&);
-
- static void
- merge (dir_path& b, const dir_path& a) {b = a;}
- };
- }
-}
-
-#endif // BUILD2_TYPES_PARSERS_HXX