From 2d9579da2144b2a8d67ea1d05fde96ec9d365944 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Fri, 22 Jul 2016 12:47:21 +0300 Subject: Adapt to fdstream extension --- build2/b.cxx | 3 + build2/cli/module.cxx | 50 +++++--- build2/config/operation.cxx | 25 ++-- build2/cxx/common.cxx | 5 +- build2/cxx/compile.cxx | 272 ++++++++++++++++++++-------------------- build2/cxx/link.cxx | 44 ++++--- build2/cxx/msvc.cxx | 77 ++++++------ build2/cxx/windows-manifest.cxx | 30 +++-- build2/cxx/windows-rpath.cxx | 11 +- build2/file.cxx | 40 +++--- build2/parser.cxx | 23 +--- build2/utility.cxx | 2 +- build2/utility.txx | 28 +++-- 13 files changed, 311 insertions(+), 299 deletions(-) (limited to 'build2') 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::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 #include -#include #include #include @@ -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::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 - #include #include #include @@ -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 // E* #include -#include #include #include @@ -167,9 +166,7 @@ namespace build2 try { - ofstream ofs; - ofs.exceptions (ofstream::failbit | ofstream::badbit); - ofs.open (am.string ()); + ofdstream ofs (am); ofs << "\n" << "\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 -#include #include // cin #include // 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 #include // is{alpha alnum}() -#include #include #include @@ -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 (); -- cgit v1.1