aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/cc/guess.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/cc/guess.cxx')
-rw-r--r--libbuild2/cc/guess.cxx371
1 files changed, 260 insertions, 111 deletions
diff --git a/libbuild2/cc/guess.cxx b/libbuild2/cc/guess.cxx
index 9409604..d7e9c63 100644
--- a/libbuild2/cc/guess.cxx
+++ b/libbuild2/cc/guess.cxx
@@ -106,7 +106,7 @@ namespace build2
else if (id.compare (0, p, "icc" ) == 0) type = compiler_type::icc;
else
throw invalid_argument (
- "invalid compiler type '" + string (id, 0, p) + "'");
+ "invalid compiler type '" + string (id, 0, p) + '\'');
if (p != string::npos)
{
@@ -181,12 +181,12 @@ namespace build2
// could also be because there is something wrong with the compiler or
// options but that we simply leave to blow up later).
//
- process pr (run_start (3 /* verbosity */,
+ process pr (run_start (3 /* verbosity */,
xp,
args,
- -1 /* stdin */,
- -1 /* stdout */,
- false /* error */));
+ -1 /* stdin */,
+ -1 /* stdout */,
+ 1 /* stderr (to stdout) */));
string l, r;
try
{
@@ -222,7 +222,7 @@ namespace build2
// that.
}
- if (!run_finish_code (args.data (), pr, l))
+ if (!run_finish_code (args.data (), pr, l, 2 /* verbosity */))
r = "none";
if (r.empty ())
@@ -412,11 +412,13 @@ namespace build2
//
// Note that Visual Studio versions prior to 15.0 are not supported.
//
+ // Note also the directories are absolute and normalized.
+ //
struct msvc_info
{
- dir_path msvc_dir; // VC directory (...\Tools\MSVC\<ver>\).
- dir_path psdk_dir; // Platfor SDK version (under Include/, Lib/, etc).
- string psdk_ver; // Platfor SDK directory (...\Windows Kits\<ver>\).
+ dir_path msvc_dir; // VC tools directory (...\Tools\MSVC\<ver>\).
+ dir_path psdk_dir; // Platform SDK directory (...\Windows Kits\<ver>\).
+ string psdk_ver; // Platform SDK version (under Include/, Lib/, etc).
};
#if defined(_WIN32) && !defined(BUILD2_BOOTSTRAP)
@@ -458,13 +460,16 @@ namespace build2
{0x87, 0xBF, 0xD5, 0x77, 0x83, 0x8F, 0x1D, 0x5C}};
// If cl is not empty, then find an installation that contains this cl.exe
- // path.
+ // path. In this case the path must be absolute and normalized.
//
static optional<msvc_info>
- find_msvc (const path& cl = path ())
+ find_msvc (const path& cl = path ())
{
using namespace butl;
+ assert (cl.empty () ||
+ (cl.absolute () && cl.normalized (false /* sep */)));
+
msvc_info r;
// Try to obtain the MSVC directory.
@@ -530,7 +535,7 @@ namespace build2
// Note: we cannot use bstr_t due to the Clang 9.0 bug #42842.
//
BSTR p;
- if (vs->ResolvePath (L"VC", &p) != S_OK)
+ if (vs->ResolvePath (L"VC", &p) != S_OK)
return dir_path ();
unique_ptr<wchar_t, bstr_deleter> deleter (p);
@@ -636,36 +641,73 @@ namespace build2
return nullopt;
}
- // Read the VC version from the file and bail out on error.
+ // If cl.exe path is not specified, then deduce the default VC tools
+ // directory for this Visual Studio instance. Otherwise, extract the
+ // tools directory from this path.
//
- string vc_ver; // For example, 14.23.28105.
+ // Note that in the latter case we could potentially avoid the above
+ // iterating over the VS instances, but let's make sure that the
+ // specified cl.exe path actually belongs to one of them as a sanity
+ // check.
+ //
+ if (cl.empty ())
+ {
+ // Read the VC version from the file and bail out on error.
+ //
+ string vc_ver; // For example, 14.23.28105.
- path vp (
- r.msvc_dir /
- path ("Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt"));
+ path vp (
+ r.msvc_dir /
+ path ("Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt"));
- try
- {
- ifdstream is (vp);
- vc_ver = trim (is.read_text ());
- }
- catch (const io_error&) {}
+ try
+ {
+ ifdstream is (vp);
+ vc_ver = trim (is.read_text ());
+ }
+ catch (const io_error&) {}
- // Make sure that the VC version directory exists.
- //
- if (!vc_ver.empty ())
- try
- {
- ((r.msvc_dir /= "Tools") /= "MSVC") /= vc_ver;
+ if (vc_ver.empty ())
+ return nullopt;
+
+ // Make sure that the VC version directory exists.
+ //
+ try
+ {
+ ((r.msvc_dir /= "Tools") /= "MSVC") /= vc_ver;
- if (!dir_exists (r.msvc_dir))
- r.msvc_dir.clear ();
+ if (!dir_exists (r.msvc_dir))
+ return nullopt;
+ }
+ catch (const invalid_path&) {return nullopt;}
+ catch (const system_error&) {return nullopt;}
}
- catch (const invalid_path&) {}
- catch (const system_error&) {}
+ else
+ {
+ (r.msvc_dir /= "Tools") /= "MSVC";
- if (r.msvc_dir.empty ())
- return nullopt;
+ // Extract the VC tools version from the cl.exe path and append it
+ // to r.msvc_dir.
+ //
+ if (!cl.sub (r.msvc_dir))
+ return nullopt;
+
+ // For example, 14.23.28105\bin\Hostx64\x64\cl.exe.
+ //
+ path p (cl.leaf (r.msvc_dir)); // Can't throw.
+
+ auto i (p.begin ()); // Tools version.
+ if (i == p.end ())
+ return nullopt;
+
+ r.msvc_dir /= *i; // Can't throw.
+
+ // For good measure, make sure that the tools version is not the
+ // last component in the cl.exe path.
+ //
+ if (++i == p.end ())
+ return nullopt;
+ }
}
// Try to obtain the latest Platform SDK directory and version.
@@ -719,7 +761,7 @@ namespace build2
//
for (const dir_entry& de:
dir_iterator (r.psdk_dir / dir_path ("Include"),
- false /* ignore_dangling */))
+ dir_iterator::no_follow))
{
if (de.type () == entry_type::directory)
{
@@ -737,6 +779,16 @@ namespace build2
return nullopt;
}
+ try
+ {
+ r.msvc_dir.normalize ();
+ r.psdk_dir.normalize ();
+ }
+ catch (const invalid_path&)
+ {
+ return nullopt;
+ }
+
return r;
}
#endif
@@ -777,7 +829,8 @@ namespace build2
// Note: allowed to change pre if succeeds.
//
static guess_result
- guess (const char* xm,
+ guess (context& ctx,
+ const char* xm,
lang xl,
const path& xc,
const strings& x_mo,
@@ -928,10 +981,12 @@ namespace build2
// We try to find the matching installation only for MSVC (for Clang
// we extract this information from the compiler).
//
- if (xc.absolute () &&
- (pt == type::msvc && !pv))
+ if (xc.absolute () && (pt == type::msvc && !pv))
{
- if (optional<msvc_info> mi = find_msvc (xc))
+ path cl (xc); // Absolute but may not be normalized.
+ cl.normalize (); // Can't throw since this is an existing path.
+
+ if (optional<msvc_info> mi = find_msvc (cl))
{
search_info = info_ptr (
new msvc_info (move (*mi)), msvc_info_deleter);
@@ -967,7 +1022,7 @@ namespace build2
#endif
string cache;
- auto run = [&cs, &env, &args, &cache] (
+ auto run = [&ctx, &cs, &env, &args, &cache] (
const char* o,
auto&& f,
bool checksum = false) -> guess_result
@@ -975,9 +1030,10 @@ namespace build2
args[args.size () - 2] = o;
cache.clear ();
return build2::run<guess_result> (
+ ctx,
3 /* verbosity */,
env,
- args.data (),
+ args,
forward<decltype (f)> (f),
false /* error */,
false /* ignore_exit */,
@@ -1024,7 +1080,7 @@ namespace build2
// The gcc -v output will have a last line in the form:
//
- // "gcc version X.Y[.Z][...] ..."
+ // "gcc version X[.Y[.Z]][...] ..."
//
// The "version" word can probably be translated. For example:
//
@@ -1036,6 +1092,7 @@ namespace build2
// gcc version 5.1.0 (Ubuntu 5.1.0-0ubuntu11~14.04.1)
// gcc version 6.0.0 20160131 (experimental) (GCC)
// gcc version 9.3-win32 20200320 (GCC)
+ // gcc version 10-win32 20220324 (GCC)
//
if (cache.empty ())
{
@@ -1275,7 +1332,11 @@ namespace build2
//
const char* evars[] = {"CL=", "_CL_=", nullptr};
- r = build2::run<guess_result> (3, process_env (xp, evars), f, false);
+ r = build2::run<guess_result> (ctx,
+ 3,
+ process_env (xp, evars),
+ f,
+ false);
if (r.empty ())
{
@@ -1426,10 +1487,12 @@ namespace build2
// And VC 16 seems to have the runtime version 14.1 (and not 14.2, as
// one might expect; DLLs are still *140.dll but there are now _1 and _2
// variants for, say, msvcp140.dll). We will, however, call it 14.2
- // (which is the version of the "toolset") in our target triplet.
+ // (which is the version of the "toolset") in our target triplet. And we
+ // will call VC 17 14.3 (which is also the version of the "toolset").
//
// year ver cl crt/dll toolset
//
+ // 2022 17.X 19.3X 14.?/140 14.3X
// 2019 16.X 19.2X 14.2/140 14.2X
// 2017 15.9 19.16 14.1/140 14.16
// 2017 15.8 19.15 14.1/140
@@ -1448,7 +1511,8 @@ namespace build2
//
// _MSC_VER is the numeric cl version, e.g., 1921 for 19.21.
//
- /**/ if (v.major == 19 && v.minor >= 20) return "14.2";
+ /**/ if (v.major == 19 && v.minor >= 30) return "14.3";
+ else if (v.major == 19 && v.minor >= 20) return "14.2";
else if (v.major == 19 && v.minor >= 10) return "14.1";
else if (v.major == 19 && v.minor == 0) return "14.0";
else if (v.major == 18 && v.minor == 0) return "12.0";
@@ -1472,8 +1536,8 @@ namespace build2
// Studio command prompt puts into INCLUDE) including any paths from the
// compiler mode and their count.
//
- // Note that currently we don't add any ATL/MFC or WinRT paths (but could
- // do that probably first checking if they exist/empty).
+ // Note that currently we don't add any ATL/MFC paths (but could do that
+ // probably first checking if they exist/empty).
//
static pair<dir_paths, size_t>
msvc_hdr (const msvc_info& mi, const strings& mo)
@@ -1485,6 +1549,8 @@ namespace build2
msvc_extract_header_search_dirs (mo, r);
size_t rn (r.size ());
+ // Note: the resulting directories are normalized by construction.
+ //
r.push_back (dir_path (mi.msvc_dir) /= "include");
// This path structure only appeared in Platform SDK 10 (if anyone wants
@@ -1498,6 +1564,7 @@ namespace build2
r.push_back (dir_path (d) /= "ucrt" );
r.push_back (dir_path (d) /= "shared");
r.push_back (dir_path (d) /= "um" );
+ r.push_back (dir_path (d) /= "winrt" );
}
return make_pair (move (r), rn);
@@ -1533,6 +1600,8 @@ namespace build2
msvc_extract_library_search_dirs (mo, r);
size_t rn (r.size ());
+ // Note: the resulting directories are normalized by construction.
+ //
r.push_back ((dir_path (mi.msvc_dir) /= "lib") /= cpu);
// This path structure only appeared in Platform SDK 10 (if anyone wants
@@ -1587,7 +1656,8 @@ namespace build2
"LIB", "LINK", "_LINK_", nullptr};
static compiler_info
- guess_msvc (const char* xm,
+ guess_msvc (context&,
+ const char* xm,
lang xl,
const path& xc,
const string* xv,
@@ -1706,7 +1776,7 @@ namespace build2
//
// OS-ABI is where things are not as clear cut. The OS part shouldn't
// probably be just 'windows' since we have Win32 and WinCE. And
- // WinRT. And Universal Windows Platform (UWP). So perhaps the
+ // WinRT. And Universal Windows Platform (UWP). So perhaps the
// following values for OS: 'win32', 'wince', 'winrt', 'winup'.
//
// For 'win32' the ABI part could signal the Microsoft C/C++ runtime
@@ -1858,7 +1928,8 @@ namespace build2
"SDKROOT", "MACOSX_DEPLOYMENT_TARGET", nullptr};
static compiler_info
- guess_gcc (const char* xm,
+ guess_gcc (context& ctx,
+ const char* xm,
lang xl,
const path& xc,
const string* xv,
@@ -1877,7 +1948,7 @@ namespace build2
// though language words can be translated and even rearranged (see
// examples above).
//
- // "gcc version X.Y[.Z][...]"
+ // "gcc version X[.Y[.Z]][...]"
//
compiler_version ver;
{
@@ -1916,7 +1987,10 @@ namespace build2
//
try
{
- semantic_version v (string (s, b, e - b), ".-+");
+ semantic_version v (string (s, b, e - b),
+ semantic_version::allow_omit_minor |
+ semantic_version::allow_build,
+ ".-+");
ver.major = v.major;
ver.minor = v.minor;
ver.patch = v.patch;
@@ -1968,7 +2042,7 @@ namespace build2
//
auto f = [] (string& l, bool) {return move (l);};
- t = run<string> (3, xp, args.data (), f, false);
+ t = run<string> (ctx, 3, xp, args, f, false);
if (t.empty ())
{
@@ -1976,7 +2050,7 @@ namespace build2
<< "falling back to -dumpmachine";});
args[args.size () - 2] = "-dumpmachine";
- t = run<string> (3, xp, args.data (), f, false);
+ t = run<string> (ctx, 3, xp, args, f, false);
}
if (t.empty ())
@@ -2119,9 +2193,9 @@ namespace build2
process pr (run_start (3 /* verbosity */,
xp,
args,
- -2 /* stdin (/dev/null) */,
- -1 /* stdout */,
- false /* error (2>&1) */));
+ -2 /* stdin (to /dev/null) */,
+ -1 /* stdout */,
+ 1 /* stderr (to stdout) */));
clang_msvc_info r;
@@ -2273,7 +2347,7 @@ namespace build2
// that.
}
- if (!run_finish_code (args.data (), pr, l))
+ if (!run_finish_code (args.data (), pr, l, 2 /* verbosity */))
fail << "unable to extract MSVC information from " << xp;
if (const char* w = (
@@ -2291,23 +2365,27 @@ namespace build2
// These are derived from gcc_* plus the sparse documentation (clang(1))
// and source code.
//
+ // Note that for now for Clang targeting MSVC we use msvc_env but should
+ // probably use a combined list.
+ //
// See also the note on environment and caching below if adding any new
// variables.
//
static const char* clang_c_env[] = {
- "CPATH", "C_INCLUDE_PATH",
+ "CPATH", "C_INCLUDE_PATH", "CCC_OVERRIDE_OPTIONS",
"LIBRARY_PATH", "LD_RUN_PATH",
"COMPILER_PATH",
nullptr};
static const char* clang_cxx_env[] = {
- "CPATH", "CPLUS_INCLUDE_PATH",
+ "CPATH", "CPLUS_INCLUDE_PATH", "CCC_OVERRIDE_OPTIONS",
"LIBRARY_PATH", "LD_RUN_PATH",
"COMPILER_PATH",
nullptr};
static compiler_info
- guess_clang (const char* xm,
+ guess_clang (context& ctx,
+ const char* xm,
lang xl,
const path& xc,
const string* xv,
@@ -2346,6 +2424,12 @@ namespace build2
//
// emcc (...) 2.0.8
//
+ // Pre-releases of the vanilla Clang append `rc` or `git` to the
+ // version, unfortunately without a separator. So we will handle these
+ // ad hoc. For example:
+ //
+ // FreeBSD clang version 18.1.0rc (https://github.com/llvm/llvm-project.git llvmorg-18-init-18361-g22683463740e)
+ //
auto extract_version = [] (const string& s, bool patch, const char* what)
-> compiler_version
{
@@ -2360,8 +2444,28 @@ namespace build2
// end of the word position (first space). In fact, we can just
// check if it is >= e.
//
- if (s.find_first_not_of ("1234567890.", b, 11) >= e)
+ size_t p (s.find_first_not_of ("1234567890.", b, 11));
+ if (p >= e)
break;
+
+ // Handle the unseparated `rc` and `git` suffixes.
+ //
+ if (p != string::npos)
+ {
+ if (p + 2 == e && (e - b) > 2 &&
+ s[p] == 'r' && s[p + 1] == 'c')
+ {
+ e -= 2;
+ break;
+ }
+
+ if (p + 3 == e && (e - b) > 3 &&
+ s[p] == 'g' && s[p + 1] == 'i' && s[p + 2] == 't')
+ {
+ e -= 3;
+ break;
+ }
+ }
}
if (b == e)
@@ -2397,7 +2501,14 @@ namespace build2
ver.patch = next ("patch", patch);
if (e != s.size ())
- ver.build.assign (s, e + 1, string::npos);
+ {
+ // Skip the separator (it could also be unseparated `rc` or `git`).
+ //
+ if (s[e] == ' ' || s[e] == '-')
+ e++;
+
+ ver.build.assign (s, e, string::npos);
+ }
return ver;
};
@@ -2421,7 +2532,10 @@ namespace build2
// Some overrides for testing.
//
+ //string s (xv != nullptr ? *xv : "");
+ //
//s = "clang version 3.7.0 (tags/RELEASE_370/final)";
+ //s = "FreeBSD clang version 18.1.0rc (https://github.com/llvm/llvm-project.git llvmorg-18-init-18361-g22683463740e)";
//
//gr.id.variant = "apple";
//s = "Apple LLVM version 7.3.0 (clang-703.0.16.1)";
@@ -2449,10 +2563,21 @@ namespace build2
//
// Specifically, we now look in the libc++'s __config file for the
// _LIBCPP_VERSION and use the previous version as a conservative
- // estimate (note that there could be multiple __config files with
+ // estimate (NOTE: that there could be multiple __config files with
// potentially different versions so compile with -v to see which one
// gets picked up).
//
+ // Also, lately, we started seeing _LIBCPP_VERSION values like 15.0.6
+ // or 16.0.2 which would suggest the base is 15.0.5 or 16.0.1. But
+ // that assumption did not check out with the actual usage. For
+ // example, vanilla Clang 16 should no longer require -fmodules-ts but
+ // the Apple's version (that is presumably based on it) still does. So
+ // the theory here is that Apple upgrades to newer libc++ while
+ // keeping the old compiler. Which means we must be more conservative
+ // and assume something like 15.0.6 is still 14-based. But then you
+ // get -Wunqualified-std-cast-call in 14, which was supposedly only
+ // introduced in Clang 15. So maybe not.
+ //
// Note that this is Apple Clang version and not XCode version.
//
// 4.2 -> 3.2svn
@@ -2472,34 +2597,41 @@ namespace build2
// 12.0.0 -> 9.0
// 12.0.5 -> 10.0 (yes, seriously!)
// 13.0.0 -> 11.0
+ // 13.1.6 -> 12.0
+ // 14.0.0 -> 12.0 (_LIBCPP_VERSION=130000)
+ // 14.0.3 -> 15.0 (_LIBCPP_VERSION=150006)
+ // 15.0.0 -> 16.0 (_LIBCPP_VERSION=160002)
//
uint64_t mj (var_ver->major);
uint64_t mi (var_ver->minor);
uint64_t pa (var_ver->patch);
- if (mj >= 13) {mj = 11; mi = 0;}
- else if (mj == 12 && (mi > 0 || pa >= 5)) {mj = 10; mi = 0;}
- else if (mj == 12) {mj = 9; mi = 0;}
- else if (mj == 11 && (mi > 0 || pa >= 3)) {mj = 8; mi = 0;}
- else if (mj == 11) {mj = 7; mi = 0;}
- else if (mj == 10) {mj = 6; mi = 0;}
- else if (mj == 9 && mi >= 1) {mj = 5; mi = 0;}
- else if (mj == 9) {mj = 4; mi = 0;}
- else if (mj == 8) {mj = 3; mi = 9;}
- else if (mj == 7 && mi >= 3) {mj = 3; mi = 8;}
- else if (mj == 7) {mj = 3; mi = 7;}
- else if (mj == 6 && mi >= 1) {mj = 3; mi = 5;}
- else if (mj == 6) {mj = 3; mi = 4;}
- else if (mj == 5 && mi >= 1) {mj = 3; mi = 3;}
- else if (mj == 5) {mj = 3; mi = 2;}
- else if (mj == 4 && mi >= 2) {mj = 3; mi = 1;}
- else {mj = 3; mi = 0;}
+ if (mj >= 15) {mj = 16; mi = 0; pa = 0;}
+ else if (mj == 14 && (mi > 0 || pa >= 3)) {mj = 15; mi = 0; pa = 0;}
+ else if (mj == 14 || (mj == 13 && mi >= 1)) {mj = 12; mi = 0; pa = 0;}
+ else if (mj == 13) {mj = 11; mi = 0; pa = 0;}
+ else if (mj == 12 && (mi > 0 || pa >= 5)) {mj = 10; mi = 0; pa = 0;}
+ else if (mj == 12) {mj = 9; mi = 0; pa = 0;}
+ else if (mj == 11 && (mi > 0 || pa >= 3)) {mj = 8; mi = 0; pa = 0;}
+ else if (mj == 11) {mj = 7; mi = 0; pa = 0;}
+ else if (mj == 10) {mj = 6; mi = 0; pa = 0;}
+ else if (mj == 9 && mi >= 1) {mj = 5; mi = 0; pa = 0;}
+ else if (mj == 9) {mj = 4; mi = 0; pa = 0;}
+ else if (mj == 8) {mj = 3; mi = 9; pa = 0;}
+ else if (mj == 7 && mi >= 3) {mj = 3; mi = 8; pa = 0;}
+ else if (mj == 7) {mj = 3; mi = 7; pa = 0;}
+ else if (mj == 6 && mi >= 1) {mj = 3; mi = 5; pa = 0;}
+ else if (mj == 6) {mj = 3; mi = 4; pa = 0;}
+ else if (mj == 5 && mi >= 1) {mj = 3; mi = 3; pa = 0;}
+ else if (mj == 5) {mj = 3; mi = 2; pa = 0;}
+ else if (mj == 4 && mi >= 2) {mj = 3; mi = 1; pa = 0;}
+ else {mj = 3; mi = 0; pa = 0;}
ver = compiler_version {
- to_string (mj) + '.' + to_string (mi) + ".0",
+ to_string (mj) + '.' + to_string (mi) + '.' + to_string (pa),
mj,
mi,
- 0,
+ pa,
""};
}
else if (emscr)
@@ -2552,7 +2684,7 @@ namespace build2
// for LC_ALL.
//
auto f = [] (string& l, bool) {return move (l);};
- t = run<string> (3, xp, args.data (), f, false);
+ t = run<string> (ctx, 3, xp, args, f, false);
if (t.empty ())
fail << "unable to extract target architecture from " << xc
@@ -2612,7 +2744,7 @@ namespace build2
const char* cpu (msvc_cpu (tt.cpu));
// Come up with the system library search paths. Ideally we would want
- // to extract this from Clang and -print-search-paths would have been
+ // to extract this from Clang and -print-search-dirs would have been
// the natural way for Clang to report it. But no luck.
//
lib_dirs = msvc_lib (mi, x_mo, cpu);
@@ -2780,7 +2912,8 @@ namespace build2
}
static compiler_info
- guess_icc (const char* xm,
+ guess_icc (context& ctx,
+ const char* xm,
lang xl,
const path& xc,
const string* xv,
@@ -2844,7 +2977,7 @@ namespace build2
//
// @@ TODO: running without the mode options.
//
- s = run<string> (3, env, "-V", f, false);
+ s = run<string> (ctx, 3, env, "-V", f, false);
if (s.empty ())
fail << "unable to extract signature from " << xc << " -V output";
@@ -2970,7 +3103,7 @@ namespace build2
// The -V output is sent to STDERR.
//
- t = run<string> (3, env, args.data (), f, false);
+ t = run<string> (ctx, 3, env, args, f, false);
if (t.empty ())
fail << "unable to extract target architecture from " << xc
@@ -3021,7 +3154,7 @@ namespace build2
//
{
auto f = [] (string& l, bool) {return move (l);};
- t = run<string> (3, xp, "-dumpmachine", f);
+ t = run<string> (ctx, 3, xp, "-dumpmachine", f);
}
if (t.empty ())
@@ -3102,7 +3235,8 @@ namespace build2
static global_cache<compiler_info> cache;
const compiler_info&
- guess (const char* xm,
+ guess (context& ctx,
+ const char* xm,
lang xl,
const string& ec,
const path& xc,
@@ -3176,7 +3310,7 @@ namespace build2
if (pre.type != invalid_compiler_type)
{
- gr = guess (xm, xl, xc, x_mo, xi, pre, cs);
+ gr = guess (ctx, xm, xl, xc, x_mo, xi, pre, cs);
if (gr.empty ())
{
@@ -3192,13 +3326,14 @@ namespace build2
}
if (gr.empty ())
- gr = guess (xm, xl, xc, x_mo, xi, pre, cs);
+ gr = guess (ctx, xm, xl, xc, x_mo, xi, pre, cs);
if (gr.empty ())
fail << "unable to guess " << xl << " compiler type of " << xc <<
info << "use config." << xm << ".id to specify explicitly";
compiler_info (*gf) (
+ context&,
const char*, lang, const path&, const string*, const string*,
const strings&,
const strings*, const strings*,
@@ -3218,7 +3353,8 @@ namespace build2
case compiler_type::icc: gf = &guess_icc; break;
}
- compiler_info r (gf (xm, xl, xc, xv, xt,
+ compiler_info r (gf (ctx,
+ xm, xl, xc, xv, xt,
x_mo, c_po, x_po, c_co, x_co, c_lo, x_lo,
move (gr), cs));
@@ -3376,6 +3512,7 @@ namespace build2
// In the future we will probably have to maintain per-standard additions.
//
static const char* std_importable[] = {
+ "<initializer_list>", // Note: keep first (present in freestanding).
"<algorithm>",
"<any>",
"<array>",
@@ -3400,7 +3537,6 @@ namespace build2
"<fstream>",
"<functional>",
"<future>",
- "<initializer_list>",
"<iomanip>",
"<ios>",
"<iosfwd>",
@@ -3499,6 +3635,9 @@ namespace build2
// is currently not provided by GCC. Though entering missing headers
// should be harmless.
//
+ // Plus, a freestanding implementation may only have a subset of such
+ // headers (see [compliance]).
+ //
pair<const path, importable_headers::groups>* p;
auto add_groups = [&p] (bool imp)
{
@@ -3520,29 +3659,39 @@ namespace build2
}
else
{
+ // While according to [compliance] a freestanding implementation
+ // should provide a subset of headers, including <initializer_list>,
+ // there seem to be cases where no headers are provided at all (see GH
+ // issue #219). So if we cannot find <initializer_list>, we just skip
+ // the whole thing.
+ //
p = hs.insert_angle (sys_hdr_dirs, std_importable[0]);
- assert (p != nullptr);
- add_groups (true);
+ if (p != nullptr)
+ {
+ assert (p != nullptr);
- dir_path d (p->first.directory ());
+ add_groups (true);
- auto add_header = [&hs, &d, &p, add_groups] (const char* f, bool imp)
- {
- path fp (d);
- fp.combine (f + 1, strlen (f) - 2, '\0'); // Assuming simple.
+ dir_path d (p->first.directory ());
- p = &hs.insert_angle (move (fp), f);
- add_groups (imp);
- };
+ auto add_header = [&hs, &d, &p, add_groups] (const char* f, bool imp)
+ {
+ path fp (d);
+ fp.combine (f + 1, strlen (f) - 2, '\0'); // Assuming simple.
- for (size_t i (1);
- i != sizeof (std_importable) / sizeof (std_importable[0]);
- ++i)
- add_header (std_importable[i], true);
+ p = &hs.insert_angle (move (fp), f);
+ add_groups (imp);
+ };
- for (const char* f: std_non_importable)
- add_header (f, false);
+ for (size_t i (1);
+ i != sizeof (std_importable) / sizeof (std_importable[0]);
+ ++i)
+ add_header (std_importable[i], true);
+
+ for (const char* f: std_non_importable)
+ add_header (f, false);
+ }
}
}
}