From 2835794b28d482b1e391dc85f79dfa91f9e63d3e Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 17 Feb 2022 16:33:27 +0300 Subject: Move parse_cmdline() to libbuild2 --- libbuild2/b-options.cxx | 1710 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1710 insertions(+) create mode 100644 libbuild2/b-options.cxx (limited to 'libbuild2/b-options.cxx') diff --git a/libbuild2/b-options.cxx b/libbuild2/b-options.cxx new file mode 100644 index 0000000..86f5bfe --- /dev/null +++ b/libbuild2/b-options.cxx @@ -0,0 +1,1710 @@ +// -*- C++ -*- +// +// This file was generated by CLI, a command line interface +// compiler for C++. +// + +// Begin prologue. +// +#include +// +// End prologue. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace build2 +{ + namespace build + { + namespace cli + { + // 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_; + + ++start_position_; + return r; + } + else + throw eos_reached (); + } + + void argv_scanner:: + skip () + { + if (i_ < argc_) + { + ++i_; + ++start_position_; + } + else + throw eos_reached (); + } + + std::size_t argv_scanner:: + position () + { + return start_position_; + } + + // 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 (); + ++start_position_; + 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 (); + ++start_position_; + } + } + + 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; + } + + std::size_t argv_file_scanner:: + position () + { + return start_position_; + } + + 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 + 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 + { + static void + parse (bool& x, scanner& s) + { + s.next (); + x = true; + } + + static void + merge (bool& b, const bool&) + { + b = true; + } + }; + + template <> + struct parser + { + 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 + struct parser > + { + static void + parse (std::pair& x, bool& xs, scanner& s) + { + x.second = s.position (); + parser::parse (x.first, xs, s); + } + + static void + merge (std::pair& b, const std::pair& a) + { + b = a; + } + }; + + template + struct parser > + { + static void + parse (std::vector& c, bool& xs, scanner& s) + { + X x; + bool dummy; + parser::parse (x, dummy, s); + c.push_back (x); + xs = true; + } + + static void + merge (std::vector& b, const std::vector& a) + { + b.insert (b.end (), a.begin (), a.end ()); + } + }; + + template + struct parser > + { + static void + parse (std::set& c, bool& xs, scanner& s) + { + X x; + bool dummy; + parser::parse (x, dummy, s); + c.insert (x); + xs = true; + } + + static void + merge (std::set& b, const std::set& a) + { + b.insert (a.begin (), a.end ()); + } + }; + + template + struct parser > + { + static void + parse (std::map& m, bool& xs, scanner& s) + { + const char* o (s.next ()); + + if (s.more ()) + { + std::size_t pos (s.position ()); + 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 (o), + 0 + }; + + bool dummy; + if (!kstr.empty ()) + { + av[1] = const_cast (kstr.c_str ()); + argv_scanner s (0, ac, av, false, pos); + parser::parse (k, dummy, s); + } + + if (!vstr.empty ()) + { + av[1] = const_cast (vstr.c_str ()); + argv_scanner s (0, ac, av, false, pos); + parser::parse (v, dummy, s); + } + + m[k] = v; + } + else + throw missing_value (o); + + xs = true; + } + + static void + merge (std::map& b, const std::map& a) + { + for (typename std::map::const_iterator i (a.begin ()); + i != a.end (); + ++i) + b[i->first] = i->second; + } + }; + + template + void + thunk (X& x, scanner& s) + { + parser::parse (x.*M, s); + } + + template + void + thunk (X& x, scanner& s) + { + parser::parse (x.*M, x.*S, s); + } + } + } +} + +#include +#include + +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::build::cli::unknown_mode opt, + ::build2::build::cli::unknown_mode arg) + { + ::build2::build::cli::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::build::cli::unknown_mode opt, + ::build2::build::cli::unknown_mode arg) + { + ::build2::build::cli::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::build::cli::unknown_mode opt, + ::build2::build::cli::unknown_mode arg) + { + ::build2::build::cli::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::build::cli::unknown_mode opt, + ::build2::build::cli::unknown_mode arg) + { + ::build2::build::cli::argv_scanner s (start, argc, argv, erase); + bool r = _parse (s, opt, arg); + end = s.end (); + return r; + } + + bool options:: + parse (::build2::build::cli::scanner& s, + ::build2::build::cli::unknown_mode opt, + ::build2::build::cli::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::build::cli::parser< uint64_t>::merge ( + this->build2_metadata_, a.build2_metadata_); + this->build2_metadata_specified_ = true; + } + + if (a.v_) + { + ::build2::build::cli::parser< bool>::merge ( + this->v_, a.v_); + } + + if (a.V_) + { + ::build2::build::cli::parser< bool>::merge ( + this->V_, a.V_); + } + + if (a.quiet_) + { + ::build2::build::cli::parser< bool>::merge ( + this->quiet_, a.quiet_); + } + + if (a.silent_) + { + ::build2::build::cli::parser< bool>::merge ( + this->silent_, a.silent_); + } + + if (a.verbose_specified_) + { + ::build2::build::cli::parser< uint16_t>::merge ( + this->verbose_, a.verbose_); + this->verbose_specified_ = true; + } + + if (a.stat_) + { + ::build2::build::cli::parser< bool>::merge ( + this->stat_, a.stat_); + } + + if (a.dump_specified_) + { + ::build2::build::cli::parser< std::set>::merge ( + this->dump_, a.dump_); + this->dump_specified_ = true; + } + + if (a.progress_) + { + ::build2::build::cli::parser< bool>::merge ( + this->progress_, a.progress_); + } + + if (a.no_progress_) + { + ::build2::build::cli::parser< bool>::merge ( + this->no_progress_, a.no_progress_); + } + + if (a.jobs_specified_) + { + ::build2::build::cli::parser< size_t>::merge ( + this->jobs_, a.jobs_); + this->jobs_specified_ = true; + } + + if (a.max_jobs_specified_) + { + ::build2::build::cli::parser< size_t>::merge ( + this->max_jobs_, a.max_jobs_); + this->max_jobs_specified_ = true; + } + + if (a.queue_depth_specified_) + { + ::build2::build::cli::parser< size_t>::merge ( + this->queue_depth_, a.queue_depth_); + this->queue_depth_specified_ = true; + } + + if (a.file_cache_specified_) + { + ::build2::build::cli::parser< string>::merge ( + this->file_cache_, a.file_cache_); + this->file_cache_specified_ = true; + } + + if (a.max_stack_specified_) + { + ::build2::build::cli::parser< size_t>::merge ( + this->max_stack_, a.max_stack_); + this->max_stack_specified_ = true; + } + + if (a.serial_stop_) + { + ::build2::build::cli::parser< bool>::merge ( + this->serial_stop_, a.serial_stop_); + } + + if (a.dry_run_) + { + ::build2::build::cli::parser< bool>::merge ( + this->dry_run_, a.dry_run_); + } + + if (a.match_only_) + { + ::build2::build::cli::parser< bool>::merge ( + this->match_only_, a.match_only_); + } + + if (a.no_external_modules_) + { + ::build2::build::cli::parser< bool>::merge ( + this->no_external_modules_, a.no_external_modules_); + } + + if (a.structured_result_) + { + ::build2::build::cli::parser< bool>::merge ( + this->structured_result_, a.structured_result_); + } + + if (a.mtime_check_) + { + ::build2::build::cli::parser< bool>::merge ( + this->mtime_check_, a.mtime_check_); + } + + if (a.no_mtime_check_) + { + ::build2::build::cli::parser< bool>::merge ( + this->no_mtime_check_, a.no_mtime_check_); + } + + if (a.no_column_) + { + ::build2::build::cli::parser< bool>::merge ( + this->no_column_, a.no_column_); + } + + if (a.no_line_) + { + ::build2::build::cli::parser< bool>::merge ( + this->no_line_, a.no_line_); + } + + if (a.buildfile_specified_) + { + ::build2::build::cli::parser< path>::merge ( + this->buildfile_, a.buildfile_); + this->buildfile_specified_ = true; + } + + if (a.config_guess_specified_) + { + ::build2::build::cli::parser< path>::merge ( + this->config_guess_, a.config_guess_); + this->config_guess_specified_ = true; + } + + if (a.config_sub_specified_) + { + ::build2::build::cli::parser< path>::merge ( + this->config_sub_, a.config_sub_); + this->config_sub_specified_ = true; + } + + if (a.pager_specified_) + { + ::build2::build::cli::parser< string>::merge ( + this->pager_, a.pager_); + this->pager_specified_ = true; + } + + if (a.pager_option_specified_) + { + ::build2::build::cli::parser< strings>::merge ( + this->pager_option_, a.pager_option_); + this->pager_option_specified_ = true; + } + + if (a.options_file_specified_) + { + ::build2::build::cli::parser< string>::merge ( + this->options_file_, a.options_file_); + this->options_file_specified_ = true; + } + + if (a.default_options_specified_) + { + ::build2::build::cli::parser< dir_path>::merge ( + this->default_options_, a.default_options_); + this->default_options_specified_ = true; + } + + if (a.no_default_options_) + { + ::build2::build::cli::parser< bool>::merge ( + this->no_default_options_, a.no_default_options_); + } + + if (a.help_) + { + ::build2::build::cli::parser< bool>::merge ( + this->help_, a.help_); + } + + if (a.version_) + { + ::build2::build::cli::parser< bool>::merge ( + this->version_, a.version_); + } + } + + ::build2::build::cli::usage_para options:: + print_usage (::std::ostream& os, ::build2::build::cli::usage_para p) + { + CLI_POTENTIALLY_UNUSED (os); + + if (p != ::build2::build::cli::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 on Windows (which is known not to" << ::std::endl + << " guarantee monotonically increasing mtimes) and for the" << ::std::endl + << " staged version of the build system on other platforms." << ::std::endl + << " 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. See" << ::std::endl + << " \033[1m--mtime-check\033[0m for details." << ::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::build::cli::usage_para::option; + + return p; + } + + typedef + std::map + _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::build::cli::thunk< options, uint64_t, &options::build2_metadata_, + &options::build2_metadata_specified_ >; + _cli_options_map_["-v"] = + &::build2::build::cli::thunk< options, bool, &options::v_ >; + _cli_options_map_["-V"] = + &::build2::build::cli::thunk< options, bool, &options::V_ >; + _cli_options_map_["--quiet"] = + &::build2::build::cli::thunk< options, bool, &options::quiet_ >; + _cli_options_map_["-q"] = + &::build2::build::cli::thunk< options, bool, &options::quiet_ >; + _cli_options_map_["--silent"] = + &::build2::build::cli::thunk< options, bool, &options::silent_ >; + _cli_options_map_["--verbose"] = + &::build2::build::cli::thunk< options, uint16_t, &options::verbose_, + &options::verbose_specified_ >; + _cli_options_map_["--stat"] = + &::build2::build::cli::thunk< options, bool, &options::stat_ >; + _cli_options_map_["--dump"] = + &::build2::build::cli::thunk< options, std::set, &options::dump_, + &options::dump_specified_ >; + _cli_options_map_["--progress"] = + &::build2::build::cli::thunk< options, bool, &options::progress_ >; + _cli_options_map_["--no-progress"] = + &::build2::build::cli::thunk< options, bool, &options::no_progress_ >; + _cli_options_map_["--jobs"] = + &::build2::build::cli::thunk< options, size_t, &options::jobs_, + &options::jobs_specified_ >; + _cli_options_map_["-j"] = + &::build2::build::cli::thunk< options, size_t, &options::jobs_, + &options::jobs_specified_ >; + _cli_options_map_["--max-jobs"] = + &::build2::build::cli::thunk< options, size_t, &options::max_jobs_, + &options::max_jobs_specified_ >; + _cli_options_map_["-J"] = + &::build2::build::cli::thunk< options, size_t, &options::max_jobs_, + &options::max_jobs_specified_ >; + _cli_options_map_["--queue-depth"] = + &::build2::build::cli::thunk< options, size_t, &options::queue_depth_, + &options::queue_depth_specified_ >; + _cli_options_map_["-Q"] = + &::build2::build::cli::thunk< options, size_t, &options::queue_depth_, + &options::queue_depth_specified_ >; + _cli_options_map_["--file-cache"] = + &::build2::build::cli::thunk< options, string, &options::file_cache_, + &options::file_cache_specified_ >; + _cli_options_map_["--max-stack"] = + &::build2::build::cli::thunk< options, size_t, &options::max_stack_, + &options::max_stack_specified_ >; + _cli_options_map_["--serial-stop"] = + &::build2::build::cli::thunk< options, bool, &options::serial_stop_ >; + _cli_options_map_["-s"] = + &::build2::build::cli::thunk< options, bool, &options::serial_stop_ >; + _cli_options_map_["--dry-run"] = + &::build2::build::cli::thunk< options, bool, &options::dry_run_ >; + _cli_options_map_["-n"] = + &::build2::build::cli::thunk< options, bool, &options::dry_run_ >; + _cli_options_map_["--match-only"] = + &::build2::build::cli::thunk< options, bool, &options::match_only_ >; + _cli_options_map_["--no-external-modules"] = + &::build2::build::cli::thunk< options, bool, &options::no_external_modules_ >; + _cli_options_map_["--structured-result"] = + &::build2::build::cli::thunk< options, bool, &options::structured_result_ >; + _cli_options_map_["--mtime-check"] = + &::build2::build::cli::thunk< options, bool, &options::mtime_check_ >; + _cli_options_map_["--no-mtime-check"] = + &::build2::build::cli::thunk< options, bool, &options::no_mtime_check_ >; + _cli_options_map_["--no-column"] = + &::build2::build::cli::thunk< options, bool, &options::no_column_ >; + _cli_options_map_["--no-line"] = + &::build2::build::cli::thunk< options, bool, &options::no_line_ >; + _cli_options_map_["--buildfile"] = + &::build2::build::cli::thunk< options, path, &options::buildfile_, + &options::buildfile_specified_ >; + _cli_options_map_["--config-guess"] = + &::build2::build::cli::thunk< options, path, &options::config_guess_, + &options::config_guess_specified_ >; + _cli_options_map_["--config-sub"] = + &::build2::build::cli::thunk< options, path, &options::config_sub_, + &options::config_sub_specified_ >; + _cli_options_map_["--pager"] = + &::build2::build::cli::thunk< options, string, &options::pager_, + &options::pager_specified_ >; + _cli_options_map_["--pager-option"] = + &::build2::build::cli::thunk< options, strings, &options::pager_option_, + &options::pager_option_specified_ >; + _cli_options_map_["--options-file"] = + &::build2::build::cli::thunk< options, string, &options::options_file_, + &options::options_file_specified_ >; + _cli_options_map_["--default-options"] = + &::build2::build::cli::thunk< options, dir_path, &options::default_options_, + &options::default_options_specified_ >; + _cli_options_map_["--no-default-options"] = + &::build2::build::cli::thunk< options, bool, &options::no_default_options_ >; + _cli_options_map_["--help"] = + &::build2::build::cli::thunk< options, bool, &options::help_ >; + _cli_options_map_["--version"] = + &::build2::build::cli::thunk< options, bool, &options::version_ >; + } + }; + + static _cli_options_map_init _cli_options_map_init_; + + bool options:: + _parse (const char* o, ::build2::build::cli::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::build::cli::scanner& s, + ::build2::build::cli::unknown_mode opt_mode, + ::build2::build::cli::unknown_mode arg_mode) + { + // Can't skip combined flags (--no-combined-flags). + // + assert (opt_mode != ::build2::build::cli::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 (co.c_str ()), + const_cast (v) + }; + + ::build2::build::cli::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::build::cli::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::build::cli::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::build::cli::unknown_mode::skip: + { + s.skip (); + r = true; + continue; + } + case ::build2::build::cli::unknown_mode::stop: + { + break; + } + case ::build2::build::cli::unknown_mode::fail: + { + throw ::build2::build::cli::unknown_option (o); + } + } + + break; + } + } + + switch (arg_mode) + { + case ::build2::build::cli::unknown_mode::skip: + { + s.skip (); + r = true; + continue; + } + case ::build2::build::cli::unknown_mode::stop: + { + break; + } + case ::build2::build::cli::unknown_mode::fail: + { + throw ::build2::build::cli::unknown_argument (o); + } + } + + break; + } + + return r; + } +} + +namespace build2 +{ + ::build2::build::cli::usage_para + print_b_usage (::std::ostream& os, ::build2::build::cli::usage_para p) + { + CLI_POTENTIALLY_UNUSED (os); + + if (p != ::build2::build::cli::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::build::cli::usage_para::text); + + if (p != ::build2::build::cli::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::build::cli::usage_para::text; + + return p; + } +} + +// Begin epilogue. +// +// +// End epilogue. + -- cgit v1.1