aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/utility.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/utility.hxx')
-rw-r--r--libbuild2/utility.hxx638
1 files changed, 451 insertions, 187 deletions
diff --git a/libbuild2/utility.hxx b/libbuild2/utility.hxx
index a07d928..b534f41 100644
--- a/libbuild2/utility.hxx
+++ b/libbuild2/utility.hxx
@@ -4,20 +4,21 @@
#ifndef LIBBUILD2_UTILITY_HXX
#define LIBBUILD2_UTILITY_HXX
-#include <map>
-#include <tuple> // make_tuple()
-#include <memory> // make_shared()
-#include <string> // to_string()
-#include <utility> // move(), forward(), declval(), make_pair(), swap()
-#include <cassert> // assert()
-#include <iterator> // make_move_iterator()
-#include <algorithm> // *
-#include <functional> // ref(), cref()
+#include <tuple> // make_tuple()
+#include <memory> // make_shared()
+#include <string> // to_string()
+#include <utility> // move(), forward(), declval(), make_pair(), swap()
+#include <cassert> // assert()
+#include <iterator> // make_move_iterator(), back_inserter()
+#include <algorithm> // *
+#include <functional> // ref(), cref()
+#include <type_traits>
#include <libbutl/ft/lang.hxx>
-#include <libbutl/utility.mxx> // combine_hash(), reverse_iterate(), etc
-#include <libbutl/fdstream.mxx>
+#include <libbutl/utility.hxx> // combine_hash(), reverse_iterate(), etc
+#include <libbutl/fdstream.hxx>
+#include <libbutl/path-pattern.hxx>
#include <libbuild2/types.hxx>
#include <libbuild2/forward.hxx>
@@ -50,11 +51,18 @@ namespace build2
using std::make_tuple;
using std::make_shared;
using std::make_move_iterator;
- using std::to_string;
+ using std::back_inserter;
using std::stoul;
using std::stoull;
- // <libbutl/utility.mxx>
+ using std::to_string;
+
+ // Currently only supports base 10 and 16. Note: adds `0x` if base 16.
+ //
+ LIBBUILD2_SYMEXPORT string
+ to_string (uint64_t, int base, size_t width = 0);
+
+ // <libbutl/utility.hxx>
//
using butl::reverse_iterate;
using butl::compare_c_string;
@@ -69,6 +77,7 @@ namespace build2
using butl::alpha;
using butl::alnum;
using butl::digit;
+ using butl::wspace;
using butl::trim;
using butl::next_word;
@@ -81,19 +90,37 @@ namespace build2
using butl::function_cast;
using butl::getenv;
- using butl::setenv;
- using butl::unsetenv;
+ using butl::auto_thread_env;
using butl::throw_generic_error;
using butl::throw_system_error;
using butl::eof;
- // <libbutl/fdstream.mxx>
+ // <libbutl/fdstream.hxx>
//
+ using butl::fdopen_null;
using butl::open_file_or_stdin;
using butl::open_file_or_stdout;
+ // <libbutl/path-pattern.hxx>
+ //
+ using butl::path_pattern;
+ using butl::path_match;
+
+ // Perform process-wide initializations/adjustments/workarounds. Should be
+ // called once early in main(). In particular, besides other things, this
+ // functions does the following:
+ //
+ // - Sets PATH to include baseutils /bin on Windows.
+ //
+ // - Ignores SIGPIPE.
+ //
+ // - Calls tzset().
+ //
+ LIBBUILD2_SYMEXPORT void
+ init_process ();
+
// Diagnostics state (verbosity level, etc; see <libbuild2/diagnostics.hxx>).
//
// Note on naming of values (here and in the global state below) that come
@@ -110,6 +137,7 @@ namespace build2
init_diag (uint16_t verbosity,
bool silent = false,
optional<bool> progress = nullopt,
+ optional<bool> diag_color = nullopt,
bool no_lines = false,
bool no_columns = false,
bool stderr_term = false);
@@ -119,13 +147,21 @@ namespace build2
LIBBUILD2_SYMEXPORT extern bool silent;
// --[no-]progress
+ // --[no-]diag-color
//
LIBBUILD2_SYMEXPORT extern optional<bool> diag_progress_option;
+ LIBBUILD2_SYMEXPORT extern optional<bool> diag_color_option;
LIBBUILD2_SYMEXPORT extern bool diag_no_line; // --no-line
LIBBUILD2_SYMEXPORT extern bool diag_no_column; // --no-column
- LIBBUILD2_SYMEXPORT extern bool stderr_term; // True if stderr is a terminal.
+ // True if stderr is a terminal.
+ //
+ LIBBUILD2_SYMEXPORT extern bool stderr_term;
+
+ // True if the color can be used on the stderr terminal.
+ //
+ LIBBUILD2_SYMEXPORT extern bool stderr_term_color;
// Global state (verbosity, home/work directories, etc).
@@ -135,6 +171,7 @@ namespace build2
LIBBUILD2_SYMEXPORT void
init (void (*terminate) (bool),
const char* argv0,
+ bool serial_stop,
optional<bool> mtime_check = nullopt,
optional<path> config_sub = nullopt,
optional<path> config_guess = nullopt);
@@ -153,11 +190,15 @@ namespace build2
LIBBUILD2_SYMEXPORT extern const standard_version build_version;
LIBBUILD2_SYMEXPORT extern const string build_version_interface;
- // Whether running installed build and, if so, the library installation
- // directory (empty otherwise).
+ // Whether running installed build as well as the library installation
+ // directory (only if installed, empty otherwise), the exported buildfile
+ // installation directory (only if configured, empty otherwise), and data
+ // installation directory (only if installed, src_root otherwise).
//
LIBBUILD2_SYMEXPORT extern const bool build_installed;
LIBBUILD2_SYMEXPORT extern const dir_path build_install_lib; // $install.lib
+ LIBBUILD2_SYMEXPORT extern const dir_path build_install_buildfile; // $install.buildfile
+ LIBBUILD2_SYMEXPORT extern const dir_path build_install_data; // $install.data
// --[no-]mtime-check
//
@@ -208,7 +249,7 @@ namespace build2
// Basic process utilities.
//
- // The run*() functions with process_path assume that you are printing
+ // The run*() functions with process_path/_env assume that you are printing
// the process command line yourself.
// Search for a process executable. Issue diagnostics and throw failed in
@@ -242,126 +283,55 @@ namespace build2
[[noreturn]] LIBBUILD2_SYMEXPORT void
run_search_fail (const path&, const location& = location ());
- // Wait for process termination returning true if the process exited
- // normally with a zero code and false otherwise. The latter case is
- // normally followed up with a call to run_finish().
- //
- LIBBUILD2_SYMEXPORT bool
- run_wait (const char* args[], process&, const location& = location ());
-
- bool
- run_wait (cstrings& args, process&, const location& = location ());
-
- // Wait for process termination. Issue diagnostics and throw failed in case
- // of abnormal termination. If the process has terminated normally but with
- // a non-zero exit status, then assume the diagnostics has already been
- // issued and just throw failed. The last argument is used in cooperation
- // with run_start() in case STDERR is redirected to STDOUT.
- //
- void
- run_finish (const char* args[],
- process&,
- const string& = string (),
- const location& = location ());
-
- void
- run_finish (cstrings& args, process& pr, const location& l = location ());
-
- // As above but if the process has exited normally with a non-zero code,
- // then return false rather than throwing.
- //
- bool
- run_finish_code (const char* args[],
- process&,
- const string& = string (),
- const location& = location ());
-
- // Start a process with the specified arguments. If in is -1, then redirect
- // STDIN to a pipe (can also be -2 to redirect to /dev/null or equivalent).
- // If out is -1, redirect STDOUT to a pipe. If error is false, then
- // redirecting STDERR to STDOUT (this can be used to suppress diagnostics
- // from the child process). Issue diagnostics and throw failed in case of an
- // error.
+ // Start a process with the specified arguments. Issue diagnostics and throw
+ // failed in case of an error. If in is -1, then redirect stdin to a pipe
+ // (can also be -2 to redirect it to /dev/null or equivalent). If out is -1,
+ // then redirect stdout to a pipe. If stderr is redirected to stdout (can
+ // be used to analyze diagnostics from the child process), then, in case of
+ // an error, the last line read from stdout must be passed to run_finish()
+ // below.
//
LIBBUILD2_SYMEXPORT process
run_start (uint16_t verbosity,
const process_env&, // Implicit-constructible from process_path.
- const char* args[],
+ const char* const* args,
int in = 0,
int out = 1,
- bool error = true,
- const dir_path& cwd = dir_path (),
- const location& = location ());
+ int err = 2,
+ const location& = {});
inline process
run_start (uint16_t verbosity,
const process_env& pe,
- cstrings& args,
+ const cstrings& args,
int in = 0,
int out = 1,
- bool error = true,
- const dir_path& cwd = dir_path (),
- const location& l = location ())
+ int err = 2,
+ const location& l = {})
{
- return run_start (verbosity, pe, args.data (), in, out, error, cwd, l);
+ return run_start (verbosity, pe, args.data (), in, out, err, l);
}
inline process
run_start (const process_env& pe,
- const char* args[],
+ const char* const* args,
int in = 0,
int out = 1,
- bool error = true,
- const dir_path& cwd = dir_path (),
- const location& l = location ())
+ int err = 2,
+ const location& l = {})
{
- return run_start (verb_never, pe, args, in, out, error, cwd, l);
+ return run_start (verb_never, pe, args, in, out, err, l);
}
inline process
run_start (const process_env& pe,
- cstrings& args,
+ const cstrings& args,
int in = 0,
int out = 1,
- bool error = true,
- const dir_path& cwd = dir_path (),
- const location& l = location ())
- {
- return run_start (pe, args.data (), in, out, error, cwd, l);
- }
-
- inline void
- run (const process_env& pe, // Implicit-constructible from process_path.
- const char* args[])
- {
- process pr (run_start (pe, args));
- run_finish (args, pr);
- }
-
- inline void
- run (const process_env& pe, // Implicit-constructible from process_path.
- cstrings& args)
- {
- run (pe, args.data ());
- }
-
- inline void
- run (const process_path& p,
- const char* args[],
- const dir_path& cwd,
- const char* const* env = nullptr)
+ int err = 2,
+ const location& l = {})
{
- process pr (run_start (process_env (p, env), args, 0, 1, true, cwd));
- run_finish (args, pr);
- }
-
- inline void
- run (const process_path& p,
- cstrings& args,
- const dir_path& cwd,
- const char* const* env = nullptr)
- {
- run (p, args.data (), cwd, env);
+ return run_start (pe, args.data (), in, out, err, l);
}
// As above, but search for the process (including updating args[0]) and
@@ -372,16 +342,16 @@ namespace build2
const char* args[],
int in = 0,
int out = 1,
- bool error = true,
- const dir_path& cwd = dir_path (),
+ int err = 2,
const char* const* env = nullptr,
- const location& l = location ())
+ const dir_path& cwd = {},
+ const location& l = {})
{
process_path pp (run_search (args[0], l));
return run_start (verbosity,
- process_env (pp, env), args,
- in, out, error,
- cwd, l);
+ process_env (pp, cwd, env), args,
+ in, out, err,
+ l);
}
inline process
@@ -389,55 +359,215 @@ namespace build2
cstrings& args,
int in = 0,
int out = 1,
- bool error = true,
- const dir_path& cwd = dir_path (),
+ int err = 2,
const char* const* env = nullptr,
- const location& l = location ())
+ const dir_path& cwd = {},
+ const location& l = {})
+ {
+ return run_start (verbosity, args.data (), in, out, err, env, cwd, l);
+ }
+
+ // Wait for process termination returning true if the process exited
+ // normally with a zero code and false otherwise. The latter case is
+ // normally followed up with a call to run_finish().
+ //
+ LIBBUILD2_SYMEXPORT bool
+ run_wait (const char* const* args, process&, const location& = location ());
+
+ bool
+ run_wait (const cstrings& args, process&, const location& = location ());
+
+ // Wait for process termination, issues diagnostics, and throw failed.
+ //
+ // If the child process exited abnormally or normally with non-0 code, then
+ // print the error diagnostics to this effect. Additionally, if the
+ // verbosity level is between 1 and the specified value, then print the
+ // command line as info after the error. If omit_normal is true, then don't
+ // print either for the normal exit (usually used for custom diagnostics or
+ // when process failure can be tolerated).
+ //
+ // Normally the specified verbosity will be 1 and the command line args
+ // represent the verbosity level 2 (logical) command line. Or, to put it
+ // another way, it should be 1 less than what gets passed to run_start().
+ // Note that args should only represent a single command in a pipe (see
+ // print_process() for details).
+ //
+ // See also diag_buffer::close().
+ //
+ // The line argument is used in cooperation with run_start() to diagnose a
+ // failure to exec in case stderr is redirected to stdout (see the
+ // implementation for details).
+ //
+ void
+ run_finish (const char* const* args,
+ process&,
+ uint16_t verbosity,
+ bool omit_normal = false,
+ const location& = location ());
+
+ void
+ run_finish (const cstrings& args,
+ process&,
+ uint16_t verbosity,
+ bool omit_normal = false,
+ const location& = location ());
+
+ void
+ run_finish (const char* const* args,
+ process&,
+ const string& line,
+ uint16_t verbosity,
+ bool omit_normal = false,
+ const location& = location ());
+
+ // As above but if the process has exited normally with a non-zero code,
+ // then return false rather than throwing.
+ //
+ // Note that the normal non-0 exit diagnostics is omitted by default
+ // assuming appropriate custom diagnostics will be issued, if required.
+ //
+ bool
+ run_finish_code (const char* const* args,
+ process&,
+ uint16_t verbosity,
+ bool omit_normal = true,
+ const location& = location ());
+
+ bool
+ run_finish_code (const cstrings& args,
+ process&,
+ uint16_t verbosity,
+ bool omit_normal = true,
+ const location& = location ());
+
+ bool
+ run_finish_code (const char* const* args,
+ process&,
+ const string&,
+ uint16_t verbosity,
+ bool omit_normal = true,
+ const location& = location ());
+
+ // As above but with diagnostics buffering.
+ //
+ // Specifically, this version first waits for the process termination, then
+ // calls diag_buffer::close(verbosity, omit_normal), and finally throws
+ // failed if the process didn't exit with 0 code.
+ //
+ class diag_buffer;
+
+ void
+ run_finish (diag_buffer&,
+ const char* const* args,
+ process&,
+ uint16_t verbosity,
+ bool omit_normal = false,
+ const location& = location ());
+
+ void
+ run_finish (diag_buffer&,
+ const cstrings& args,
+ process&,
+ uint16_t verbosity,
+ bool omit_normal = false,
+ const location& = location ());
+
+ // As above but if the process has exited normally with a non-zero code,
+ // then return false rather than throwing.
+ //
+ // Note that the normal non-0 exit diagnostics is omitted by default
+ // assuming appropriate custom diagnostics will be issued, if required.
+ //
+ bool
+ run_finish_code (diag_buffer&,
+ const char* const* args,
+ process&,
+ uint16_t verbosity,
+ bool omit_normal = true,
+ const location& = location ());
+
+ bool
+ run_finish_code (diag_buffer&,
+ const cstrings& args,
+ process&,
+ uint16_t verbosity,
+ bool omit_normal = true,
+ const location& = location ());
+
+ // Run the process with the specified arguments by calling the above start
+ // and finish functions. Buffer diagnostics unless in the load phase.
+ //
+ LIBBUILD2_SYMEXPORT void
+ run (context&,
+ const process_env& pe, // Implicit-constructible from process_path.
+ const char* const* args,
+ uint16_t finish_verbosity);
+
+ inline void
+ run (context& ctx,
+ const process_env& pe,
+ const cstrings& args,
+ uint16_t finish_verbosity)
{
- return run_start (verbosity, args.data (), in, out, error, cwd, env, l);
+ run (ctx, pe, args.data (), finish_verbosity);
}
+ // As above but pass cwd/env vars as arguments rather than as part of
+ // process_env.
+ //
inline void
- run (uint16_t verbosity,
- const char* args[],
- const dir_path& cwd = dir_path (),
- const char* const* env = nullptr)
+ run (context& ctx,
+ const process_path& p,
+ const char* const* args,
+ uint16_t finish_verbosity,
+ const char* const* env,
+ const dir_path& cwd = {})
{
- process pr (run_start (verbosity, args, 0, 1, true, cwd, env));
- run_finish (args, pr);
+ run (ctx, process_env (p, cwd, env), args, finish_verbosity);
}
inline void
- run (uint16_t verbosity,
- cstrings& args,
- const dir_path& cwd = dir_path (),
- const char* const* env = nullptr)
+ run (context& ctx,
+ const process_path& p,
+ const cstrings& args,
+ uint16_t finish_verbosity,
+ const char* const* env,
+ const dir_path& cwd = {})
{
- run (verbosity, args.data (), cwd, env);
+ run (ctx, p, args.data (), finish_verbosity, env, cwd);
}
// Start the process as above and then call the specified function on each
// trimmed line of the output until it returns a non-empty object T (tested
// with T::empty()) which is then returned to the caller.
//
+ // If verbosity is specified, print the process commands line at that level
+ // (with the verbosite-1 value passed run_finish()).
+ //
+ // If error is false, then redirecting stderr to stdout and don't fail if
+ // the process exits normally but with non-0 code (can be used to suppress
+ // and/or analyze diagnostics from the child process). Otherwise, buffer
+ // diagnostics unless in the load phase.
+ //
// The predicate can move the value out of the passed string but, if error
// is false, only in case of a "content match" (so that any diagnostics
// lines are left intact). The function signature should be:
//
// T (string& line, bool last)
//
- // If ignore_exit is true, then the program's exit status is ignored (if it
- // is false and the program exits with the non-zero status, then an empty T
- // instance is returned).
+ // If, in addition to error being false, ignore_exit is true, then the
+ // program's normal exit status is ignored (if it is false and the program
+ // exits with the non-zero status, then an empty T instance is returned).
//
// If checksum is not NULL, then feed it the content of each trimmed line
// (including those that come after the callback returns non-empty object).
//
template <typename T, typename F>
T
- run (uint16_t verbosity,
+ run (context&,
+ uint16_t verbosity,
const process_env&, // Implicit-constructible from process_path.
- const char* args[],
+ const char* const* args,
F&&,
bool error = true,
bool ignore_exit = false,
@@ -445,20 +575,55 @@ namespace build2
template <typename T, typename F>
inline T
- run (const process_env& pe, // Implicit-constructible from process_path.
- const char* args[],
+ run (context& ctx,
+ uint16_t verbosity,
+ const process_env& pe,
+ const cstrings& args,
+ F&& f,
+ bool error = true,
+ bool ignore_exit = false,
+ sha256* checksum = nullptr)
+ {
+ return run<T> (ctx,
+ verbosity,
+ pe, args.data (),
+ forward<F> (f),
+ error, ignore_exit, checksum);
+ }
+
+ template <typename T, typename F>
+ inline T
+ run (context&,
+ const process_env&,
+ const char* const* args,
+ uint16_t finish_verbosity,
+ F&&,
+ bool error = true,
+ bool ignore_exit = false,
+ sha256* checksum = nullptr);
+
+ template <typename T, typename F>
+ inline T
+ run (context& ctx,
+ const process_env& pe,
+ const cstrings& args,
+ uint16_t finish_verbosity,
F&& f,
bool error = true,
bool ignore_exit = false,
sha256* checksum = nullptr)
{
- return run<T> (
- verb_never, pe, args, forward<F> (f), error, ignore_exit, checksum);
+ return run<T> (ctx,
+ pe, args.data (),
+ finish_verbosity,
+ forward<F> (f),
+ error, ignore_exit, checksum);
}
template <typename T, typename F>
inline T
- run (uint16_t verbosity,
+ run (context& ctx,
+ uint16_t verbosity,
const char* args[],
F&& f,
bool error = true,
@@ -466,15 +631,38 @@ namespace build2
sha256* checksum = nullptr)
{
process_path pp (run_search (args[0]));
- return run<T> (
- verbosity, pp, args, forward<F> (f), error, ignore_exit, checksum);
+ return run<T> (ctx,
+ verbosity,
+ pp, args,
+ forward<F> (f),
+ error, ignore_exit, checksum);
}
+ template <typename T, typename F>
+ inline T
+ run (context& ctx,
+ uint16_t verbosity,
+ cstrings& args,
+ F&& f,
+ bool error = true,
+ bool ignore_exit = false,
+ sha256* checksum = nullptr)
+ {
+ return run<T> (ctx,
+ verbosity,
+ args.data (),
+ forward<F> (f),
+ error, ignore_exit, checksum);
+ }
+
+ // As above but run a program without any arguments or with one argument.
+ //
// run <prog>
//
template <typename T, typename F>
inline T
- run (uint16_t verbosity,
+ run (context& ctx,
+ uint16_t verbosity,
const path& prog,
F&& f,
bool error = true,
@@ -482,13 +670,20 @@ namespace build2
sha256* checksum = nullptr)
{
const char* args[] = {prog.string ().c_str (), nullptr};
- return run<T> (
- verbosity, args, forward<F> (f), error, ignore_exit, checksum);
+ return run<T> (ctx,
+ verbosity,
+ args,
+ forward<F> (f),
+ error, ignore_exit, checksum);
}
template <typename T, typename F>
- inline T
- run (uint16_t verbosity,
+ inline typename std::enable_if<
+ (!std::is_same<typename std::decay<F>::type, const char**>::value &&
+ !std::is_same<typename std::remove_reference<F>::type, cstrings>::value),
+ T>::type
+ run (context& ctx,
+ uint16_t verbosity,
const process_env& pe, // Implicit-constructible from process_path.
F&& f,
bool error = true,
@@ -496,15 +691,19 @@ namespace build2
sha256* checksum = nullptr)
{
const char* args[] = {pe.path->recall_string (), nullptr};
- return run<T> (
- verbosity, pe, args, forward<F> (f), error, ignore_exit, checksum);
+ return run<T> (ctx,
+ verbosity,
+ pe, args,
+ forward<F> (f),
+ error, ignore_exit, checksum);
}
// run <prog> <arg>
//
template <typename T, typename F>
inline T
- run (uint16_t verbosity,
+ run (context& ctx,
+ uint16_t verbosity,
const path& prog,
const char* arg,
F&& f,
@@ -513,13 +712,17 @@ namespace build2
sha256* checksum = nullptr)
{
const char* args[] = {prog.string ().c_str (), arg, nullptr};
- return run<T> (
- verbosity, args, forward<F> (f), error, ignore_exit, checksum);
+ return run<T> (ctx,
+ verbosity,
+ args,
+ forward<F> (f),
+ error, ignore_exit, checksum);
}
template <typename T, typename F>
inline T
- run (uint16_t verbosity,
+ run (context& ctx,
+ uint16_t verbosity,
const process_env& pe, // Implicit-constructible from process_path.
const char* arg,
F&& f,
@@ -528,42 +731,48 @@ namespace build2
sha256* checksum = nullptr)
{
const char* args[] = {pe.path->recall_string (), arg, nullptr};
- return run<T> (
- verbosity, pe, args, forward<F> (f), error, ignore_exit, checksum);
+ return run<T> (ctx,
+ verbosity,
+ pe, args,
+ forward<F> (f),
+ error, ignore_exit, checksum);
}
- // Global, MT-safe information cache. Normally used for caching information
- // (versions, targets, search paths, etc) extracted from other programs
- // (compilers, etc).
+ // As above but a lower-level interface that erases T and F and can also be
+ // used to suppress trimming.
//
- // The key is normally a hash of all the inputs that can affect the output.
+ // The passed function should return true if it should be called again
+ // (i.e., the object is still empty in the T & F interface) and false
+ // otherwise.
//
- // Note that insertion is racy and it's possible the cache entry already
- // exists, in which case we ignore our value assuming it is the same.
+ // The first version ruturn true if the result is usable and false
+ // otherwise, depending on the process exit code and error/ignore_exit
+ // values. (In the latter case, the T & F interface makes the resulting
+ // object empty).
//
- template <typename T>
- class global_cache
+ LIBBUILD2_SYMEXPORT bool
+ run (context&,
+ uint16_t verbosity,
+ const process_env&,
+ const char* const* args,
+ uint16_t finish_verbosity,
+ const function<bool (string& line, bool last)>&,
+ bool trim = true,
+ bool error = true,
+ bool ignore_exit = false,
+ sha256* checksum = nullptr);
+
+ // Concatenate the program path and arguments into a shallow NULL-terminated
+ // vector of C-strings.
+ //
+ LIBBUILD2_SYMEXPORT cstrings
+ process_args (const char* program, const strings& args);
+
+ inline cstrings
+ process_args (const string& program, const strings& args)
{
- public:
- const T*
- find (const string& k) const
- {
- mlock l (mutex_);
- auto i (cache_.find (k));
- return i != cache_.end () ? &i->second : nullptr;
- }
-
- const T&
- insert (string k, T v)
- {
- mlock l (mutex_);
- return cache_.insert (make_pair (move (k), move (v))).first->second;
- }
-
- private:
- std::map<string, T> cache_;
- mutable mutex mutex_;
- };
+ return process_args (program.c_str (), args);
+ }
// File descriptor streams.
//
@@ -680,6 +889,26 @@ namespace build2
I begin, I end,
F&& get = [] (const string& s) {return s;});
+ // As above but append a single option (used for append/hash uniformity).
+ //
+ inline void
+ append_option (cstrings& args, const char* o)
+ {
+ args.push_back (o);
+ }
+
+ inline void
+ append_option (strings& args, const char* o)
+ {
+ args.push_back (o);
+ }
+
+ inline void
+ append_option (sha256& csum, const char* o)
+ {
+ csum.append (o);
+ }
+
// Check if a specified option is present in the variable or value. T is
// either target or scope. For the interator version use rbegin()/rend() to
// search backwards.
@@ -799,6 +1028,41 @@ namespace build2
const cstrings&,
bool = false);
+ // Hash environment variable (its name and value) normally to be used as a
+ // checksum. See also config::save_environment().
+ //
+ void
+ hash_environment (sha256&, const char* name);
+
+ void
+ hash_environment (sha256&, const string& name);
+
+ void
+ hash_environment (sha256&, initializer_list<const char*> names);
+
+ string
+ hash_environment (initializer_list<const char*> names);
+
+ void
+ hash_environment (sha256&, const cstrings& names);
+
+ string
+ hash_environment (const cstrings& names);
+
+ void
+ hash_environment (sha256&, const strings& names);
+
+ string
+ hash_environment (const strings& names);
+
+ // A NULL-terminated list of variables (may itself be NULL).
+ //
+ void
+ hash_environment (sha256&, const char* const* names);
+
+ string
+ hash_environment (const char* const* names);
+
// Find in the string the stem separated from other characters with the
// specified separators or begin/end of the string. Return the stem's
// position or npos if not found.