diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2017-06-24 11:43:45 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2017-06-24 11:43:45 +0200 |
commit | 1958b829f22e3b69d4c4c23662e0d1c7c4d2e62b (patch) | |
tree | fb94b1cba0d34e9b4cc6e1834495a9bd1e62a289 | |
parent | ff8ed209cd80799199e0b2e3d37213d549bc342f (diff) |
Make VC compatible with 'export module M;' by fixing up preprocessed output
-rw-r--r-- | build2/cc/compile.cxx | 32 | ||||
-rw-r--r-- | build2/cc/lexer.cxx | 7 | ||||
-rw-r--r-- | build2/cc/lexer.hxx | 21 | ||||
-rw-r--r-- | build2/cc/parser.cxx | 5 | ||||
-rw-r--r-- | build2/cc/parser.hxx | 3 | ||||
-rw-r--r-- | tests/cc/modules/testscript | 11 |
6 files changed, 66 insertions, 13 deletions
diff --git a/build2/cc/compile.cxx b/build2/cc/compile.cxx index eddd465..9b8f31b 100644 --- a/build2/cc/compile.cxx +++ b/build2/cc/compile.cxx @@ -2398,7 +2398,37 @@ namespace build2 // implementation units. // if (cid == compiler_id::msvc && src.is_a (*x_mod)) - tu.mod.iface = true; + { + // It's quite painful to guard the export with an #if/#endif so + // if it is present, "fixup" the (temporary) preprocessed output + // by getting rid of the keyword. + // + // Note: when removing this also remember to remove the test. + // + if (tu.mod.iface) + { + // We can only fixup a temporary file. + // + if (!ps) + fail (relative (src)) << "fixup requires preprocessor"; + + // Stomp out the export keyword with spaces. We are using + // std::fstream since our fdstream does not yet support + // seeking. + // + fstream os (psrc.path ().string (), + fstream::out | fstream::in); + + auto pos (static_cast<fstream::pos_type> (p.export_pos)); + + if (!os.is_open () || + !os.seekp (pos) || + !os.write (" ", 6)) + fail << "unable to overwrite preprocessor output"; + } + else + tu.mod.iface = true; + } return tu; } diff --git a/build2/cc/lexer.cxx b/build2/cc/lexer.cxx index faf73c8..ba6ea18 100644 --- a/build2/cc/lexer.cxx +++ b/build2/cc/lexer.cxx @@ -330,6 +330,13 @@ namespace build2 if (alpha (c) || c == '_') { + // This smells a little: we know skip_spaces() did not peek at + // the next character because this is not '/'. Which means the + // position in the stream must be of this character + 1. + // + if (buf_ != nullptr) + t.position = buf_->tellg () - 1; + string& id (t.value); id.clear (); diff --git a/build2/cc/lexer.hxx b/build2/cc/lexer.hxx index c74a0a9..65e9012 100644 --- a/build2/cc/lexer.hxx +++ b/build2/cc/lexer.hxx @@ -50,22 +50,19 @@ namespace build2 struct token { - token_type type; + token_type type = token_type::eos; string value; + // Logical position. + // path file; - uint64_t line; - uint64_t column; - - public: - token () - : token (token_type::eos, 0, 0) {} + uint64_t line = 0; + uint64_t column = 0; - token (token_type t, uint64_t l, uint64_t c) - : token (t, string (), l, c) {} - - token (token_type t, string v, uint64_t l, uint64_t c) - : type (t), value (move (v)), line (l), column (c) {} + // Physical position in the stream, currently only for identifiers and + // only if the stream is ifdstream. + // + uint64_t position = 0; }; // Output the token value in a format suitable for diagnostics. diff --git a/build2/cc/parser.cxx b/build2/cc/parser.cxx index aae49dc..df2e257 100644 --- a/build2/cc/parser.cxx +++ b/build2/cc/parser.cxx @@ -82,13 +82,18 @@ namespace build2 } else if (id == "export") { + uint64_t pos (t.position); + switch (l_->next (t)) { case type::lcbrace: ++bb; ex = true; break; case type::identifier: { if (id == "module") + { + export_pos = pos; parse_module (t, true); + } else if (id == "import") parse_import (t, true); else diff --git a/build2/cc/parser.hxx b/build2/cc/parser.hxx index 8f327cd..d542d57 100644 --- a/build2/cc/parser.hxx +++ b/build2/cc/parser.hxx @@ -37,6 +37,9 @@ namespace build2 string parse_module_name (token&); + public: + uint64_t export_pos; // Temporary hack, see parse_unit(). + private: lexer* l_; translation_unit* u_; diff --git a/tests/cc/modules/testscript b/tests/cc/modules/testscript index a65bdac..d35de50 100644 --- a/tests/cc/modules/testscript +++ b/tests/cc/modules/testscript @@ -345,3 +345,14 @@ $* test clean <<EOI exe{test}: cxx{driver} lib{foo} lib{foo}: mxx{core} cxx{core-f} # core-g @@ VC EOI + +: export-fixup +: +: Test removing the export keyword for VC compatibility. +: +ln -s ../core.cxx ../driver.cxx ./; +cat <<EOI >=core.mxx; + export module foo.core; + export int f (int); + EOI +$* test clean <'exe{test}: cxx{driver core} mxx{core}' |