aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2023-09-08 06:17:08 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2023-09-08 06:17:08 +0200
commit6f6b82d00051587fa3496d0bc3f4fe1ff512dda3 (patch)
tree8492b6b7ccd17a38b5b9e01b2ef77782fec9697a
parent17c1214943959b304ab5cdcccacec8a70c7a6c0f (diff)
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.
-rw-r--r--libbuild2/cc/gcc.cxx140
-rw-r--r--libbuild2/cc/module.cxx8
-rw-r--r--libbuild2/cc/module.hxx8
-rw-r--r--libbuild2/cc/msvc.cxx4
4 files changed, 90 insertions, 70 deletions
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 </dev/null` method.
//
@@ -92,14 +157,15 @@ namespace build2
// do this is to run the compiler twice.
//
pair<dir_paths, size_t> 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<dir_paths, size_t> 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
// "<name>: =" where name can be "install", "programs", or "libraries".
@@ -267,12 +333,12 @@ namespace build2
gcc_extract_library_search_dirs (cast<strings> (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<string> 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<dir_paths, size_t>
- gcc_header_search_dirs (const process_path&, scope&) const;
+ gcc_header_search_dirs (const compiler_info&, scope&) const;
pair<dir_paths, size_t>
- gcc_library_search_dirs (const process_path&, scope&) const;
+ gcc_library_search_dirs (const compiler_info&, scope&) const;
// Defined in msvc.cxx.
//
pair<dir_paths, size_t>
- msvc_header_search_dirs (const process_path&, scope&) const;
+ msvc_header_search_dirs (const compiler_info&, scope&) const;
pair<dir_paths, size_t>
- 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<dir_paths, size_t> 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<dir_paths, size_t> 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