From d730f40440e213bc08cce4587439960c80ad9aa5 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 8 Oct 2019 09:33:45 +0200 Subject: Redo bin pattern as PATH-like search paths rather than fallback directory Also, unlike the fallback directory, the search paths are searched first rather than last. --- libbuild2/bin/guess.cxx | 105 ++++++++++++++++++++++++------------------------ libbuild2/bin/guess.hxx | 6 +-- libbuild2/bin/init.cxx | 62 +++++++++++++++++----------- 3 files changed, 94 insertions(+), 79 deletions(-) (limited to 'libbuild2/bin') diff --git a/libbuild2/bin/guess.cxx b/libbuild2/bin/guess.cxx index 68ef827..633c798 100644 --- a/libbuild2/bin/guess.cxx +++ b/libbuild2/bin/guess.cxx @@ -37,37 +37,60 @@ namespace build2 return v ? *v : semantic_version (); } - ar_info - guess_ar (const path& ar, const path* rl, const dir_path& fallback) + // Search for a program first in paths if not NULL and then using the + // standard path search semantics. Use var to suggest an override if the + // search fails. + // + // Only search in PATH (specifically, omitting the current executable's + // directory on Windows). + // + static process_path + search (const path& prog, const char* paths, const char* var) { - tracer trace ("bin::guess_ar"); - - process_path arp, rlp; - guess_result arr, rlr; - + if (paths != nullptr) { - auto df = make_diag_frame ( - [](const diag_record& dr) - { - dr << info << "use config.bin.ar to override"; - }); + process_path r ( + try_run_search (prog, + true /* init */, + dir_path () /* fallback */, + true /* path_only */, + paths)); - // Only search in PATH (specifically, omitting the current - // executable's directory on Windows). - // - arp = run_search (ar, true, fallback, true /* path_only */); + if (!r.empty ()) + { + // Clear the recall path since we found it in custom search paths. + // An alternative would have been to also do a search in PATH and if + // the two effective paths are the same (which means, this program + // is also in PATH), keep the recall. The benefit of this approach + // is that we will have tidier command lines without long absolute + // paths. The drawback is the extra complexity (we would need to + // normalize the paths, etc). Let's keep it simple for now. + // + r.clear_recall (); + return r; + } } - if (rl != nullptr) - { - auto df = make_diag_frame ( - [](const diag_record& dr) - { - dr << info << "use config.bin.ranlib to override"; - }); + auto df = make_diag_frame ( + [var](const diag_record& dr) + { + dr << info << "use " << var << " to override"; + }); - rlp = run_search (*rl, true, fallback, true /* path_only */); - } + return run_search (prog, true, dir_path (), true); + } + + ar_info + guess_ar (const path& ar, const path* rl, const char* paths) + { + tracer trace ("bin::guess_ar"); + + guess_result arr, rlr; + + process_path arp (search (ar, paths, "config.bin.ar")); + process_path rlp (rl != nullptr + ? search (*rl, paths, "config.bin.ranlib") + : process_path ()); // Binutils, LLVM, and FreeBSD ar/ranlib all recognize the --version // option. While Microsoft's lib.exe doesn't support --version, it only @@ -258,25 +281,13 @@ namespace build2 } ld_info - guess_ld (const path& ld, const dir_path& fallback) + guess_ld (const path& ld, const char* paths) { tracer trace ("bin::guess_ld"); guess_result r; - process_path pp; - { - auto df = make_diag_frame ( - [](const diag_record& dr) - { - dr << info << "use config.bin.ld to override"; - }); - - // Only search in PATH (specifically, omitting the current - // executable's directory on Windows). - // - pp = run_search (ld, true, fallback, true /* path_only */); - } + process_path pp (search (ld, paths, "config.bin.ld")); // Binutils ld recognizes the --version option. Microsoft's link.exe // doesn't support --version (nor any other way to get the version @@ -389,25 +400,13 @@ namespace build2 } rc_info - guess_rc (const path& rc, const dir_path& fallback) + guess_rc (const path& rc, const char* paths) { tracer trace ("bin::guess_rc"); guess_result r; - process_path pp; - { - auto df = make_diag_frame ( - [](const diag_record& dr) - { - dr << info << "use config.bin.rc to override"; - }); - - // Only search in PATH (specifically, omitting the current - // executable's directory on Windows). - // - pp = run_search (rc, true, fallback, true /* path_only */); - } + process_path pp (search (rc, paths, "config.bin.rc")); // Binutils windres recognizes the --version option. // diff --git a/libbuild2/bin/guess.hxx b/libbuild2/bin/guess.hxx index 0e04ba5..b4239c2 100644 --- a/libbuild2/bin/guess.hxx +++ b/libbuild2/bin/guess.hxx @@ -46,7 +46,7 @@ namespace build2 // attemplated and the returned ranlib_* members will be left empty. // ar_info - guess_ar (const path& ar, const path* ranlib, const dir_path& fallback); + guess_ar (const path& ar, const path* ranlib, const char* paths); // ld information. // @@ -77,7 +77,7 @@ namespace build2 }; ld_info - guess_ld (const path& ld, const dir_path& fallback); + guess_ld (const path& ld, const char* paths); // rc information. // @@ -101,7 +101,7 @@ namespace build2 }; rc_info - guess_rc (const path& rc, const dir_path& fallback); + guess_rc (const path& rc, const char* paths); } } diff --git a/libbuild2/bin/init.cxx b/libbuild2/bin/init.cxx index d56e0a5..7f7fd02 100644 --- a/libbuild2/bin/init.cxx +++ b/libbuild2/bin/init.cxx @@ -37,6 +37,30 @@ 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&, @@ -370,7 +394,9 @@ namespace build2 (!path::traits_type::is_separator (s.back ()) && s.find ('*') == string::npos)) { - fail << "missing '*' in binutils pattern '" << s << "'"; + fail << "missing '*' or trailing '" + << path::traits_type::directory_separator + << "' in binutils pattern '" << s << "'"; } rs.assign ("bin.pattern") = s; @@ -602,12 +628,9 @@ namespace build2 const string& tsys (cast (rs["bin.target.system"])); const char* ar_d (tsys == "win32-msvc" ? "lib" : "ar"); - // This can be either a pattern or a fallback search directory. + // This can be either a pattern or search path(s). // - const string* pat (cast_null (rs["bin.pattern"])); - - bool fb (pat != nullptr && - path::traits_type::is_separator (pat->back ())); + pattern_paths pat (lookup_pattern (rs)); // Don't save the default value to config.build so that if the user // changes, say, the C++ compiler (which hinted the pattern), then @@ -617,7 +640,7 @@ namespace build2 config::required ( rs, "config.bin.ar", - path (apply_pattern (ar_d, fb ? nullptr : pat)), + path (apply_pattern (ar_d, pat.pattern)), false, config::save_commented)); @@ -632,8 +655,7 @@ namespace build2 const path& ar (cast (ap.first)); const path* ranlib (cast_null (rp.first)); - ar_info ari ( - guess_ar (ar, ranlib, fb ? dir_path (*pat) : dir_path ())); + ar_info ari (guess_ar (ar, ranlib, pat.paths)); // If this is a new value (e.g., we are configuring), then print the // report at verbosity level 2 and up (-v). @@ -762,23 +784,20 @@ namespace build2 const string& tsys (cast (rs["bin.target.system"])); const char* ld_d (tsys == "win32-msvc" ? "link" : "ld"); - // This can be either a pattern or a fallback search directory. + // This can be either a pattern or search path(s). // - const string* pat (cast_null (rs["bin.pattern"])); - - bool fb (pat != nullptr && - path::traits_type::is_separator (pat->back ())); + pattern_paths pat (lookup_pattern (rs)); auto p ( config::required ( rs, "config.bin.ld", - path (apply_pattern (ld_d, fb ? nullptr : pat)), + path (apply_pattern (ld_d, pat.pattern)), false, config::save_commented)); const path& ld (cast (p.first)); - ld_info ldi (guess_ld (ld, fb ? dir_path (*pat) : dir_path ())); + ld_info ldi (guess_ld (ld, pat.paths)); // If this is a new value (e.g., we are configuring), then print the // report at verbosity level 2 and up (-v). @@ -875,23 +894,20 @@ namespace build2 const string& tsys (cast (rs["bin.target.system"])); const char* rc_d (tsys == "win32-msvc" ? "rc" : "windres"); - // This can be either a pattern or a fallback search directory. + // This can be either a pattern or search path(s). // - const string* pat (cast_null (rs["bin.pattern"])); - - bool fb (pat != nullptr && - path::traits_type::is_separator (pat->back ())); + pattern_paths pat (lookup_pattern (rs)); auto p ( config::required ( rs, "config.bin.rc", - path (apply_pattern (rc_d, fb ? nullptr : pat)), + path (apply_pattern (rc_d, pat.pattern)), false, config::save_commented)); const path& rc (cast (p.first)); - rc_info rci (guess_rc (rc, fb ? dir_path (*pat) : dir_path ())); + rc_info rci (guess_rc (rc, pat.paths)); // If this is a new value (e.g., we are configuring), then print the // report at verbosity level 2 and up (-v). -- cgit v1.1