aboutsummaryrefslogtreecommitdiff
path: root/build2/cxx
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2016-07-22 12:47:21 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2016-07-23 20:13:21 +0300
commit2d9579da2144b2a8d67ea1d05fde96ec9d365944 (patch)
treeb4e033f0e8284309efeecd68ba1e9cd70dc75220 /build2/cxx
parent3425432752d362341b8e39cd319d7f3c56aef169 (diff)
Adapt to fdstream extension
Diffstat (limited to 'build2/cxx')
-rw-r--r--build2/cxx/common.cxx5
-rw-r--r--build2/cxx/compile.cxx272
-rw-r--r--build2/cxx/link.cxx44
-rw-r--r--build2/cxx/msvc.cxx77
-rw-r--r--build2/cxx/windows-manifest.cxx30
-rw-r--r--build2/cxx/windows-rpath.cxx11
6 files changed, 230 insertions, 209 deletions
diff --git a/build2/cxx/common.cxx b/build2/cxx/common.cxx
index 0b66eb5..ec724a5 100644
--- a/build2/cxx/common.cxx
+++ b/build2/cxx/common.cxx
@@ -18,7 +18,10 @@ namespace build2
lorder
link_order (scope& bs, otype ot)
{
- const char* var;
+ // Initialize to suppress 'may be used uninitialized' warning produced by
+ // MinGW GCC 5.4.0.
+ //
+ const char* var (nullptr);
switch (ot)
{
diff --git a/build2/cxx/compile.cxx b/build2/cxx/compile.cxx
index 5205fdf..730ab5a 100644
--- a/build2/cxx/compile.cxx
+++ b/build2/cxx/compile.cxx
@@ -1042,180 +1042,184 @@ namespace build2
cid == "msvc" ? -2 : -1,
cid == "msvc" ? -1 : 2);
- ifdstream is (cid == "msvc" ? pr.in_efd : pr.in_ofd,
- fdtranslate::text);
-
- // In some cases we may need to ignore the error return
- // status. The good_error flag keeps track of that. Similarly
- // we sometimes expect the error return status based on the
- // output we see. The bad_error flag is for that.
- //
- bool good_error (false), bad_error (false);
-
- size_t skip (skip_count);
- for (bool first (true), second (false); !(restart || is.eof ()); )
+ try
{
- string l;
- getline (is, l);
+ // We may not read all the output (e.g., due to a restart).
+ // Before we used to just close the file descriptor to signal to
+ // the other end that we are not interested in the rest. This
+ // works fine with GCC but Clang (3.7.0) finds this impolite and
+ // complains, loudly (broken pipe). So now we are going to skip
+ // until the end.
+ //
+ ifdstream is (cid == "msvc" ? pr.in_efd : pr.in_ofd,
+ fdstream_mode::text | fdstream_mode::skip,
+ ifdstream::badbit);
+
+ // In some cases we may need to ignore the error return
+ // status. The good_error flag keeps track of that. Similarly
+ // we sometimes expect the error return status based on the
+ // output we see. The bad_error flag is for that.
+ //
+ bool good_error (false), bad_error (false);
- if (is.fail ())
+ size_t skip (skip_count);
+ for (bool first (true), second (false);
+ !(restart || is.eof ()); )
{
- if (is.eof ()) // Trailing newline.
- break;
+ string l;
+ getline (is, l);
- fail << "unable to read C++ compiler header dependency output";
- }
-
- l6 ([&]{trace << "header dependency line '" << l << "'";});
-
- // Parse different dependency output formats.
- //
- if (cid == "msvc")
- {
- if (first)
+ if (is.fail ())
{
- // The first line should be the file we are compiling. If it
- // is not, then something went wrong even before we could
- // compile anything (e.g., file does not exist). In this
- // case the first line (and everything after it) is
- // presumably diagnostics.
- //
- if (l != s.path ().leaf ().string ())
- {
- text << l;
- bad_error = true;
+ if (is.eof ()) // Trailing newline.
break;
- }
- first = false;
- continue;
+ throw ifdstream::failure ("");
}
- string f (next_show (l, good_error));
-
- if (f.empty ()) // Some other diagnostics.
- {
- text << l;
- bad_error = true;
- break;
- }
+ l6 ([&]{trace << "header dependency line '" << l << "'";});
- // Skip until where we left off.
+ // Parse different dependency output formats.
//
- if (skip != 0)
+ if (cid == "msvc")
{
- // We can't be skipping over a non-existent header.
- //
- assert (!good_error);
- skip--;
- }
- else
- {
- restart = add (path (move (f)), false);
- skip_count++;
+ if (first)
+ {
+ // The first line should be the file we are compiling. If
+ // it is not, then something went wrong even before we
+ // could compile anything (e.g., file does not exist). In
+ // this case the first line (and everything after it) is
+ // presumably diagnostics.
+ //
+ if (l != s.path ().leaf ().string ())
+ {
+ text << l;
+ bad_error = true;
+ break;
+ }
+
+ first = false;
+ continue;
+ }
- // If the header does not exist, we better restart.
- //
- assert (!good_error || restart);
+ string f (next_show (l, good_error));
- if (restart)
- l6 ([&]{trace << "restarting";});
- }
- }
- else
- {
- // Make dependency declaration.
- //
- size_t pos (0);
-
- if (first)
- {
- // Empty output should mean the wait() call below will
- // return false.
- //
- if (l.empty ())
+ if (f.empty ()) // Some other diagnostics.
{
+ text << l;
bad_error = true;
break;
}
- assert (l[0] == '^' && l[1] == ':' && l[2] == ' ');
-
- first = false;
- second = true;
-
- // While normally we would have the source file on the first
- // line, if too long, it will be moved to the next line and
- // all we will have on this line is "^: \".
+ // Skip until where we left off.
//
- if (l.size () == 4 && l[3] == '\\')
- continue;
+ if (skip != 0)
+ {
+ // We can't be skipping over a non-existent header.
+ //
+ assert (!good_error);
+ skip--;
+ }
else
- pos = 3; // Skip "^: ".
+ {
+ restart = add (path (move (f)), false);
+ skip_count++;
- // Fall through to the 'second' block.
- }
+ // If the header does not exist, we better restart.
+ //
+ assert (!good_error || restart);
- if (second)
- {
- second = false;
- next_make (l, pos); // Skip the source file.
+ if (restart)
+ l6 ([&]{trace << "restarting";});
+ }
}
-
- while (pos != l.size ())
+ else
{
- string f (next_make (l, pos));
-
- // Skip until where we left off.
+ // Make dependency declaration.
//
- if (skip != 0)
+ size_t pos (0);
+
+ if (first)
{
- skip--;
- continue;
+ // Empty output should mean the wait() call below will
+ // return false.
+ //
+ if (l.empty ())
+ {
+ bad_error = true;
+ break;
+ }
+
+ assert (l[0] == '^' && l[1] == ':' && l[2] == ' ');
+
+ first = false;
+ second = true;
+
+ // While normally we would have the source file on the
+ // first line, if too long, it will be moved to the next
+ // line and all we will have on this line is "^: \".
+ //
+ if (l.size () == 4 && l[3] == '\\')
+ continue;
+ else
+ pos = 3; // Skip "^: ".
+
+ // Fall through to the 'second' block.
}
- restart = add (path (move (f)), false);
- skip_count++;
+ if (second)
+ {
+ second = false;
+ next_make (l, pos); // Skip the source file.
+ }
- if (restart)
+ while (pos != l.size ())
{
- l6 ([&]{trace << "restarting";});
- break;
+ string f (next_make (l, pos));
+
+ // Skip until where we left off.
+ //
+ if (skip != 0)
+ {
+ skip--;
+ continue;
+ }
+
+ restart = add (path (move (f)), false);
+ skip_count++;
+
+ if (restart)
+ {
+ l6 ([&]{trace << "restarting";});
+ break;
+ }
}
}
}
- }
- // We may not have read all the output (e.g., due to a restart).
- // Before we used to just close the file descriptor to signal to
- // the other end that we are not interested in the rest. This
- // works fine with GCC but Clang (3.7.0) finds this impolite and
- // complains, loudly (broken pipe). So now we are going to skip
- // until the end.
- //
- // Also, in case of VC++, we are parsing stderr and if things go
- // south, we need to copy the diagnostics for the user to see.
- //
- if (!is.eof ())
- {
- if (cid == "msvc" && bad_error)
+ // In case of VC++, we are parsing stderr and if things go south,
+ // we need to copy the diagnostics for the user to see.
+ //
+ if (!is.eof () && cid == "msvc" && bad_error)
*diag_stream << is.rdbuf ();
- else
- is.ignore (numeric_limits<streamsize>::max ());
- }
- is.close ();
+ is.close ();
- // We assume the child process issued some diagnostics.
- //
- if (!pr.wait ())
+ // We assume the child process issued some diagnostics.
+ //
+ if (!pr.wait ())
+ {
+ if (!good_error) // Ignore expected errors (restart).
+ throw failed ();
+ }
+ else if (bad_error)
+ fail << "expected error exist status from C++ compiler";
+ }
+ catch (const ifdstream::failure&)
{
- if (!good_error) // Ignore expected errors (restart).
- throw failed ();
+ pr.wait ();
+ fail << "unable to read C++ compiler header dependency output";
}
- else if (bad_error)
- fail << "expected error exist status from C++ compiler";
-
}
catch (const process_error& e)
{
diff --git a/build2/cxx/link.cxx b/build2/cxx/link.cxx
index e714bc1..19bf6d9 100644
--- a/build2/cxx/link.cxx
+++ b/build2/cxx/link.cxx
@@ -56,27 +56,31 @@ namespace build2
try
{
process pr (args.data (), 0, -1); // Open pipe to stdout.
- ifdstream is (pr.in_ofd);
- while (!is.eof ())
+ try
{
- string s;
- getline (is, s);
-
- if (is.fail () && !is.eof ())
- fail << "error reading C++ compiler -print-search-dirs output";
+ ifdstream is (pr.in_ofd, fdstream_mode::skip, ifdstream::badbit);
- if (s.compare (0, 12, "libraries: =") == 0)
+ string s;
+ while (getline (is, s))
{
- l.assign (s, 12, string::npos);
- break;
+ if (s.compare (0, 12, "libraries: =") == 0)
+ {
+ l.assign (s, 12, string::npos);
+ break;
+ }
}
- }
- is.close (); // Don't block.
+ is.close (); // Don't block.
- if (!pr.wait ())
- throw failed ();
+ if (!pr.wait ())
+ throw failed ();
+ }
+ catch (const ifdstream::failure&)
+ {
+ pr.wait ();
+ fail << "error reading C++ compiler -print-search-dirs output";
+ }
}
catch (const process_error& e)
{
@@ -1147,7 +1151,6 @@ namespace build2
try
{
ofdstream os (pr.out_fd);
- os.exceptions (ofdstream::badbit | ofdstream::failbit);
// 1 is resource ID, 24 is RT_MANIFEST. We also need to escape
// Windows path backslashes.
@@ -1170,15 +1173,16 @@ namespace build2
os << "\"" << endl;
os.close ();
+
+ if (!pr.wait ())
+ throw failed (); // Assume diagnostics issued.
}
- catch (const ofdstream::failure&)
+ catch (const ofdstream::failure& e)
{
if (pr.wait ()) // Ignore if child failed.
- fail << "unable to pipe resource file to " << args[0];
+ fail << "unable to pipe resource file to " << args[0]
+ << ": " << e.what ();
}
-
- if (!pr.wait ())
- throw failed (); // Assume diagnostics issued.
}
catch (const process_error& e)
{
diff --git a/build2/cxx/msvc.cxx b/build2/cxx/msvc.cxx
index 97d8fd5..294ac03 100644
--- a/build2/cxx/msvc.cxx
+++ b/build2/cxx/msvc.cxx
@@ -89,56 +89,63 @@ namespace build2
// redirect stderr to stdout.
//
process pr (start_run (args, false));
- ifdstream is (pr.in_ofd);
bool obj (false), dll (false);
-
string s;
- while (getline (is, s))
- {
- // Detect the one error we should let through.
- //
- if (s.compare (0, 18, "unable to execute ") == 0)
- break;
- // The lines we are interested in seem to have this form (though
- // presumably the "Archive member name at" part can be translated):
- //
- // Archive member name at 746: [...]hello.dll[/][ ]*
- // Archive member name at 8C70: [...]hello.lib.obj[/][ ]*
- //
- size_t n (s.size ());
-
- for (; n != 0 && s[n - 1] == ' '; --n) ; // Skip trailing spaces.
+ try
+ {
+ ifdstream is (pr.in_ofd, fdstream_mode::skip, ifdstream::badbit);
- if (n >= 7) // At least ": X.obj" or ": X.dll".
+ while (getline (is, s))
{
- --n;
-
- if (s[n] == '/') // Skip trailing slash if one is there.
+ // Detect the one error we should let through.
+ //
+ if (s.compare (0, 18, "unable to execute ") == 0)
+ break;
+
+ // The lines we are interested in seem to have this form (though
+ // presumably the "Archive member name at" part can be translated):
+ //
+ // Archive member name at 746: [...]hello.dll[/][ ]*
+ // Archive member name at 8C70: [...]hello.lib.obj[/][ ]*
+ //
+ size_t n (s.size ());
+
+ for (; n != 0 && s[n - 1] == ' '; --n) ; // Skip trailing spaces.
+
+ if (n >= 7) // At least ": X.obj" or ": X.dll".
+ {
--n;
- n -= 3; // Beginning of extension.
+ if (s[n] == '/') // Skip trailing slash if one is there.
+ --n;
- if (s[n] == '.')
- {
- // Make sure there is ": ".
- //
- size_t p (s.rfind (':', n - 1));
+ n -= 3; // Beginning of extension.
- if (p != string::npos && s[p + 1] == ' ')
+ if (s[n] == '.')
{
- if (s.compare (n + 1, 3, "obj") == 0) // @@ CASE
- obj = true;
-
- if (s.compare (n + 1, 3, "dll") == 0) // @@ CASE
- dll = true;
+ // Make sure there is ": ".
+ //
+ size_t p (s.rfind (':', n - 1));
+
+ if (p != string::npos && s[p + 1] == ' ')
+ {
+ if (s.compare (n + 1, 3, "obj") == 0) // @@ CASE
+ obj = true;
+
+ if (s.compare (n + 1, 3, "dll") == 0) // @@ CASE
+ dll = true;
+ }
}
}
}
}
-
- is.close (); // Don't block.
+ catch (const ifdstream::failure&)
+ {
+ // Presumably the child process failed. Let finish_run() deal with
+ // that.
+ }
if (!finish_run (args, false, pr, s))
return otype::e;
diff --git a/build2/cxx/windows-manifest.cxx b/build2/cxx/windows-manifest.cxx
index cabc6ca..915610d 100644
--- a/build2/cxx/windows-manifest.cxx
+++ b/build2/cxx/windows-manifest.cxx
@@ -2,8 +2,6 @@
// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
-#include <fstream>
-
#include <build2/scope>
#include <build2/target>
#include <build2/context>
@@ -103,12 +101,19 @@ namespace build2
if (file_exists (mf))
{
- ifstream ifs (mf.string ());
- string s;
- getline (ifs, s, '\0');
-
- if (s == m)
- return mf;
+ try
+ {
+ ifdstream ifs (mf);
+ string s;
+ getline (ifs, s, '\0');
+
+ if (s == m)
+ return mf;
+ }
+ catch (const ifdstream::failure&)
+ {
+ // Whatever the reason we failed for , let's rewrite the file.
+ }
}
if (verb >= 3)
@@ -116,14 +121,13 @@ namespace build2
try
{
- ofstream ofs;
- ofs.exceptions (ofstream::failbit | ofstream::badbit);
- ofs.open (mf.string (), ofstream::out | ofstream::trunc);
+ ofdstream ofs (mf);
ofs << m;
+ ofs.close ();
}
- catch (const ofstream::failure&)
+ catch (const ofdstream::failure& e)
{
- fail << "unable to write to " << m;
+ fail << "unable to write to " << m << ": " << e.what ();
}
return mf;
diff --git a/build2/cxx/windows-rpath.cxx b/build2/cxx/windows-rpath.cxx
index b5bad5e..b52315c 100644
--- a/build2/cxx/windows-rpath.cxx
+++ b/build2/cxx/windows-rpath.cxx
@@ -5,7 +5,6 @@
#include <errno.h> // E*
#include <set>
-#include <fstream>
#include <build2/scope>
#include <build2/context>
@@ -167,9 +166,7 @@ namespace build2
try
{
- ofstream ofs;
- ofs.exceptions (ofstream::failbit | ofstream::badbit);
- ofs.open (am.string ());
+ ofdstream ofs (am);
ofs << "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>\n"
<< "<assembly xmlns='urn:schemas-microsoft-com:asm.v1'\n"
@@ -265,10 +262,12 @@ namespace build2
}
ofs << "</assembly>\n";
+
+ ofs.close ();
}
- catch (const ofstream::failure&)
+ catch (const ofdstream::failure& e)
{
- fail << "unable to write to " << am;
+ fail << "unable to write to " << am << ": " << e.what ();
}
}
}