aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/b.cxx3
-rw-r--r--build2/cli/module.cxx50
-rw-r--r--build2/config/operation.cxx25
-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
-rw-r--r--build2/file.cxx40
-rw-r--r--build2/parser.cxx23
-rw-r--r--build2/utility.cxx2
-rw-r--r--build2/utility.txx28
13 files changed, 311 insertions, 299 deletions
diff --git a/build2/b.cxx b/build2/b.cxx
index d16c0c6..748eda7 100644
--- a/build2/b.cxx
+++ b/build2/b.cxx
@@ -168,6 +168,9 @@ main (int argc, char* argv[])
//
return p.wait () ? 0 : 1;
}
+ // Catch ios_base::failure as std::system_error together with the
+ // pager-specific exceptions.
+ //
catch (const system_error& e)
{
error << "pager failed: " << e.what ();
diff --git a/build2/cli/module.cxx b/build2/cli/module.cxx
index e604bcf..a9bed86 100644
--- a/build2/cli/module.cxx
+++ b/build2/cli/module.cxx
@@ -102,34 +102,42 @@ namespace build2
if (verb >= 3)
print_process (args);
- string ver;
try
{
process pr (args, 0, -1); // Open pipe to stdout.
- ifdstream is (pr.in_ofd);
- // The version should be the last word on the first line.
- //
- getline (is, ver);
- auto p (ver.rfind (' '));
- if (p != string::npos)
- ver = string (ver, p + 1);
+ try
+ {
+ ifdstream is (pr.in_ofd, fdstream_mode::skip);
- // Skip until the end as cli doesn't handle writing to the closed
- // pipe very well (SIGPIPE).
- //
- if (is.good ())
- is.ignore (numeric_limits<streamsize>::max ());
+ // The version should be the last word on the first line.
+ //
+ string ver;
+ getline (is, ver);
+ auto p (ver.rfind (' '));
+ if (p != string::npos)
+ ver = string (ver, p + 1);
- is.close (); // Don't block the other end.
+ is.close (); // Don't block the other end.
- if (!pr.wait ()) // Presumably issued diagnostics.
- return string (); // Not found.
+ if (pr.wait ())
+ {
+ if (ver.empty ())
+ fail << "unexpected output from " << cli;
- if (ver.empty ())
- fail << "unexpected output from " << cli;
+ return ver;
+ }
- return ver;
+ // Presumably issued diagnostics. Fall through.
+ }
+ catch (const ifdstream::failure&)
+ {
+ pr.wait ();
+
+ // Fall through.
+ }
+
+ // Fall through.
}
catch (const process_error& e)
{
@@ -143,8 +151,10 @@ namespace build2
if (e.child ())
exit (1);
- return string (); // Not found.
+ // Fall through.
}
+
+ return string (); // Not found.
};
string ver; // Empty means unconfigured.
diff --git a/build2/config/operation.cxx b/build2/config/operation.cxx
index 1b40832..617e74c 100644
--- a/build2/config/operation.cxx
+++ b/build2/config/operation.cxx
@@ -5,7 +5,6 @@
#include <build2/config/operation>
#include <set>
-#include <fstream>
#include <build2/file>
#include <build2/scope>
@@ -48,21 +47,19 @@ namespace build2
try
{
- ofstream ofs (f.string ());
- if (!ofs.is_open ())
- fail << "unable to open " << f;
-
- ofs.exceptions (ofstream::failbit | ofstream::badbit);
+ ofdstream ofs (f);
ofs << "# Created automatically by the config module." << endl
<< "#" << endl
<< "src_root = ";
to_stream (ofs, name (src_root), true, '@'); // Quote.
ofs << endl;
+
+ ofs.close ();
}
- catch (const ofstream::failure&)
+ catch (const ofdstream::failure& e)
{
- fail << "unable to write " << f;
+ fail << "unable to write " << f << ": " << e.what ();
}
}
@@ -79,11 +76,7 @@ namespace build2
try
{
- ofstream ofs (f.string ());
- if (!ofs.is_open ())
- fail << "unable to open " << f;
-
- ofs.exceptions (ofstream::failbit | ofstream::badbit);
+ ofdstream ofs (f);
ofs << "# Created automatically by the config module, but feel " <<
"free to edit." << endl
@@ -248,10 +241,12 @@ namespace build2
ofs << n << " = [null]" << endl;
}
}
+
+ ofs.close ();
}
- catch (const ofstream::failure&)
+ catch (const ofdstream::failure& e)
{
- fail << "unable to write " << f;
+ fail << "unable to write " << f << ": " << e.what ();
}
}
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 ();
}
}
}
diff --git a/build2/file.cxx b/build2/file.cxx
index 9ab01ce..2030d1c 100644
--- a/build2/file.cxx
+++ b/build2/file.cxx
@@ -4,7 +4,6 @@
#include <build2/file>
-#include <fstream>
#include <iostream> // cin
#include <butl/filesystem> // file_exists()
@@ -85,26 +84,23 @@ namespace build2
{
bool sin (bf.string () == "-");
- ifstream ifs;
- if (!sin)
- {
- ifs.open (bf.string ());
+ ifdstream ifs;
- if (!ifs.is_open ())
- fail << "unable to open " << bf;
- }
+ if (!sin)
+ ifs.open (bf);
+ else
+ cin.exceptions (ifdstream::failbit | ifdstream::badbit);
- istream& is (sin ? std::cin : ifs);
- is.exceptions (ifstream::failbit | ifstream::badbit);
+ istream& is (sin ? cin : ifs);
l5 ([&]{trace << "sourcing " << bf;});
parser p (boot);
p.parse_buildfile (is, bf, root, base);
}
- catch (const ifstream::failure&)
+ catch (const ifdstream::failure& e)
{
- fail << "unable to read buildfile " << bf;
+ fail << "unable to read buildfile " << bf << ": " << e.what ();
}
}
@@ -274,11 +270,7 @@ namespace build2
{
try
{
- ifstream ifs (bf.string ());
- if (!ifs.is_open ())
- fail << "unable to open " << bf;
-
- ifs.exceptions (ifstream::failbit | ifstream::badbit);
+ ifdstream ifs (bf);
lexer lex (ifs, bf);
token t (lex.next ());
@@ -303,9 +295,9 @@ namespace build2
assert (v != nullptr);
return move (*v); // Steal the value, the scope is going away.
}
- catch (const ifstream::failure&)
+ catch (const ifdstream::failure& e)
{
- fail << "unable to read buildfile " << bf;
+ fail << "unable to read buildfile " << bf << ": " << e.what ();
}
return value (); // Never reaches.
@@ -973,11 +965,7 @@ namespace build2
try
{
- ifstream ifs (es.string ());
- if (!ifs.is_open ())
- fail (loc) << "unable to open " << es;
-
- ifs.exceptions (ifstream::failbit | ifstream::badbit);
+ ifdstream ifs (es);
l5 ([&]{trace << "importing " << es;});
@@ -988,9 +976,9 @@ namespace build2
parser p;
return p.parse_export_stub (ifs, es, iroot, ts);
}
- catch (const ifstream::failure&)
+ catch (const ifdstream::failure& e)
{
- fail (loc) << "unable to read buildfile " << es;
+ fail (loc) << "unable to read buildfile " << es << ": " << e.what ();
}
return names (); // Never reached.
diff --git a/build2/parser.cxx b/build2/parser.cxx
index 04accd2..99e4227 100644
--- a/build2/parser.cxx
+++ b/build2/parser.cxx
@@ -5,7 +5,6 @@
#include <build2/parser>
#include <cctype> // is{alpha alnum}()
-#include <fstream>
#include <iostream>
#include <build2/version>
@@ -735,12 +734,7 @@ namespace build2
try
{
- ifstream ifs (p.string ());
-
- if (!ifs.is_open ())
- fail (l) << "unable to open " << p;
-
- ifs.exceptions (ifstream::failbit | ifstream::badbit);
+ ifdstream ifs (p);
l5 ([&]{trace (t) << "entering " << p;});
@@ -766,9 +760,9 @@ namespace build2
lexer_ = ol;
path_ = op;
}
- catch (const ifstream::failure&)
+ catch (const ifdstream::failure& e)
{
- fail (l) << "unable to read buildfile " << p;
+ fail (l) << "unable to read buildfile " << p << ": " << e.what ();
}
}
@@ -871,12 +865,7 @@ namespace build2
try
{
- ifstream ifs (p.string ());
-
- if (!ifs.is_open ())
- fail (l) << "unable to open " << p;
-
- ifs.exceptions (ifstream::failbit | ifstream::badbit);
+ ifdstream ifs (p);
l5 ([&]{trace (t) << "entering " << p;});
@@ -908,9 +897,9 @@ namespace build2
lexer_ = ol;
path_ = op;
}
- catch (const ifstream::failure&)
+ catch (const ifdstream::failure& e)
{
- fail (l) << "unable to read buildfile " << p;
+ fail (l) << "unable to read buildfile " << p << ": " << e.what ();
}
scope_ = ocs;
diff --git a/build2/utility.cxx b/build2/utility.cxx
index 15a0aee..c43d048 100644
--- a/build2/utility.cxx
+++ b/build2/utility.cxx
@@ -126,7 +126,7 @@ namespace build2
// want to let through is the inability to execute the program itself.
// We cannot reserve a special exit status to signal this so we will
// just have to compare the output. This particular situation will
- // result in a single error line printed by run_start() above.
+ // result in a single error line printed by start_run() above.
//
if (l.compare (0, 18, "unable to execute ") == 0)
fail << l;
diff --git a/build2/utility.txx b/build2/utility.txx
index bf9d9ab..a00f3fb 100644
--- a/build2/utility.txx
+++ b/build2/utility.txx
@@ -13,24 +13,30 @@ namespace build2
sha256* checksum)
{
process pr (start_run (args, err));
- ifdstream is (pr.in_ofd);
T r;
-
string l; // Last line of output.
- while (is.peek () != ifdstream::traits_type::eof () && // Keep last line.
- getline (is, l))
+
+ try
{
- trim (l);
+ ifdstream is (pr.in_ofd);
- if (checksum != nullptr)
- checksum->append (l);
+ while (is.peek () != ifdstream::traits_type::eof () && // Keep last line.
+ getline (is, l))
+ {
+ trim (l);
- if (r.empty ())
- r = f (l);
- }
+ if (checksum != nullptr)
+ checksum->append (l);
- is.close (); // Don't block.
+ if (r.empty ())
+ r = f (l);
+ }
+ }
+ catch (const ifdstream::failure&)
+ {
+ // Presumably the child process failed. Let finish_run() deal with that.
+ }
if (!(finish_run (args, err, pr, l) || ignore_exit))
r = T ();