From 6f6b82d00051587fa3496d0bc3f4fe1ff512dda3 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 8 Sep 2023 06:17:08 +0200 Subject: Manually extract library search paths from LIBRARY_PATH for Clang Unlike GCC, Clang does not incorporate the LIBRARY_PATH environment variable value into the -print-search-dirs output. --- libbuild2/cc/gcc.cxx | 140 +++++++++++++++++++++++++++--------------------- libbuild2/cc/module.cxx | 8 +-- libbuild2/cc/module.hxx | 8 +-- libbuild2/cc/msvc.cxx | 4 +- 4 files changed, 90 insertions(+), 70 deletions(-) (limited to 'libbuild2') diff --git a/libbuild2/cc/gcc.cxx b/libbuild2/cc/gcc.cxx index b553c8c..0cae150 100644 --- a/libbuild2/cc/gcc.cxx +++ b/libbuild2/cc/gcc.cxx @@ -82,6 +82,71 @@ namespace build2 } #endif + // Parse color/semicolon-separated list of search directories (from + // -print-search-dirs output, environment variables). + // + static void + parse_search_dirs (const string& v, dir_paths& r, + const char* what, const char* what2 = "") + { + // Now the fun part: figuring out which delimiter is used. Normally it + // is ':' but on Windows it is ';' (or can be; who knows for sure). Also + // note that these paths are absolute (or should be). So here is what we + // are going to do: first look for ';'. If found, then that's the + // delimiter. If not found, then there are two cases: it is either a + // single Windows path or the delimiter is ':'. To distinguish these two + // cases we check if the path starts with a Windows drive. + // + char d (';'); + string::size_type e (v.find (d)); + + if (e == string::npos && + (v.size () < 2 || v[0] == '/' || v[1] != ':')) + { + d = ':'; + e = v.find (d); + } + + // Now chop it up. We already have the position of the first delimiter + // (if any). + // + for (string::size_type b (0);; e = v.find (d, (b = e + 1))) + { + dir_path d; + try + { + string ds (v, b, (e != string::npos ? e - b : e)); + + // Skip empty entries (sometimes found in random MinGW toolchains). + // + if (!ds.empty ()) + { +#ifdef _WIN32 + if (path_traits::is_separator (ds[0])) + add_current_drive (ds); +#endif + d = dir_path (move (ds)); + + if (d.relative ()) + throw invalid_path (move (d).string ()); + + d.normalize (); + } + } + catch (const invalid_path& e) + { + fail << "invalid directory '" << e.path << "'" << " in " + << what << what2; + } + + if (!d.empty () && find (r.begin (), r.end (), d) == r.end ()) + r.push_back (move (d)); + + if (e == string::npos) + break; + } + } + // Extract system header search paths from GCC (gcc/g++) or compatible // (Clang, Intel) using the `-v -E config_module:: - gcc_header_search_dirs (const process_path& xc, scope& rs) const + gcc_header_search_dirs (const compiler_info& xi, scope& rs) const { dir_paths r; // Note also that any -I and similar that we may specify on the command - // line are factored into the output. + // line are factored into the output. As well as the CPATH, etc., + // environment variable values. // - cstrings args {xc.recall_string ()}; + cstrings args {xi.path.recall_string ()}; append_options (args, rs, x_mode); // Compile as. @@ -123,7 +189,7 @@ namespace build2 args.push_back ("-"); args.push_back (nullptr); - process_env env (xc); + process_env env (xi.path); // For now let's assume that all the platforms other than Windows // recognize LC_ALL. @@ -240,7 +306,7 @@ namespace build2 // (Clang, Intel) using the -print-search-dirs option. // pair config_module:: - gcc_library_search_dirs (const process_path& xc, scope& rs) const + gcc_library_search_dirs (const compiler_info& xi, scope& rs) const { // The output of -print-search-dirs are a bunch of lines that start with // ": =" where name can be "install", "programs", or "libraries". @@ -267,12 +333,12 @@ namespace build2 gcc_extract_library_search_dirs (cast (rs[x_mode]), r); size_t rn (r.size ()); - cstrings args {xc.recall_string ()}; + cstrings args {xi.path.recall_string ()}; append_options (args, rs, x_mode); args.push_back ("-print-search-dirs"); args.push_back (nullptr); - process_env env (xc); + process_env env (xi.path); // For now let's assume that all the platforms other than Windows // recognize LC_ALL. @@ -330,62 +396,16 @@ namespace build2 fail << "unable to extract " << x_lang << " compiler system library " << "search paths"; - // Now the fun part: figuring out which delimiter is used. Normally it - // is ':' but on Windows it is ';' (or can be; who knows for sure). Also - // note that these paths are absolute (or should be). So here is what we - // are going to do: first look for ';'. If found, then that's the - // delimiter. If not found, then there are two cases: it is either a - // single Windows path or the delimiter is ':'. To distinguish these two - // cases we check if the path starts with a Windows drive. - // - char d (';'); - string::size_type e (l.find (d)); + parse_search_dirs (l, r, args[0], " -print-search-dirs output"); - if (e == string::npos && - (l.size () < 2 || l[0] == '/' || l[1] != ':')) - { - d = ':'; - e = l.find (d); - } - - // Now chop it up. We already have the position of the first delimiter - // (if any). + // While GCC incorporates the LIBRARY_PATH environment variable value + // into the -print-search-dirs output, Clang does not. Also, unlike GCC, + // it appears to consider such paths last. // - for (string::size_type b (0);; e = l.find (d, (b = e + 1))) + if (xi.id.type == compiler_type::clang) { - dir_path d; - try - { - string ds (l, b, (e != string::npos ? e - b : e)); - - // Skip empty entries (sometimes found in random MinGW toolchains). - // - if (!ds.empty ()) - { -#ifdef _WIN32 - if (path_traits::is_separator (ds[0])) - add_current_drive (ds); -#endif - - d = dir_path (move (ds)); - - if (d.relative ()) - throw invalid_path (move (d).string ()); - - d.normalize (); - } - } - catch (const invalid_path& e) - { - fail << "invalid directory '" << e.path << "'" << " in " - << args[0] << " -print-search-dirs output"; - } - - if (!d.empty () && find (r.begin (), r.end (), d) == r.end ()) - r.emplace_back (move (d)); - - if (e == string::npos) - break; + if (optional v = getenv ("LIBRARY_PATH")) + parse_search_dirs (*v, r, "LIBRARY_PATH environment variable"); } return make_pair (move (r), rn); diff --git a/libbuild2/cc/module.cxx b/libbuild2/cc/module.cxx index e0bdf25..40857d7 100644 --- a/libbuild2/cc/module.cxx +++ b/libbuild2/cc/module.cxx @@ -613,10 +613,10 @@ namespace build2 switch (xi.class_) { case compiler_class::gcc: - lib_dirs = gcc_library_search_dirs (xi.path, rs); + lib_dirs = gcc_library_search_dirs (xi, rs); break; case compiler_class::msvc: - lib_dirs = msvc_library_search_dirs (xi.path, rs); + lib_dirs = msvc_library_search_dirs (xi, rs); break; } } @@ -630,10 +630,10 @@ namespace build2 switch (xi.class_) { case compiler_class::gcc: - hdr_dirs = gcc_header_search_dirs (xi.path, rs); + hdr_dirs = gcc_header_search_dirs (xi, rs); break; case compiler_class::msvc: - hdr_dirs = msvc_header_search_dirs (xi.path, rs); + hdr_dirs = msvc_header_search_dirs (xi, rs); break; } } diff --git a/libbuild2/cc/module.hxx b/libbuild2/cc/module.hxx index 2a8611b..dc929dd 100644 --- a/libbuild2/cc/module.hxx +++ b/libbuild2/cc/module.hxx @@ -115,18 +115,18 @@ namespace build2 // Defined in gcc.cxx. // pair - gcc_header_search_dirs (const process_path&, scope&) const; + gcc_header_search_dirs (const compiler_info&, scope&) const; pair - gcc_library_search_dirs (const process_path&, scope&) const; + gcc_library_search_dirs (const compiler_info&, scope&) const; // Defined in msvc.cxx. // pair - msvc_header_search_dirs (const process_path&, scope&) const; + msvc_header_search_dirs (const compiler_info&, scope&) const; pair - msvc_library_search_dirs (const process_path&, scope&) const; + msvc_library_search_dirs (const compiler_info&, scope&) const; }; class LIBBUILD2_CC_SYMEXPORT module: public build2::module, diff --git a/libbuild2/cc/msvc.cxx b/libbuild2/cc/msvc.cxx index 3a7fd6f..d21969c 100644 --- a/libbuild2/cc/msvc.cxx +++ b/libbuild2/cc/msvc.cxx @@ -345,7 +345,7 @@ namespace build2 // Extract system header search paths from MSVC. // pair config_module:: - msvc_header_search_dirs (const process_path&, scope& rs) const + msvc_header_search_dirs (const compiler_info&, scope& rs) const { // MSVC doesn't have any built-in paths and all of them either come from // the INCLUDE environment variable or are specified explicitly on the @@ -373,7 +373,7 @@ namespace build2 // Extract system library search paths from MSVC. // pair config_module:: - msvc_library_search_dirs (const process_path&, scope& rs) const + msvc_library_search_dirs (const compiler_info&, scope& rs) const { // MSVC doesn't seem to have any built-in paths and all of them either // come from the LIB environment variable or are specified explicitly on -- cgit v1.1