From 66de0d06e5b6c002cbc7d18e18685e3ea44d3848 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 9 Oct 2019 12:08:45 +0200 Subject: Prepend pattern search paths to PATH when running binutils This way any dependent tools (such as mt.exe that is invoked by link.exe) are first search for in there. --- libbuild2/bin/init.cxx | 25 +---------------- libbuild2/bin/utility.hxx | 47 +++++++++++++++++++++++++++++++ libbuild2/cc/link-rule.cxx | 70 +++++++++++++++++++++++++++++++++++++++++++--- libbuild2/parser.cxx | 11 ++++---- libbuild2/utility.hxx | 34 ++++++++++++---------- 5 files changed, 139 insertions(+), 48 deletions(-) create mode 100644 libbuild2/bin/utility.hxx diff --git a/libbuild2/bin/init.cxx b/libbuild2/bin/init.cxx index 07888f6..db9db0e 100644 --- a/libbuild2/bin/init.cxx +++ b/libbuild2/bin/init.cxx @@ -20,6 +20,7 @@ #include #include #include +#include using namespace std; using namespace butl; @@ -37,30 +38,6 @@ namespace build2 static const strings liba_lib {"static", "shared"}; static const strings libs_lib {"shared", "static"}; - struct pattern_paths - { - const char* pattern = nullptr; - const char* paths = nullptr; - }; - - static inline pattern_paths - lookup_pattern (scope& rs) - { - pattern_paths r; - - // Theoretically, we could have both the pattern and the search paths, - // for example, the pattern can come first followed by the paths. - // - if (const string* v = cast_null (rs["bin.pattern"])) - { - (path::traits_type::is_separator (v->back ()) - ? r.paths - : r.pattern) = v->c_str (); - } - - return r; - } - bool vars_init (scope& rs, scope&, diff --git a/libbuild2/bin/utility.hxx b/libbuild2/bin/utility.hxx new file mode 100644 index 0000000..cc2b727 --- /dev/null +++ b/libbuild2/bin/utility.hxx @@ -0,0 +1,47 @@ +// file : libbuild2/bin/utility.hxx -*- C++ -*- +// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef LIBBUILD2_BIN_UTILITY_HXX +#define LIBBUILD2_BIN_UTILITY_HXX + +#include +#include + +#include +#include + +namespace build2 +{ + namespace bin + { + // Lookup the bin.pattern value and split it into the pattern and the + // search paths. + // + struct pattern_paths + { + const char* pattern = nullptr; + const char* paths = nullptr; + }; + + inline pattern_paths + lookup_pattern (const scope& rs) + { + pattern_paths r; + + // Theoretically, we could have both the pattern and the search paths, + // for example, the pattern can come first followed by the paths. + // + if (const string* v = cast_null (rs["bin.pattern"])) + { + (path::traits_type::is_separator (v->back ()) + ? r.paths + : r.pattern) = v->c_str (); + } + + return r; + } + } +} + +#endif // LIBBUILD2_BIN_UTILITY_HXX diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx index cd31058..8aedcad 100644 --- a/libbuild2/cc/link-rule.cxx +++ b/libbuild2/cc/link-rule.cxx @@ -19,6 +19,7 @@ #include #include +#include #include // c, pc* #include @@ -37,7 +38,7 @@ namespace build2 link_rule:: link_rule (data&& d) : common (move (d)), - rule_id (string (x) += ".link 1") + rule_id (string (x) += ".link 2") { static_assert (sizeof (match_data) <= target::data_size, "insufficient space"); @@ -1939,6 +1940,47 @@ namespace build2 // depdb dd (tp + ".d"); + // Adjust the environment. + // + using environment = small_vector; + environment env; + sha256 env_cs; + + // If we have the search paths in the binutils pattern, prepend them to + // the PATH environment variable so that any dependent tools (such as + // mt.exe that is invoked by link.exe) are first search for in there. + // + { + bin::pattern_paths pat (bin::lookup_pattern (rs)); + + if (pat.paths != nullptr) + { + string v ("PATH="); + v += pat.paths; + + env_cs.append (v); // Hash only what we are adding. + + if (optional o = getenv ("PATH")) + { + v += path::traits_type::path_separator; + v += *o; + } + + env.push_back (move (v)); + } + } + + // Convert the environment to what's expected by the process API. + // + small_vector env_ptrs; + if (!env.empty ()) + { + for (const string& v: env) + env_ptrs.push_back (v.c_str ()); + + env_ptrs.push_back (nullptr); + } + // If targeting Windows, take care of the manifest. // path manifest; // Manifest itself (msvc) or compiled object file. @@ -1989,7 +2031,13 @@ namespace build2 try { - process pr (rc, args, -1); + process pr (rc, + args, + -1 /* stdin */, + 1 /* stdout */, + 2 /* stderr */, + nullptr /* cwd */, + env_ptrs.empty () ? nullptr : env_ptrs.data ()); try { @@ -2090,6 +2138,11 @@ namespace build2 l4 ([&]{trace << "linker mismatch forcing update of " << t;}); } + // Hash and compare any changes to the environment. + // + if (dd.expect (env_cs.string ()) != nullptr) + l4 ([&]{trace << "environment mismatch forcing update of " << t;}); + // Next check the target. While it might be incorporated into the linker // checksum, it also might not (e.g., VC link.exe). // @@ -2905,7 +2958,13 @@ namespace build2 // bool filter (tsys == "win32-msvc" && !lt.static_library ()); - process pr (*ld, args.data (), 0, (filter ? -1 : 2)); + process pr (*ld, + args.data (), + 0 /* stdin */, + (filter ? -1 : 2) /* stdout */, + 2 /* stderr */, + nullptr /* cwd */, + env_ptrs.empty () ? nullptr : env_ptrs.data ()); if (filter) { @@ -2986,7 +3045,10 @@ namespace build2 print_process (args); if (!ctx.dry_run) - run (rl, args); + run (rl, + args, + dir_path () /* cwd */, + env_ptrs.empty () ? nullptr : env_ptrs.data ()); } // For Windows generate (or clean up) rpath-emulating assembly. diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx index b33ba78..6e15cf3 100644 --- a/libbuild2/parser.cxx +++ b/libbuild2/parser.cxx @@ -1568,12 +1568,13 @@ namespace build2 [] (const string& s) {return s.c_str ();}); cargs.push_back (nullptr); - process pr (run_start (3 /* verbosity */, + process pr (run_start (3 /* verbosity */, cargs, - 0 /* stdin */, - -1 /* stdout */, - true /* error */, - empty_dir_path /* cwd */, + 0 /* stdin */, + -1 /* stdout */, + true /* error */, + dir_path () /* cwd */, + nullptr /* env */, l)); bool bad (false); try diff --git a/libbuild2/utility.hxx b/libbuild2/utility.hxx index c362b34..980c31f 100644 --- a/libbuild2/utility.hxx +++ b/libbuild2/utility.hxx @@ -280,18 +280,20 @@ namespace build2 inline void run (const process_path& p, const char* args[], - const dir_path& cwd = dir_path ()) + const dir_path& cwd = dir_path (), + const char* const* env = nullptr) { - process pr (run_start (p, args, 0 /* stdin */, 1 /* stdout */, true, cwd)); + 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 = dir_path ()) + const dir_path& cwd = dir_path (), + const char* const* env = nullptr) { - run (p, args.data (), cwd); + run (p, args.data (), cwd, env); } // As above, but search for the process (including updating args[0]) and @@ -304,10 +306,14 @@ namespace build2 int out, bool error = true, const dir_path& cwd = dir_path (), + const char* const* env = nullptr, const location& l = location ()) { process_path pp (run_search (args[0], l)); - return run_start (verbosity, pp, args, in, out, error, cwd, l); + return run_start (verbosity, + process_env (pp, env), args, + in, out, error, + cwd, l); } inline process @@ -317,31 +323,29 @@ namespace build2 int out, bool error = true, const dir_path& cwd = dir_path (), + const char* const* env = nullptr, const location& l = location ()) { - return run_start (verbosity, args.data (), in, out, error, cwd, l); + return run_start (verbosity, args.data (), in, out, error, cwd, env, l); } inline void run (uint16_t verbosity, const char* args[], - const dir_path& cwd = dir_path ()) + const dir_path& cwd = dir_path (), + const char* const* env = nullptr) { - process pr (run_start (verbosity, - args, - 0 /* stdin */, - 1 /* stdout */, - true, - cwd)); + process pr (run_start (verbosity, args, 0, 1, true, cwd, env)); run_finish (args, pr); } inline void run (uint16_t verbosity, cstrings& args, - const dir_path& cwd = dir_path ()) + const dir_path& cwd = dir_path (), + const char* const* env = nullptr) { - run (verbosity, args.data (), cwd); + run (verbosity, args.data (), cwd, env); } // Start the process as above and then call the specified function on each -- cgit v1.1