diff options
Diffstat (limited to 'libbuild2/cc/msvc.cxx')
-rw-r--r-- | libbuild2/cc/msvc.cxx | 261 |
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); } } } |