aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-07-26 11:51:45 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-07-26 11:51:45 +0200
commitbf497c1f7716e6d904245409bfe65cb8970fe4ae (patch)
tree22d73f63933330039d8c883637263d0dc903c41c
parent896c2e1af6a8a82c976651d757115ea1033e7b82 (diff)
Implement module map storage in .d, use -fmodule-file-map in GCC
-rw-r--r--build2/cc/compile.cxx57
-rw-r--r--build2/cc/compile.hxx2
-rw-r--r--build2/depdb.cxx45
-rw-r--r--build2/depdb.hxx23
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<file> ().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<string> (f.vars[c_module_name]));
- s.insert (0, "-fmodule-file=");
+ //s.insert (0, 1, '=');
+ //s.insert (0, cast<string> (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<streamsize> (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