aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/cc/gcc.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/cc/gcc.cxx')
-rw-r--r--libbuild2/cc/gcc.cxx215
1 files changed, 130 insertions, 85 deletions
diff --git a/libbuild2/cc/gcc.cxx b/libbuild2/cc/gcc.cxx
index 30f2092..b553c8c 100644
--- a/libbuild2/cc/gcc.cxx
+++ b/libbuild2/cc/gcc.cxx
@@ -45,6 +45,13 @@ namespace build2
d = dir_path (o, 2, string::npos);
else
continue;
+
+ // Ignore relative paths. Or maybe we should warn?
+ //
+ if (d.relative ())
+ continue;
+
+ d.normalize ();
}
catch (const invalid_path& e)
{
@@ -52,13 +59,29 @@ namespace build2
<< o << "'";
}
- // Ignore relative paths. Or maybe we should warn?
- //
- if (!d.relative ())
- r.push_back (move (d));
+ r.push_back (move (d));
}
}
+#ifdef _WIN32
+ // Some misconfigured MinGW GCC builds add absolute POSIX directories to
+ // their built-in search paths (e.g., /mingw/{include,lib}) which GCC then
+ // interprets as absolute paths relative to the current drive (so the set
+ // of built-in search paths starts depending on where we run things from).
+ //
+ // While that's definitely misguided, life is short and we don't want to
+ // waste it explaining this in long mailing list threads and telling
+ // people to complain to whomever built their GCC. So we will just
+ // recreate the behavior in a way that's consistent with GCC and let
+ // people discover this on their own.
+ //
+ static inline void
+ add_current_drive (string& s)
+ {
+ s.insert (0, work.string (), 0, 2); // Add e.g., `c:`.
+ }
+#endif
+
// Extract system header search paths from GCC (gcc/g++) or compatible
// (Clang, Intel) using the `-v -E </dev/null` method.
//
@@ -113,101 +136,94 @@ namespace build2
if (verb >= 3)
print_process (env, args);
+ // Open pipe to stderr, redirect stdin and stdout to /dev/null.
+ //
+ process pr (run_start (
+ env,
+ args,
+ -2, /* stdin */
+ -2, /* stdout */
+ -1 /* stderr */));
try
{
- //@@ TODO: why don't we use run_start() here? Because it's unable to
- // open pipe for stderr and we need to change it first, for example,
- // making the err parameter a file descriptor rather than a flag.
- //
+ ifdstream is (
+ move (pr.in_efd), fdstream_mode::skip, ifdstream::badbit);
- // Open pipe to stderr, redirect stdin and stdout to /dev/null.
+ // Normally the system header paths appear between the following
+ // lines:
//
- process pr (xc,
- args.data (),
- -2, /* stdin */
- -2, /* stdout */
- -1, /* stderr */
- nullptr /* cwd */,
- env.vars);
-
- try
+ // #include <...> search starts here:
+ // End of search list.
+ //
+ // The exact text depends on the current locale. What we can rely on
+ // is the presence of the "#include <...>" substring in the "opening"
+ // line and the fact that the paths are indented with a single space
+ // character, unlike the "closing" line.
+ //
+ // Note that on Mac OS we will also see some framework paths among
+ // system header paths, followed with a comment. For example:
+ //
+ // /Library/Frameworks (framework directory)
+ //
+ // For now we ignore framework paths and to filter them out we will
+ // only consider valid paths to existing directories, skipping those
+ // which we fail to normalize or stat. @@ Maybe this is a bit too
+ // loose, especially compared to gcc_library_search_dirs()?
+ //
+ string s;
+ for (bool found (false); getline (is, s); )
{
- ifdstream is (
- move (pr.in_efd), fdstream_mode::skip, ifdstream::badbit);
-
- // Normally the system header paths appear between the following
- // lines:
- //
- // #include <...> search starts here:
- // End of search list.
- //
- // The exact text depends on the current locale. What we can rely on
- // is the presence of the "#include <...>" substring in the
- // "opening" line and the fact that the paths are indented with a
- // single space character, unlike the "closing" line.
- //
- // Note that on Mac OS we will also see some framework paths among
- // system header paths, followed with a comment. For example:
- //
- // /Library/Frameworks (framework directory)
- //
- // For now we ignore framework paths and to filter them out we will
- // only consider valid paths to existing directories, skipping those
- // which we fail to normalize or stat.
- //
- string s;
- for (bool found (false); getline (is, s); )
+ if (!found)
+ found = s.find ("#include <...>") != string::npos;
+ else
{
- if (!found)
- found = s.find ("#include <...>") != string::npos;
- else
+ if (s[0] != ' ')
+ break;
+
+ dir_path d;
+ try
{
- if (s[0] != ' ')
- break;
-
- try
- {
- dir_path d (s, 1, s.size () - 1);
-
- if (d.absolute () && exists (d, true) &&
- find (r.begin (), r.end (), d.normalize ()) == r.end ())
- r.emplace_back (move (d));
- }
- catch (const invalid_path&)
- {
- // Skip this path.
- }
- }
- }
+ string ds (s, 1, s.size () - 1);
- is.close (); // Don't block.
+#ifdef _WIN32
+ if (path_traits::is_separator (ds[0]))
+ add_current_drive (ds);
+#endif
+ d = dir_path (move (ds));
- if (!pr.wait ())
- {
- // We have read stderr so better print some diagnostics.
- //
- diag_record dr (fail);
+ if (d.relative () || !exists (d, true))
+ continue;
- dr << "failed to extract " << x_lang << " header search paths" <<
- info << "command line: ";
+ d.normalize ();
+ }
+ catch (const invalid_path&)
+ {
+ continue;
+ }
- print_process (dr, args);
+ if (find (r.begin (), r.end (), d) == r.end ())
+ r.emplace_back (move (d));
}
}
- catch (const io_error&)
+
+ is.close (); // Don't block.
+
+ if (!run_wait (args, pr))
{
- pr.wait ();
- fail << "error reading " << x_lang << " compiler -v -E output";
+ // We have read stderr so better print some diagnostics.
+ //
+ diag_record dr (fail);
+
+ dr << "failed to extract " << x_lang << " header search paths" <<
+ info << "command line: ";
+
+ print_process (dr, args);
}
}
- catch (const process_error& e)
+ catch (const io_error&)
{
- error << "unable to execute " << args[0] << ": " << e;
-
- if (e.child)
- exit (1);
-
- throw failed ();
+ run_wait (args, pr);
+ fail << "error reading " << x_lang << " compiler -v -E output";
}
// It's highly unlikely not to have any system directories. More likely
@@ -271,6 +287,9 @@ namespace build2
// Open pipe to stdout.
//
+ // Note: this function is called in the serial load phase and so no
+ // diagnostics buffering is needed.
+ //
process pr (run_start (env,
args,
0, /* stdin */
@@ -305,7 +324,7 @@ namespace build2
// by that and let run_finish() deal with it.
}
- run_finish (args, pr);
+ run_finish (args, pr, 2 /* verbosity */);
if (l.empty ())
fail << "unable to extract " << x_lang << " compiler system library "
@@ -334,9 +353,35 @@ namespace build2
//
for (string::size_type b (0);; e = l.find (d, (b = e + 1)))
{
- dir_path d (l, b, (e != string::npos ? e - b : e));
+ 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 (find (r.begin (), r.end (), d.normalize ()) == r.end ())
+ if (!d.empty () && find (r.begin (), r.end (), d) == r.end ())
r.emplace_back (move (d));
if (e == string::npos)