aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/cc/msvc.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/cc/msvc.cxx')
-rw-r--r--libbuild2/cc/msvc.cxx261
1 files changed, 169 insertions, 92 deletions
diff --git a/libbuild2/cc/msvc.cxx b/libbuild2/cc/msvc.cxx
index 0b8491b..d21969c 100644
--- a/libbuild2/cc/msvc.cxx
+++ b/libbuild2/cc/msvc.cxx
@@ -164,18 +164,21 @@ namespace build2
// Filter cl.exe and link.exe noise.
//
+ // Note: must be followed with the dbuf.read() call.
+ //
void
- msvc_filter_cl (ifdstream& is, const path& src)
+ msvc_filter_cl (diag_buffer& dbuf, const path& src)
+ try
{
// While it appears VC always prints the source name (event if the
// file does not exist), let's do a sanity check. Also handle the
// command line errors/warnings which come before the file name.
//
- for (string l; !eof (getline (is, l)); )
+ for (string l; !eof (getline (dbuf.is, l)); )
{
if (l != src.leaf ().string ())
{
- diag_stream_lock () << l << endl;
+ dbuf.write (l, true /* newline */);
if (msvc_sense_diag (l, 'D').first != string::npos)
continue;
@@ -184,14 +187,19 @@ namespace build2
break;
}
}
+ catch (const io_error& e)
+ {
+ fail << "unable to read from " << dbuf.args0 << " stderr: " << e;
+ }
void
- msvc_filter_link (ifdstream& is, const file& t, otype lt)
+ msvc_filter_link (diag_buffer& dbuf, const file& t, otype lt)
+ try
{
// Filter lines until we encounter something we don't recognize. We also
// have to assume the messages can be translated.
//
- for (string l; getline (is, l); )
+ for (string l; getline (dbuf.is, l); )
{
// " Creating library foo\foo.dll.lib and object foo\foo.dll.exp"
//
@@ -216,12 +224,15 @@ namespace build2
// /INCREMENTAL causes linker to sometimes issue messages but now I
// can't quite reproduce it.
- //
- diag_stream_lock () << l << endl;
+ dbuf.write (l, true /* newline */);
break;
}
}
+ catch (const io_error& e)
+ {
+ fail << "unable to read from " << dbuf.args0 << " stderr: " << e;
+ }
void
msvc_extract_header_search_dirs (const strings& v, dir_paths& r)
@@ -233,12 +244,15 @@ namespace build2
dir_path d;
try
{
- // -I can either be in the "-Ifoo" or "-I foo" form. For VC it can
- // also be /I.
+ // -I can either be in the "-Ifoo" or "-I foo" form. For MSVC it can
+ // also be /I. And from 16.10 it can also be /external:I.
//
- if (o.size () > 1 && (o[0] == '-' || o[0] == '/') && o[1] == 'I')
+ size_t p;
+ if ((o[0] == '-' || o[0] == '/') &&
+ (p = (o[1] == 'I' ? 2 :
+ o.compare (1, 10, "external:I") == 0 ? 11 : 0)) != 0)
{
- if (o.size () == 2)
+ if (o.size () == p)
{
if (++i == e)
break; // Let the compiler complain.
@@ -246,10 +260,17 @@ namespace build2
d = dir_path (*i);
}
else
- d = dir_path (o, 2, string::npos);
+ d = dir_path (o, p, string::npos);
}
else
continue;
+
+ // Ignore relative paths. Or maybe we should warn?
+ //
+ if (d.relative ())
+ continue;
+
+ d.normalize ();
}
catch (const invalid_path& e)
{
@@ -257,10 +278,7 @@ namespace build2
<< o << "'";
}
- // Ignore relative paths. Or maybe we should warn?
- //
- if (!d.relative ())
- r.push_back (move (d));
+ r.push_back (move (d));
}
}
@@ -281,6 +299,13 @@ namespace build2
d = dir_path (o, 9, string::npos);
else
continue;
+
+ // Ignore relative paths. Or maybe we should warn?
+ //
+ if (d.relative ())
+ continue;
+
+ d.normalize ();
}
catch (const invalid_path& e)
{
@@ -288,62 +313,72 @@ namespace build2
<< o << "'";
}
- // Ignore relative paths. Or maybe we should warn?
- //
- if (!d.relative ())
- r.push_back (move (d));
+ r.push_back (move (d));
+ }
+ }
+
+ // Parse semicolon-separated list of search directories (from INCLUDE/LIB
+ // environment variables).
+ //
+ static void
+ parse_search_dirs (const string& v, dir_paths& r, const char* what)
+ {
+ for (size_t b (0), e (0); next_word (v, b, e, ';'); )
+ {
+ string d (v, b, e - b);
+ trim (d);
+
+ if (!d.empty ())
+ {
+ try
+ {
+ r.push_back (dir_path (move (d)).normalize ());
+ }
+ catch (const invalid_path&)
+ {
+ fail << "invalid path '" << d << "' in " << what;
+ }
+ }
}
}
// Extract system header search paths from MSVC.
//
pair<dir_paths, size_t> config_module::
- msvc_header_search_dirs (const process_path&, scope& rs) const
+ msvc_header_search_dirs (const compiler_info&, scope& rs) const
{
- // The compiler doesn't seem to have any built-in paths and all of them
- // either come from the INCLUDE environment variable or are specified
- // explicitly on the command line (we now do this if running out of the
- // command prompt; see guess).
-
- // @@ VC: how are we going to do this? E.g., cl-14 does this internally.
- // cl.exe /Be prints INCLUDE. One advantage of going through the
- // compiler is that it may be a wrapper (like our msvc-linux). Note
- // also that we will still have to incorporate mode options. And this
- // is not used for Clang targeting MSVC.
- //
- // Should we actually bother? INCLUDE is normally used for system
- // headers and its highly unlikely we will see an imported library
- // that lists one of those directories in pkg-config Cflags value.
- // So the only benefit is to be able to print them. Let's wait and
- // see.
+ // MSVC doesn't have any built-in paths and all of them either come from
+ // the INCLUDE environment variable or are specified explicitly on the
+ // command line (we now do this if running out of the command prompt;
+ // see guess). Note that this is not used for Clang targeting MSVC (but
+ // is for clang-cl).
- // Extract -I paths from the compiler mode.
+ // Extract /I and similar paths from the compiler mode.
//
dir_paths r;
msvc_extract_header_search_dirs (cast<strings> (rs[x_mode]), r);
size_t rn (r.size ());
+ // @@ This does not work for our msvc-linux wrappers which set the
+ // environment variable internally. One way to make this work would
+ // be run `cl.exe /Be` which prints INCLUDE and LIB (but not for
+ // clang-cl).
+ //
+ if (optional<string> v = getenv ("INCLUDE"))
+ parse_search_dirs (*v, r, "INCLUDE environment variable");
+
return make_pair (move (r), rn);
}
// Extract system library search paths from MSVC.
//
pair<dir_paths, size_t> config_module::
- msvc_library_search_dirs (const process_path&, scope& rs) const
+ msvc_library_search_dirs (const compiler_info&, scope& rs) const
{
- // The linker doesn't seem to have any built-in paths and all of them
- // either come from the LIB environment variable or are specified
- // explicitly on the command line (we now do this if running out of the
- // command prompt; see guess).
-
- // @@ VC: how are we going to do this? E.g., cl-14 does this internally.
- // cl.exe /Be prints LIB. See above for further discussion.
- //
- // Should we actually bother? LIB is normally used for system
- // libraries and its highly unlikely we will see an explicit import
- // for a library from one of those directories. So the only benefit
- // is to be able to print them. Let's wait and see.
- //
+ // MSVC doesn't seem to have any built-in paths and all of them either
+ // come from the LIB environment variable or are specified explicitly on
+ // the command line (we now do this if running out of the command
+ // prompt; see guess). See the header case above for details.
// Extract /LIBPATH paths from the compiler mode.
//
@@ -351,15 +386,34 @@ namespace build2
msvc_extract_library_search_dirs (cast<strings> (rs[x_mode]), r);
size_t rn (r.size ());
+ // @@ This does not work for our msvc-linux wrappers (see above for
+ // details).
+ //
+ if (optional<string> v = getenv ("LIB"))
+ parse_search_dirs (*v, r, "LIB environment variable");
+
return make_pair (move (r), rn);
}
// Inspect the file and determine if it is static or import library.
// Return otype::e if it is neither (which we quietly ignore).
//
+ static global_cache<otype> library_type_cache;
+
static otype
library_type (const process_path& ld, const path& l)
{
+ string key;
+ {
+ sha256 cs;
+ cs.append (ld.effect_string ());
+ cs.append (l.string ());
+ key = cs.string ();
+
+ if (const otype* r = library_type_cache.find (key))
+ return *r;
+ }
+
// The are several reasonably reliable methods to tell whether it is a
// static or import library. One is lib.exe /LIST -- if there aren't any
// .obj members, then it is most likely an import library (it can also
@@ -400,13 +454,14 @@ namespace build2
//
process pr (run_start (ld,
args,
- 0 /* stdin */,
- -1 /* stdout */,
- false /* error */));
+ 0 /* stdin */,
+ -1 /* stdout */,
+ 1 /* stderr (to stdout) */));
bool obj (false), dll (false);
string s;
+ bool io (false);
try
{
ifdstream is (
@@ -424,14 +479,11 @@ namespace build2
// libhello\hello.lib.obj
// hello-0.1.0-a.0.19700101000000.dll
//
- // 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".
+ if (n >= 5) // At least "X.obj" or "X.dll".
{
n -= 4; // Beginning of extension.
@@ -446,14 +498,18 @@ namespace build2
}
}
}
+
+ is.close ();
}
catch (const io_error&)
{
- // Presumably the child process failed. Let run_finish() deal with
- // that.
+ // Presumably the child process failed so let run_finish() deal with
+ // that first.
+ //
+ io = true;
}
- if (!run_finish_code (args, pr, s))
+ if (!run_finish_code (args, pr, s, 2 /* verbosity */) || io)
{
diag_record dr;
dr << warn << "unable to detect " << l << " library type, ignoring" <<
@@ -462,23 +518,25 @@ namespace build2
return otype::e;
}
- if (obj && dll)
+ otype r;
+ if (obj != dll)
+ r = obj ? otype::a : otype::s;
+ else
{
- warn << l << " looks like hybrid static/import library, ignoring";
- return otype::e;
- }
+ if (obj && dll)
+ warn << l << " looks like hybrid static/import library, ignoring";
- if (!obj && !dll)
- {
- warn << l << " looks like empty static or import library, ignoring";
- return otype::e;
+ if (!obj && !dll)
+ warn << l << " looks like empty static or import library, ignoring";
+
+ r = otype::e;
}
- return obj ? otype::a : otype::s;
+ return library_type_cache.insert (move (key), r);
}
template <typename T>
- static T*
+ static pair<T*, bool>
msvc_search_library (const process_path& ld,
const dir_path& d,
const prerequisite_key& p,
@@ -524,20 +582,26 @@ namespace build2
//
timestamp mt (mtime (f));
- if (mt != timestamp_nonexistent && library_type (ld, f) == lt)
+ pair<T*, bool> r (nullptr, true);
+
+ if (mt != timestamp_nonexistent)
{
- // Enter the target.
- //
- T* t;
- common::insert_library (p.scope->ctx, t, name, d, ld, e, exist, trace);
- t->path_mtime (move (f), mt);
- return t;
+ if (library_type (ld, f) == lt)
+ {
+ // Enter the target.
+ //
+ common::insert_library (
+ p.scope->ctx, r.first, name, d, ld, e, exist, trace);
+ r.first->path_mtime (move (f), mt);
+ }
+ else
+ r.second = false; // Don't search for binless.
}
- return nullptr;
+ return r;
}
- liba* common::
+ pair<bin::liba*, bool> common::
msvc_search_static (const process_path& ld,
const dir_path& d,
const prerequisite_key& p,
@@ -545,14 +609,21 @@ namespace build2
{
tracer trace (x, "msvc_search_static");
- liba* r (nullptr);
+ liba* a (nullptr);
+ bool b (true);
- auto search = [&r, &ld, &d, &p, exist, &trace] (
+ auto search = [&a, &b, &ld, &d, &p, exist, &trace] (
const char* pf, const char* sf) -> bool
{
- r = msvc_search_library<liba> (
- ld, d, p, otype::a, pf, sf, exist, trace);
- return r != nullptr;
+ pair<liba*, bool> r (msvc_search_library<liba> (
+ ld, d, p, otype::a, pf, sf, exist, trace));
+
+ if (r.first != nullptr)
+ a = r.first;
+ else if (!r.second)
+ b = false;
+
+ return a != nullptr;
};
// Try:
@@ -565,10 +636,10 @@ namespace build2
search ("", "") ||
search ("lib", "") ||
search ("", "lib") ||
- search ("", "_static") ? r : nullptr;
+ search ("", "_static") ? make_pair (a, true) : make_pair (nullptr, b);
}
- libs* common::
+ pair<bin::libs*, bool> common::
msvc_search_shared (const process_path& ld,
const dir_path& d,
const prerequisite_key& pk,
@@ -579,12 +650,14 @@ namespace build2
assert (pk.scope != nullptr);
libs* s (nullptr);
+ bool b (true);
- auto search = [&s, &ld, &d, &pk, exist, &trace] (
+ auto search = [&s, &b, &ld, &d, &pk, exist, &trace] (
const char* pf, const char* sf) -> bool
{
- if (libi* i = msvc_search_library<libi> (
- ld, d, pk, otype::s, pf, sf, exist, trace))
+ pair<libi*, bool> r (msvc_search_library<libi> (
+ ld, d, pk, otype::s, pf, sf, exist, trace));
+ if (r.first != nullptr)
{
ulock l (
insert_library (
@@ -592,6 +665,8 @@ namespace build2
if (!exist)
{
+ libi* i (r.first);
+
if (l.owns_lock ())
{
s->adhoc_member = i; // We are first.
@@ -605,6 +680,8 @@ namespace build2
s->path_mtime (path (), i->mtime ());
}
}
+ else if (!r.second)
+ b = false;
return s != nullptr;
};
@@ -617,7 +694,7 @@ namespace build2
return
search ("", "") ||
search ("lib", "") ||
- search ("", "dll") ? s : nullptr;
+ search ("", "dll") ? make_pair (s, true) : make_pair (nullptr, b);
}
}
}