From bf497c1f7716e6d904245409bfe65cb8970fe4ae Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 26 Jul 2017 11:51:45 +0200 Subject: Implement module map storage in .d, use -fmodule-file-map in GCC --- build2/cc/compile.cxx | 57 +++++++++++++++++++++++++++++++++++++++++++-------- build2/cc/compile.hxx | 2 +- build2/depdb.cxx | 45 ++++++++++++++++++++++++++++++++++++---- build2/depdb.hxx | 23 ++++++++++++++------- 4 files changed, 106 insertions(+), 21 deletions(-) diff --git a/build2/cc/compile.cxx b/build2/cc/compile.cxx index bd54f35..c5ab236 100644 --- a/build2/cc/compile.cxx +++ b/build2/cc/compile.cxx @@ -681,6 +681,9 @@ namespace build2 fsdir_rule::perform_update_direct (act, t); } + // Note: the leading '@' is reserved for the module map prefix (see + // extract_modules()) and no other line must start with it. + // md.dd = tp + ".d"; depdb dd (md.dd); @@ -2641,12 +2644,38 @@ namespace build2 sha256 cs; if (!mi.imports.empty ()) - md.mods = search_modules ( - act, t, lo, tt.bmi, src, move (mi.imports), cs); + md.mods = search_modules (act, t, lo, tt.bmi, src, mi.imports, cs); if (dd.expect (cs.string ()) != nullptr) updating = true; + // Save the module map for compilers that use it. + // + if (cid == compiler_id::gcc && md.mods.start != 0) + { + // We don't need to redo this if the above hash hasn't changed and the + // database is valid. + // + if (dd.writing () || !dd.skip ()) + { + const auto& pts (t.prerequisite_targets); + + for (size_t i (md.mods.start); i != pts.size (); ++i) + { + if (const target* m = pts[i]) + { + // Save a variable lookup by getting the module name from the + // import list (see search_modules()). + // + dd.write ('@', false); + dd.write (mi.imports[i - md.mods.start].name, false); + dd.write ('=', false); + dd.write (m->as ().path ()); + } + } + } + } + // Set the cc.module_name variable if this is an interface unit. Note // that it may seem like a good idea to set it on the bmi{} group to // avoid duplication. We, however, cannot do it MT-safely since we don't @@ -2678,7 +2707,7 @@ namespace build2 lorder lo, const target_type& mtt, const file& src, - module_imports&& imports, + module_imports& imports, sha256& cs) const { tracer trace (x, "compile::search_modules"); @@ -3179,10 +3208,19 @@ namespace build2 // switch (cid) { - case compiler_id::clang: n = ms.copied != 0 ? ms.copied : n; break; case compiler_id::gcc: - case compiler_id::msvc: break; // All of them. - case compiler_id::icc: assert (false); + { + // Use the module map stored in depdb. + // + string s (relative (md.dd).string ()); + s.insert (0, "-fmodule-file-map=@="); + stor.push_back (move (s)); + n = ms.start; // Don't add individual entries below. + break; + } + case compiler_id::clang: n = ms.copied != 0 ? ms.copied : n; break; + case compiler_id::msvc: break; // All of them. + case compiler_id::icc: assert (false); } dir_path stdifc; // See the VC case below. @@ -3204,9 +3242,10 @@ namespace build2 { case compiler_id::gcc: { - s.insert (0, 1, '='); - s.insert (0, cast (f.vars[c_module_name])); - s.insert (0, "-fmodule-file="); + //s.insert (0, 1, '='); + //s.insert (0, cast (f.vars[c_module_name])); + //s.insert (0, "-fmodule-file="); + assert (false); break; } case compiler_id::clang: diff --git a/build2/cc/compile.hxx b/build2/cc/compile.hxx index 7bf182e..afd0cfc 100644 --- a/build2/cc/compile.hxx +++ b/build2/cc/compile.hxx @@ -115,7 +115,7 @@ namespace build2 module_positions search_modules (action, file&, lorder, const target_type&, - const file&, module_imports&&, sha256&) const; + const file&, module_imports&, sha256&) const; void append_modules (environment&, cstrings&, strings&, diff --git a/build2/depdb.cxx b/build2/depdb.cxx index 5aa2970..c74536c 100644 --- a/build2/depdb.cxx +++ b/build2/depdb.cxx @@ -123,8 +123,41 @@ namespace build2 return &line_; } + bool depdb:: + skip () + { + if (state_ == state::read_eof) + return true; + + assert (state_ == state::read); + + // The rest is pretty similar in logic to read_() above. + // + pos_ = fs_.tellg (); + + // Keep reading lines checking for the end marker after each newline. + // + fstream::int_type c; + do + { + if ((c = fs_.get ()) == '\n') + { + if ((c = fs_.get ()) == '\0') + { + state_ = state::read_eof; + return true; + } + } + } while (c != fstream::traits_type::eof ()); + + // Invalid database so change over to writing. + // + change (); + return false; + } + void depdb:: - write (const char* s, size_t n) + write (const char* s, size_t n, bool nl) { // Switch to writing if we are still reading. // @@ -132,11 +165,13 @@ namespace build2 change (); fs_.write (s, static_cast (n)); - fs_.put ('\n'); + + if (nl) + fs_.put ('\n'); } void depdb:: - write (char c) + write (char c, bool nl) { // Switch to writing if we are still reading. // @@ -144,7 +179,9 @@ namespace build2 change (); fs_.put (c); - fs_.put ('\n'); + + if (nl) + fs_.put ('\n'); } void depdb:: diff --git a/build2/depdb.hxx b/build2/depdb.hxx index b747096..da45a4a 100644 --- a/build2/depdb.hxx +++ b/build2/depdb.hxx @@ -117,23 +117,32 @@ namespace build2 bool touched () const {return touch_;} - // Write the next line. Note that this switches the database into the - // write mode and no further reading will be possible. + // Skip to the end of the database and return true if it is valid. + // Otherwise, return false, in which case the database must be + // overwritten. Note that this function expects the database to be in the + // read state. + // + bool + skip (); + + // Write the next line. If nl is false then don't write the newline yet. + // Note that this switches the database into the write mode and no further + // reading will be possible. // void - write (const string& l) {write (l.c_str (), l.size ());} + write (const string& l, bool nl = true) {write (l.c_str (), l.size (), nl);} void - write (const path& p) {write (p.string ());} + write (const path& p, bool nl = true) {write (p.string (), nl);} void - write (const char* s) {write (s, std::strlen (s));} + write (const char* s, bool nl = true) {write (s, std::strlen (s), nl);} void - write (const char*, size_t); + write (const char*, size_t, bool nl = true); void - write (char); + write (char, bool nl = true); // Read the next line and compare it to the expected value. If it matches, // return NULL. Otherwise, overwrite it and return the old value (which -- cgit v1.1